diff options
| author | adamdottv <[email protected]> | 2025-05-30 15:34:22 -0500 |
|---|---|---|
| committer | adamdottv <[email protected]> | 2025-05-30 15:34:25 -0500 |
| commit | c69c9327da4a43a63928807fcf36b24755cfac18 (patch) | |
| tree | df79a6c58976af977a28717619d70db4a62f4853 /js/src | |
| parent | f5e2c596d4f887daa4df579975dd5451fadc8457 (diff) | |
| download | opencode-c69c9327da4a43a63928807fcf36b24755cfac18.tar.gz opencode-c69c9327da4a43a63928807fcf36b24755cfac18.zip | |
wip: refactoring tui
Diffstat (limited to 'js/src')
| -rw-r--r-- | js/src/config/config.ts | 2 | ||||
| -rw-r--r-- | js/src/llm/llm.ts | 79 | ||||
| -rw-r--r-- | js/src/provider/provider.ts | 5 | ||||
| -rw-r--r-- | js/src/server/server.ts | 8 |
4 files changed, 53 insertions, 41 deletions
diff --git a/js/src/config/config.ts b/js/src/config/config.ts index 76181b792..8c374b3f3 100644 --- a/js/src/config/config.ts +++ b/js/src/config/config.ts @@ -14,7 +14,7 @@ export namespace Config { export const Info = z .object({ - providers: z.record(z.string(), Provider.Info).optional(), + providers: Provider.Info.array().optional(), }) .strict(); diff --git a/js/src/llm/llm.ts b/js/src/llm/llm.ts index 990c30069..a7d31fb99 100644 --- a/js/src/llm/llm.ts +++ b/js/src/llm/llm.ts @@ -1,6 +1,6 @@ import { App } from "../app/app"; import { Log } from "../util/log"; -import { mergeDeep } from "remeda"; +import { concat } from "remeda"; import path from "path"; import { Provider } from "../provider/provider"; @@ -19,26 +19,32 @@ export namespace LLM { } } - const NATIVE_PROVIDERS: Record<string, Provider.Info> = { - anthropic: { - models: { - "claude-sonnet-4-20250514": { - name: "Claude 4 Sonnet", + const NATIVE_PROVIDERS: Provider.Info[] = [ + { + id: "anthropic", + name: "Anthropic", + models: [ + { + id: "claude-sonnet-4-20250514", + name: "Claude Sonnet 4", cost: { input: 3.0 / 1_000_000, output: 15.0 / 1_000_000, inputCached: 3.75 / 1_000_000, outputCached: 0.3 / 1_000_000, }, - contextWindow: 200000, - maxTokens: 50000, + contextWindow: 200_000, + maxOutputTokens: 50_000, attachment: true, }, - }, + ], }, - openai: { - models: { - "codex-mini-latest": { + { + id: "openai", + name: "OpenAI", + models: [ + { + id: "codex-mini-latest", name: "Codex Mini", cost: { input: 1.5 / 1_000_000, @@ -46,16 +52,19 @@ export namespace LLM { output: 6.0 / 1_000_000, outputCached: 0.0 / 1_000_000, }, - contextWindow: 200000, - maxTokens: 100000, + contextWindow: 200_000, + maxOutputTokens: 100_000, attachment: true, reasoning: true, }, - }, + ], }, - google: { - models: { - "gemini-2.5-pro-preview-03-25": { + { + id: "google", + name: "Google", + models: [ + { + id: "gemini-2.5-pro-preview-03-25", name: "Gemini 2.5 Pro", cost: { input: 1.25 / 1_000_000, @@ -63,18 +72,18 @@ export namespace LLM { output: 10 / 1_000_000, outputCached: 0 / 1_000_000, }, - contextWindow: 1000000, - maxTokens: 50000, + contextWindow: 1_000_000, + maxOutputTokens: 50_000, attachment: true, }, - }, + ], }, - }; + ]; const AUTODETECT: Record<string, string[]> = { anthropic: ["ANTHROPIC_API_KEY"], openai: ["OPENAI_API_KEY"], - google: ["GOOGLE_GENERATIVE_AI_API_KEY"], + google: ["GOOGLE_GENERATIVE_AI_API_KEY", "GEMINI_API_KEY"], }; const state = App.state("llm", async () => { @@ -91,33 +100,33 @@ export namespace LLM { { info: Provider.Model; instance: LanguageModel } >(); - const list = mergeDeep(NATIVE_PROVIDERS, config.providers ?? {}); + const list = concat(NATIVE_PROVIDERS, config.providers ?? []); - for (const [providerID, providerInfo] of Object.entries(list)) { + for (const provider of list) { if ( - !config.providers?.[providerID] && - !AUTODETECT[providerID]?.some((env) => process.env[env]) + !config.providers?.find((p) => p.id === provider.id) && + !AUTODETECT[provider.id]?.some((env) => process.env[env]) ) continue; const dir = path.join( Global.cache(), `node_modules`, `@ai-sdk`, - providerID, + provider.id, ); if (!(await Bun.file(path.join(dir, "package.json")).exists())) { - BunProc.run(["add", "--exact", `@ai-sdk/${providerID}@alpha`], { + BunProc.run(["add", "--exact", `@ai-sdk/${provider.id}@alpha`], { cwd: Global.cache(), }); } const mod = await import( - path.join(Global.cache(), `node_modules`, `@ai-sdk`, providerID) + path.join(Global.cache(), `node_modules`, `@ai-sdk`, provider.id) ); const fn = mod[Object.keys(mod).find((key) => key.startsWith("create"))!]; - const loaded = fn(providerInfo.options); - log.info("loaded", { provider: providerID }); - providers[providerID] = { - info: providerInfo, + const loaded = fn(provider.options); + log.info("loaded", { provider: provider.id }); + providers[provider.id] = { + info: provider, instance: loaded, }; } @@ -142,7 +151,7 @@ export namespace LLM { providerID, modelID, }); - const info = provider.info.models[modelID]; + const info = provider.info.models.find((m) => m.id === modelID); if (!info) throw new ModelNotFoundError(modelID); try { const match = provider.instance.languageModel(modelID); diff --git a/js/src/provider/provider.ts b/js/src/provider/provider.ts index a35645e69..d4719ffbb 100644 --- a/js/src/provider/provider.ts +++ b/js/src/provider/provider.ts @@ -3,6 +3,7 @@ import z from "zod"; export namespace Provider { export const Model = z .object({ + id: z.string(), name: z.string().optional(), cost: z.object({ input: z.number(), @@ -22,8 +23,10 @@ export namespace Provider { export const Info = z .object({ + id: z.string(), + name: z.string(), options: z.record(z.string(), z.any()).optional(), - models: z.record(z.string(), Model), + models: Model.array(), }) .openapi({ ref: "Provider.Info", diff --git a/js/src/server/server.ts b/js/src/server/server.ts index b93ca5a69..28591cbd2 100644 --- a/js/src/server/server.ts +++ b/js/src/server/server.ts @@ -263,7 +263,7 @@ export namespace Server { description: "List of providers", content: { "application/json": { - schema: resolver(z.record(z.string(), Provider.Info)), + schema: resolver(Provider.Info.array()), }, }, }, @@ -271,9 +271,9 @@ export namespace Server { }), async (c) => { const providers = await LLM.providers(); - const result: Record<string, Provider.Info> = {}; - for (const [providerID, provider] of Object.entries(providers)) { - result[providerID] = provider.info; + const result = [] as (Provider.Info & { key: string })[]; + for (const [key, provider] of Object.entries(providers)) { + result.push({ ...provider.info, key }); } return c.json(result); }, |
