summaryrefslogtreecommitdiffhomepage
path: root/js/src
diff options
context:
space:
mode:
authoradamdottv <[email protected]>2025-05-30 15:34:22 -0500
committeradamdottv <[email protected]>2025-05-30 15:34:25 -0500
commitc69c9327da4a43a63928807fcf36b24755cfac18 (patch)
treedf79a6c58976af977a28717619d70db4a62f4853 /js/src
parentf5e2c596d4f887daa4df579975dd5451fadc8457 (diff)
downloadopencode-c69c9327da4a43a63928807fcf36b24755cfac18.tar.gz
opencode-c69c9327da4a43a63928807fcf36b24755cfac18.zip
wip: refactoring tui
Diffstat (limited to 'js/src')
-rw-r--r--js/src/config/config.ts2
-rw-r--r--js/src/llm/llm.ts79
-rw-r--r--js/src/provider/provider.ts5
-rw-r--r--js/src/server/server.ts8
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);
},