mirror of
https://github.com/aljazceru/opencode.git
synced 2026-01-04 16:34:55 +01:00
wip: refactoring tui
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user