/ commands / advisor.ts
advisor.ts
  1  import type { Command } from '../commands.js'
  2  import type { LocalCommandCall } from '../types/command.js'
  3  import {
  4    canUserConfigureAdvisor,
  5    isValidAdvisorModel,
  6    modelSupportsAdvisor,
  7  } from '../utils/advisor.js'
  8  import {
  9    getDefaultMainLoopModelSetting,
 10    normalizeModelStringForAPI,
 11    parseUserSpecifiedModel,
 12  } from '../utils/model/model.js'
 13  import { validateModel } from '../utils/model/validateModel.js'
 14  import { updateSettingsForSource } from '../utils/settings/settings.js'
 15  
 16  const call: LocalCommandCall = async (args, context) => {
 17    const arg = args.trim().toLowerCase()
 18    const baseModel = parseUserSpecifiedModel(
 19      context.getAppState().mainLoopModel ?? getDefaultMainLoopModelSetting(),
 20    )
 21  
 22    if (!arg) {
 23      const current = context.getAppState().advisorModel
 24      if (!current) {
 25        return {
 26          type: 'text',
 27          value:
 28            'Advisor: not set\nUse "/advisor <model>" to enable (e.g. "/advisor opus").',
 29        }
 30      }
 31      if (!modelSupportsAdvisor(baseModel)) {
 32        return {
 33          type: 'text',
 34          value: `Advisor: ${current} (inactive)\nThe current model (${baseModel}) does not support advisors.`,
 35        }
 36      }
 37      return {
 38        type: 'text',
 39        value: `Advisor: ${current}\nUse "/advisor unset" to disable or "/advisor <model>" to change.`,
 40      }
 41    }
 42  
 43    if (arg === 'unset' || arg === 'off') {
 44      const prev = context.getAppState().advisorModel
 45      context.setAppState(s => {
 46        if (s.advisorModel === undefined) return s
 47        return { ...s, advisorModel: undefined }
 48      })
 49      updateSettingsForSource('userSettings', { advisorModel: undefined })
 50      return {
 51        type: 'text',
 52        value: prev
 53          ? `Advisor disabled (was ${prev}).`
 54          : 'Advisor already unset.',
 55      }
 56    }
 57  
 58    const normalizedModel = normalizeModelStringForAPI(arg)
 59    const resolvedModel = parseUserSpecifiedModel(arg)
 60    const { valid, error } = await validateModel(resolvedModel)
 61    if (!valid) {
 62      return {
 63        type: 'text',
 64        value: error
 65          ? `Invalid advisor model: ${error}`
 66          : `Unknown model: ${arg} (${resolvedModel})`,
 67      }
 68    }
 69  
 70    if (!isValidAdvisorModel(resolvedModel)) {
 71      return {
 72        type: 'text',
 73        value: `The model ${arg} (${resolvedModel}) cannot be used as an advisor`,
 74      }
 75    }
 76  
 77    context.setAppState(s => {
 78      if (s.advisorModel === normalizedModel) return s
 79      return { ...s, advisorModel: normalizedModel }
 80    })
 81    updateSettingsForSource('userSettings', { advisorModel: normalizedModel })
 82  
 83    if (!modelSupportsAdvisor(baseModel)) {
 84      return {
 85        type: 'text',
 86        value: `Advisor set to ${normalizedModel}.\nNote: Your current model (${baseModel}) does not support advisors. Switch to a supported model to use the advisor.`,
 87      }
 88    }
 89  
 90    return {
 91      type: 'text',
 92      value: `Advisor set to ${normalizedModel}.`,
 93    }
 94  }
 95  
 96  const advisor = {
 97    type: 'local',
 98    name: 'advisor',
 99    description: 'Configure the advisor model',
100    argumentHint: '[<model>|off]',
101    isEnabled: () => canUserConfigureAdvisor(),
102    get isHidden() {
103      return !canUserConfigureAdvisor()
104    },
105    supportsNonInteractive: true,
106    load: () => Promise.resolve({ call }),
107  } satisfies Command
108  
109  export default advisor