feat(providers): ACP V1 — Cursor, Hermes, and OpenCode agent providers#87
Open
SawyerHood wants to merge 7 commits into
Open
feat(providers): ACP V1 — Cursor, Hermes, and OpenCode agent providers#87SawyerHood wants to merge 7 commits into
SawyerHood wants to merge 7 commits into
Conversation
861aa5a to
d67d7bc
Compare
Add Agent Client Protocol (ACP) support with three built-in provider profiles: acp-cursor (`cursor acp`), acp-hermes (`hermes acp`), and acp-opencode (`opencode acp`). - New generic ACP adapter + bridge in @bb/agent-runtime (src/acp/): the bridge acts as the ACP client, spawning one agent subprocess and one ACP session per bb thread over newline-delimited JSON-RPC stdio. - Permission modes enforced cooperatively in the bridge: full auto-allows session/request_permission, ask forwards to bb approvals, deny rides the runtime auto-deny; client fs writes are path-checked against workspace write roots and surfaced as fileChange events. - Steer is emulated by chaining input onto the active turn; resume uses session/load when supported, else a fresh session plus a warning. - ACP agents own model selection: model/list serves a synthetic "Agent default" entry and no model/reasoning overrides are forwarded. - Catalog/registry/bundling/UI wiring; bb-workflows skill typings updated to the grown provider union. Tests: ACP adapter unit tests (22) and bridge tests against a scripted fake ACP agent subprocess (14) covering lifecycle, permissions in all three modes, fs policy, steer chaining, cancellation, resume with and without loadSession, agent crash, and missing binaries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…election ACP V1 shipped three untested profiles behind a synthetic "Agent default" model. This pares the integration down to what's real and makes Cursor a first-class provider: - Launch the Cursor CLI agent binary: the CLI installs as `agent` (cursor.com/docs/cli) and speaks ACP via `agent acp`; `cursor` is the editor's shell launcher and does not. - Real model list: the bridge runs the profile's `--list-models` command and groups the `base[-effort][-fast]` ids into model families with reasoning-effort variants (bridge/model-catalog.ts). `extra-high` maps onto xhigh; ids outside the grammar stay standalone single-effort models. - Reasoning selection: the session's (model, reasoningLevel) rides thread/start as `modelSelection`; the bridge resolves it to the exact raw variant id by catalog lookup — never suffix synthesis, spellings vary — and launches `agent --model <id> acp`. Unresolvable combos fall back to the family id with an acp/warning. Applied per session: a mid-thread change takes effect on the next session spawn, not the next turn. - Widen the acp-cursor reasoning ladder to low..max so server validation admits the levels the variants actually expose. - Remove the Hermes and OpenCode profiles, provider ids, and catalog entries; `modelCli` becomes required on the (now single) profile and `model/list` always carries the list command. Verification: turbo typecheck for agent-providers, agent-runtime, thread-view, host-daemon, server, app, cli; tests green for agent-providers (5), agent-runtime (639, incl. new model-catalog and bridge launch-pin coverage), thread-view (291), host-daemon (316), server (569). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
d67d7bc to
991f039
Compare
…section The full Cursor catalog is 53 model families — too many for the default picker. The cursor profile now declares its primary families (Auto, Fable 5 + Thinking, Opus 4.8 + Thinking, GPT-5.5, Composer 2.5 Fast); the bridge serves them in declared order as `models` and everything else as `selectedOnlyModels`, falling back to everything-primary when no name matches a future catalog. The default flag is re-anchored onto the primary list. selectedOnlyModels graduates from "hidden unless already selected" to a browsable pool: the model picker renders a collapsed "More models" row that expands in place (per-open state), for committed and previewed providers alike — claude-code's legacy entries become reachable the same way. Execution-override validation now accepts selected-only models as swap targets so a More-models selection applies mid-thread too. Verification: turbo typecheck for agent-runtime, server, app; tests green for agent-runtime (642), server (569), app (419); picker collapsed/expanded states exercised in a live dev instance. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Trim the primary Cursor list to Auto, Fable 5 Thinking, Opus 4.8
Thinking, GPT-5.5, and Composer 2.5 Fast — the non-thinking Fable/Opus
variants move under More models.
Cursor bakes the effort word into variant names ("Opus 4.8 1M Medium")
while bb renders the reasoning level separately, so the picker showed
the level twice. Family display names now shed the default variant's
own effort word by token ("Opus 4.8 1M Medium" → "Opus 4.8 1M");
stripping is keyed to the variant's explicit id token, so brand words
that collide with effort spellings ("Codex 5.1 Max") are untouched. Raw
variant names survive as the per-effort descriptions.
Verification: agent-runtime typecheck + tests (644); picker exercised
in a live dev instance — trigger and rows show each level once.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The picker rendered efforts in the agent's listing order (Medium, High, Extra High, Low, Max for the Opus/Fable families). Family members keep listing order — it anchors the no-medium default — but the supportedReasoningEfforts projection now sorts by the canonical domain ladder, so every reasoning menu reads low → max. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Renders the Cursor glyph (monochrome path via Simple Icons) in provider tabs and the model picker trigger instead of the "C" letter fallback, following the existing ClaudeIcon/OpenAiIcon/PiIcon pattern. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
For @jt — review requested; do not merge yet.
Summary
V1 support for connecting BB to Agent Client Protocol agent servers, with three built-in provider profiles:
acp-cursorcursor acpacp-hermeshermes acpacp-opencodeopencode acpArchitecture — one generic ACP adapter + bridge (
packages/agent-runtime/src/acp/), following the existing pi/claude-code bridge pattern:bb-acp-bridge(one process per provider id) acts as the ACP client: spawns one agent subprocess + one ACP session per bb thread, NDJSON JSON-RPC on both sides. The consumed ACP subset is validated with in-repo zod schemas (wire.ts) rather than the pre-1.0 external SDK.fullauto-allowssession/request_permission;askforwards to bb's approval flow (acp/permission/request→ pending interaction → user decision → ACP optionId);denyrides the runtime's existing auto-deny. Clientfs/write_text_fileis path-checked against workspace write roots and surfaced asfileChangeevents with diffs; readonly refuses writes.agent_message_chunk/agent_thought_chunkstream as deltas with accumulation for faithfulitem/completed; tool calls map by kind to commandExecution / fileChange (diff content) / generic toolCall; ACPplan→turn/plan/updated.session/promptwithin the same bb turn. Resume usessession/loadwhen the agent advertisesloadSession, else falls back to a fresh session with a visibleprovider/warning.model/listserves a synthetic "Agent default" entry; no model/reasoning overrides are forwarded to the agent.--provider acp-opencodeflows through existing spawn/tell/stop paths; daemon bundle manifest, packaged-app artifact checks, tarball smoke test, app icon fallback, thread-view display names, and bb-workflows skill typings are wired.Verification
loadSession, agent crash, missing binary)turbo run testfor @bb/agent-providers, @bb/agent-runtime, @bb/domain, @bb/thread-view, @bb/server, @bb/host-daemon, @bb/app, @bb/cli, @bb/workflow-runtime — all greenturbo run typecheckrepo-wide — green except 8 pre-existing @bb/host-daemon errors (Timer/Timeout type mismatch in untouched files; verified identical with this change stashed)turbo run lint— greenKnown follow-ups / caveats
opencode/hermes/cursoron PATH viascripts/bb-dev-app.true(like other providers); a missing agent binary fails thread start with a clear error, but a daemon-side PATH check would improve the picker.terminal/*client capability, MCP server pass-through onsession/new,authenticateflows, image-URL prompt blocks.🤖 Generated with Claude Code