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

This commit is contained in:
Dax Raad 2025-06-16 15:02:25 -04:00
parent 63996c4189
commit 2c9fd1e776
8 changed files with 28 additions and 19 deletions

View file

@ -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"

View file

@ -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"
},

View file

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

View file

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

View file

@ -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"))

View file

@ -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)

View file

@ -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({

View file

@ -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 =