/** * ACP model/mode derivation — adapted from Paseo acp-agent.ts. */ import type { SessionConfigOption, SessionModelState, SessionModeState, } from '@agentclientprotocol/sdk'; import type { ProviderMode, ProviderModel, ThinkingOption } from './provider-types.js'; type SelectConfigOption = Extract; interface SelectConfigChoice { value: string; name: string; description?: string | null; group?: string; } function findSelectConfigOption({ configOptions, category, id, }: { configOptions: SessionConfigOption[] | null | undefined; category: string; id?: string; }): SelectConfigOption | null { const option = configOptions?.find( (entry): entry is SelectConfigOption => entry.type === 'select' && entry.category === category && (!id || entry.id === id), ); return option ?? null; } function flattenSelectOptions(options: SelectConfigOption['options']): SelectConfigChoice[] { const flattened: SelectConfigChoice[] = []; for (const option of options) { if ('value' in option) { flattened.push(option); continue; } for (const groupOption of option.options) { flattened.push({ ...groupOption, group: option.group }); } } return flattened; } function deriveSelectorOptions( configOptions: SessionConfigOption[] | null | undefined, category: string, ): ThinkingOption[] { const option = findSelectConfigOption({ configOptions, category }); if (!option) return []; return flattenSelectOptions(option.options).map((value) => ({ id: value.value, label: value.name, isDefault: value.value === option.currentValue, })); } export function deriveModesFromACP( fallbackModes: ProviderMode[], modeState?: SessionModeState | null, configOptions?: SessionConfigOption[] | null, ): { modes: ProviderMode[]; currentModeId: string | null } { if (modeState?.availableModes?.length) { return { modes: modeState.availableModes.map((mode) => ({ id: mode.id, label: mode.name, description: mode.description ?? undefined, })), currentModeId: modeState.currentModeId ?? null, }; } const modeOption = findSelectConfigOption({ configOptions, category: 'mode' }); if (modeOption) { const flatOptions = flattenSelectOptions(modeOption.options); return { modes: flatOptions.map((option) => ({ id: option.value, label: option.name, description: option.description ?? undefined, })), currentModeId: modeOption.currentValue, }; } return { modes: fallbackModes, currentModeId: null }; } export function deriveModelDefinitionsFromACP( models: SessionModelState | null | undefined, configOptions?: SessionConfigOption[] | null, ): ProviderModel[] { const thinkingOptions = deriveSelectorOptions(configOptions, 'thought_level'); const defaultThinkingOptionId = thinkingOptions.find((o) => o.isDefault)?.id; if (models?.availableModels?.length) { return models.availableModels.map((model) => ({ id: model.modelId, label: model.name, description: model.description ?? undefined, isDefault: model.modelId === models.currentModelId, thinkingOptions: thinkingOptions.length > 0 ? thinkingOptions : undefined, defaultThinkingOptionId: defaultThinkingOptionId ?? undefined, })); } const modelOptions = deriveSelectorOptions(configOptions, 'model'); return modelOptions.map((option) => ({ id: option.id, label: option.label, isDefault: option.isDefault, thinkingOptions: thinkingOptions.length > 0 ? thinkingOptions : undefined, defaultThinkingOptionId: defaultThinkingOptionId ?? undefined, })); } export function findThoughtLevelConfigId( configOptions: SessionConfigOption[] | null | undefined, ): string | null { return findSelectConfigOption({ configOptions, category: 'thought_level' })?.id ?? null; }