1import {
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";
11import { createModelCapabilities, resolveSelectableModel } from "@t3tools/shared/model";
12
13const EMPTY_CAPABILITIES: ModelCapabilities = createModelCapabilities({
14 optionDescriptors: [],
15});
16const DEFAULT_DRIVER_KIND = ProviderDriverKind.make("codex");
17
18export 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
26export function getProviderModels(
27 providers: ReadonlyArray<ServerProvider>,
28 provider: ProviderDriverKind,
29): ReadonlyArray<ServerProviderModel> {
30 return getProviderSnapshot(providers, provider)?.models ?? [];
31}
32
33function 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.
44export 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
55export 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.
75function 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
95export 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}