support global config

This commit is contained in:
Dax Raad 2025-06-18 18:56:41 -04:00
parent 6a00e063c4
commit 6a3392385e
4 changed files with 16 additions and 42 deletions

View file

@ -114,43 +114,6 @@ messages_last = "ctrl+alt+g"
app_exit = "ctrl+c,<leader>q"
```
#### Models.dev
You can also extend the models.dev database with your own providers by mirroring the structure found [here](https://github.com/sst/models.dev/tree/dev/providers/anthropic)
Start with a `provider.toml` file in `~/.config/opencode/providers`
```toml
# ~/.config/opencode/providers/openrouter/provider.toml
[provider]
name = "OpenRouter"
env = ["OPENROUTER_API_KEY"]
npm = "@openrouter/ai-sdk-provider"
[options]
baseURL = "https://api.openrouter.ai" # optional settings
```
And models in `~/.config/opencode/providers/openrouter/models/[model-id]`
```toml
# ~/.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
```
### Project Config
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.
@ -230,9 +193,7 @@ OpenRouter is not in the Models.dev database yet, but you can configure it manua
"openrouter": {
"npm": "@openrouter/ai-sdk-provider",
"name": "OpenRouter",
"options": {
"apiKey": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
"options": {},
"models": {
"anthropic/claude-3.5-sonnet": {
"name": "Claude 3.5 Sonnet"
@ -243,6 +204,8 @@ OpenRouter is not in the Models.dev database yet, but you can configure it manua
}
```
And then to configure an api key you can do `opencode auth login` and select "Other -> 'openrouter'"
#### How is this different than Claude Code?
It's very similar to Claude Code in terms of capability. Here are the key differences:

View file

@ -1,14 +1,20 @@
import { Log } from "../util/log"
import path from "path"
import { z } from "zod"
import { App } from "../app/app"
import { Filesystem } from "../util/filesystem"
import { ModelsDev } from "../provider/models"
import { mergeDeep } from "remeda"
import { Global } from "../global"
export namespace Config {
const log = Log.create({ service: "config" })
export const state = App.state("config", async (app) => {
let result: Info = {}
let result = await Bun.file(path.join(Global.Path.config, "config.json"))
.json()
.then((mod) => Info.parse(mod))
.catch(() => ({}) as Info)
for (const file of ["opencode.jsonc", "opencode.json"]) {
const [resolved] = await Filesystem.findUp(
file,
@ -17,7 +23,10 @@ export namespace Config {
)
if (!resolved) continue
try {
result = await import(resolved).then((mod) => Info.parse(mod.default))
result = mergeDeep(
result,
await import(resolved).then((mod) => Info.parse(mod.default)),
)
log.info("found", { path: resolved })
break
} catch (e) {

View file

@ -32,6 +32,7 @@ export namespace ModelsDev {
export const Provider = z
.object({
api: z.string().optional(),
name: z.string(),
env: z.array(z.string()),
id: z.string(),

View file

@ -103,6 +103,7 @@ export namespace Provider {
if (!provider) {
const info = database[id]
if (!info) return
if (info.api) options["baseURL"] = info.api
providers[id] = {
source,
info,