| 1 | import { |
| 2 | DEFAULT_MODEL, |
| 3 | DEFAULT_MODEL_BY_PROVIDER, |
| 4 | defaultInstanceIdForDriver, |
| 5 | ProviderDriverKind, |
| 6 | type ModelCapabilities, |
| 7 | type ProviderInstanceId, |
| 8 | type ServerProvider, |
| 9 | type ServerProviderModel, |
| 10 | } from "@t3tools/contracts"; |
| 11 | import { createModelCapabilities, resolveSelectableModel } from "@t3tools/shared/model"; |
| 12 | |
| 13 | const EMPTY_CAPABILITIES: ModelCapabilities = createModelCapabilities({ |
| 14 | optionDescriptors: [], |
| 15 | }); |
| 16 | const DEFAULT_DRIVER_KIND = ProviderDriverKind.make("codex"); |
| 17 | |
| 18 | export function formatProviderDriverKindLabel(provider: ProviderDriverKind): string { |
| 19 | return provider |
| 20 | .replace(/([a-z])([A-Z])/g, "$1 $2") |
| 21 | .replace(/[_-]+/g, " ") |
| 22 | .trim() |
| 23 | .replace(/\b\w/g, (char) => char.toUpperCase()); |
| 24 | } |
| 25 | |
| 26 | export function getProviderModels( |
| 27 | providers: ReadonlyArray<ServerProvider>, |
| 28 | provider: ProviderDriverKind, |
| 29 | ): ReadonlyArray<ServerProviderModel> { |
| 30 | return getProviderSnapshot(providers, provider)?.models ?? []; |
| 31 | } |
| 32 | |
| 33 | function getProviderSnapshot( |
| 34 | providers: ReadonlyArray<ServerProvider>, |
| 35 | provider: ProviderDriverKind, |
| 36 | ): ServerProvider | undefined { |
| 37 | const defaultInstanceId = defaultInstanceIdForDriver(provider); |
| 38 | return providers.find((candidate) => candidate.instanceId === defaultInstanceId); |
| 39 | } |
| 40 | |
| 41 | // Resolve an instance selection to the correlated live driver. If the |
| 42 | // instance is absent, fall back to a live enabled provider instead of |
| 43 | // inferring a driver from the missing instance id. |
| 44 | export function resolveSelectableProvider( |
| 45 | providers: ReadonlyArray<ServerProvider>, |
| 46 | provider: ProviderDriverKind | ProviderInstanceId | null | undefined, |
| 47 | ): ProviderDriverKind { |
| 48 | const requestedEntry = providers.find((candidate) => candidate.instanceId === provider); |
| 49 | if (requestedEntry?.enabled) { |
| 50 | return requestedEntry.driver; |
| 51 | } |
| 52 | return providers.find((candidate) => candidate.enabled)?.driver ?? DEFAULT_DRIVER_KIND; |
| 53 | } |
| 54 | |
| 55 | export function getProviderModelCapabilities( |
| 56 | models: ReadonlyArray<ServerProviderModel>, |
| 57 | model: string | null | undefined, |
| 58 | provider: ProviderDriverKind, |
| 59 | planModeEnabled = true, |
| 60 | ): ModelCapabilities { |
| 61 | const slug = resolveSelectableModel(provider, model, models); |
| 62 | const selectedModel = models.find((candidate) => candidate.slug === slug); |
| 63 | const caps = selectedModel?.capabilities ?? EMPTY_CAPABILITIES; |
| 64 | if (planModeEnabled) { |
| 65 | return caps; |
| 66 | } |
| 67 | return withoutPlanAgentOption(caps); |
| 68 | } |
| 69 | |
| 70 | // The opencode "plan" agent is only reachable while legacy plan mode is on. |
| 71 | // With it off, drop the option so it cannot be selected or dispatched, and |
| 72 | // drop the descriptor entirely when nothing remains selectable. currentValue |
| 73 | // is re-resolved against the surviving options so a stale or defaulted "plan" |
| 74 | // value cannot leak back into dispatch. |
| 75 | function withoutPlanAgentOption(caps: ModelCapabilities): ModelCapabilities { |
| 76 | return { |
| 77 | ...caps, |
| 78 | optionDescriptors: (caps.optionDescriptors ?? []).flatMap((descriptor) => { |
| 79 | if (descriptor.type !== "select" || descriptor.id !== "agent") { |
| 80 | return [descriptor]; |
| 81 | } |
| 82 | const options = descriptor.options.filter((option) => option.id !== "plan"); |
| 83 | if (options.length === 0) { |
| 84 | return []; |
| 85 | } |
| 86 | const currentValue = |
| 87 | descriptor.currentValue && options.some((option) => option.id === descriptor.currentValue) |
| 88 | ? descriptor.currentValue |
| 89 | : (options.find((option) => option.isDefault)?.id ?? options[0]?.id); |
| 90 | return [{ ...descriptor, options, ...(currentValue ? { currentValue } : {}) }]; |
| 91 | }), |
| 92 | }; |
| 93 | } |
| 94 | |
| 95 | export function getDefaultServerModel( |
| 96 | providers: ReadonlyArray<ServerProvider>, |
| 97 | provider: ProviderDriverKind, |
| 98 | ): string { |
| 99 | const models = getProviderModels(providers, provider); |
| 100 | return ( |
| 101 | models.find((model) => model.isDefault && !model.isCustom)?.slug ?? |
| 102 | models.find((model) => !model.isCustom)?.slug ?? |
| 103 | models[0]?.slug ?? |
| 104 | DEFAULT_MODEL_BY_PROVIDER[provider] ?? |
| 105 | DEFAULT_MODEL |
| 106 | ); |
| 107 | } |