Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
49a07ae
Add provider-specific model resolution and defaults
juliusmarminge Feb 27, 2026
fa0dcca
redo contracts a bit
juliusmarminge Feb 27, 2026
2e06f7c
revised plan
juliusmarminge Feb 27, 2026
0382f4d
Add Claude Code adapter live layer with error mapping tests
juliusmarminge Feb 27, 2026
a17ea27
Wire Claude adapter into registry and server provider layer
juliusmarminge Feb 27, 2026
8ed1217
Support provider-aware session selection in reactor
juliusmarminge Feb 27, 2026
0b8e994
Enable Claude provider selection in chat composer
juliusmarminge Feb 27, 2026
148b1da
Add Claude checkpoint and revert reactor coverage
juliusmarminge Feb 27, 2026
28f9333
Add Claude integration coverage across orchestration flows
juliusmarminge Feb 27, 2026
78cf175
Make Claude runtime boundary Effect-native
juliusmarminge Feb 27, 2026
d305e98
Use typed errors for unavailable Claude runtime path
juliusmarminge Feb 27, 2026
b2ef479
unnecessary catch
juliusmarminge Feb 27, 2026
365dd15
Inline Claude adapter behavior into live layer
juliusmarminge Feb 27, 2026
84892ad
Use grouped provider/model select in chat composer
juliusmarminge Feb 27, 2026
a0d86e4
Show provider logos in composer model trigger
juliusmarminge Feb 27, 2026
290d098
Update Claude model catalog to latest 4.6/4.5 gen
juliusmarminge Feb 27, 2026
1d64027
Fix Claude model fallback in web store sync
juliusmarminge Feb 27, 2026
86608b1
Include all provider models in /model slash command
juliusmarminge Feb 27, 2026
94116da
Integrate Claude agent SDK into server provider adapter
juliusmarminge Feb 27, 2026
f087c61
Refactor ClaudeCodeAdapter session flow and stream handling
juliusmarminge Feb 27, 2026
b51fd94
Fix Claude resume cursor to only persist valid session UUIDs
juliusmarminge Feb 27, 2026
a32a7ae
Align orchestration integration tests with latestTurn metadata
juliusmarminge Feb 27, 2026
5b7e114
Ignore stale resume cursors and Claude placeholder thread IDs
juliusmarminge Feb 28, 2026
a4cc4d5
Fix ProviderService sendTurn recovery expectation after rebase
juliusmarminge Feb 28, 2026
9bb6ab3
Stabilize Claude turn event ordering and native event logging
juliusmarminge Feb 28, 2026
13e7249
Align Claude permissions and provider-specific reasoning effort
juliusmarminge Feb 28, 2026
a5a5246
Track runtime event sequence and order thread activities by sequence
juliusmarminge Feb 28, 2026
222294d
Add Cursor CLI stream event schemas and decoding tests
juliusmarminge Feb 27, 2026
0f9f0f2
Add Cursor provider support across backend, contracts, and UI
juliusmarminge Feb 28, 2026
f3bbd39
Add Cursor ACP probe script and captured session logs
juliusmarminge Mar 1, 2026
b315101
Revise Cursor provider plan for ACP JSON-RPC integration
juliusmarminge Mar 1, 2026
cfae88f
Document Cursor ACP mapping in canonical runtime event spec
juliusmarminge Mar 1, 2026
7c0ccb5
Introduce v2 provider runtime event schema and validation tests
juliusmarminge Mar 1, 2026
e805648
Scope reasoning effort defaults and options by provider
juliusmarminge Mar 1, 2026
fd65a35
Unify provider runtime events and add Cursor adapter layer
juliusmarminge Mar 1, 2026
4f47f33
Scope composer draft reasoning effort to Codex options
juliusmarminge Mar 2, 2026
43b64bf
Fix effort and provider handling in thread turn start
juliusmarminge Mar 3, 2026
d096cb8
Respect provider model-switch limits and canonical runtime events
juliusmarminge Mar 3, 2026
78e6125
Normalize approval request kinds and persist draft provider state
juliusmarminge Mar 3, 2026
196f331
Handle stale approval responses and cover Cursor resume IDs
juliusmarminge Mar 3, 2026
7c5a543
Normalize runtime events and tighten orchestration approval flow
juliusmarminge Mar 4, 2026
d715c3a
Inject native event loggers into provider adapters
juliusmarminge Mar 4, 2026
0ccc40a
Support provider custom models and fix runtime event mapping
juliusmarminge Mar 4, 2026
b39480a
Handle session.state.changed in provider runtime ingestion
juliusmarminge Mar 4, 2026
b5d5b39
Add runtime mode tracking across provider orchestration pipeline
juliusmarminge Mar 4, 2026
ed2c4bd
Rewrite plan-mode deep dive as implementation blueprint
juliusmarminge Mar 4, 2026
1d4ccdb
Clarify Cursor plan-mode semantics and ACP extension mapping
juliusmarminge Mar 4, 2026
9a115a8
Persist thread runtime mode and handle mode-switch session restarts
juliusmarminge Mar 4, 2026
13c113f
Improve session restart handling and server logging
juliusmarminge Mar 5, 2026
1f9ea61
Migrate provider runtime/session flow to thread-scoped IDs
juliusmarminge Mar 5, 2026
8572ca2
Add plan interaction mode and user-input request handling
juliusmarminge Mar 5, 2026
ede96ce
Persist proposed plans as first-class thread projection data
juliusmarminge Mar 5, 2026
da30070
style
juliusmarminge Mar 5, 2026
3f503cc
Prune internal contract exports and remove checkpoint RPC schemas
juliusmarminge Mar 6, 2026
0c4999b
Fix post-rebase typecheck regressions
juliusmarminge Mar 6, 2026
7d2e2b3
Plumb Codex model options through orchestration and composer
juliusmarminge Mar 6, 2026
576dc73
Add GPT-5.4 to Codex model options
juliusmarminge Mar 6, 2026
bf07122
Remove Cursor adapter from stack base
juliusmarminge Mar 6, 2026
d4f823f
Remove Claude adapter from stack base
juliusmarminge Mar 6, 2026
6df3c42
test: move Claude coverage out of core PR
juliusmarminge Mar 6, 2026
a01aaa3
rm tmp
juliusmarminge Mar 6, 2026
a2ee346
sync lock
juliusmarminge Mar 6, 2026
8d9bc7c
Show unavailable providers as coming-soon placeholders
juliusmarminge Mar 6, 2026
0789b38
contracts: move Claude schemas out of core
juliusmarminge Mar 6, 2026
0213228
model: move Claude catalogs out of core
juliusmarminge Mar 6, 2026
ef976af
split: move Claude provider surface to sibling stack
juliusmarminge Mar 6, 2026
a535aec
split: move Claude SDK and plan doc to sibling stack
juliusmarminge Mar 6, 2026
28c5177
Restore Claude adapter on sibling stack
juliusmarminge Mar 6, 2026
7e6ca87
test: restore Claude coverage on sibling stack
juliusmarminge Mar 6, 2026
7613142
contracts: restore Claude schemas on sibling stack
juliusmarminge Mar 6, 2026
6e6083c
model: restore Claude catalogs on sibling stack
juliusmarminge Mar 6, 2026
fa60ec4
split: restore Claude provider surface on sibling stack
juliusmarminge Mar 6, 2026
480a8cf
split: restore Claude SDK manifest and plan doc
juliusmarminge Mar 6, 2026
3af67f5
build: sync Claude SDK lockfile on sibling stack
juliusmarminge Mar 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
471 changes: 183 additions & 288 deletions .plans/17-claude-code.md

Large diffs are not rendered by default.

327 changes: 327 additions & 0 deletions .plans/18-cursor-agent-provider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,327 @@
# Plan: Cursor ACP (`agent acp`) Provider Integration

## Goal

Add Cursor as a first-class provider in T3 Code using ACP (`agent acp`) over JSON-RPC 2.0 stdio, with robust session lifecycle handling and canonical `ProviderRuntimeEvent` projection.

---

## 1) Exploration Findings (from live ACP probes)

### 1.1 Core invocation and transport

1. Binary is `agent` on PATH (`2026.02.27-e7d2ef6` observed).
2. ACP server command is `agent acp`.
3. Transport is newline-delimited JSON-RPC 2.0 over stdio.
4. Messages:
- client -> server: requests and responses to server-initiated requests
- server -> client: responses, notifications (`session/update`), and server requests (`session/request_permission`)

### 1.2 Handshake and session calls observed

1. `initialize` returns:
- `protocolVersion`
- `agentCapabilities` (`loadSession`, `mcpCapabilities`, `promptCapabilities`)
- `authMethods` (includes `cursor_login`)
2. `authenticate { methodId: "cursor_login" }` returns `{}` when logged in.
3. `session/new` returns:
- `sessionId`
- `modes` (`agent`, `plan`, `ask`)
4. `session/load` works and requires `sessionId`, `cwd`, `mcpServers`.
5. `session/prompt` returns terminal response `{ stopReason: "end_turn" | "cancelled" }`.

Important sequence note:
1. ACP currently allows `session/new` even without explicit `initialize`/`authenticate` when local auth already exists.
2. For adapter consistency and forward compatibility, we should still send `initialize` and `authenticate` during startup.

### 1.3 `session/update` event families observed

Observed `params.update.sessionUpdate` values:

1. `available_commands_update`
2. `agent_thought_chunk`
3. `agent_message_chunk`
4. `tool_call`
5. `tool_call_update`

Observed payload behavior:

1. `agent_*_chunk` provides `content: { type: "text", text: string }`.
2. `tool_call` may be emitted multiple times for same `toolCallId`:
- initial generic form (`title: "Terminal"`, `rawInput: {}`)
- enriched form (`title: "\`pwd\`"`, `rawInput: { command: "pwd" }`)
3. `tool_call_update` statuses observed:
- `in_progress`
- `completed`
4. `tool_call_update` on completion may include `rawOutput`:
- terminal: `{ exitCode, stdout, stderr }`
- search/find: `{ totalFiles, truncated }`

### 1.4 Permission flow observed

1. ACP server sends `session/request_permission` (JSON-RPC request with `id`).
2. Request shape includes:
- `params.sessionId`
- `params.toolCall`
- `params.options` (`allow-once`, `allow-always`, `reject-once`)
3. Client must respond on same `id` with:
- `{ outcome: { outcome: "selected", optionId: "<one-option-id>" } }`
4. Reject path still results in tool lifecycle completion events (`tool_call_update status: completed`), typically without `rawOutput`.

### 1.5 Error and capability quirks

1. `session/cancel` currently returns:
- JSON-RPC error `-32601` Method not found
2. Error shape examples:
- unknown auth method: `-32602`
- `session/load` missing/invalid params: `-32602`
- `session/prompt` unknown session: `-32603` with details
3. Parallel prompts on same session are effectively single-flight:
- second prompt can cause first to complete with `stopReason: "cancelled"`.
4. `session/new` accepts a `model` field (no explicit echo in response).

Probe artifacts:
1. `.tmp/acp-probe/*/transcript.ndjson`
2. `.tmp/acp-probe/*/summary.json`
3. `scripts/cursor-acp-probe.mjs`

---

## 2) Integration Constraints for T3

1. T3 adapter contract still requires:
- `startSession`, `sendTurn`, `interruptTurn`, `respondToRequest`, `readThread`, `rollbackThread`, `stopSession`, `listSessions`, `hasSession`, `stopAll`, `streamEvents`.
2. Orchestration consumes canonical `ProviderRuntimeEvent` only.
3. `ProviderCommandReactor` provider precedence fix remains required (respect explicit provider on turn start).
4. ACP now supports external permission decisions, so Cursor can participate in T3 approval UX via adapter-managed request/response plumbing.

---

## 3) Proposed Architecture

### 3.1 New server components

1. `apps/server/src/provider/Services/CursorAdapter.ts` (service contract/tag + ACP event schemas).
2. `apps/server/src/provider/Layers/CursorAdapter.ts` (single implementation unit; owns ACP process lifecycle, JSON-RPC routing, runtime projection).
3. No manager indirection; keep logic in layer implementation.

### 3.2 Session model

1. One long-lived ACP child process per T3 Cursor provider session.
2. Track:
- `providerSessionId` (T3 synthetic ID)
- `acpSessionId` (from `session/new` or restored via `session/load`)
- `cwd`, `model`, in-flight turn state
- pending permission requests by JSON-RPC request id
3. Resume support:
- persist `acpSessionId` in provider resume metadata and call `session/load` on reattach.

### 3.3 Command strategy

1. `startSession`:
- spawn `agent acp`
- `initialize`
- `authenticate(cursor_login)` (best-effort, typed failure handling)
- `session/new` or `session/load`
2. `sendTurn`:
- send `session/prompt { sessionId, prompt: [...] }`
- consume streaming `session/update` notifications until terminal prompt response
3. `interruptTurn`:
- no native `session/cancel` today; implement fallback:
- terminate ACP process + restart + `session/load` for subsequent turns
- mark in-flight turn as interrupted/failed in canonical events
4. `respondToRequest`:
- map T3 approval decision -> ACP `optionId`
- reply to exact JSON-RPC request id from `session/request_permission`

### 3.4 Effect-first implementation style (required)

1. Keep logic inside `CursorAdapterLive`.
2. Use Effect primitives:
- `Queue` + `Stream.fromQueue` for event fan-out
- `Ref` / `Ref.Synchronized` for session/process/request state
- scoped fibers for stdout/stderr read loops
3. Typed JSON decode at boundary:
- request/response envelopes
- `session/update` union schema
- permission-request schema
4. Keep adapter errors in typed error algebra with explicit mapping at process/protocol boundaries.

---

## 4) Canonical Event Mapping Plan (ACP -> ProviderRuntimeEvent)

1. `session/update: agent_message_chunk`
- emit `message.delta` for assistant stream
2. prompt terminal response (`session/prompt` result `stopReason: end_turn`)
- emit `message.completed` + `turn.completed`
3. `session/update: agent_thought_chunk`
- initial mapping: emit thinking activity (or ignore if we keep current canonical surface minimal)
4. `session/update: tool_call`
- first-seen `toolCallId` emits `tool.started`
- subsequent `tool_call` for same ID treated as metadata update (no duplicate started event)
5. `session/update: tool_call_update`
- `in_progress`: optional progress activity
- `completed`: emit `tool.completed` with summarized `rawOutput` when present
6. `session/request_permission`
- emit `approval.requested` with mapped options
- when client decision sent, emit `approval.resolved`
7. protocol/process error
- emit `runtime.error`
- fail active turn/session as appropriate

Synthetic IDs:
1. `turnId`: T3-generated UUID per `sendTurn`.
2. `itemId`:
- assistant stream: `${turnId}:assistant`
- tools: `${turnId}:${toolCallId}`

---

## 5) Approval, Resume, and Rollback Behavior

### 5.1 Approvals

1. Cursor ACP permission requests are externally controllable; implement full `respondToRequest` path in v1.
2. Decision mapping:
- allow once -> `allow-once`
- allow always -> `allow-always`
- reject -> `reject-once`

### 5.2 Resume

1. `session/load` is available and should be first-class for adapter restart/reconnect.
2. Must send required params: `sessionId`, `cwd`, `mcpServers`.

### 5.3 Rollback / thread read

1. ACP currently has no observed rollback API.
2. Plan for v1:
- `readThread`: adapter-maintained snapshot projection
- `rollbackThread`: explicit unsupported error
3. Product guard:
- disable checkpoint revert for Cursor threads in UI until rollback exists.

---

## 6) Required Contract and Runtime Changes

### 6.1 Contracts

1. Add `cursor` to `ProviderKind`.
2. Add Cursor provider start options (`providerOptions.cursor`), ACP-oriented:
- optional `binaryPath`
- optional auth/mode knobs if needed later
3. Extend model options for Cursor list and traits mapping.
4. Add schemas for ACP-native event union in Cursor adapter service file.

### 6.2 Server orchestration and registry

1. Register `CursorAdapter` in provider registry and server layer wiring.
2. Update provider-kind persistence decoding for `cursor`.
3. Fix `ProviderCommandReactor` precedence to honor explicit provider in turn-start command.

### 6.3 Web

1. Cursor in provider picker and model picker (already partially done).
2. Trait controls map to concrete Cursor model identifiers.
3. Surface unsupported rollback behavior in UX.

---

## 7) Implementation Phases

### Phase A: ACP process and protocol skeleton

1. Implement ACP process lifecycle in `CursorAdapterLive`.
2. Implement JSON-RPC request/response multiplexer.
3. Implement `initialize`/`authenticate`/`session/new|load` flow.
4. Wire `streamEvents` from ACP notifications.

### Phase B: Runtime projection and approvals

1. Map `session/update` variants to canonical runtime events.
2. Implement permission-request bridging to `respondToRequest`.
3. Implement dedupe for repeated `tool_call` on same `toolCallId`.

### Phase C: Turn control and interruption

1. Implement single in-flight prompt protection per session.
2. Implement interruption fallback (process restart + reload) because `session/cancel` unavailable.
3. Ensure clean state recovery on ACP process crash.

### Phase D: Orchestration + UX polish

1. Provider routing precedence fix.
2. Cursor-specific UX notes for unsupported rollback.
3. End-to-end smoke and event log validation.

---

## 8) Test Plan

Follow project rule: backend external-service integrations tested via layered fakes, not by mocking core business logic.

### 8.1 Unit tests (`CursorAdapter`)

1. JSON-RPC envelope parsing:
- response matching by id
- server request handling (`session/request_permission`)
- notification decode (`session/update`)
2. Event projection:
- `agent_message_chunk` / `agent_thought_chunk`
- `tool_call` + `tool_call_update` dedupe/lifecycle
- permission request -> approval events
3. Error mapping:
- unknown session
- method-not-found (`session/cancel`)
- invalid params

### 8.2 Provider service/routing tests

1. Registry resolves `cursor`.
2. Session directory persistence reads/writes `cursor`.
3. ProviderService fan-out ordering with Cursor ACP events.

### 8.3 Orchestration tests

1. `thread.turn.start` with `provider: cursor` routes to Cursor adapter.
2. approval response command maps to ACP permission response.
3. checkpoint revert on Cursor thread returns controlled unsupported failure.

### 8.4 Optional live smoke

1. Env-gated ACP smoke:
- start session
- run prompt
- observe deltas + completion
- exercise permission request path with one tool call

---

## 9) Operational Notes

1. Keep one in-flight turn per ACP session.
2. Keep per-session ACP process logs/NDJSON artifacts for debugging.
3. Treat `session/cancel` as unsupported until Cursor ships it; avoid relying on it.
4. Preserve resume metadata (`acpSessionId`) for crash recovery.

---

## 10) Open Questions

1. Should we call `authenticate` always, or only after auth-required errors?
2. Should model selection be passed at `session/new` only, or can/should we support model switching mid-session if ACP adds API?
3. For interruption UX, do we expose “hard interrupt” semantics (process restart) explicitly?

---

## 11) Delivery Checklist

1. Plan/documentation switched from headless `agent -p` to ACP `agent acp`.
2. Contracts updated (`ProviderKind`, Cursor options, model/trait mapping).
3. Cursor ACP adapter layer implemented and registered.
4. Provider precedence fixed in orchestration router.
5. Approval response path wired through ACP permission requests.
6. Tests added for protocol decode, projection, approval flow, and routing.
7. Lint + tests green.
64 changes: 0 additions & 64 deletions .test-favicon.mjs

This file was deleted.

Loading