docs(opencode): document v2 config, mark v1 deprecated
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
17747694bd
commit
d9fc3418a1
1 file changed
+109
-33
@@ -2,18 +2,114 @@
|
|||||||
|
|
||||||
[← back to overview](index.md)
|
[← back to overview](index.md)
|
||||||
|
|
||||||
> **Source of truth:** [OpenCode's docs](https://opencode.ai/docs/) for config keys; the [overview](index.md) for the gateway endpoint and context size. If this page disagrees with them, they win.
|
> **Source of truth:** [OpenCode v2 docs](https://opencode.ai/v2/docs) for config keys; the [overview](index.md) for the gateway endpoint and context size. If this page disagrees with them, they win. The v1 config is [deprecated](#v1-config-deprecated) but kept for installs that haven't migrated.
|
||||||
|
|
||||||
Confirmed project: **`anomalyco/opencode`** (renamed from `sst/opencode` — don't confuse with the unrelated `opencode-ai/opencode` Go TUI). Docs: https://opencode.ai/docs/
|
OpenCode is **`anomalyco/opencode`** (renamed from `sst/opencode`). Don't confuse it with the unrelated `opencode-ai/opencode` Go TUI. It speaks plain **OpenAI Chat Completions**, so it talks to the gateway like any other OpenAI-compatible client.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
**Install**:
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://opencode.ai/install | bash
|
curl -fsSL https://opencode.ai/v2/install | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
**Config** (`opencode.json`, project root or `~/.config/opencode/opencode.json`):
|
Homebrew, npm, bun, pnpm, yarn and AUR also work. See the [v2 docs](https://opencode.ai/v2/docs).
|
||||||
|
|
||||||
```json
|
## Config (v2)
|
||||||
|
|
||||||
|
`opencode.json` or `opencode.jsonc`, in the project root (or `.opencode/`) or globally at `~/.config/opencode/opencode.json`. OpenCode searches upward from the current directory and merges, closest file wins.
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"$schema": "https://opencode.ai/config.json",
|
||||||
|
"providers": {
|
||||||
|
"omniroute": {
|
||||||
|
"name": "OmniRoute",
|
||||||
|
"package": "aisdk:@ai-sdk/openai-compatible",
|
||||||
|
"settings": {
|
||||||
|
"baseURL": "https://<YOUR-OMNIROUTE-PROXY>/v1",
|
||||||
|
"apiKey": "<token>"
|
||||||
|
},
|
||||||
|
"models": {
|
||||||
|
"qwen3.8-27b": {
|
||||||
|
"modelID": "qwen3.8-27b-local//models/Qwen3.8-27B-UD-Q4_K_XL.gguf",
|
||||||
|
"name": "Qwen3.8-27B",
|
||||||
|
"capabilities": { "tools": true, "input": ["text"], "output": ["text"] },
|
||||||
|
"compatibility": { "reasoningField": "reasoning_content" },
|
||||||
|
"limit": { "context": 260000, "output": 32000 },
|
||||||
|
"cost": { "input": 0.4, "output": 3 },
|
||||||
|
"body": {
|
||||||
|
"temperature": 1,
|
||||||
|
"top_p": 0.95,
|
||||||
|
"top_k": 20,
|
||||||
|
"min_p": 0,
|
||||||
|
"presence_penalty": 0,
|
||||||
|
"chat_template_kwargs": { "reasoning_effort": "xhigh" }
|
||||||
|
},
|
||||||
|
"variants": [
|
||||||
|
{ "id": "medium", "body": { "chat_template_kwargs": { "reasoning_effort": "medium" } } },
|
||||||
|
{ "id": "fast", "body": { "chat_template_kwargs": { "reasoning_effort": "low" } } },
|
||||||
|
{
|
||||||
|
"id": "instruct",
|
||||||
|
"body": {
|
||||||
|
"temperature": 0.7,
|
||||||
|
"top_p": 0.8,
|
||||||
|
"presence_penalty": 1.5,
|
||||||
|
"chat_template_kwargs": { "enable_thinking": false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### What each part does
|
||||||
|
|
||||||
|
| Key | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `providers` | Plural in v2 (v1: `provider`). The key (`omniroute`) is the prefix in model references. |
|
||||||
|
| `package` | The adapter for the API shape. This stack uses an OpenAI-compatible one. |
|
||||||
|
| `settings.baseURL` | The gateway URL, up to and including `/v1`. |
|
||||||
|
| `settings.apiKey` | The gateway API key issued to OpenCode ([gateway → API keys](../gateway.md#api-keys)). The v2 docs' own examples use an `env` list instead, to keep the key out of the file. |
|
||||||
|
| `models.<key>` | The short name you select. `modelID` is the id the gateway exposes, which the key doesn't have to match. |
|
||||||
|
| `capabilities` | Declares tool calling and input/output modalities. |
|
||||||
|
| `compatibility.reasoningField` | Where the backend returns reasoning text. llama.cpp uses `reasoning_content`. |
|
||||||
|
| `limit` | OpenCode's own context bookkeeping. The server doesn't read it. See [overview](index.md) for the number to use. |
|
||||||
|
| `body` | Extra request fields, sent on every call. Sampling values and `chat_template_kwargs` go here. |
|
||||||
|
| `variants` | Named overrides on top of `body`. |
|
||||||
|
|
||||||
|
### Selecting a model and variant
|
||||||
|
|
||||||
|
Format: `provider/model#variant`. The provider ends at the first `/`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
opencode run --model omniroute/qwen3.8-27b # default: xhigh reasoning
|
||||||
|
opencode run --model omniroute/qwen3.8-27b#medium
|
||||||
|
opencode run --model omniroute/qwen3.8-27b#fast # low reasoning effort
|
||||||
|
opencode run --model omniroute/qwen3.8-27b#instruct # thinking off, instruct sampling
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
- **Unverified keys:** the v2 docs show `"package": "@opencode/ai/providers/openai-compatible"` for custom providers, while this config uses the `aisdk:@ai-sdk/openai-compatible` form. The docs pages I could read don't confirm that prefix. If OpenCode rejects the provider, switch `package` to the documented value.
|
||||||
|
- **Variants:** the v2 docs' own variant example puts settings under `settings`. This config uses `body`, which the models page lists as valid for provider-specific request fields.
|
||||||
|
- **`limit.context`:** [overview](index.md) explains how per-slot context is derived. The example above uses a larger value than a plain per-slot division gives.
|
||||||
|
|
||||||
|
## OpenCode-specific risks
|
||||||
|
|
||||||
|
On top of the shared Qwen3.8-27B tool-calling risk (see [overview](index.md)):
|
||||||
|
|
||||||
|
- Relies on the backend's `--jinja` flag ([architecture → llama-server](../architecture.md#llama-server)). Without it, OpenCode's unconditional tool-call scaffolding gets a 500.
|
||||||
|
- [anomalyco/opencode#20669](https://github.com/anomalyco/opencode/issues/20669) (closed as "not planned", so a live, unfixed risk): OpenCode's `bash` tool crashes if the model omits the optional `description` field on a tool call. Some local backends return `finish_reason: tool_calls` with an empty array, which can hang the agent loop instead of stopping it.
|
||||||
|
- Reasoning control goes through `chat_template_kwargs` in `body`, not OpenCode's native `reasoningEffort`. The native key has no effect against llama.cpp.
|
||||||
|
|
||||||
|
## V1 config (deprecated)
|
||||||
|
|
||||||
|
Use this only on OpenCode v1. It is no longer maintained here. Differences from v2: `provider` (singular), `npm` instead of `package`, `options` instead of `settings`, and a flat `reasoning` / `interleaved` block instead of `capabilities` / `compatibility`, and no `variants` or `body` in this config.
|
||||||
|
|
||||||
|
```jsonc
|
||||||
{
|
{
|
||||||
"$schema": "https://opencode.ai/config.json",
|
"$schema": "https://opencode.ai/config.json",
|
||||||
"model": "omniroute/qwen3.8-27b-local//models/Qwen3.8-27B-UD-Q4_K_XL.gguf",
|
"model": "omniroute/qwen3.8-27b-local//models/Qwen3.8-27B-UD-Q4_K_XL.gguf",
|
||||||
@@ -21,43 +117,23 @@ curl -fsSL https://opencode.ai/install | bash
|
|||||||
"omniroute": {
|
"omniroute": {
|
||||||
"npm": "@ai-sdk/openai-compatible",
|
"npm": "@ai-sdk/openai-compatible",
|
||||||
"name": "OmniRoute",
|
"name": "OmniRoute",
|
||||||
"options": {
|
"options": { "baseURL": "https://<YOUR-OMNIROUTE-PROXY>/v1" },
|
||||||
"baseURL": "https://<YOUR-OMNIROUTE-PROXY>/v1"
|
|
||||||
},
|
|
||||||
"models": {
|
"models": {
|
||||||
"qwen3.8-27b-local//models/Qwen3.8-27B-UD-Q4_K_XL.gguf": {
|
"qwen3.8-27b-local//models/Qwen3.8-27B-UD-Q4_K_XL.gguf": {
|
||||||
"name": "Qwen3.8-27B",
|
"name": "Qwen3.8-27B",
|
||||||
"reasoning": true,
|
"reasoning": true,
|
||||||
"interleaved": {
|
"interleaved": { "field": "reasoning_content" },
|
||||||
"field": "reasoning_content"
|
"limit": { "context": 131000, "output": 65536 },
|
||||||
},
|
"cost": { "input": 0.4, "output": 3.0, "cache": { "read": 0.04, "write": 0 } }
|
||||||
"limit": {
|
|
||||||
"context": 131000,
|
|
||||||
"output": 65536
|
|
||||||
},
|
|
||||||
"cost": {
|
|
||||||
"input": 0.4,
|
|
||||||
"output": 3.0,
|
|
||||||
"cache": {
|
|
||||||
"read": 0.04,
|
|
||||||
"write": 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`limit.context` is the per-slot context ([overview](index.md)). OpenCode uses it for its own context bookkeeping; the server doesn't read it.
|
Select the model with `omniroute/<model-key>`. The v1 install script is `curl -fsSL https://opencode.ai/install | bash`.
|
||||||
|
|
||||||
Select the model with `llm-server/qwen3.8-27b-local`.
|
## Further reading
|
||||||
|
|
||||||
**OpenCode-specific risks** (on top of the shared Qwen3.8-27B tool-calling risk — see [overview](index.md)):
|
[`research/opencode-cli-setup.md`](../research/opencode-cli-setup.md) (v1-era, base URL predates the gateway), [`research/opencode-auto-compact.md`](../research/opencode-auto-compact.md).
|
||||||
- Relies on the backend's `--jinja` flag ([architecture → llama-server](../architecture.md#llama-server)); without it, OpenCode's unconditional tool-call scaffolding gets a 500.
|
|
||||||
- [anomalyco/opencode#20669](https://github.com/anomalyco/opencode/issues/20669) (closed as "not planned" — a live, unfixed risk): OpenCode's `bash` tool crashes if the model omits the optional `description` field on a tool call; some local backends return `finish_reason: tool_calls` with an empty array, which can hang the agent loop instead of stopping cleanly.
|
|
||||||
- Thinking-mode handling (`options.reasoningEffort`) is undocumented for models that emit inline `<think>` tags rather than a native reasoning API field — expect no effect from that config on this model; untested.
|
|
||||||
|
|
||||||
Further reading: [`research/opencode-cli-setup.md`](../research/opencode-cli-setup.md) (its base URL example predates the gateway), [`research/opencode-auto-compact.md`](../research/opencode-auto-compact.md).
|
|
||||||
Reference in new issue
Block a user