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
41export function resolveSelectableProvider(
42 providers: ReadonlyArray<ServerProvider>,
43 provider: ProviderDriverKind | ProviderInstanceId | null | undefined,
44): ProviderDriverKind {
45 const requestedEntry = providers.find((candidate) => candidate.instanceId === provider);
46 if (requestedEntry?.enabled) {
47 return requestedEntry.driver;
48 }
49 return providers.find((candidate) => candidate.enabled)?.driver ?? DEFAULT_DRIVER_KIND;
50}
51
52export function getProviderModelCapabilities(
53 models: ReadonlyArray<ServerProviderModel>,
54 model: string | null | undefined,
55 provider: ProviderDriverKind,
56 includePlanAgent = false,
57): ModelCapabilities {
58 const slug = resolveSelectableModel(provider, model, models);
59 const selectedModel = models.find((candidate) => candidate.slug === slug);
60 const caps = selectedModel?.capabilities ?? EMPTY_CAPABILITIES;
61 if (includePlanAgent) {
62 return caps;
63 }
64 return withoutPlanAgentOption(caps);
65}
66
67function withoutPlanAgentOption(caps: ModelCapabilities): ModelCapabilities {
68 return {
69 ...caps,
70 optionDescriptors: (caps.optionDescriptors ?? []).flatMap((descriptor) => {
71 if (descriptor.type !== "select" || descriptor.id !== "agent") {
72 return [descriptor];
73 }
74 const options = descriptor.options.filter((option) => option.id !== "plan");
75 if (options.length === 0) {
76 return [];
77 }
78 const currentValue =
79 descriptor.currentValue && options.some((option) => option.id === descriptor.currentValue)
80 ? descriptor.currentValue
81 : (options.find((option) => option.isDefault)?.id ?? options[0]?.id);
82 return [{ ...descriptor, options, ...(currentValue ? { currentValue } : {}) }];
83 }),
84 };
85}
86
87export function getDefaultServerModel(
88 providers: ReadonlyArray<ServerProvider>,
89 provider: ProviderDriverKind,
90): string {
91 const models = getProviderModels(providers, provider);
92 return (
93 models.find((model) => model.isDefault && !model.isCustom)?.slug ??
94 models.find((model) => !model.isCustom)?.slug ??
95 models[0]?.slug ??
96 DEFAULT_MODEL_BY_PROVIDER[provider] ??
97 DEFAULT_MODEL
98 );
99}