Skip to content

Latest commit

 

History

History
73 lines (48 loc) · 3.48 KB

File metadata and controls

73 lines (48 loc) · 3.48 KB

Runtime Architecture: Cursor Agent + OpenCode Tool Loop

This document describes the current runtime architecture on main, with the default settings:

  • CURSOR_ACP_TOOL_LOOP_MODE=opencode
  • CURSOR_ACP_PROVIDER_BOUNDARY=v1
  • CURSOR_ACP_PROVIDER_BOUNDARY_AUTOFALLBACK=true

High-Level Flow

  1. OpenCode sends chat requests to the cursor-acp provider (/v1/chat/completions).
  2. The plugin proxy spawns cursor-agent per request and streams NDJSON (stream-json format).
  3. Assistant text/thinking streams back to OpenCode as SSE.
  4. tool_call events are intercepted at the provider boundary.
  5. Intercepted calls are normalized and guarded, then returned as OpenAI tool_calls.
  6. OpenCode executes tools locally and sends results back as role: "tool" messages in the next turn.
  7. Prompt builder renders tool results into TOOL_RESULT (call_id: ...) blocks for the next cursor-agent invocation.

Tool Ownership Model

opencode mode (default)

  • OpenCode owns execution of the active tool list.
  • In chat.params, existing OpenCode tool definitions are preserved and passed through.
  • cursor-acp does not execute SDK/MCP tools in this mode; it translates tool-call protocol boundaries.

proxy-exec mode (legacy/compat mode)

  • cursor-acp can inject tool definitions and execute via internal router:
    • Local tools
    • SDK-discovered tools
    • MCP-discovered tools
  • Used as compatibility path and fallback strategy.

off mode

  • Tool-loop behavior is disabled.

Provider Boundary (legacy vs v1)

The boundary abstraction is implemented in src/provider/boundary.ts and runtime handling in src/provider/runtime-interception.ts.

  • v1 (default): shared extraction/interception path for Bun + Node proxy handlers.
  • legacy: previous extraction/runtime behavior.

v1 adds:

  • Tool name alias resolution (shell, runCommand, delegateTask, skillMcp, etc.)
  • Schema compatibility normalization (src/provider/tool-schema-compat.ts)
  • Optional edit-to-write reroute for malformed full-file replacement edits
  • Tool-loop guard with fingerprinting (src/provider/tool-loop-guard.ts)
  • Guarded fallback to legacy when enabled and specific termination/error conditions are met

Loop Safety and Error Handling

v1 loop safety is driven by two mechanisms:

  • Schema validation guard: tracks repeated schema-invalid calls by tool + schema signature.
  • Tool-loop guard: tracks repeated calls using fingerprints with error class awareness.

The guard classifies outcomes (validation, not_found, permission, timeout, tool_error, success, unknown) and terminates repetitive loops before they spin indefinitely.

Plugin Tool Hook Layer

The OpenCode plugin tool hook (buildToolHookEntries in src/plugin.ts) registers local tools (bash, read, write, edit, grep, ls, glob, mkdir, rm, stat) and compatibility aliases such as shell -> bash.

When tool-hook execution is used, path/cwd defaults are normalized against tool context (worktree / directory) to keep file and shell behavior workspace-aware.

Operational Notes

  • Proxy reuse is enabled by default (CURSOR_ACP_REUSE_EXISTING_PROXY); this can reuse an already-running process on port 32124.
  • During debugging or rollouts, disable reuse (CURSOR_ACP_REUSE_EXISTING_PROXY=false) or restart OpenCode to ensure the active proxy process matches the latest build.
  • If ~/.config/opencode is reset/wiped, reinstall or re-run model/config sync to restore provider config and plugin symlink.