Files
platform/src/servers/api/chat/list-models.ts
T
pastilhasandClaude Opus 4.8 ab134aa02b chat: surface all OpenCode models (drop the curated allow-list)
Removes the Big Pickle + Claude Haiku allow-list; the picker now lists every model
the fixed server reports from GET /config/providers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:15:10 +00:00

59 lines
2.1 KiB
TypeScript

import type { ModelInfo } from './types';
import { OPENCODE_SERVER_URL } from './opencode/server-manager';
// The Claude harness runs the `claude` CLI, so its tiers are a fixed set.
const CLAUDE_CODE_MODELS: ModelInfo[] = [
{ id: 'claude-code/opus', name: 'opus', provider: 'claude-code', contextWindow: 200000, maxTokens: 16000, reasoning: true, images: true },
{ id: 'claude-code/sonnet', name: 'sonnet', provider: 'claude-code', contextWindow: 200000, maxTokens: 16000, reasoning: true, images: true },
{ id: 'claude-code/haiku', name: 'haiku', provider: 'claude-code', contextWindow: 200000, maxTokens: 8192, reasoning: false, images: true },
];
// Cache the OpenCode catalog; it's stable for a session.
let openCodeCache: ModelInfo[] | null = null;
export function invalidateModelCache(): void {
openCodeCache = null;
}
type ProvidersResponse = {
providers?: Array<{ id?: string; models?: Record<string, unknown> }>;
};
// Enumerate OpenCode models from the fixed server's GET /config/providers (reliable — no subprocess).
// Model ids are `providerID/modelID` (e.g. `opencode/claude-haiku-4-5`); metadata is left at neutral
// defaults for now.
async function listOpenCodeModels(): Promise<ModelInfo[]> {
if (openCodeCache) return openCodeCache;
try {
const res = await fetch(`${OPENCODE_SERVER_URL}/config/providers`, { signal: AbortSignal.timeout(5000) });
if (!res.ok) return [];
const data = (await res.json()) as ProvidersResponse;
const models: ModelInfo[] = [];
for (const provider of data.providers ?? []) {
const providerId = provider.id ?? '';
for (const modelId of Object.keys(provider.models ?? {})) {
models.push({
id: `${providerId}/${modelId}`,
name: modelId,
provider: providerId,
contextWindow: 200000,
maxTokens: 8192,
reasoning: false,
images: true,
});
}
}
openCodeCache = models;
return models;
} catch {
return [];
}
}
export async function listChatModels(): Promise<ModelInfo[]> {
const openCode = await listOpenCodeModels();
return [...CLAUDE_CODE_MODELS, ...openCode];
}