ソースを参照

Enhance provider system with dynamic package resolution and improved logging

- Add npm registry lookup for AI SDK packages with fallback support
- Enhance error logging with cause information
- Add timing deltas to log output for performance monitoring

🤖 Generated with [opencode](https://opencode.ai)

Co-Authored-By: opencode <[email protected]>
Dax Raad 8 ヶ月 前
コミット
574d494c3c

+ 16 - 0
opencode.json

@@ -0,0 +1,16 @@
+{
+  "$schema": "https://opencode.ai/config.json",
+  "provider": {
+    "@openrouter/ai-sdk-provider": {
+      "name": "OpenRouter",
+      "options": {
+        "apiKey": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+      },
+      "models": {
+        "anthropic/claude-3.5-sonnet": {
+          "name": "claude-3.5-sonnet"
+        }
+      }
+    }
+  }
+}

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

@@ -1,4 +1,5 @@
 import { Global } from "../global"
+import { lazy } from "../util/lazy"
 import { Log } from "../util/log"
 import path from "path"
 import { z } from "zod"
@@ -62,4 +63,30 @@ export namespace ModelsDev {
       throw new Error(`Failed to fetch models.dev: ${result.statusText}`)
     await Bun.write(file, result)
   }
+
+  const aisdk = lazy(async () => {
+    log.info("fetching ai-sdk")
+    const response = await fetch(
+      "https://registry.npmjs.org/-/v1/search?text=scope:@ai-sdk",
+    )
+    if (!response.ok)
+      throw new Error(
+        `Failed to fetch ai-sdk information: ${response.statusText}`,
+      )
+    const result = await response.json()
+    log.info("found ai-sdk", result.objects.length)
+    return result.objects
+      .filter((obj: any) => obj.package.name.startsWith("@ai-sdk/"))
+      .reduce((acc: any, obj: any) => {
+        acc[obj.package.name] = obj
+        return acc
+      }, {})
+  })
+
+  export async function pkg(providerID: string): Promise<[string, string]> {
+    const packages = await aisdk()
+    const match = packages[`@ai-sdk/${providerID}`]
+    if (match) return [match.package.name, "alpha"]
+    return [providerID, "latest"]
+  }
 }

+ 2 - 3
packages/opencode/src/provider/provider.ts

@@ -186,9 +186,8 @@ export namespace Provider {
       const s = await state()
       const existing = s.sdk.get(providerID)
       if (existing) return existing
-      const mod = await import(
-        await BunProc.install(`@ai-sdk/${providerID}`, "alpha")
-      )
+      const [pkg, version] = await ModelsDev.pkg(providerID)
+      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)

+ 4 - 1
packages/opencode/src/util/error.ts

@@ -29,7 +29,10 @@ export abstract class NamedError extends Error {
       ) {
         super(name, options)
         this.name = name
-        log.error(name, this.data)
+        log.error(name, {
+          ...this.data,
+          cause: options?.cause?.toString(),
+        })
       }
 
       static isInstance(input: any): input is InstanceType<typeof result> {

+ 7 - 2
packages/opencode/src/util/log.ts

@@ -45,6 +45,7 @@ export namespace Log {
     )
   }
 
+  let last = Date.now()
   export function create(tags?: Record<string, any>) {
     tags = tags || {}
 
@@ -56,9 +57,13 @@ export namespace Log {
         .filter(([_, value]) => value !== undefined && value !== null)
         .map(([key, value]) => `${key}=${value}`)
         .join(" ")
+      const next = new Date()
+      const diff = next.getTime() - last
+      last = next.getTime()
       return (
-        [new Date().toISOString(), prefix, message].filter(Boolean).join(" ") +
-        "\n"
+        [next.toISOString().split(".")[0], "+" + diff + "ms", prefix, message]
+          .filter(Boolean)
+          .join(" ") + "\n"
       )
     }
     const result = {