Skip to content

feat: support OpenCode V2 plugin API (dual V1/V2 entrypoint) - #4

Merged
grikomsn merged 1 commit into
mainfrom
feat/opencode-v2-plugin
Sep 12, 2026
Merged

grikomsn merged 1 commit into
mainfrom
feat/opencode-v2-plugin

Conversation

@grikomsn

Copy link
Copy Markdown
Owner

Summary

Adds OpenCode V2 plugin API support in a minor release (0.3.0), following the official V1 plugin migration guide. The 0.2.x line remains the V1-only line; users on OpenCode < 1.18.29 stay on 0.2.

Changes

  • Dual entrypoint (plugin.ts): default export spreads a V2 Plugin.define({ id: "orvix", setup }) with the V1 server() function returning the classic config + auth hooks. V1 (≥ 1.18.29) calls server(); V2 reads id/setup.
  • src/v2.ts (new) — V2 registration:
    • ctx.catalog.transform: creates the orvix provider (aisdk:@ai-sdk/openai-compatible, baseURL https://api.orvix.id/v1, integrationID) and upserts the model catalog in the V2 shape (variants as array, tiered $/Mtok costs, capabilities).
    • ctx.integration.transform: registers env (ORVIX_API_KEY) + key credential methods on the orvix integration (V2 replacement for the V1 auth hook).
    • Live /models discovery, fallback catalog, and user-model preservation match V1 semantics exactly.
  • @opencode/plugin added as a runtime dependency; @ai-sdk/openai-compatible stays an optional peer.
  • Docs: README gains V2 quick-start/config sections; AGENTS.md documents the dual-entrypoint and the runtime provider.list() shape caveat.

Validation

  • npm run check (typecheck + 58 tests, incl. 10 new V2 tests with a stubbed plugin context) and npm run package pass locally.
  • Validated the real plugin.ts against local OpenCode 2.0.2: provider + 19 fallback models registered, env credential resolved through the registered env method, and all orvix/* models selectable via opencode models.
  • Spike findings that shaped the implementation (all verified against OpenCode 2.0.2):
    • catalog.provider.update creates missing providers (applied on registry replay).
    • orvix exists as a built-in V2 integration; methods can be attached by the plugin.
    • Runtime catalog.provider.list() returns flat records, unlike the published .d.ts — V2 context is typed structurally in src/v2.ts to avoid coupling.
  • Remaining follow-up: one live request with a real API key (local .env key is empty); routing path/provider/package are otherwise verified.

- Dual default export: V2 Plugin.define({ id: "orvix", setup }) spread with
  the V1 server() function (config + auth hooks), per the official
  migrate-v1 pattern. Requires OpenCode >= 1.18.29 for the V1 object
  entrypoint.
- New src/v2.ts: catalog transform registering the orvix provider
  (aisdk:@ai-sdk/openai-compatible, base URL, integrationID) and upserting
  models in the V2 shape (variant array, tiered costs, capabilities);
  integration transforms registering env + key credential methods.
- Live /models discovery, fallback catalog, and user-model preservation
  match V1 semantics.
- Add @opencode/plugin as a runtime dependency.
- Validate against local OpenCode 2.0.2: provider + 19 models registered,
  env credential resolved, orvix/* selectable via 'opencode models'.
@grikomsn
grikomsn merged commit 3b2eaa3 into main Sep 12, 2026
3 checks passed
@grikomsn
grikomsn deleted the feat/opencode-v2-plugin branch September 12, 2026 19:57
algonacci added a commit that referenced this pull request Oct 3, 2026
## Summary

The OpenCode 2.x entrypoint no longer loads on current OpenCode.
`@opencode/plugin` 2.0.4 (2026-09-16) removed `ctx.catalog`, so setup
throws:

```
failed to load plugin  plugin.id=orvix  cause="TypeError: undefined is not an object (evaluating 'ctx.catalog.transform')"
```

After that error every `orvix/*` model reports `Model unavailable`. The
V2 support from #4 targeted 2.0.2, which still had `catalog`.

This PR makes two changes:

- **Register through `ctx.provider.transform`.** If the provider does
not exist yet, the plugin calls `add({ info, models })`. If the user
already configured it, the plugin fills in missing provider fields with
`update` and appends its models with `models.set`. User-configured
provider fields and models are still never overwritten. Each model
record now carries `id` (the OpenCode key), `modelID` (the exact
upstream id, so managed `orvix/*` and BYOK ids still go upstream
verbatim), and `providerID`.
- **Put reasoning variants in `body`.** Variants stored
`reasoning_effort` under `settings`, which configures the provider
package and is never sent in the request. Selecting
`orvix/muse-spark-1.3#high` therefore sent no `reasoning_effort`.
Variants now use `body`.

The test fakes now mirror the provider editor. AGENTS.md and the README
no longer mention the catalog API. A patch changeset is included.

## Verification

- `npm run check`: typecheck clean, 58/58 tests pass.
- `npm run package`: passes.
- End-to-end on OpenCode 2.0.21 (`opencode run --standalone`, isolated
XDG dirs) against a local mock OpenAI-compatible server, with
`providers.orvix.settings.baseURL` pointing at the mock:
- Before: the plugin fails to load and `orvix/glm-5.3-flash` is
unavailable.
- After: the plugin loads, and requests reach `/v1/chat/completions`
with `model: "orvix/muse-spark-1.3"` / `"orvix/glm-5.3-flash"` and a
bearer key. The user's `baseURL` override is respected.
- `-m orvix/muse-spark-1.3#high` now sends `reasoning_effort: "high"`.
Models without variants send none.
- Not tested against the live Orvix API.

## Checklist

- [x] The change is focused and contains no unrelated churn.
- [x] Tests pass with `npm run check`.
- [x] Packaging passes with `npm run package`.
- [x] User-visible changes include a Changeset; otherwise, this is not
applicable.
- [x] Relevant documentation is updated; otherwise, this is not
applicable.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant