فهرست منبع

fix(cli): ensure clean exit on provider/model errors (#4223)

Co-authored-by: GitHub Action <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>
Ian Maurer 3 ماه پیش
والد
کامیت
e018e16898
2فایلهای تغییر یافته به همراه29 افزوده شده و 2 حذف شده
  1. 13 0
      packages/opencode/src/cli/error.ts
  2. 16 2
      packages/opencode/src/provider/provider.ts

+ 13 - 0
packages/opencode/src/cli/error.ts

@@ -1,11 +1,24 @@
 import { ConfigMarkdown } from "@/config/markdown"
 import { Config } from "../config/config"
 import { MCP } from "../mcp"
+import { Provider } from "../provider/provider"
 import { UI } from "./ui"
 
 export function FormatError(input: unknown) {
   if (MCP.Failed.isInstance(input))
     return `MCP server "${input.data.name}" failed. Note, opencode does not support MCP authentication yet.`
+  if (Provider.ModelNotFoundError.isInstance(input)) {
+    const { providerID, modelID, suggestions } = input.data
+    return [
+      `Model not found: ${providerID}/${modelID}`,
+      ...(Array.isArray(suggestions) && suggestions.length ? ["Did you mean: " + suggestions.join(", ")] : []),
+      `Try: \`opencode models\` to list available models`,
+      `Or check your config (opencode.json) provider/model names`,
+    ].join("\n")
+  }
+  if (Provider.InitError.isInstance(input)) {
+    return `Failed to initialize provider "${input.data.providerID}". Check credentials and configuration.`
+  }
   if (Config.JsonError.isInstance(input)) {
     return (
       `Config file at ${input.data.path} is not valid JSON(C)` + (input.data.message ? `: ${input.data.message}` : "")

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

@@ -1,4 +1,5 @@
 import z from "zod"
+import fuzzysort from "fuzzysort"
 import { Config } from "../config/config"
 import { mergeDeep, sortBy } from "remeda"
 import { NoSuchModelError, type LanguageModel, type Provider as SDK } from "ai"
@@ -597,9 +598,21 @@ export namespace Provider {
     })
 
     const provider = s.providers[providerID]
-    if (!provider) throw new ModelNotFoundError({ providerID, modelID })
+    if (!provider) {
+      const availableProviders = Object.keys(s.providers)
+      const matches = fuzzysort.go(providerID, availableProviders, { limit: 3, threshold: -10000 })
+      const suggestions = matches.map((m) => m.target)
+      throw new ModelNotFoundError({ providerID, modelID, suggestions })
+    }
+
     const info = provider.info.models[modelID]
-    if (!info) throw new ModelNotFoundError({ providerID, modelID })
+    if (!info) {
+      const availableModels = Object.keys(provider.info.models)
+      const matches = fuzzysort.go(modelID, availableModels, { limit: 3, threshold: -10000 })
+      const suggestions = matches.map((m) => m.target)
+      throw new ModelNotFoundError({ providerID, modelID, suggestions })
+    }
+
     const sdk = await getSDK(provider.info, info)
 
     try {
@@ -700,6 +713,7 @@ export namespace Provider {
     z.object({
       providerID: z.string(),
       modelID: z.string(),
+      suggestions: z.array(z.string()).optional(),
     }),
   )