Custom plugins for opencode.
  • JavaScript 100%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
rwxd a0cbe57a66
fix(partial pricing): only include finite cost fields, add network failure test
- Build cost object only from present finite values
- Skip cache_read/cache_write unless input or output pricing exists
- Omit cost key entirely when no finite pricing data
- Add test for ECONNREFUSED path (fetch throws, not HTTP error)
2026-09-21 21:07:29 +02:00
test fix(partial pricing): only include finite cost fields, add network failure test 2026-09-21 21:07:29 +02:00
dynamic-models.mjs fix(partial pricing): only include finite cost fields, add network failure test 2026-09-21 21:07:29 +02:00
package.json feat: support litellm-style gateways and add unit tests 2026-09-21 14:44:10 +02:00
README.md docs: plugin path 2026-09-21 15:37:33 +02:00

opencode-plugins

Custom plugins for opencode.

Setup

git clone ssh://git@git.chaops.de/rwxd/opencode-plugins.git <path>
mkdir -p ~/.config/opencode/plugin
ln -s <path>/dynamic-models.mjs ~/.config/opencode/plugin/<plugin>

Replace <path> with the directory you want to clone into, e.g. ~/dev/opencode-plugins.

Then register the symlink in ~/.config/opencode/opencode.json and restart opencode:

{
  "plugin": ["/home/<user>/.config/opencode/plugin/dynamic-models.mjs"]
}

Plugins

dynamic-models

Discovers models, pricing and capabilities for any OpenAI-compatible provider by querying its /v1/models endpoint at startup. Use it for gateways that expose an OpenAI-compatible API but are not a provider opencode already knows a model catalogue for (e.g. GoModel instances). opencode has no built-in support for this, so a custom provider plus this plugin is required.

Set dynamic: true on the provider's options. No models entry is needed, they are discovered automatically. Multiple providers are supported, add dynamic: true to each. Discovery failures are shown as a toast and logged via client.app.log, the provider simply has no models for that session.

apiKey is optional. If set it is used as a fallback, but credentials from opencode auth login for the same provider ID take precedence. They are read from $XDG_DATA_HOME/opencode/auth.json (default ~/.local/share/opencode/auth.json), honoring the OPENCODE_AUTH_CONTENT environment variable. Only api type credentials are used, OAuth credentials are ignored. A provider without a resolvable key is skipped and reported as an error.

Custom providers like this do not appear in /connect's provider list, that list only contains models.dev providers and providers registered by plugin auth hooks. To store a key via opencode, run /connect (or opencode auth login), pick Other, enter the provider ID (e.g. my-gateway) and paste the API key, the plugin picks it up from auth.json automatically.

{
  "provider": {
    "my-gateway": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "My Gateway",
      "options": {
        "baseURL": "https://<your-gateway>/v1",
        "apiKey": "sk-...",
        "dynamic": true
      }
    }
  }
}

Discovered metadata is mapped to opencode's model fields when present:

/v1/models field opencode field
metadata.display_name name
metadata.capabilities.reasoning reasoning
metadata.capabilities.function_calling tool_call
metadata.capabilities.vision attachment
metadata.context_window / metadata.max_output_tokens limit.context / limit.output
metadata.pricing.*_per_mtok cost.input / cost.output / cost.cache_read / cost.cache_write

Model IDs are used verbatim, so a gateway that advertises a virtual model (e.g. deepseek-flash) alongside the concrete provider model it targets (deepseek/deepseek-flash) lists both. When both share a display name, the concrete entry is named by its full ID so the two stay distinguishable in the picker; the virtual model keeps its display name. Missing metadata fields are omitted so opencode's defaults apply (e.g. tool_call defaults to true).

Models whose mode is set to anything other than chat or completion are skipped, so LiteLLM-style gateways that also expose embeddings or rerankers don't list them in the picker. Gateways that don't send mode are unaffected.

Tests

npm test

Uses Node's built-in test runner, no dependencies. Gateway /v1/models responses are stored as fixtures in test/fixtures/.