mirror of
https://github.com/sst/opencode.git
synced 2025-07-07 16:14:59 +00:00
support global config for providers
This commit is contained in:
parent
ee91f31313
commit
d579c5e8aa
4 changed files with 84 additions and 22 deletions
48
README.md
48
README.md
|
@ -61,9 +61,51 @@ The Models.dev dataset is also used to detect common environment variables like
|
|||
|
||||
If there are additional providers you want to use you can submit a PR to the [Models.dev repo](https://github.com/sst/models.dev). If configuring just for yourself check out the Config section below.
|
||||
|
||||
### Global Config
|
||||
|
||||
Some basic configuration is available in the global config file.
|
||||
|
||||
```toml title="~/.config/opencode/config.toml"
|
||||
theme = "opencode"
|
||||
provider = "anthropic"
|
||||
model = "claude-sonnet-4-20250514"
|
||||
autoupdate = true
|
||||
```
|
||||
|
||||
You can also extend the models.dev database with your own providers and models by placing a `provider.toml` file in `~/.config/opencode/providers`.
|
||||
|
||||
```toml title="~/.config/opencode/providers/openrouter/provider.toml"
|
||||
[provider]
|
||||
name = "OpenRouter"
|
||||
env = ["OPENROUTER_API_KEY"]
|
||||
id = "openrouter"
|
||||
npm = "@openrouter/ai-sdk-provider"
|
||||
```
|
||||
|
||||
And models in `~/.config/opencode/providers/openrouter/models/[model-id]`.
|
||||
|
||||
```toml title="~/.config/opencode/providers/openrouter/models/anthropic/claude-3.5-sonnet.toml"
|
||||
name = "Claude 4 Sonnet"
|
||||
attachment = true
|
||||
reasoning = false
|
||||
temperature = true
|
||||
|
||||
[cost]
|
||||
input = 3.00
|
||||
output = 15.00
|
||||
inputCached = 3.75
|
||||
outputCached = 0.30
|
||||
|
||||
[limit]
|
||||
context = 200_000
|
||||
output = 50_000
|
||||
```
|
||||
|
||||
This mirrors the structure found [here](https://github.com/sst/models.dev/tree/dev/providers/anthropic)
|
||||
|
||||
### Project Config
|
||||
|
||||
Project configuration is optional. You can place an `opencode.json` file in the root of your repo, and it'll be loaded.
|
||||
Project configuration is optional. You can place an `opencode.json` file in the root of your repo and is meant to be checked in and shared with your team.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
|
@ -106,9 +148,7 @@ You can use opencode with any provider listed at [here](https://ai-sdk.dev/provi
|
|||
"baseURL": "http://localhost:11434/v1"
|
||||
},
|
||||
"models": {
|
||||
"llama2": {
|
||||
"name": "llama2"
|
||||
}
|
||||
"llama2": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"mcp": {},
|
||||
"provider": {
|
||||
"openrouter": {
|
||||
"npm": "@openrouter/ai-sdk-provider",
|
||||
"name": "OpenRouter",
|
||||
"models": {
|
||||
"anthropic/claude-sonnet-4": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
"provider": {}
|
||||
}
|
||||
|
|
|
@ -8,17 +8,19 @@ const data = path.join(xdgData!, app)
|
|||
const cache = path.join(xdgCache!, app)
|
||||
const config = path.join(xdgConfig!, app)
|
||||
|
||||
await Promise.all([
|
||||
fs.mkdir(data, { recursive: true }),
|
||||
fs.mkdir(config, { recursive: true }),
|
||||
fs.mkdir(cache, { recursive: true }),
|
||||
])
|
||||
|
||||
export namespace Global {
|
||||
export const Path = {
|
||||
data,
|
||||
bin: path.join(data, "bin"),
|
||||
providers: path.join(config, "providers"),
|
||||
cache,
|
||||
config,
|
||||
} as const
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
fs.mkdir(data, { recursive: true }),
|
||||
fs.mkdir(config, { recursive: true }),
|
||||
fs.mkdir(cache, { recursive: true }),
|
||||
fs.mkdir(Global.Path.providers, { recursive: true }),
|
||||
])
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import z from "zod"
|
||||
import path from "path"
|
||||
import { App } from "../app/app"
|
||||
import { Config } from "../config/config"
|
||||
import { mergeDeep, sortBy } from "remeda"
|
||||
|
@ -24,6 +25,7 @@ import { NamedError } from "../util/error"
|
|||
import { Auth } from "../auth"
|
||||
import { TaskTool } from "../tool/task"
|
||||
import { GlobalConfig } from "../global/config"
|
||||
import { Global } from "../global"
|
||||
|
||||
export namespace Provider {
|
||||
const log = Log.create({ service: "provider" })
|
||||
|
@ -103,9 +105,35 @@ export namespace Provider {
|
|||
provider.source = source
|
||||
}
|
||||
|
||||
for (const [providerID, provider] of Object.entries(
|
||||
config.provider ?? {},
|
||||
)) {
|
||||
const configProviders = Object.entries(config.provider ?? {})
|
||||
for await (const providerPath of new Bun.Glob("*/provider.toml").scan({
|
||||
cwd: Global.Path.providers,
|
||||
})) {
|
||||
const [providerID] = providerPath.split("/")
|
||||
const toml = await import(
|
||||
path.join(Global.Path.providers, providerPath),
|
||||
{
|
||||
with: {
|
||||
type: "toml",
|
||||
},
|
||||
}
|
||||
).then((mod) => mod.default)
|
||||
toml.models = {}
|
||||
const modelsPath = path.join(Global.Path.providers, providerID, "models")
|
||||
for await (const modelPath of new Bun.Glob("**/*.toml").scan({
|
||||
cwd: modelsPath,
|
||||
})) {
|
||||
const modelID = modelPath.slice(0, -5)
|
||||
toml.models[modelID] = await import(path.join(modelsPath, modelPath), {
|
||||
with: {
|
||||
type: "toml",
|
||||
},
|
||||
})
|
||||
}
|
||||
configProviders.unshift([providerID, toml])
|
||||
}
|
||||
|
||||
for (const [providerID, provider] of configProviders) {
|
||||
const existing = database[providerID]
|
||||
const parsed: ModelsDev.Provider = {
|
||||
id: providerID,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue