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

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
This commit is contained in:
Ian Maurer 2025-11-21 03:01:19 -05:00 committed by GitHub
parent d16c8c9f0f
commit e018e16898
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 29 additions and 2 deletions

View file

@ -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}` : "")

View file

@ -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(),
}),
)