Sfoglia il codice sorgente

BREAKING CHANGE: the config structure has changed, custom providers have an `npm` field now to specify which npm package to load. see examples in README.md

Dax Raad 8 mesi fa
parent
commit
2c9fd1e776

+ 4 - 3
README.md

@@ -84,8 +84,8 @@ You can use opencode with any provider listed at [here](https://ai-sdk.dev/provi
 {
   "$schema": "https://opencode.ai/config.json",
   "provider": {
-    "@ai-sdk/openai-compatible": {
-      "name": "ollama",
+    "ollama": {
+      "npm": "@ai-sdk/openai-compatible",
       "options": {
         "baseURL": "http://localhost:11434/v1"
       },
@@ -124,7 +124,8 @@ OpenRouter is not yet in the models.dev database, but you can configure it manua
 {
   "$schema": "https://opencode.ai/config.json",
   "provider": {
-    "@openrouter/ai-sdk-provider": {
+    "openrouter": {
+      "npm": "@openrouter/ai-sdk-provider",
       "name": "OpenRouter",
       "options": {
         "apiKey": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

+ 2 - 2
opencode.json

@@ -1,8 +1,8 @@
 {
   "$schema": "https://opencode.ai/config.json",
   "provider": {
-    "@ai-sdk/openai-compatible": {
-      "name": "ollama",
+    "ollama": {
+      "npm": "@ai-sdk/openai-compatible",
       "options": {
         "baseURL": "http://localhost:11434/v1"
       },

+ 3 - 0
packages/opencode/config.schema.json

@@ -21,6 +21,9 @@
           "id": {
             "type": "string"
           },
+          "npm": {
+            "type": "string"
+          },
           "models": {
             "type": "object",
             "additionalProperties": {

+ 0 - 1
packages/opencode/src/auth/anthropic.ts

@@ -1,5 +1,4 @@
 import { generatePKCE } from "@openauthjs/openauth/pkce"
-import fs from "fs/promises"
 import { Auth } from "./index"
 
 export namespace AuthAnthropic {

+ 1 - 0
packages/opencode/src/bun/index.ts

@@ -43,6 +43,7 @@ export namespace BunProc {
       version: z.string(),
     }),
   )
+
   export async function install(pkg: string, version = "latest") {
     const mod = path.join(Global.Path.cache, "node_modules", pkg)
     const pkgjson = Bun.file(path.join(Global.Path.cache, "package.json"))

+ 8 - 4
packages/opencode/src/cli/cmd/auth.ts

@@ -5,7 +5,7 @@ import * as prompts from "@clack/prompts"
 import open from "open"
 import { UI } from "../ui"
 import { ModelsDev } from "../../provider/models"
-import { map, pipe, sort, sortBy, values } from "remeda"
+import { map, pipe, sortBy, values } from "remeda"
 
 export const AuthCommand = cmd({
   command: "auth",
@@ -16,7 +16,7 @@ export const AuthCommand = cmd({
       .command(AuthLogoutCommand)
       .command(AuthListCommand)
       .demandCommand(),
-  async handler(args) {},
+  async handler() {},
 })
 
 export const AuthListCommand = cmd({
@@ -78,8 +78,10 @@ export const AuthLoginCommand = cmd({
 
     if (provider === "other") {
       provider = await prompts.text({
-        message: "Enter provider - must match @ai-sdk/<provider>",
+        message:
+          "Enter provider - must be package name from https://ai-sdk.dev/providers",
       })
+      provider = provider.replace(/^@ai-sdk\//, "")
       if (prompts.isCancel(provider)) throw new UI.CancelledError()
     }
 
@@ -115,7 +117,9 @@ export const AuthLoginCommand = cmd({
         try {
           await open(url)
         } catch (e) {
-          prompts.log.error("Failed to open browser perhaps you are running without a display or X server, please open the following URL in your browser:")
+          prompts.log.error(
+            "Failed to open browser perhaps you are running without a display or X server, please open the following URL in your browser:",
+          )
         }
         prompts.log.info(url)
 

+ 1 - 0
packages/opencode/src/provider/models.ts

@@ -36,6 +36,7 @@ export namespace ModelsDev {
       name: z.string(),
       env: z.array(z.string()),
       id: z.string(),
+      npm: z.string().optional(),
       models: z.record(Model),
     })
     .openapi({

+ 9 - 9
packages/opencode/src/provider/provider.ts

@@ -108,6 +108,7 @@ export namespace Provider {
       const existing = database[providerID]
       const parsed: ModelsDev.Provider = {
         id: providerID,
+        npm: provider.npm ?? existing?.npm,
         name: provider.name ?? existing?.name ?? providerID,
         env: provider.env ?? existing?.env ?? [],
         models: existing?.models ?? {},
@@ -181,22 +182,22 @@ export namespace Provider {
     return state().then((state) => state.providers)
   }
 
-  async function getSDK(providerID: string) {
+  async function getSDK(provider: ModelsDev.Provider) {
     return (async () => {
       using _ = log.time("getSDK", {
-        providerID,
+        providerID: provider.id,
       })
       const s = await state()
-      const existing = s.sdk.get(providerID)
+      const existing = s.sdk.get(provider.id)
       if (existing) return existing
-      const [pkg, version] = await ModelsDev.pkg(providerID)
+      const [pkg, version] = await ModelsDev.pkg(provider.npm ?? provider.id)
       const mod = await import(await BunProc.install(pkg, version))
       const fn = mod[Object.keys(mod).find((key) => key.startsWith("create"))!]
-      const loaded = fn(s.providers[providerID]?.options)
-      s.sdk.set(providerID, loaded)
+      const loaded = fn(s.providers[provider.id]?.options)
+      s.sdk.set(provider.id, loaded)
       return loaded as SDK
     })().catch((e) => {
-      throw new InitError({ providerID: providerID }, { cause: e })
+      throw new InitError({ providerID: provider.id }, { cause: e })
     })
   }
 
@@ -214,8 +215,7 @@ export namespace Provider {
     if (!provider) throw new ModelNotFoundError({ providerID, modelID })
     const info = provider.info.models[modelID]
     if (!info) throw new ModelNotFoundError({ providerID, modelID })
-
-    const sdk = await getSDK(providerID)
+    const sdk = await getSDK(provider.info)
 
     try {
       const language =