Add features & update project
Build and Push Spoon Images / quality (push) Successful in 1m41s
Build and Push Spoon Images / build-images (push) Successful in 7m4s

This commit is contained in:
Gabriel Brown
2026-06-23 02:06:58 -04:00
parent fe72fc2957
commit d207b8b0b8
26 changed files with 1257 additions and 231 deletions
-56
View File
@@ -1,56 +0,0 @@
type ModelsDevModel = {
id?: string;
name?: string;
tool_call?: boolean;
reasoning?: boolean;
limit?: { context?: number };
};
type ModelsDevProvider = {
id?: string;
name?: string;
models?: Record<string, ModelsDevModel>;
};
const providerMap = {
openai: 'openai',
anthropic: 'anthropic',
google: 'google',
openrouter: 'openrouter',
requesty: 'requesty',
litellm: 'litellm',
cloudflare_ai_gateway: 'cloudflare',
custom_openai_compatible: '',
opencode_openai_login: 'openai',
} as const;
export type ProviderModelOption = {
id: string;
label: string;
reasoning: boolean;
toolCall: boolean;
context?: number;
};
export const loadModelsDevOptions = async (provider: string) => {
const mapped = providerMap[provider as keyof typeof providerMap];
if (!mapped) return [];
const response = await fetch('https://models.dev/api.json', {
cache: 'force-cache',
});
if (!response.ok) return [];
const catalog = (await response.json()) as Record<string, ModelsDevProvider>;
const providerCatalog = catalog[mapped];
return Object.entries(providerCatalog?.models ?? {})
.map(
([id, model]): ProviderModelOption => ({
id: model.id ?? id,
label: model.name ?? model.id ?? id,
reasoning: Boolean(model.reasoning),
toolCall: Boolean(model.tool_call),
context: model.limit?.context,
}),
)
.filter((model) => model.toolCall)
.sort((a, b) => a.label.localeCompare(b.label));
};
@@ -0,0 +1,72 @@
export type ProviderModelOption = {
id: string;
label: string;
reasoning: boolean;
toolCall: boolean;
context?: number;
};
const options = {
openai: ['gpt-5.1-codex', 'gpt-5.1', 'gpt-5', 'gpt-5-mini'],
opencode_openai_login: ['gpt-5.1-codex', 'gpt-5.1', 'gpt-5'],
anthropic: ['claude-sonnet-4-5', 'claude-opus-4-5', 'claude-haiku-4-5'],
google: ['gemini-3-pro', 'gemini-2.5-pro', 'gemini-2.5-flash'],
openrouter: ['openai/gpt-5.1-codex', 'anthropic/claude-sonnet-4-5'],
requesty: ['openai/gpt-5.1-codex', 'anthropic/claude-sonnet-4-5'],
litellm: ['openai/gpt-5.1-codex', 'anthropic/claude-sonnet-4-5'],
cloudflare_ai_gateway: ['openai/gpt-5.1-codex'],
custom_openai_compatible: ['gpt-5.1-codex'],
} as const;
export type ProviderModelKey = keyof typeof options;
const modelOptionsByProvider: Record<string, readonly string[]> = options;
const labelForModel = (id: string) => {
const label = id
.split('/')
.at(-1)
?.replaceAll('-', ' ')
.replace(/\b\w/g, (letter) => letter.toUpperCase());
return label ?? id;
};
export const suggestedModelOptions = (
provider: string,
): ProviderModelOption[] =>
(modelOptionsByProvider[provider] ?? []).map((id) => ({
id,
label: labelForModel(id),
reasoning: true,
toolCall: true,
}));
export const modelOptionsFromIds = (
ids: string[] | undefined,
): ProviderModelOption[] =>
(ids ?? [])
.map((id) => id.trim())
.filter(Boolean)
.filter((id, index, all) => all.indexOf(id) === index)
.map((id) => ({
id,
label: labelForModel(id),
reasoning: true,
toolCall: true,
}));
export const modelIdsForProfile = (profile?: {
defaultModel?: string;
modelOptions?: string[];
}) =>
[profile?.defaultModel, ...(profile?.modelOptions ?? [])]
.filter((model): model is string => Boolean(model?.trim()))
.filter((model, index, all) => all.indexOf(model) === index);
export const supportsCustomModelOptions = (provider: string) =>
[
'openrouter',
'requesty',
'litellm',
'cloudflare_ai_gateway',
'custom_openai_compatible',
].includes(provider);