Skip to content

feat: rebuild the Cursor adapter for OpenCode V2 - #35

Open
CasualDeveloper wants to merge 2 commits into
otto-assistant:betafrom
CasualDeveloper:feat/opencode-v2-host-owned-cursor
Open

CasualDeveloper wants to merge 2 commits into
otto-assistant:betafrom
CasualDeveloper:feat/opencode-v2-host-owned-cursor

Conversation

@CasualDeveloper

@CasualDeveloper CasualDeveloper commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Hey, @makeittech - was excited to try out Astra and I think it did a great job with our plugin!

Issue for this PR

Refs #31. Please keep it open through publication and release checks.

This PR supersedes #34 and includes its release-flow documentation and constants-test explanation. Please review and merge this PR directly.

Type of change

  • New feature
  • Refactor / code improvement

What does this PR do?

I rebuilt the Cursor adapter for OpenCode V2 and removed the old proxy and compatibility code. It keeps private models and exact variants while OpenCode manages history, tools, permissions, and compaction.

Each new Cursor Run is built from OpenCode's messages and tool results, including images and reasoning data. This lets the host recover after a lost connection or restart without a second conversation store.

It also fixes usage reporting that could trigger compaction too early. Cursor Run totals are saved separately from per-call usage. Where per-call counts are unavailable, OpenCode's displayed token and cost totals remain incomplete.

I updated the adapter after OpenCode removed context.catalog. It now uses context.provider.transform() and reload(), refreshes models on credential.switched, and preserves failed-tool outcomes in structured compaction requests. Dependencies and the test host are pinned to released @opencode/* 2.0.6. Older hosts with the catalog API are no longer supported.

Grok opaque-reasoning checkpoints no longer fail a completed turn when a root has no unique assistant anchor. Cursor usable-model IDs group into families: none is the non-thinking SKU, and thinking SKUs become low/medium/high/xhigh/max.

The OpenCode id stays the stable catalog name, such as grok-4.6. Each variant still sends Cursor's exact wire id, such as cursor-grok-4.6-xhigh. All non-duplicate models from AvailableModels are published so newly released and parameterized models (such as Grok 4.7 and Grok 4.7 500K) appear in OpenCode's picker. If OpenCode has loaded a models.dev Cursor row, I copy that row's limits and price. I do not copy lab caps, and I do not replace the live catalog with a static list.

I also fixed model grouping against Cursor's real parameter spellings: any effort parameter (including reasoning_effort and minimal) groups into variants on one model, and Claude's thinking flag stays on that same model (none is non-thinking, while effort variants keep thinking enabled) instead of creating separate models. Connect error message details are also preserved in the transport.

The restrictive x-cursor-agent-allowed-tools header is omitted when tools are enabled so Cursor does not strip its internal meta-tools (GET_MCP_TOOLS) or fail at bootstrap, and only sent as "" when tools are explicitly disabled. The runner supports Cursor's native workspace execution requests (shellStreamArgs, shellArgs, grepArgs, readArgs, writeArgs, lsArgs) by mapping them to OpenCode host tools and formatting their native results. Calls to grepArgs with an empty or whitespace pattern automatically route to OpenCode's glob tool with files_with_matches results, and tool result JSON envelopes are unwrapped for native Cursor actions.

How did you verify your code works?

The current head is b99cfe8. I amended this onto the previous head because #35 had no review activity. Unit tests and typecheck pass locally.

Live end-to-end multi-turn tool loops were verified on Mac and WSL for both Composer 2.5 and Grok 4.7 (reading files, searching glob/grep, executing shell commands, and returning final answers).

The earlier CI run for 30f75a3 failed in test:v2-host: OpenCode 2.0.6 rejected a permission reply as Missing key ["decision"].

Instruction priority, opaque-reasoning replay, and continued work after automatic compaction still need live verification.

The test report records the remaining limits.

Checklist

  • I have tested my changes locally.
  • I have not included unrelated changes in this PR.

@CasualDeveloper
CasualDeveloper marked this pull request as draft September 10, 2026 13:03
@CasualDeveloper
CasualDeveloper force-pushed the feat/opencode-v2-host-owned-cursor branch from 4faffe5 to 341c781 Compare September 10, 2026 18:11
@CasualDeveloper CasualDeveloper changed the title feat: rebuild Cursor V2 adapter around host-owned history feat: replace beta with a V2-only host-owned Cursor adapter Sep 10, 2026
@CasualDeveloper
CasualDeveloper marked this pull request as ready for review September 10, 2026 18:17
@CasualDeveloper CasualDeveloper changed the title feat: replace beta with a V2-only host-owned Cursor adapter feat: rebuild the Cursor adapter for OpenCode V2 Sep 10, 2026
@CasualDeveloper
CasualDeveloper force-pushed the feat/opencode-v2-host-owned-cursor branch from 341c781 to 3670345 Compare September 16, 2026 05:07
@CasualDeveloper
CasualDeveloper force-pushed the feat/opencode-v2-host-owned-cursor branch 10 times, most recently from 5383b10 to 9719566 Compare September 22, 2026 23:55
Reconstruct roles, tool outcomes, images, and reasoning from OpenCode's
history. Preserve exact private-model selections while OpenCode owns tools,
permissions, steering, persistence, and compaction. Remove the old proxy
and compatibility implementation from the V2 channel.

Use bounded per-Run HTTP/2 workers, validated Connect completion, and
authoritative host tool handoffs. Save aggregate Run usage separately from
per-call usage, and preserve signed and opaque reasoning through restart.
Host instructions use ordered global rules with best-effort precedence.

Target released @opencode/plugin, @opencode/schema, and @opencode/cli 2.0.6.
Replace the removed catalog API with provider source registration and reload.

Match opaque checkpoint roots to visible text and tools even when Cursor
also streamed thinking. Omit unmatched extra roots instead of failing an
already-streamed answer.

Treat Cursor reasoning-effort as a variant parameter, recognizing any
effort-valued parameter including reasoning_effort and minimal. Keep Claude
thinking on that same model: none is non-thinking, and thinking SKUs become
low/medium/high/xhigh/max. Prefer default, then none, low, medium, high,
xhigh, max. Preserve Connect error message details in the transport.

Publish all non-duplicate models from AvailableModels so newly released and
parameterized models (including Grok 4.7 and Grok 4.7 500K) appear in
OpenCode's picker, sending exact usable wire IDs on each variant. Omit the
restrictive x-cursor-agent-allowed-tools header when tools are enabled so
Cursor does not strip its internal meta-tools and fail at bootstrap with
GET_MCP_TOOLS errors. Support Cursor native workspace tool execution
(shellStreamArgs, shellArgs, grepArgs, readArgs, writeArgs, lsArgs) by mapping
them directly to OpenCode host tools and formatting native results. Route
empty-pattern grep calls to OpenCode's glob tool and unwrap tool result JSON
envelopes for native Cursor actions. Use a models.dev Cursor row for limits
and price when OpenCode has one; do not copy lab caps.

Verified with bun test, capability tests, typecheck, build, and live
end-to-end multi-turn tool runs for Composer 2.5 and Grok 4.7.

Refs otto-assistant#31
@CasualDeveloper
CasualDeveloper force-pushed the feat/opencode-v2-host-owned-cursor branch from 9719566 to b99cfe8 Compare September 23, 2026 00:34
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