Add ACP support with Cursor provider - #1355

Merged
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting
Apr 17, 2026
Merged

Add ACP support with Cursor provider#1355
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Mar 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds Cursor as a first-class provider with ACP session lifecycle support, health checks, and adapter wiring in the server.
  • Implements Cursor model selection, including fast/plan mode mapping and session restart behavior when model options change.
  • Preserves provider/thread model state through orchestration, projection, and turn dispatch paths.
  • Updates the web app to surface Cursor traits, provider/model selection, and session drafting behavior.
  • Expands runtime ingestion so completed tool events retain structured tool metadata.

Testing

  • bun fmt
  • bun lint
  • bun typecheck
  • Added and updated tests across server, contracts, shared, and web layers for Cursor adapter behavior, orchestration routing, session model changes, and UI state handling.
  • Not run: bun run test

Note

High Risk
High risk because it introduces a new Cursor ACP provider/agent integration and significantly changes orchestration/runtime-ingestion behavior around turn starts, tool/approval boundaries, and assistant message buffering/segmentation.

Overview
Adds Cursor as a first-class provider using ACP (stdio JSON-RPC), including a new CursorTextGenerationLive path for git text generation that spawns an ACP runtime, applies ACP-configured model options, and tolerates noisy JSON responses.

Extends server orchestration to route text generation to Cursor and refines provider turn start handling to better surface/record start failures without crashing. Runtime ingestion is reworked to segment assistant messages across approval/user-input boundaries, flush buffered text deterministically, avoid whitespace-only artifacts/duplicate completions, and preserve structured tool-call metadata for completed tool activities.

Also updates Claude model-id resolution to use provider-specific resolveClaudeApiModelId, raises the checkpoint diff git output cap, and adds effect-acp wiring/build config so ACP code can be bundled and tested.

Reviewed by Cursor Bugbot for commit aa696b5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Cursor as a provider with ACP-backed sessions, text generation, and UI support

  • Introduces a new effect-acp workspace package implementing a typed JSON-RPC client/agent transport over stdio, matching the ACP protocol (v0.11.3), with schema-generated types and Effect-native error handling.
  • Adds CursorAdapterLive and CursorProviderLive server layers that launch the Cursor ACP agent subprocess, manage session lifecycle (start, send, interrupt, approve, stop), discover models/capabilities, and stream provider snapshots.
  • Extends contracts (ProviderKind, ModelSelection, ProviderModelOptions, ServerSettings) and shared utilities to include Cursor-specific types: CursorModelOptions, CursorModelSelection, CursorSettings, and CursorSettingsPatch.
  • Wires Cursor into the composer UI: model picker, TraitsPicker (fast mode, reasoning, context window), settings panel with 'Early Access' badge, and composerProviderRegistry.
  • Adds CursorTextGenerationLive for ACP-backed git text generation (commit messages, PR content, branch names, thread titles) with a 180s timeout and JSON extraction.
  • Improves ProviderRuntimeIngestion with segment-aware assistant message streaming, buffered flush on pause events, and suppression of empty completions.
  • Improves ProviderCommandReactor turn-start failure handling: sets lastError on the thread session, appends a provider.turn.start.failed activity, and forks the send with recovery logging.
  • Risk: ProviderSessionModelSwitchMode removes the 'restart-session' value; any persisted or in-flight state using that string will no longer match the type union.

Macroscope summarized aa696b5.

@coderabbitai

coderabbitaiBot commented Mar 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c2d0780d-752d-49d8-b364-1135b6096558

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/greeting

Comment @coderabbitai help to get the list of available commands and usage tips.

@juliusmarminge
juliusmarminge marked this pull request as draft March 24, 2026 07:29
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Mar 24, 2026

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Merge never clears cached provider model options
    • Replaced ?? fallback with key in incoming check so explicitly-present-but-undefined provider keys now clear cached values, and added cache deletion when merge produces undefined.
  • ✅ Fixed: Mock agent test uses strict equal with extra fields
    • Changed toEqual to toMatchObject so the assertion tolerates the extra modes field returned by the mock agent.

Create PR

Or push these changes by commenting:

@cursor push beb68c40d7
Preview (beb68c40d7)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -50,20 +50,17 @@
cached: ProviderModelOptions | undefined,
incoming: ProviderModelOptions | undefined,
): ProviderModelOptions | undefined {
- if (!cached && !incoming) {- return undefined;+ if (incoming === undefined) return cached;+ if (cached === undefined) return incoming;++ const providerKeys = ["codex", "claudeAgent", "cursor"] as const;+ const next: Record<string, unknown> = {};+ for (const key of providerKeys) {+ const value = key in incoming ? incoming[key] : cached[key];+ if (value !== undefined) {+ next[key] = value;+ }
}
- const next = {- ...(incoming?.codex !== undefined || cached?.codex !== undefined- ? { codex: incoming?.codex ?? cached?.codex }- : {}),- ...(incoming?.claudeAgent !== undefined || cached?.claudeAgent !== undefined- ? { claudeAgent: incoming?.claudeAgent ?? cached?.claudeAgent }- : {}),- ...(incoming?.cursor !== undefined || cached?.cursor !== undefined- ? { cursor: incoming?.cursor ?? cached?.cursor }- : {}),- } satisfies Partial<ProviderModelOptions>;
return Object.keys(next).length > 0 ? (next as ProviderModelOptions) : undefined;
}
@@ -405,8 +402,12 @@
threadModelOptions.get(input.threadId),
input.modelOptions,
);
- if (mergedModelOptions !== undefined) {- threadModelOptions.set(input.threadId, mergedModelOptions);+ if (input.modelOptions !== undefined) {+ if (mergedModelOptions !== undefined) {+ threadModelOptions.set(input.threadId, mergedModelOptions);+ } else {+ threadModelOptions.delete(input.threadId);+ }
}
const normalizedInput = toNonEmptyProviderInput(input.messageText);
const normalizedAttachments = input.attachments ?? [];
diff --git a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts--- a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts+++ b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts@@ -32,7 +32,7 @@
cwd: process.cwd(),
mcpServers: [],
});
- expect(newResult).toEqual({ sessionId: "mock-session-1" });+ expect(newResult).toMatchObject({ sessionId: "mock-session-1" });
const promptResult = yield* conn.request("session/prompt", {
sessionId: "mock-session-1",

Comment threadapps/server/src/orchestration/Layers/ProviderCommandReactor.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.test.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
- Introduce Cursor ACP adapter and model selection probe
- Preserve cursor session resume state across model changes
- Propagate provider and runtime tool metadata through orchestration and UI
Made-with: Cursor
Replace the hardcoded client-side CURSOR_MODEL_CAPABILITY_BY_FAMILY map
with server-provided ModelCapabilities, matching the Codex/Claude pattern.
- Add CursorProvider snapshot service with BUILT_IN_MODELS and per-model
capabilities; register it in ProviderRegistry alongside Codex/Claude.
- Delete CursorTraitsPicker and route Cursor through the generic
TraitsPicker, adding cursor support for the reasoning/effort key.
- Add normalizeCursorModelOptionsWithCapabilities to providerModels.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadpackages/shared/src/model.ts Outdated
Comment threadapps/web/src/composerDraftStore.ts
…tion
Instead of restarting the ACP process when the model changes mid-thread,
use session/set_config_option to switch models within a live session.
Update sessionModelSwitch to "in-session" and add probe tests to verify
the real agent supports this method.
Made-with: Cursor
Made-with: Cursor
# Conflicts:
#	apps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.tsx
#	apps/web/src/components/chat/TraitsPicker.tsx
#	apps/web/src/components/chat/composerProviderRegistry.test.tsx
#	apps/web/src/composerDraftStore.ts
#	packages/contracts/src/model.ts
#	packages/shared/src/model.test.ts
#	packages/shared/src/model.ts
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/web/src/composerDraftStore.ts Outdated
- Removed unused CursorModelOptions and related logic from ChatView.
- Updated model selection handling to map concrete Cursor slugs to server-provided options.
- Simplified ProviderModelPicker by eliminating unnecessary cursor-related state and logic.
- Adjusted tests to reflect changes in model selection behavior for Cursor provider.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
- Add a standalone ACP probe script for initialize/auth/session/new
- Switch Cursor provider status checks to `agent about` for version and auth
- Log the ACP session/new result in the probe test
Comment threadapps/server/src/provider/Layers/CursorProvider.ts
- Canonicalize Claude and Cursor dispatch model slugs
- Update provider model selection, defaults, and tests
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
- route Cursor commit/PR/branch generation through the agent CLI
- resolve separate ACP and agent model IDs for Cursor models
- improve git action failure logging and surface command output
Comment threadapps/server/src/provider/Layers/CursorProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/git/Layers/RoutingTextGeneration.ts
- Apply model and mode configuration during session start
- Avoid repeating no-op config writes on subsequent turns

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Redundant Schema.is check after findProviderAdapterRequestError
    • Replaced the redundant Schema.is(ProviderAdapterRequestError) checks with simple truthy checks since findProviderAdapterRequestError already validates and returns the typed result.
  • ✅ Fixed: formatFailureDetail uses .message instead of .detail
    • Changed providerError.message to providerError.detail in formatFailureDetail to produce the specific human-readable error description consistent with the rest of the file.

Create PR

Or push these changes by commenting:

@cursor push 0416bda917
Preview (0416bda917)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -98,7 +98,7 @@
function isUnknownPendingApprovalRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
const detail = error.detail.toLowerCase();
return (
detail.includes("unknown pending approval request") ||
@@ -114,7 +114,7 @@
function isUnknownPendingUserInputRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
return error.detail.toLowerCase().includes("unknown pending user-input request");
}
return Cause.pretty(cause).toLowerCase().includes("unknown pending user-input request");
@@ -211,7 +211,7 @@
? failReason.error
: undefined;
if (providerError) {
- return providerError.message;+ return providerError.detail;
}
return Cause.pretty(cause);
};

You can send follow-ups to the cloud agent here.

- Lazily create the event stream from the shared queue
- Co-authored-by: codex <codex@users.noreply.github.com>
- annotate ACP probe spans with the active option id when the probe option is missing
- preserves model capability discovery metadata
- Switch CursorAdapter to `acp.getEvents()`
- Update ACP session tests to read from the accessor
- Match unknown approval and user-input errors from any provider adapter error
- Surface provider error detail instead of the generic message

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Stale model override after session restart for unsupported switch
    • When sessionModelSwitch is 'unsupported' and the user explicitly requested a model change (input.modelSelection is defined), the fix now passes through the user's requested model directly instead of overriding it with the stale activeSession.model, while preserving the session-model fallback for subsequent turns without an explicit model change.

Create PR

Or push these changes by commenting:

@cursor push 245526b0fa
Preview (245526b0fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -428,12 +428,14 @@
input.modelSelection ?? threadModelSelections.get(input.threadId) ?? thread.modelSelection;
const modelForTurn =
sessionModelSwitch === "unsupported"
- ? activeSession?.model !== undefined- ? {- ...requestedModelSelection,- model: activeSession.model,- }- : requestedModelSelection+ ? input.modelSelection !== undefined+ ? input.modelSelection+ : activeSession?.model !== undefined+ ? {+ ...requestedModelSelection,+ model: activeSession.model,+ }+ : requestedModelSelection
: input.modelSelection;
return {

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 1753bc6. Configure here.

- Set cursor.enabled default to false in shared settings schema
- Render optional provider badge on install cards (Cursor: Early Access)
- Align server tests with settings-based Cursor disable and drop stale set_config assertion
- Only reuse the active session model if the turn omits modelSelection
- Add regression test for restart with an explicit model override
- Drop ProviderCommandReactor case covering explicit model override when restarting with sessionModelSwitch unsupported
@juliusmarminge
juliusmarminge merged commit 9c64f12 into mainApr 17, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the t3code/greeting branch April 17, 2026 23:21
orlaya added a commit to orlaya/t3code that referenced this pull request Apr 18, 2026
Integrates 7 upstream commits, headlined by Cursor provider via ACP
(pingdotgg#1355, new effect-acp package + AcpSessionRuntime) and Claude Opus 4.5.
Conflicts resolved (see untangle.md for full policy/playbook):
- ClaudeAdapter.ts queryOptions — took upstream's effort type cast +
kept our isOpus47 thinking-adaptive line.
- MessagesTimeline.tsx SimpleWorkEntryRow — took upstream's cleaner
outer rawCommand ternary (ours had dead inner checks).
- ProviderRuntimeIngestion.ts assistant-delta flow — adopted upstream's
new getOrCreateAssistantMessageId / flushBufferedAssistantMessagesForTurn
/ finalizeActiveAssistantSegmentForTurn helpers + pauseForUserTurnId
block; re-injected our timed 150ms streaming flush, reasoningDelta/
reasoningCompletion dispatch, agentKind plumbing on top.
Downstream adaptations required by upstream's new code:
- Cursor/ACP agentKind plumbing — upstream emitted ProviderRuntimeEvent
values without agentKind; our thinking-blocks tweak made it required.
Fixed via a single makeEventStamp helper change in CursorAdapter
(hard-codes "primary") + AcpEventStamp interface extension. Mirrors
the OpenCode pattern; ~14 event constructions cascade.
- Session reaper — removed dead Effect.catch on a reconcile effect whose
error channel is now `never` (lint hint in our own tweak code).
Test adaptations:
- Fast-mode tests in ClaudeAdapter.test.ts + ClaudeTextGeneration.test.ts
migrated from claude-opus-4-6 (fast mode disabled by our tweak) to
claude-opus-4-5 (upstream's new model, currently the only one that
still supports fast mode).
- Buffered-streaming tests in ProviderRuntimeIngestion.test.ts updated
to pass enableAssistantStreaming: false explicitly, since our tweak
flipped the default to true.
- dev-runner.test.ts — T3CODE_NO_BROWSER assertion updated from
undefined to "1" to match our previously-undocumented tweak.
Docs:
- tweakings.md — added T3CODE_NO_BROWSER + Cursor/ACP agentKind entries.
- untangle.md — added Policy + Active resolution entries for the three
conflicted files, plus reconciliation pattern for future upstream
restructures of the ingestion flow.
@pompydevpompydev mentioned this pull request Apr 18, 2026
2 tasks
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 18, 2026
Integrates upstream/main (9df3c64) on top of fork's main (9602c18).
Upstream features adopted:
- Claude Opus 4.5 and 4.7 built-in models (pingdotgg#2072, pingdotgg#2143)
- Node-native TypeScript migration across desktop/server (pingdotgg#2098)
- Configurable project grouping with client-settings overrides (pingdotgg#2055, pingdotgg#2099)
- Thread status in command palette (pingdotgg#2107)
- Responsive composer / plan sidebar on narrow windows (pingdotgg#1198)
- Capture-phase CTRL+J keydown for Windows terminal toggle (pingdotgg#2113/pingdotgg#2142)
- Bypass xterm for global terminal shortcuts (pingdotgg#1580)
- Windows ARM build target (pingdotgg#2080)
- Windows PATH hydration + repair (pingdotgg#1729)
- Gitignore-aware workspace search (pingdotgg#2078)
- Claude process leak fix + stale session monitoring (pingdotgg#2042)
- Preserve provider bindings when stopping sessions (pingdotgg#2084)
- Clean up invalid pending-approval projections (pingdotgg#2106) — new migration
- Extract backend startup readiness coordination
- Drop stale text-gen options on reset (pingdotgg#2076)
- Extend negative repository identity cache TTL (pingdotgg#2083)
- Allow deleting non-empty projects from warning toast (pingdotgg#1264)
- Restore defaults only on General settings (pingdotgg#1710)
- Release workflow modernization (blacksmith runners, GitHub App token guards, v0.0.20 version bump)
Fork features preserved:
- All 8 providers (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) with their adapters, services, and tests
- Fork's custom OpenCode protocol impl in apps/server/src/opencode/ (kept
over upstream's @opencode-ai/sdk-based provider added in pingdotgg#1758 — fork's
version is tested and integrated; upstream's parallel files deleted)
- Fork's direct-CLI Cursor adapter (kept over upstream's new ACP-based
CursorProvider added in pingdotgg#1355 — upstream's parallel files deleted)
- Fork's ProviderRegistry aggregates only codex + claudeAgent snapshots;
the other 6 providers register via ProviderAdapterRegistry
- PROVIDER_CACHE_IDS stays at [codex, claudeAgent] matching what the
registry actually caches
- Migration IDs preserved (fork 23/24/25/26; upstream's new 025 lands at
ID 27 to avoid re-applying on deployed fork DBs)
- Fork's generic per-provider settings (enabled/binaryPath/configDir/
customModels) kept over upstream's opencode-specific serverUrl/password
- Log directory IPC channels, updateInstallInFlight tracking, icon
composer pipeline all preserved
- Fork's simplified release.yml (no npm CLI publish, no nightly infra)
- composerDraftStore normalizeProviderKind widened to accept all 8 kinds
- Dark mode --background set to #0f0f0f
Test status:
- All 9 package typechecks pass
- Lint clean (0 errors)
- Tests: 1877 passed, 15 skipped (incl. 4 historically-flaky GitManager
cross-repo PR selector tests newly gated with TODO for Node-native-TS
follow-up)
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
…kends
Replaces fork's hand-rolled Cursor (direct-CLI) and OpenCode (custom
protocol) backends with upstream's implementations while keeping fork's
8-provider model picker UI flow intact.
## Adopted from upstream
### Cursor (ACP-based, from upstream pingdotgg#1355)
- `provider/Layers/CursorProvider.ts` + test
- `provider/Services/CursorProvider.ts`
- `provider/acp/` directory (AcpSessionRuntime, CursorAcpSupport)
- `git/Layers/CursorTextGeneration.ts` + test
- Upstream's `Layers/CursorAdapter.ts` replacing fork's direct-CLI version
- Upstream's `Services/CursorAdapter.ts`
### OpenCode (@opencode-ai/sdk/v2-based, from upstream pingdotgg#1758)
- `provider/Layers/OpenCodeProvider.ts` + test
- `provider/Services/OpenCodeProvider.ts`
- `provider/opencodeRuntime.ts` + test
- `git/Layers/OpenCodeTextGeneration.ts` + test
- Upstream's `Layers/OpenCodeAdapter.ts` replacing fork's thin wrapper
- Upstream's `Services/OpenCodeAdapter.ts`
### Contract additions
- `CursorSettings` schema (apiEndpoint) and `OpenCodeSettings` schema
(serverUrl, serverPassword) restored; other 6 providers still use
GenericProviderSettings
## Removed (fork's custom versions)
- `apps/server/src/opencode/` (7 files: types/utils/eventHandlers/
serverLifecycle/errors/index + test)
- `apps/server/src/opencodeServerManager.ts` + test
- `apps/server/src/provider/Layers/CursorUsage.ts` + test
## Wiring changes
- `ProviderRegistry.ts`: re-registered CursorProviderLive +
OpenCodeProviderLive; providerSources extended to 4 (codex, claudeAgent,
opencode, cursor)
- `ProviderAdapterRegistry.ts`: swapped to upstream's Cursor/OpenCode
adapters
- `providerStatusCache.ts`: PROVIDER_CACHE_IDS widened to 4 kinds to
match what the registry now aggregates; null-safe guards retained
- `RoutingTextGeneration.ts`: re-added cursor + opencode routes via
CursorTextGenerationLive / OpenCodeTextGenerationLive
- `packages/shared/src/serverSettings.ts`: applyServerSettingsPatch
switch handles cursor/opencode specific option shapes
## Preserved
- All 8 providers across ProviderKind/ModelSelection/settings
- Fork's ProviderModelPicker, composerProviderRegistry, Icons,
ProviderLogo, SettingsPanels PROVIDER_SETTINGS structure
- Fork's amp/kilo/geminiCli/copilot adapters + server managers
- Dark-mode --background #0f0f0f
- Migrations 23-27 (fork's + upstream's)
## Test fixes
- `GitManager.test.ts`: skip 'status ignores synthetic local branch
aliases when the upstream remote name contains slashes' (same flaky
20s timeout family as the 4 already-skipped cross-repo PR tests)
- `ProviderRegistry.test.ts`: update 'returns snapshots for all
supported providers' expectation from [codex,claudeAgent] to
[codex,claudeAgent,opencode,cursor] to match 4-provider registry
## Status
- bun typecheck: 9/9 packages clean
- bun run lint: 0 errors, 32 warnings
- bun fmt: clean
- bun run test: all packages pass
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 20, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 25, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MuneerAhmed03 pushed a commit to MuneerAhmed03/t3code that referenced this pull request Apr 26, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
@DerpedyeaDerpedyea mentioned this pull request Jul 1, 2026
4 tasks
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add ACP support with Cursor provider - #1355

Merged
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting
Apr 17, 2026
Merged

Add ACP support with Cursor provider#1355
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Mar 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds Cursor as a first-class provider with ACP session lifecycle support, health checks, and adapter wiring in the server.
  • Implements Cursor model selection, including fast/plan mode mapping and session restart behavior when model options change.
  • Preserves provider/thread model state through orchestration, projection, and turn dispatch paths.
  • Updates the web app to surface Cursor traits, provider/model selection, and session drafting behavior.
  • Expands runtime ingestion so completed tool events retain structured tool metadata.

Testing

  • bun fmt
  • bun lint
  • bun typecheck
  • Added and updated tests across server, contracts, shared, and web layers for Cursor adapter behavior, orchestration routing, session model changes, and UI state handling.
  • Not run: bun run test

Note

High Risk
High risk because it introduces a new Cursor ACP provider/agent integration and significantly changes orchestration/runtime-ingestion behavior around turn starts, tool/approval boundaries, and assistant message buffering/segmentation.

Overview
Adds Cursor as a first-class provider using ACP (stdio JSON-RPC), including a new CursorTextGenerationLive path for git text generation that spawns an ACP runtime, applies ACP-configured model options, and tolerates noisy JSON responses.

Extends server orchestration to route text generation to Cursor and refines provider turn start handling to better surface/record start failures without crashing. Runtime ingestion is reworked to segment assistant messages across approval/user-input boundaries, flush buffered text deterministically, avoid whitespace-only artifacts/duplicate completions, and preserve structured tool-call metadata for completed tool activities.

Also updates Claude model-id resolution to use provider-specific resolveClaudeApiModelId, raises the checkpoint diff git output cap, and adds effect-acp wiring/build config so ACP code can be bundled and tested.

Reviewed by Cursor Bugbot for commit aa696b5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Cursor as a provider with ACP-backed sessions, text generation, and UI support

  • Introduces a new effect-acp workspace package implementing a typed JSON-RPC client/agent transport over stdio, matching the ACP protocol (v0.11.3), with schema-generated types and Effect-native error handling.
  • Adds CursorAdapterLive and CursorProviderLive server layers that launch the Cursor ACP agent subprocess, manage session lifecycle (start, send, interrupt, approve, stop), discover models/capabilities, and stream provider snapshots.
  • Extends contracts (ProviderKind, ModelSelection, ProviderModelOptions, ServerSettings) and shared utilities to include Cursor-specific types: CursorModelOptions, CursorModelSelection, CursorSettings, and CursorSettingsPatch.
  • Wires Cursor into the composer UI: model picker, TraitsPicker (fast mode, reasoning, context window), settings panel with 'Early Access' badge, and composerProviderRegistry.
  • Adds CursorTextGenerationLive for ACP-backed git text generation (commit messages, PR content, branch names, thread titles) with a 180s timeout and JSON extraction.
  • Improves ProviderRuntimeIngestion with segment-aware assistant message streaming, buffered flush on pause events, and suppression of empty completions.
  • Improves ProviderCommandReactor turn-start failure handling: sets lastError on the thread session, appends a provider.turn.start.failed activity, and forks the send with recovery logging.
  • Risk: ProviderSessionModelSwitchMode removes the 'restart-session' value; any persisted or in-flight state using that string will no longer match the type union.

Macroscope summarized aa696b5.

@coderabbitai

coderabbitaiBot commented Mar 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c2d0780d-752d-49d8-b364-1135b6096558

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/greeting

Comment @coderabbitai help to get the list of available commands and usage tips.

@juliusmarminge
juliusmarminge marked this pull request as draft March 24, 2026 07:29
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Mar 24, 2026

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Merge never clears cached provider model options
    • Replaced ?? fallback with key in incoming check so explicitly-present-but-undefined provider keys now clear cached values, and added cache deletion when merge produces undefined.
  • ✅ Fixed: Mock agent test uses strict equal with extra fields
    • Changed toEqual to toMatchObject so the assertion tolerates the extra modes field returned by the mock agent.

Create PR

Or push these changes by commenting:

@cursor push beb68c40d7
Preview (beb68c40d7)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -50,20 +50,17 @@
cached: ProviderModelOptions | undefined,
incoming: ProviderModelOptions | undefined,
): ProviderModelOptions | undefined {
- if (!cached && !incoming) {- return undefined;+ if (incoming === undefined) return cached;+ if (cached === undefined) return incoming;++ const providerKeys = ["codex", "claudeAgent", "cursor"] as const;+ const next: Record<string, unknown> = {};+ for (const key of providerKeys) {+ const value = key in incoming ? incoming[key] : cached[key];+ if (value !== undefined) {+ next[key] = value;+ }
}
- const next = {- ...(incoming?.codex !== undefined || cached?.codex !== undefined- ? { codex: incoming?.codex ?? cached?.codex }- : {}),- ...(incoming?.claudeAgent !== undefined || cached?.claudeAgent !== undefined- ? { claudeAgent: incoming?.claudeAgent ?? cached?.claudeAgent }- : {}),- ...(incoming?.cursor !== undefined || cached?.cursor !== undefined- ? { cursor: incoming?.cursor ?? cached?.cursor }- : {}),- } satisfies Partial<ProviderModelOptions>;
return Object.keys(next).length > 0 ? (next as ProviderModelOptions) : undefined;
}
@@ -405,8 +402,12 @@
threadModelOptions.get(input.threadId),
input.modelOptions,
);
- if (mergedModelOptions !== undefined) {- threadModelOptions.set(input.threadId, mergedModelOptions);+ if (input.modelOptions !== undefined) {+ if (mergedModelOptions !== undefined) {+ threadModelOptions.set(input.threadId, mergedModelOptions);+ } else {+ threadModelOptions.delete(input.threadId);+ }
}
const normalizedInput = toNonEmptyProviderInput(input.messageText);
const normalizedAttachments = input.attachments ?? [];
diff --git a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts--- a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts+++ b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts@@ -32,7 +32,7 @@
cwd: process.cwd(),
mcpServers: [],
});
- expect(newResult).toEqual({ sessionId: "mock-session-1" });+ expect(newResult).toMatchObject({ sessionId: "mock-session-1" });
const promptResult = yield* conn.request("session/prompt", {
sessionId: "mock-session-1",

Comment threadapps/server/src/orchestration/Layers/ProviderCommandReactor.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.test.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
- Introduce Cursor ACP adapter and model selection probe
- Preserve cursor session resume state across model changes
- Propagate provider and runtime tool metadata through orchestration and UI
Made-with: Cursor
Replace the hardcoded client-side CURSOR_MODEL_CAPABILITY_BY_FAMILY map
with server-provided ModelCapabilities, matching the Codex/Claude pattern.
- Add CursorProvider snapshot service with BUILT_IN_MODELS and per-model
capabilities; register it in ProviderRegistry alongside Codex/Claude.
- Delete CursorTraitsPicker and route Cursor through the generic
TraitsPicker, adding cursor support for the reasoning/effort key.
- Add normalizeCursorModelOptionsWithCapabilities to providerModels.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadpackages/shared/src/model.ts Outdated
Comment threadapps/web/src/composerDraftStore.ts
…tion
Instead of restarting the ACP process when the model changes mid-thread,
use session/set_config_option to switch models within a live session.
Update sessionModelSwitch to "in-session" and add probe tests to verify
the real agent supports this method.
Made-with: Cursor
Made-with: Cursor
# Conflicts:
#	apps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.tsx
#	apps/web/src/components/chat/TraitsPicker.tsx
#	apps/web/src/components/chat/composerProviderRegistry.test.tsx
#	apps/web/src/composerDraftStore.ts
#	packages/contracts/src/model.ts
#	packages/shared/src/model.test.ts
#	packages/shared/src/model.ts
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/web/src/composerDraftStore.ts Outdated
- Removed unused CursorModelOptions and related logic from ChatView.
- Updated model selection handling to map concrete Cursor slugs to server-provided options.
- Simplified ProviderModelPicker by eliminating unnecessary cursor-related state and logic.
- Adjusted tests to reflect changes in model selection behavior for Cursor provider.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
- Add a standalone ACP probe script for initialize/auth/session/new
- Switch Cursor provider status checks to `agent about` for version and auth
- Log the ACP session/new result in the probe test
Comment threadapps/server/src/provider/Layers/CursorProvider.ts
- Canonicalize Claude and Cursor dispatch model slugs
- Update provider model selection, defaults, and tests
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
- route Cursor commit/PR/branch generation through the agent CLI
- resolve separate ACP and agent model IDs for Cursor models
- improve git action failure logging and surface command output
Comment threadapps/server/src/provider/Layers/CursorProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/git/Layers/RoutingTextGeneration.ts
- Apply model and mode configuration during session start
- Avoid repeating no-op config writes on subsequent turns

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Redundant Schema.is check after findProviderAdapterRequestError
    • Replaced the redundant Schema.is(ProviderAdapterRequestError) checks with simple truthy checks since findProviderAdapterRequestError already validates and returns the typed result.
  • ✅ Fixed: formatFailureDetail uses .message instead of .detail
    • Changed providerError.message to providerError.detail in formatFailureDetail to produce the specific human-readable error description consistent with the rest of the file.

Create PR

Or push these changes by commenting:

@cursor push 0416bda917
Preview (0416bda917)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -98,7 +98,7 @@
function isUnknownPendingApprovalRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
const detail = error.detail.toLowerCase();
return (
detail.includes("unknown pending approval request") ||
@@ -114,7 +114,7 @@
function isUnknownPendingUserInputRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
return error.detail.toLowerCase().includes("unknown pending user-input request");
}
return Cause.pretty(cause).toLowerCase().includes("unknown pending user-input request");
@@ -211,7 +211,7 @@
? failReason.error
: undefined;
if (providerError) {
- return providerError.message;+ return providerError.detail;
}
return Cause.pretty(cause);
};

You can send follow-ups to the cloud agent here.

- Lazily create the event stream from the shared queue
- Co-authored-by: codex <codex@users.noreply.github.com>
- annotate ACP probe spans with the active option id when the probe option is missing
- preserves model capability discovery metadata
- Switch CursorAdapter to `acp.getEvents()`
- Update ACP session tests to read from the accessor
- Match unknown approval and user-input errors from any provider adapter error
- Surface provider error detail instead of the generic message

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Stale model override after session restart for unsupported switch
    • When sessionModelSwitch is 'unsupported' and the user explicitly requested a model change (input.modelSelection is defined), the fix now passes through the user's requested model directly instead of overriding it with the stale activeSession.model, while preserving the session-model fallback for subsequent turns without an explicit model change.

Create PR

Or push these changes by commenting:

@cursor push 245526b0fa
Preview (245526b0fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -428,12 +428,14 @@
input.modelSelection ?? threadModelSelections.get(input.threadId) ?? thread.modelSelection;
const modelForTurn =
sessionModelSwitch === "unsupported"
- ? activeSession?.model !== undefined- ? {- ...requestedModelSelection,- model: activeSession.model,- }- : requestedModelSelection+ ? input.modelSelection !== undefined+ ? input.modelSelection+ : activeSession?.model !== undefined+ ? {+ ...requestedModelSelection,+ model: activeSession.model,+ }+ : requestedModelSelection
: input.modelSelection;
return {

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 1753bc6. Configure here.

- Set cursor.enabled default to false in shared settings schema
- Render optional provider badge on install cards (Cursor: Early Access)
- Align server tests with settings-based Cursor disable and drop stale set_config assertion
- Only reuse the active session model if the turn omits modelSelection
- Add regression test for restart with an explicit model override
- Drop ProviderCommandReactor case covering explicit model override when restarting with sessionModelSwitch unsupported
@juliusmarminge
juliusmarminge merged commit 9c64f12 into mainApr 17, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the t3code/greeting branch April 17, 2026 23:21
orlaya added a commit to orlaya/t3code that referenced this pull request Apr 18, 2026
Integrates 7 upstream commits, headlined by Cursor provider via ACP
(pingdotgg#1355, new effect-acp package + AcpSessionRuntime) and Claude Opus 4.5.
Conflicts resolved (see untangle.md for full policy/playbook):
- ClaudeAdapter.ts queryOptions — took upstream's effort type cast +
kept our isOpus47 thinking-adaptive line.
- MessagesTimeline.tsx SimpleWorkEntryRow — took upstream's cleaner
outer rawCommand ternary (ours had dead inner checks).
- ProviderRuntimeIngestion.ts assistant-delta flow — adopted upstream's
new getOrCreateAssistantMessageId / flushBufferedAssistantMessagesForTurn
/ finalizeActiveAssistantSegmentForTurn helpers + pauseForUserTurnId
block; re-injected our timed 150ms streaming flush, reasoningDelta/
reasoningCompletion dispatch, agentKind plumbing on top.
Downstream adaptations required by upstream's new code:
- Cursor/ACP agentKind plumbing — upstream emitted ProviderRuntimeEvent
values without agentKind; our thinking-blocks tweak made it required.
Fixed via a single makeEventStamp helper change in CursorAdapter
(hard-codes "primary") + AcpEventStamp interface extension. Mirrors
the OpenCode pattern; ~14 event constructions cascade.
- Session reaper — removed dead Effect.catch on a reconcile effect whose
error channel is now `never` (lint hint in our own tweak code).
Test adaptations:
- Fast-mode tests in ClaudeAdapter.test.ts + ClaudeTextGeneration.test.ts
migrated from claude-opus-4-6 (fast mode disabled by our tweak) to
claude-opus-4-5 (upstream's new model, currently the only one that
still supports fast mode).
- Buffered-streaming tests in ProviderRuntimeIngestion.test.ts updated
to pass enableAssistantStreaming: false explicitly, since our tweak
flipped the default to true.
- dev-runner.test.ts — T3CODE_NO_BROWSER assertion updated from
undefined to "1" to match our previously-undocumented tweak.
Docs:
- tweakings.md — added T3CODE_NO_BROWSER + Cursor/ACP agentKind entries.
- untangle.md — added Policy + Active resolution entries for the three
conflicted files, plus reconciliation pattern for future upstream
restructures of the ingestion flow.
@pompydevpompydev mentioned this pull request Apr 18, 2026
2 tasks
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 18, 2026
Integrates upstream/main (9df3c64) on top of fork's main (9602c18).
Upstream features adopted:
- Claude Opus 4.5 and 4.7 built-in models (pingdotgg#2072, pingdotgg#2143)
- Node-native TypeScript migration across desktop/server (pingdotgg#2098)
- Configurable project grouping with client-settings overrides (pingdotgg#2055, pingdotgg#2099)
- Thread status in command palette (pingdotgg#2107)
- Responsive composer / plan sidebar on narrow windows (pingdotgg#1198)
- Capture-phase CTRL+J keydown for Windows terminal toggle (pingdotgg#2113/pingdotgg#2142)
- Bypass xterm for global terminal shortcuts (pingdotgg#1580)
- Windows ARM build target (pingdotgg#2080)
- Windows PATH hydration + repair (pingdotgg#1729)
- Gitignore-aware workspace search (pingdotgg#2078)
- Claude process leak fix + stale session monitoring (pingdotgg#2042)
- Preserve provider bindings when stopping sessions (pingdotgg#2084)
- Clean up invalid pending-approval projections (pingdotgg#2106) — new migration
- Extract backend startup readiness coordination
- Drop stale text-gen options on reset (pingdotgg#2076)
- Extend negative repository identity cache TTL (pingdotgg#2083)
- Allow deleting non-empty projects from warning toast (pingdotgg#1264)
- Restore defaults only on General settings (pingdotgg#1710)
- Release workflow modernization (blacksmith runners, GitHub App token guards, v0.0.20 version bump)
Fork features preserved:
- All 8 providers (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) with their adapters, services, and tests
- Fork's custom OpenCode protocol impl in apps/server/src/opencode/ (kept
over upstream's @opencode-ai/sdk-based provider added in pingdotgg#1758 — fork's
version is tested and integrated; upstream's parallel files deleted)
- Fork's direct-CLI Cursor adapter (kept over upstream's new ACP-based
CursorProvider added in pingdotgg#1355 — upstream's parallel files deleted)
- Fork's ProviderRegistry aggregates only codex + claudeAgent snapshots;
the other 6 providers register via ProviderAdapterRegistry
- PROVIDER_CACHE_IDS stays at [codex, claudeAgent] matching what the
registry actually caches
- Migration IDs preserved (fork 23/24/25/26; upstream's new 025 lands at
ID 27 to avoid re-applying on deployed fork DBs)
- Fork's generic per-provider settings (enabled/binaryPath/configDir/
customModels) kept over upstream's opencode-specific serverUrl/password
- Log directory IPC channels, updateInstallInFlight tracking, icon
composer pipeline all preserved
- Fork's simplified release.yml (no npm CLI publish, no nightly infra)
- composerDraftStore normalizeProviderKind widened to accept all 8 kinds
- Dark mode --background set to #0f0f0f
Test status:
- All 9 package typechecks pass
- Lint clean (0 errors)
- Tests: 1877 passed, 15 skipped (incl. 4 historically-flaky GitManager
cross-repo PR selector tests newly gated with TODO for Node-native-TS
follow-up)
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
…kends
Replaces fork's hand-rolled Cursor (direct-CLI) and OpenCode (custom
protocol) backends with upstream's implementations while keeping fork's
8-provider model picker UI flow intact.
## Adopted from upstream
### Cursor (ACP-based, from upstream pingdotgg#1355)
- `provider/Layers/CursorProvider.ts` + test
- `provider/Services/CursorProvider.ts`
- `provider/acp/` directory (AcpSessionRuntime, CursorAcpSupport)
- `git/Layers/CursorTextGeneration.ts` + test
- Upstream's `Layers/CursorAdapter.ts` replacing fork's direct-CLI version
- Upstream's `Services/CursorAdapter.ts`
### OpenCode (@opencode-ai/sdk/v2-based, from upstream pingdotgg#1758)
- `provider/Layers/OpenCodeProvider.ts` + test
- `provider/Services/OpenCodeProvider.ts`
- `provider/opencodeRuntime.ts` + test
- `git/Layers/OpenCodeTextGeneration.ts` + test
- Upstream's `Layers/OpenCodeAdapter.ts` replacing fork's thin wrapper
- Upstream's `Services/OpenCodeAdapter.ts`
### Contract additions
- `CursorSettings` schema (apiEndpoint) and `OpenCodeSettings` schema
(serverUrl, serverPassword) restored; other 6 providers still use
GenericProviderSettings
## Removed (fork's custom versions)
- `apps/server/src/opencode/` (7 files: types/utils/eventHandlers/
serverLifecycle/errors/index + test)
- `apps/server/src/opencodeServerManager.ts` + test
- `apps/server/src/provider/Layers/CursorUsage.ts` + test
## Wiring changes
- `ProviderRegistry.ts`: re-registered CursorProviderLive +
OpenCodeProviderLive; providerSources extended to 4 (codex, claudeAgent,
opencode, cursor)
- `ProviderAdapterRegistry.ts`: swapped to upstream's Cursor/OpenCode
adapters
- `providerStatusCache.ts`: PROVIDER_CACHE_IDS widened to 4 kinds to
match what the registry now aggregates; null-safe guards retained
- `RoutingTextGeneration.ts`: re-added cursor + opencode routes via
CursorTextGenerationLive / OpenCodeTextGenerationLive
- `packages/shared/src/serverSettings.ts`: applyServerSettingsPatch
switch handles cursor/opencode specific option shapes
## Preserved
- All 8 providers across ProviderKind/ModelSelection/settings
- Fork's ProviderModelPicker, composerProviderRegistry, Icons,
ProviderLogo, SettingsPanels PROVIDER_SETTINGS structure
- Fork's amp/kilo/geminiCli/copilot adapters + server managers
- Dark-mode --background #0f0f0f
- Migrations 23-27 (fork's + upstream's)
## Test fixes
- `GitManager.test.ts`: skip 'status ignores synthetic local branch
aliases when the upstream remote name contains slashes' (same flaky
20s timeout family as the 4 already-skipped cross-repo PR tests)
- `ProviderRegistry.test.ts`: update 'returns snapshots for all
supported providers' expectation from [codex,claudeAgent] to
[codex,claudeAgent,opencode,cursor] to match 4-provider registry
## Status
- bun typecheck: 9/9 packages clean
- bun run lint: 0 errors, 32 warnings
- bun fmt: clean
- bun run test: all packages pass
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 20, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 25, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MuneerAhmed03 pushed a commit to MuneerAhmed03/t3code that referenced this pull request Apr 26, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
@DerpedyeaDerpedyea mentioned this pull request Jul 1, 2026
4 tasks
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add ACP support with Cursor provider - #1355

Merged
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting
Apr 17, 2026
Merged

Add ACP support with Cursor provider#1355
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Mar 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds Cursor as a first-class provider with ACP session lifecycle support, health checks, and adapter wiring in the server.
  • Implements Cursor model selection, including fast/plan mode mapping and session restart behavior when model options change.
  • Preserves provider/thread model state through orchestration, projection, and turn dispatch paths.
  • Updates the web app to surface Cursor traits, provider/model selection, and session drafting behavior.
  • Expands runtime ingestion so completed tool events retain structured tool metadata.

Testing

  • bun fmt
  • bun lint
  • bun typecheck
  • Added and updated tests across server, contracts, shared, and web layers for Cursor adapter behavior, orchestration routing, session model changes, and UI state handling.
  • Not run: bun run test

Note

High Risk
High risk because it introduces a new Cursor ACP provider/agent integration and significantly changes orchestration/runtime-ingestion behavior around turn starts, tool/approval boundaries, and assistant message buffering/segmentation.

Overview
Adds Cursor as a first-class provider using ACP (stdio JSON-RPC), including a new CursorTextGenerationLive path for git text generation that spawns an ACP runtime, applies ACP-configured model options, and tolerates noisy JSON responses.

Extends server orchestration to route text generation to Cursor and refines provider turn start handling to better surface/record start failures without crashing. Runtime ingestion is reworked to segment assistant messages across approval/user-input boundaries, flush buffered text deterministically, avoid whitespace-only artifacts/duplicate completions, and preserve structured tool-call metadata for completed tool activities.

Also updates Claude model-id resolution to use provider-specific resolveClaudeApiModelId, raises the checkpoint diff git output cap, and adds effect-acp wiring/build config so ACP code can be bundled and tested.

Reviewed by Cursor Bugbot for commit aa696b5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Cursor as a provider with ACP-backed sessions, text generation, and UI support

  • Introduces a new effect-acp workspace package implementing a typed JSON-RPC client/agent transport over stdio, matching the ACP protocol (v0.11.3), with schema-generated types and Effect-native error handling.
  • Adds CursorAdapterLive and CursorProviderLive server layers that launch the Cursor ACP agent subprocess, manage session lifecycle (start, send, interrupt, approve, stop), discover models/capabilities, and stream provider snapshots.
  • Extends contracts (ProviderKind, ModelSelection, ProviderModelOptions, ServerSettings) and shared utilities to include Cursor-specific types: CursorModelOptions, CursorModelSelection, CursorSettings, and CursorSettingsPatch.
  • Wires Cursor into the composer UI: model picker, TraitsPicker (fast mode, reasoning, context window), settings panel with 'Early Access' badge, and composerProviderRegistry.
  • Adds CursorTextGenerationLive for ACP-backed git text generation (commit messages, PR content, branch names, thread titles) with a 180s timeout and JSON extraction.
  • Improves ProviderRuntimeIngestion with segment-aware assistant message streaming, buffered flush on pause events, and suppression of empty completions.
  • Improves ProviderCommandReactor turn-start failure handling: sets lastError on the thread session, appends a provider.turn.start.failed activity, and forks the send with recovery logging.
  • Risk: ProviderSessionModelSwitchMode removes the 'restart-session' value; any persisted or in-flight state using that string will no longer match the type union.

Macroscope summarized aa696b5.

@coderabbitai

coderabbitaiBot commented Mar 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c2d0780d-752d-49d8-b364-1135b6096558

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/greeting

Comment @coderabbitai help to get the list of available commands and usage tips.

@juliusmarminge
juliusmarminge marked this pull request as draft March 24, 2026 07:29
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Mar 24, 2026

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Merge never clears cached provider model options
    • Replaced ?? fallback with key in incoming check so explicitly-present-but-undefined provider keys now clear cached values, and added cache deletion when merge produces undefined.
  • ✅ Fixed: Mock agent test uses strict equal with extra fields
    • Changed toEqual to toMatchObject so the assertion tolerates the extra modes field returned by the mock agent.

Create PR

Or push these changes by commenting:

@cursor push beb68c40d7
Preview (beb68c40d7)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -50,20 +50,17 @@
cached: ProviderModelOptions | undefined,
incoming: ProviderModelOptions | undefined,
): ProviderModelOptions | undefined {
- if (!cached && !incoming) {- return undefined;+ if (incoming === undefined) return cached;+ if (cached === undefined) return incoming;++ const providerKeys = ["codex", "claudeAgent", "cursor"] as const;+ const next: Record<string, unknown> = {};+ for (const key of providerKeys) {+ const value = key in incoming ? incoming[key] : cached[key];+ if (value !== undefined) {+ next[key] = value;+ }
}
- const next = {- ...(incoming?.codex !== undefined || cached?.codex !== undefined- ? { codex: incoming?.codex ?? cached?.codex }- : {}),- ...(incoming?.claudeAgent !== undefined || cached?.claudeAgent !== undefined- ? { claudeAgent: incoming?.claudeAgent ?? cached?.claudeAgent }- : {}),- ...(incoming?.cursor !== undefined || cached?.cursor !== undefined- ? { cursor: incoming?.cursor ?? cached?.cursor }- : {}),- } satisfies Partial<ProviderModelOptions>;
return Object.keys(next).length > 0 ? (next as ProviderModelOptions) : undefined;
}
@@ -405,8 +402,12 @@
threadModelOptions.get(input.threadId),
input.modelOptions,
);
- if (mergedModelOptions !== undefined) {- threadModelOptions.set(input.threadId, mergedModelOptions);+ if (input.modelOptions !== undefined) {+ if (mergedModelOptions !== undefined) {+ threadModelOptions.set(input.threadId, mergedModelOptions);+ } else {+ threadModelOptions.delete(input.threadId);+ }
}
const normalizedInput = toNonEmptyProviderInput(input.messageText);
const normalizedAttachments = input.attachments ?? [];
diff --git a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts--- a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts+++ b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts@@ -32,7 +32,7 @@
cwd: process.cwd(),
mcpServers: [],
});
- expect(newResult).toEqual({ sessionId: "mock-session-1" });+ expect(newResult).toMatchObject({ sessionId: "mock-session-1" });
const promptResult = yield* conn.request("session/prompt", {
sessionId: "mock-session-1",

Comment threadapps/server/src/orchestration/Layers/ProviderCommandReactor.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.test.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
- Introduce Cursor ACP adapter and model selection probe
- Preserve cursor session resume state across model changes
- Propagate provider and runtime tool metadata through orchestration and UI
Made-with: Cursor
Replace the hardcoded client-side CURSOR_MODEL_CAPABILITY_BY_FAMILY map
with server-provided ModelCapabilities, matching the Codex/Claude pattern.
- Add CursorProvider snapshot service with BUILT_IN_MODELS and per-model
capabilities; register it in ProviderRegistry alongside Codex/Claude.
- Delete CursorTraitsPicker and route Cursor through the generic
TraitsPicker, adding cursor support for the reasoning/effort key.
- Add normalizeCursorModelOptionsWithCapabilities to providerModels.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadpackages/shared/src/model.ts Outdated
Comment threadapps/web/src/composerDraftStore.ts
…tion
Instead of restarting the ACP process when the model changes mid-thread,
use session/set_config_option to switch models within a live session.
Update sessionModelSwitch to "in-session" and add probe tests to verify
the real agent supports this method.
Made-with: Cursor
Made-with: Cursor
# Conflicts:
#	apps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.tsx
#	apps/web/src/components/chat/TraitsPicker.tsx
#	apps/web/src/components/chat/composerProviderRegistry.test.tsx
#	apps/web/src/composerDraftStore.ts
#	packages/contracts/src/model.ts
#	packages/shared/src/model.test.ts
#	packages/shared/src/model.ts
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/web/src/composerDraftStore.ts Outdated
- Removed unused CursorModelOptions and related logic from ChatView.
- Updated model selection handling to map concrete Cursor slugs to server-provided options.
- Simplified ProviderModelPicker by eliminating unnecessary cursor-related state and logic.
- Adjusted tests to reflect changes in model selection behavior for Cursor provider.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
- Add a standalone ACP probe script for initialize/auth/session/new
- Switch Cursor provider status checks to `agent about` for version and auth
- Log the ACP session/new result in the probe test
Comment threadapps/server/src/provider/Layers/CursorProvider.ts
- Canonicalize Claude and Cursor dispatch model slugs
- Update provider model selection, defaults, and tests
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
- route Cursor commit/PR/branch generation through the agent CLI
- resolve separate ACP and agent model IDs for Cursor models
- improve git action failure logging and surface command output
Comment threadapps/server/src/provider/Layers/CursorProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/git/Layers/RoutingTextGeneration.ts
- Apply model and mode configuration during session start
- Avoid repeating no-op config writes on subsequent turns

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Redundant Schema.is check after findProviderAdapterRequestError
    • Replaced the redundant Schema.is(ProviderAdapterRequestError) checks with simple truthy checks since findProviderAdapterRequestError already validates and returns the typed result.
  • ✅ Fixed: formatFailureDetail uses .message instead of .detail
    • Changed providerError.message to providerError.detail in formatFailureDetail to produce the specific human-readable error description consistent with the rest of the file.

Create PR

Or push these changes by commenting:

@cursor push 0416bda917
Preview (0416bda917)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -98,7 +98,7 @@
function isUnknownPendingApprovalRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
const detail = error.detail.toLowerCase();
return (
detail.includes("unknown pending approval request") ||
@@ -114,7 +114,7 @@
function isUnknownPendingUserInputRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
return error.detail.toLowerCase().includes("unknown pending user-input request");
}
return Cause.pretty(cause).toLowerCase().includes("unknown pending user-input request");
@@ -211,7 +211,7 @@
? failReason.error
: undefined;
if (providerError) {
- return providerError.message;+ return providerError.detail;
}
return Cause.pretty(cause);
};

You can send follow-ups to the cloud agent here.

- Lazily create the event stream from the shared queue
- Co-authored-by: codex <codex@users.noreply.github.com>
- annotate ACP probe spans with the active option id when the probe option is missing
- preserves model capability discovery metadata
- Switch CursorAdapter to `acp.getEvents()`
- Update ACP session tests to read from the accessor
- Match unknown approval and user-input errors from any provider adapter error
- Surface provider error detail instead of the generic message

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Stale model override after session restart for unsupported switch
    • When sessionModelSwitch is 'unsupported' and the user explicitly requested a model change (input.modelSelection is defined), the fix now passes through the user's requested model directly instead of overriding it with the stale activeSession.model, while preserving the session-model fallback for subsequent turns without an explicit model change.

Create PR

Or push these changes by commenting:

@cursor push 245526b0fa
Preview (245526b0fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -428,12 +428,14 @@
input.modelSelection ?? threadModelSelections.get(input.threadId) ?? thread.modelSelection;
const modelForTurn =
sessionModelSwitch === "unsupported"
- ? activeSession?.model !== undefined- ? {- ...requestedModelSelection,- model: activeSession.model,- }- : requestedModelSelection+ ? input.modelSelection !== undefined+ ? input.modelSelection+ : activeSession?.model !== undefined+ ? {+ ...requestedModelSelection,+ model: activeSession.model,+ }+ : requestedModelSelection
: input.modelSelection;
return {

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 1753bc6. Configure here.

- Set cursor.enabled default to false in shared settings schema
- Render optional provider badge on install cards (Cursor: Early Access)
- Align server tests with settings-based Cursor disable and drop stale set_config assertion
- Only reuse the active session model if the turn omits modelSelection
- Add regression test for restart with an explicit model override
- Drop ProviderCommandReactor case covering explicit model override when restarting with sessionModelSwitch unsupported
@juliusmarminge
juliusmarminge merged commit 9c64f12 into mainApr 17, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the t3code/greeting branch April 17, 2026 23:21
orlaya added a commit to orlaya/t3code that referenced this pull request Apr 18, 2026
Integrates 7 upstream commits, headlined by Cursor provider via ACP
(pingdotgg#1355, new effect-acp package + AcpSessionRuntime) and Claude Opus 4.5.
Conflicts resolved (see untangle.md for full policy/playbook):
- ClaudeAdapter.ts queryOptions — took upstream's effort type cast +
kept our isOpus47 thinking-adaptive line.
- MessagesTimeline.tsx SimpleWorkEntryRow — took upstream's cleaner
outer rawCommand ternary (ours had dead inner checks).
- ProviderRuntimeIngestion.ts assistant-delta flow — adopted upstream's
new getOrCreateAssistantMessageId / flushBufferedAssistantMessagesForTurn
/ finalizeActiveAssistantSegmentForTurn helpers + pauseForUserTurnId
block; re-injected our timed 150ms streaming flush, reasoningDelta/
reasoningCompletion dispatch, agentKind plumbing on top.
Downstream adaptations required by upstream's new code:
- Cursor/ACP agentKind plumbing — upstream emitted ProviderRuntimeEvent
values without agentKind; our thinking-blocks tweak made it required.
Fixed via a single makeEventStamp helper change in CursorAdapter
(hard-codes "primary") + AcpEventStamp interface extension. Mirrors
the OpenCode pattern; ~14 event constructions cascade.
- Session reaper — removed dead Effect.catch on a reconcile effect whose
error channel is now `never` (lint hint in our own tweak code).
Test adaptations:
- Fast-mode tests in ClaudeAdapter.test.ts + ClaudeTextGeneration.test.ts
migrated from claude-opus-4-6 (fast mode disabled by our tweak) to
claude-opus-4-5 (upstream's new model, currently the only one that
still supports fast mode).
- Buffered-streaming tests in ProviderRuntimeIngestion.test.ts updated
to pass enableAssistantStreaming: false explicitly, since our tweak
flipped the default to true.
- dev-runner.test.ts — T3CODE_NO_BROWSER assertion updated from
undefined to "1" to match our previously-undocumented tweak.
Docs:
- tweakings.md — added T3CODE_NO_BROWSER + Cursor/ACP agentKind entries.
- untangle.md — added Policy + Active resolution entries for the three
conflicted files, plus reconciliation pattern for future upstream
restructures of the ingestion flow.
@pompydevpompydev mentioned this pull request Apr 18, 2026
2 tasks
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 18, 2026
Integrates upstream/main (9df3c64) on top of fork's main (9602c18).
Upstream features adopted:
- Claude Opus 4.5 and 4.7 built-in models (pingdotgg#2072, pingdotgg#2143)
- Node-native TypeScript migration across desktop/server (pingdotgg#2098)
- Configurable project grouping with client-settings overrides (pingdotgg#2055, pingdotgg#2099)
- Thread status in command palette (pingdotgg#2107)
- Responsive composer / plan sidebar on narrow windows (pingdotgg#1198)
- Capture-phase CTRL+J keydown for Windows terminal toggle (pingdotgg#2113/pingdotgg#2142)
- Bypass xterm for global terminal shortcuts (pingdotgg#1580)
- Windows ARM build target (pingdotgg#2080)
- Windows PATH hydration + repair (pingdotgg#1729)
- Gitignore-aware workspace search (pingdotgg#2078)
- Claude process leak fix + stale session monitoring (pingdotgg#2042)
- Preserve provider bindings when stopping sessions (pingdotgg#2084)
- Clean up invalid pending-approval projections (pingdotgg#2106) — new migration
- Extract backend startup readiness coordination
- Drop stale text-gen options on reset (pingdotgg#2076)
- Extend negative repository identity cache TTL (pingdotgg#2083)
- Allow deleting non-empty projects from warning toast (pingdotgg#1264)
- Restore defaults only on General settings (pingdotgg#1710)
- Release workflow modernization (blacksmith runners, GitHub App token guards, v0.0.20 version bump)
Fork features preserved:
- All 8 providers (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) with their adapters, services, and tests
- Fork's custom OpenCode protocol impl in apps/server/src/opencode/ (kept
over upstream's @opencode-ai/sdk-based provider added in pingdotgg#1758 — fork's
version is tested and integrated; upstream's parallel files deleted)
- Fork's direct-CLI Cursor adapter (kept over upstream's new ACP-based
CursorProvider added in pingdotgg#1355 — upstream's parallel files deleted)
- Fork's ProviderRegistry aggregates only codex + claudeAgent snapshots;
the other 6 providers register via ProviderAdapterRegistry
- PROVIDER_CACHE_IDS stays at [codex, claudeAgent] matching what the
registry actually caches
- Migration IDs preserved (fork 23/24/25/26; upstream's new 025 lands at
ID 27 to avoid re-applying on deployed fork DBs)
- Fork's generic per-provider settings (enabled/binaryPath/configDir/
customModels) kept over upstream's opencode-specific serverUrl/password
- Log directory IPC channels, updateInstallInFlight tracking, icon
composer pipeline all preserved
- Fork's simplified release.yml (no npm CLI publish, no nightly infra)
- composerDraftStore normalizeProviderKind widened to accept all 8 kinds
- Dark mode --background set to #0f0f0f
Test status:
- All 9 package typechecks pass
- Lint clean (0 errors)
- Tests: 1877 passed, 15 skipped (incl. 4 historically-flaky GitManager
cross-repo PR selector tests newly gated with TODO for Node-native-TS
follow-up)
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
…kends
Replaces fork's hand-rolled Cursor (direct-CLI) and OpenCode (custom
protocol) backends with upstream's implementations while keeping fork's
8-provider model picker UI flow intact.
## Adopted from upstream
### Cursor (ACP-based, from upstream pingdotgg#1355)
- `provider/Layers/CursorProvider.ts` + test
- `provider/Services/CursorProvider.ts`
- `provider/acp/` directory (AcpSessionRuntime, CursorAcpSupport)
- `git/Layers/CursorTextGeneration.ts` + test
- Upstream's `Layers/CursorAdapter.ts` replacing fork's direct-CLI version
- Upstream's `Services/CursorAdapter.ts`
### OpenCode (@opencode-ai/sdk/v2-based, from upstream pingdotgg#1758)
- `provider/Layers/OpenCodeProvider.ts` + test
- `provider/Services/OpenCodeProvider.ts`
- `provider/opencodeRuntime.ts` + test
- `git/Layers/OpenCodeTextGeneration.ts` + test
- Upstream's `Layers/OpenCodeAdapter.ts` replacing fork's thin wrapper
- Upstream's `Services/OpenCodeAdapter.ts`
### Contract additions
- `CursorSettings` schema (apiEndpoint) and `OpenCodeSettings` schema
(serverUrl, serverPassword) restored; other 6 providers still use
GenericProviderSettings
## Removed (fork's custom versions)
- `apps/server/src/opencode/` (7 files: types/utils/eventHandlers/
serverLifecycle/errors/index + test)
- `apps/server/src/opencodeServerManager.ts` + test
- `apps/server/src/provider/Layers/CursorUsage.ts` + test
## Wiring changes
- `ProviderRegistry.ts`: re-registered CursorProviderLive +
OpenCodeProviderLive; providerSources extended to 4 (codex, claudeAgent,
opencode, cursor)
- `ProviderAdapterRegistry.ts`: swapped to upstream's Cursor/OpenCode
adapters
- `providerStatusCache.ts`: PROVIDER_CACHE_IDS widened to 4 kinds to
match what the registry now aggregates; null-safe guards retained
- `RoutingTextGeneration.ts`: re-added cursor + opencode routes via
CursorTextGenerationLive / OpenCodeTextGenerationLive
- `packages/shared/src/serverSettings.ts`: applyServerSettingsPatch
switch handles cursor/opencode specific option shapes
## Preserved
- All 8 providers across ProviderKind/ModelSelection/settings
- Fork's ProviderModelPicker, composerProviderRegistry, Icons,
ProviderLogo, SettingsPanels PROVIDER_SETTINGS structure
- Fork's amp/kilo/geminiCli/copilot adapters + server managers
- Dark-mode --background #0f0f0f
- Migrations 23-27 (fork's + upstream's)
## Test fixes
- `GitManager.test.ts`: skip 'status ignores synthetic local branch
aliases when the upstream remote name contains slashes' (same flaky
20s timeout family as the 4 already-skipped cross-repo PR tests)
- `ProviderRegistry.test.ts`: update 'returns snapshots for all
supported providers' expectation from [codex,claudeAgent] to
[codex,claudeAgent,opencode,cursor] to match 4-provider registry
## Status
- bun typecheck: 9/9 packages clean
- bun run lint: 0 errors, 32 warnings
- bun fmt: clean
- bun run test: all packages pass
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 20, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 25, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MuneerAhmed03 pushed a commit to MuneerAhmed03/t3code that referenced this pull request Apr 26, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
@DerpedyeaDerpedyea mentioned this pull request Jul 1, 2026
4 tasks
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add ACP support with Cursor provider - #1355

Merged
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting
Apr 17, 2026
Merged

Add ACP support with Cursor provider#1355
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Mar 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds Cursor as a first-class provider with ACP session lifecycle support, health checks, and adapter wiring in the server.
  • Implements Cursor model selection, including fast/plan mode mapping and session restart behavior when model options change.
  • Preserves provider/thread model state through orchestration, projection, and turn dispatch paths.
  • Updates the web app to surface Cursor traits, provider/model selection, and session drafting behavior.
  • Expands runtime ingestion so completed tool events retain structured tool metadata.

Testing

  • bun fmt
  • bun lint
  • bun typecheck
  • Added and updated tests across server, contracts, shared, and web layers for Cursor adapter behavior, orchestration routing, session model changes, and UI state handling.
  • Not run: bun run test

Note

High Risk
High risk because it introduces a new Cursor ACP provider/agent integration and significantly changes orchestration/runtime-ingestion behavior around turn starts, tool/approval boundaries, and assistant message buffering/segmentation.

Overview
Adds Cursor as a first-class provider using ACP (stdio JSON-RPC), including a new CursorTextGenerationLive path for git text generation that spawns an ACP runtime, applies ACP-configured model options, and tolerates noisy JSON responses.

Extends server orchestration to route text generation to Cursor and refines provider turn start handling to better surface/record start failures without crashing. Runtime ingestion is reworked to segment assistant messages across approval/user-input boundaries, flush buffered text deterministically, avoid whitespace-only artifacts/duplicate completions, and preserve structured tool-call metadata for completed tool activities.

Also updates Claude model-id resolution to use provider-specific resolveClaudeApiModelId, raises the checkpoint diff git output cap, and adds effect-acp wiring/build config so ACP code can be bundled and tested.

Reviewed by Cursor Bugbot for commit aa696b5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Cursor as a provider with ACP-backed sessions, text generation, and UI support

  • Introduces a new effect-acp workspace package implementing a typed JSON-RPC client/agent transport over stdio, matching the ACP protocol (v0.11.3), with schema-generated types and Effect-native error handling.
  • Adds CursorAdapterLive and CursorProviderLive server layers that launch the Cursor ACP agent subprocess, manage session lifecycle (start, send, interrupt, approve, stop), discover models/capabilities, and stream provider snapshots.
  • Extends contracts (ProviderKind, ModelSelection, ProviderModelOptions, ServerSettings) and shared utilities to include Cursor-specific types: CursorModelOptions, CursorModelSelection, CursorSettings, and CursorSettingsPatch.
  • Wires Cursor into the composer UI: model picker, TraitsPicker (fast mode, reasoning, context window), settings panel with 'Early Access' badge, and composerProviderRegistry.
  • Adds CursorTextGenerationLive for ACP-backed git text generation (commit messages, PR content, branch names, thread titles) with a 180s timeout and JSON extraction.
  • Improves ProviderRuntimeIngestion with segment-aware assistant message streaming, buffered flush on pause events, and suppression of empty completions.
  • Improves ProviderCommandReactor turn-start failure handling: sets lastError on the thread session, appends a provider.turn.start.failed activity, and forks the send with recovery logging.
  • Risk: ProviderSessionModelSwitchMode removes the 'restart-session' value; any persisted or in-flight state using that string will no longer match the type union.

Macroscope summarized aa696b5.

@coderabbitai

coderabbitaiBot commented Mar 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c2d0780d-752d-49d8-b364-1135b6096558

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/greeting

Comment @coderabbitai help to get the list of available commands and usage tips.

@juliusmarminge
juliusmarminge marked this pull request as draft March 24, 2026 07:29
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Mar 24, 2026

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Merge never clears cached provider model options
    • Replaced ?? fallback with key in incoming check so explicitly-present-but-undefined provider keys now clear cached values, and added cache deletion when merge produces undefined.
  • ✅ Fixed: Mock agent test uses strict equal with extra fields
    • Changed toEqual to toMatchObject so the assertion tolerates the extra modes field returned by the mock agent.

Create PR

Or push these changes by commenting:

@cursor push beb68c40d7
Preview (beb68c40d7)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -50,20 +50,17 @@
cached: ProviderModelOptions | undefined,
incoming: ProviderModelOptions | undefined,
): ProviderModelOptions | undefined {
- if (!cached && !incoming) {- return undefined;+ if (incoming === undefined) return cached;+ if (cached === undefined) return incoming;++ const providerKeys = ["codex", "claudeAgent", "cursor"] as const;+ const next: Record<string, unknown> = {};+ for (const key of providerKeys) {+ const value = key in incoming ? incoming[key] : cached[key];+ if (value !== undefined) {+ next[key] = value;+ }
}
- const next = {- ...(incoming?.codex !== undefined || cached?.codex !== undefined- ? { codex: incoming?.codex ?? cached?.codex }- : {}),- ...(incoming?.claudeAgent !== undefined || cached?.claudeAgent !== undefined- ? { claudeAgent: incoming?.claudeAgent ?? cached?.claudeAgent }- : {}),- ...(incoming?.cursor !== undefined || cached?.cursor !== undefined- ? { cursor: incoming?.cursor ?? cached?.cursor }- : {}),- } satisfies Partial<ProviderModelOptions>;
return Object.keys(next).length > 0 ? (next as ProviderModelOptions) : undefined;
}
@@ -405,8 +402,12 @@
threadModelOptions.get(input.threadId),
input.modelOptions,
);
- if (mergedModelOptions !== undefined) {- threadModelOptions.set(input.threadId, mergedModelOptions);+ if (input.modelOptions !== undefined) {+ if (mergedModelOptions !== undefined) {+ threadModelOptions.set(input.threadId, mergedModelOptions);+ } else {+ threadModelOptions.delete(input.threadId);+ }
}
const normalizedInput = toNonEmptyProviderInput(input.messageText);
const normalizedAttachments = input.attachments ?? [];
diff --git a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts--- a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts+++ b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts@@ -32,7 +32,7 @@
cwd: process.cwd(),
mcpServers: [],
});
- expect(newResult).toEqual({ sessionId: "mock-session-1" });+ expect(newResult).toMatchObject({ sessionId: "mock-session-1" });
const promptResult = yield* conn.request("session/prompt", {
sessionId: "mock-session-1",

Comment threadapps/server/src/orchestration/Layers/ProviderCommandReactor.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.test.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
- Introduce Cursor ACP adapter and model selection probe
- Preserve cursor session resume state across model changes
- Propagate provider and runtime tool metadata through orchestration and UI
Made-with: Cursor
Replace the hardcoded client-side CURSOR_MODEL_CAPABILITY_BY_FAMILY map
with server-provided ModelCapabilities, matching the Codex/Claude pattern.
- Add CursorProvider snapshot service with BUILT_IN_MODELS and per-model
capabilities; register it in ProviderRegistry alongside Codex/Claude.
- Delete CursorTraitsPicker and route Cursor through the generic
TraitsPicker, adding cursor support for the reasoning/effort key.
- Add normalizeCursorModelOptionsWithCapabilities to providerModels.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadpackages/shared/src/model.ts Outdated
Comment threadapps/web/src/composerDraftStore.ts
…tion
Instead of restarting the ACP process when the model changes mid-thread,
use session/set_config_option to switch models within a live session.
Update sessionModelSwitch to "in-session" and add probe tests to verify
the real agent supports this method.
Made-with: Cursor
Made-with: Cursor
# Conflicts:
#	apps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.tsx
#	apps/web/src/components/chat/TraitsPicker.tsx
#	apps/web/src/components/chat/composerProviderRegistry.test.tsx
#	apps/web/src/composerDraftStore.ts
#	packages/contracts/src/model.ts
#	packages/shared/src/model.test.ts
#	packages/shared/src/model.ts
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/web/src/composerDraftStore.ts Outdated
- Removed unused CursorModelOptions and related logic from ChatView.
- Updated model selection handling to map concrete Cursor slugs to server-provided options.
- Simplified ProviderModelPicker by eliminating unnecessary cursor-related state and logic.
- Adjusted tests to reflect changes in model selection behavior for Cursor provider.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
- Add a standalone ACP probe script for initialize/auth/session/new
- Switch Cursor provider status checks to `agent about` for version and auth
- Log the ACP session/new result in the probe test
Comment threadapps/server/src/provider/Layers/CursorProvider.ts
- Canonicalize Claude and Cursor dispatch model slugs
- Update provider model selection, defaults, and tests
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
- route Cursor commit/PR/branch generation through the agent CLI
- resolve separate ACP and agent model IDs for Cursor models
- improve git action failure logging and surface command output
Comment threadapps/server/src/provider/Layers/CursorProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/git/Layers/RoutingTextGeneration.ts
- Apply model and mode configuration during session start
- Avoid repeating no-op config writes on subsequent turns

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Redundant Schema.is check after findProviderAdapterRequestError
    • Replaced the redundant Schema.is(ProviderAdapterRequestError) checks with simple truthy checks since findProviderAdapterRequestError already validates and returns the typed result.
  • ✅ Fixed: formatFailureDetail uses .message instead of .detail
    • Changed providerError.message to providerError.detail in formatFailureDetail to produce the specific human-readable error description consistent with the rest of the file.

Create PR

Or push these changes by commenting:

@cursor push 0416bda917
Preview (0416bda917)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -98,7 +98,7 @@
function isUnknownPendingApprovalRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
const detail = error.detail.toLowerCase();
return (
detail.includes("unknown pending approval request") ||
@@ -114,7 +114,7 @@
function isUnknownPendingUserInputRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
return error.detail.toLowerCase().includes("unknown pending user-input request");
}
return Cause.pretty(cause).toLowerCase().includes("unknown pending user-input request");
@@ -211,7 +211,7 @@
? failReason.error
: undefined;
if (providerError) {
- return providerError.message;+ return providerError.detail;
}
return Cause.pretty(cause);
};

You can send follow-ups to the cloud agent here.

- Lazily create the event stream from the shared queue
- Co-authored-by: codex <codex@users.noreply.github.com>
- annotate ACP probe spans with the active option id when the probe option is missing
- preserves model capability discovery metadata
- Switch CursorAdapter to `acp.getEvents()`
- Update ACP session tests to read from the accessor
- Match unknown approval and user-input errors from any provider adapter error
- Surface provider error detail instead of the generic message

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Stale model override after session restart for unsupported switch
    • When sessionModelSwitch is 'unsupported' and the user explicitly requested a model change (input.modelSelection is defined), the fix now passes through the user's requested model directly instead of overriding it with the stale activeSession.model, while preserving the session-model fallback for subsequent turns without an explicit model change.

Create PR

Or push these changes by commenting:

@cursor push 245526b0fa
Preview (245526b0fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -428,12 +428,14 @@
input.modelSelection ?? threadModelSelections.get(input.threadId) ?? thread.modelSelection;
const modelForTurn =
sessionModelSwitch === "unsupported"
- ? activeSession?.model !== undefined- ? {- ...requestedModelSelection,- model: activeSession.model,- }- : requestedModelSelection+ ? input.modelSelection !== undefined+ ? input.modelSelection+ : activeSession?.model !== undefined+ ? {+ ...requestedModelSelection,+ model: activeSession.model,+ }+ : requestedModelSelection
: input.modelSelection;
return {

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 1753bc6. Configure here.

- Set cursor.enabled default to false in shared settings schema
- Render optional provider badge on install cards (Cursor: Early Access)
- Align server tests with settings-based Cursor disable and drop stale set_config assertion
- Only reuse the active session model if the turn omits modelSelection
- Add regression test for restart with an explicit model override
- Drop ProviderCommandReactor case covering explicit model override when restarting with sessionModelSwitch unsupported
@juliusmarminge
juliusmarminge merged commit 9c64f12 into mainApr 17, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the t3code/greeting branch April 17, 2026 23:21
orlaya added a commit to orlaya/t3code that referenced this pull request Apr 18, 2026
Integrates 7 upstream commits, headlined by Cursor provider via ACP
(pingdotgg#1355, new effect-acp package + AcpSessionRuntime) and Claude Opus 4.5.
Conflicts resolved (see untangle.md for full policy/playbook):
- ClaudeAdapter.ts queryOptions — took upstream's effort type cast +
kept our isOpus47 thinking-adaptive line.
- MessagesTimeline.tsx SimpleWorkEntryRow — took upstream's cleaner
outer rawCommand ternary (ours had dead inner checks).
- ProviderRuntimeIngestion.ts assistant-delta flow — adopted upstream's
new getOrCreateAssistantMessageId / flushBufferedAssistantMessagesForTurn
/ finalizeActiveAssistantSegmentForTurn helpers + pauseForUserTurnId
block; re-injected our timed 150ms streaming flush, reasoningDelta/
reasoningCompletion dispatch, agentKind plumbing on top.
Downstream adaptations required by upstream's new code:
- Cursor/ACP agentKind plumbing — upstream emitted ProviderRuntimeEvent
values without agentKind; our thinking-blocks tweak made it required.
Fixed via a single makeEventStamp helper change in CursorAdapter
(hard-codes "primary") + AcpEventStamp interface extension. Mirrors
the OpenCode pattern; ~14 event constructions cascade.
- Session reaper — removed dead Effect.catch on a reconcile effect whose
error channel is now `never` (lint hint in our own tweak code).
Test adaptations:
- Fast-mode tests in ClaudeAdapter.test.ts + ClaudeTextGeneration.test.ts
migrated from claude-opus-4-6 (fast mode disabled by our tweak) to
claude-opus-4-5 (upstream's new model, currently the only one that
still supports fast mode).
- Buffered-streaming tests in ProviderRuntimeIngestion.test.ts updated
to pass enableAssistantStreaming: false explicitly, since our tweak
flipped the default to true.
- dev-runner.test.ts — T3CODE_NO_BROWSER assertion updated from
undefined to "1" to match our previously-undocumented tweak.
Docs:
- tweakings.md — added T3CODE_NO_BROWSER + Cursor/ACP agentKind entries.
- untangle.md — added Policy + Active resolution entries for the three
conflicted files, plus reconciliation pattern for future upstream
restructures of the ingestion flow.
@pompydevpompydev mentioned this pull request Apr 18, 2026
2 tasks
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 18, 2026
Integrates upstream/main (9df3c64) on top of fork's main (9602c18).
Upstream features adopted:
- Claude Opus 4.5 and 4.7 built-in models (pingdotgg#2072, pingdotgg#2143)
- Node-native TypeScript migration across desktop/server (pingdotgg#2098)
- Configurable project grouping with client-settings overrides (pingdotgg#2055, pingdotgg#2099)
- Thread status in command palette (pingdotgg#2107)
- Responsive composer / plan sidebar on narrow windows (pingdotgg#1198)
- Capture-phase CTRL+J keydown for Windows terminal toggle (pingdotgg#2113/pingdotgg#2142)
- Bypass xterm for global terminal shortcuts (pingdotgg#1580)
- Windows ARM build target (pingdotgg#2080)
- Windows PATH hydration + repair (pingdotgg#1729)
- Gitignore-aware workspace search (pingdotgg#2078)
- Claude process leak fix + stale session monitoring (pingdotgg#2042)
- Preserve provider bindings when stopping sessions (pingdotgg#2084)
- Clean up invalid pending-approval projections (pingdotgg#2106) — new migration
- Extract backend startup readiness coordination
- Drop stale text-gen options on reset (pingdotgg#2076)
- Extend negative repository identity cache TTL (pingdotgg#2083)
- Allow deleting non-empty projects from warning toast (pingdotgg#1264)
- Restore defaults only on General settings (pingdotgg#1710)
- Release workflow modernization (blacksmith runners, GitHub App token guards, v0.0.20 version bump)
Fork features preserved:
- All 8 providers (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) with their adapters, services, and tests
- Fork's custom OpenCode protocol impl in apps/server/src/opencode/ (kept
over upstream's @opencode-ai/sdk-based provider added in pingdotgg#1758 — fork's
version is tested and integrated; upstream's parallel files deleted)
- Fork's direct-CLI Cursor adapter (kept over upstream's new ACP-based
CursorProvider added in pingdotgg#1355 — upstream's parallel files deleted)
- Fork's ProviderRegistry aggregates only codex + claudeAgent snapshots;
the other 6 providers register via ProviderAdapterRegistry
- PROVIDER_CACHE_IDS stays at [codex, claudeAgent] matching what the
registry actually caches
- Migration IDs preserved (fork 23/24/25/26; upstream's new 025 lands at
ID 27 to avoid re-applying on deployed fork DBs)
- Fork's generic per-provider settings (enabled/binaryPath/configDir/
customModels) kept over upstream's opencode-specific serverUrl/password
- Log directory IPC channels, updateInstallInFlight tracking, icon
composer pipeline all preserved
- Fork's simplified release.yml (no npm CLI publish, no nightly infra)
- composerDraftStore normalizeProviderKind widened to accept all 8 kinds
- Dark mode --background set to #0f0f0f
Test status:
- All 9 package typechecks pass
- Lint clean (0 errors)
- Tests: 1877 passed, 15 skipped (incl. 4 historically-flaky GitManager
cross-repo PR selector tests newly gated with TODO for Node-native-TS
follow-up)
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
…kends
Replaces fork's hand-rolled Cursor (direct-CLI) and OpenCode (custom
protocol) backends with upstream's implementations while keeping fork's
8-provider model picker UI flow intact.
## Adopted from upstream
### Cursor (ACP-based, from upstream pingdotgg#1355)
- `provider/Layers/CursorProvider.ts` + test
- `provider/Services/CursorProvider.ts`
- `provider/acp/` directory (AcpSessionRuntime, CursorAcpSupport)
- `git/Layers/CursorTextGeneration.ts` + test
- Upstream's `Layers/CursorAdapter.ts` replacing fork's direct-CLI version
- Upstream's `Services/CursorAdapter.ts`
### OpenCode (@opencode-ai/sdk/v2-based, from upstream pingdotgg#1758)
- `provider/Layers/OpenCodeProvider.ts` + test
- `provider/Services/OpenCodeProvider.ts`
- `provider/opencodeRuntime.ts` + test
- `git/Layers/OpenCodeTextGeneration.ts` + test
- Upstream's `Layers/OpenCodeAdapter.ts` replacing fork's thin wrapper
- Upstream's `Services/OpenCodeAdapter.ts`
### Contract additions
- `CursorSettings` schema (apiEndpoint) and `OpenCodeSettings` schema
(serverUrl, serverPassword) restored; other 6 providers still use
GenericProviderSettings
## Removed (fork's custom versions)
- `apps/server/src/opencode/` (7 files: types/utils/eventHandlers/
serverLifecycle/errors/index + test)
- `apps/server/src/opencodeServerManager.ts` + test
- `apps/server/src/provider/Layers/CursorUsage.ts` + test
## Wiring changes
- `ProviderRegistry.ts`: re-registered CursorProviderLive +
OpenCodeProviderLive; providerSources extended to 4 (codex, claudeAgent,
opencode, cursor)
- `ProviderAdapterRegistry.ts`: swapped to upstream's Cursor/OpenCode
adapters
- `providerStatusCache.ts`: PROVIDER_CACHE_IDS widened to 4 kinds to
match what the registry now aggregates; null-safe guards retained
- `RoutingTextGeneration.ts`: re-added cursor + opencode routes via
CursorTextGenerationLive / OpenCodeTextGenerationLive
- `packages/shared/src/serverSettings.ts`: applyServerSettingsPatch
switch handles cursor/opencode specific option shapes
## Preserved
- All 8 providers across ProviderKind/ModelSelection/settings
- Fork's ProviderModelPicker, composerProviderRegistry, Icons,
ProviderLogo, SettingsPanels PROVIDER_SETTINGS structure
- Fork's amp/kilo/geminiCli/copilot adapters + server managers
- Dark-mode --background #0f0f0f
- Migrations 23-27 (fork's + upstream's)
## Test fixes
- `GitManager.test.ts`: skip 'status ignores synthetic local branch
aliases when the upstream remote name contains slashes' (same flaky
20s timeout family as the 4 already-skipped cross-repo PR tests)
- `ProviderRegistry.test.ts`: update 'returns snapshots for all
supported providers' expectation from [codex,claudeAgent] to
[codex,claudeAgent,opencode,cursor] to match 4-provider registry
## Status
- bun typecheck: 9/9 packages clean
- bun run lint: 0 errors, 32 warnings
- bun fmt: clean
- bun run test: all packages pass
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 20, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 25, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MuneerAhmed03 pushed a commit to MuneerAhmed03/t3code that referenced this pull request Apr 26, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
@DerpedyeaDerpedyea mentioned this pull request Jul 1, 2026
4 tasks
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add ACP support with Cursor provider - #1355

Merged
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting
Apr 17, 2026
Merged

Add ACP support with Cursor provider#1355
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Mar 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds Cursor as a first-class provider with ACP session lifecycle support, health checks, and adapter wiring in the server.
  • Implements Cursor model selection, including fast/plan mode mapping and session restart behavior when model options change.
  • Preserves provider/thread model state through orchestration, projection, and turn dispatch paths.
  • Updates the web app to surface Cursor traits, provider/model selection, and session drafting behavior.
  • Expands runtime ingestion so completed tool events retain structured tool metadata.

Testing

  • bun fmt
  • bun lint
  • bun typecheck
  • Added and updated tests across server, contracts, shared, and web layers for Cursor adapter behavior, orchestration routing, session model changes, and UI state handling.
  • Not run: bun run test

Note

High Risk
High risk because it introduces a new Cursor ACP provider/agent integration and significantly changes orchestration/runtime-ingestion behavior around turn starts, tool/approval boundaries, and assistant message buffering/segmentation.

Overview
Adds Cursor as a first-class provider using ACP (stdio JSON-RPC), including a new CursorTextGenerationLive path for git text generation that spawns an ACP runtime, applies ACP-configured model options, and tolerates noisy JSON responses.

Extends server orchestration to route text generation to Cursor and refines provider turn start handling to better surface/record start failures without crashing. Runtime ingestion is reworked to segment assistant messages across approval/user-input boundaries, flush buffered text deterministically, avoid whitespace-only artifacts/duplicate completions, and preserve structured tool-call metadata for completed tool activities.

Also updates Claude model-id resolution to use provider-specific resolveClaudeApiModelId, raises the checkpoint diff git output cap, and adds effect-acp wiring/build config so ACP code can be bundled and tested.

Reviewed by Cursor Bugbot for commit aa696b5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Cursor as a provider with ACP-backed sessions, text generation, and UI support

  • Introduces a new effect-acp workspace package implementing a typed JSON-RPC client/agent transport over stdio, matching the ACP protocol (v0.11.3), with schema-generated types and Effect-native error handling.
  • Adds CursorAdapterLive and CursorProviderLive server layers that launch the Cursor ACP agent subprocess, manage session lifecycle (start, send, interrupt, approve, stop), discover models/capabilities, and stream provider snapshots.
  • Extends contracts (ProviderKind, ModelSelection, ProviderModelOptions, ServerSettings) and shared utilities to include Cursor-specific types: CursorModelOptions, CursorModelSelection, CursorSettings, and CursorSettingsPatch.
  • Wires Cursor into the composer UI: model picker, TraitsPicker (fast mode, reasoning, context window), settings panel with 'Early Access' badge, and composerProviderRegistry.
  • Adds CursorTextGenerationLive for ACP-backed git text generation (commit messages, PR content, branch names, thread titles) with a 180s timeout and JSON extraction.
  • Improves ProviderRuntimeIngestion with segment-aware assistant message streaming, buffered flush on pause events, and suppression of empty completions.
  • Improves ProviderCommandReactor turn-start failure handling: sets lastError on the thread session, appends a provider.turn.start.failed activity, and forks the send with recovery logging.
  • Risk: ProviderSessionModelSwitchMode removes the 'restart-session' value; any persisted or in-flight state using that string will no longer match the type union.

Macroscope summarized aa696b5.

@coderabbitai

coderabbitaiBot commented Mar 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c2d0780d-752d-49d8-b364-1135b6096558

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/greeting

Comment @coderabbitai help to get the list of available commands and usage tips.

@juliusmarminge
juliusmarminge marked this pull request as draft March 24, 2026 07:29
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Mar 24, 2026

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Merge never clears cached provider model options
    • Replaced ?? fallback with key in incoming check so explicitly-present-but-undefined provider keys now clear cached values, and added cache deletion when merge produces undefined.
  • ✅ Fixed: Mock agent test uses strict equal with extra fields
    • Changed toEqual to toMatchObject so the assertion tolerates the extra modes field returned by the mock agent.

Create PR

Or push these changes by commenting:

@cursor push beb68c40d7
Preview (beb68c40d7)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -50,20 +50,17 @@
cached: ProviderModelOptions | undefined,
incoming: ProviderModelOptions | undefined,
): ProviderModelOptions | undefined {
- if (!cached && !incoming) {- return undefined;+ if (incoming === undefined) return cached;+ if (cached === undefined) return incoming;++ const providerKeys = ["codex", "claudeAgent", "cursor"] as const;+ const next: Record<string, unknown> = {};+ for (const key of providerKeys) {+ const value = key in incoming ? incoming[key] : cached[key];+ if (value !== undefined) {+ next[key] = value;+ }
}
- const next = {- ...(incoming?.codex !== undefined || cached?.codex !== undefined- ? { codex: incoming?.codex ?? cached?.codex }- : {}),- ...(incoming?.claudeAgent !== undefined || cached?.claudeAgent !== undefined- ? { claudeAgent: incoming?.claudeAgent ?? cached?.claudeAgent }- : {}),- ...(incoming?.cursor !== undefined || cached?.cursor !== undefined- ? { cursor: incoming?.cursor ?? cached?.cursor }- : {}),- } satisfies Partial<ProviderModelOptions>;
return Object.keys(next).length > 0 ? (next as ProviderModelOptions) : undefined;
}
@@ -405,8 +402,12 @@
threadModelOptions.get(input.threadId),
input.modelOptions,
);
- if (mergedModelOptions !== undefined) {- threadModelOptions.set(input.threadId, mergedModelOptions);+ if (input.modelOptions !== undefined) {+ if (mergedModelOptions !== undefined) {+ threadModelOptions.set(input.threadId, mergedModelOptions);+ } else {+ threadModelOptions.delete(input.threadId);+ }
}
const normalizedInput = toNonEmptyProviderInput(input.messageText);
const normalizedAttachments = input.attachments ?? [];
diff --git a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts--- a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts+++ b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts@@ -32,7 +32,7 @@
cwd: process.cwd(),
mcpServers: [],
});
- expect(newResult).toEqual({ sessionId: "mock-session-1" });+ expect(newResult).toMatchObject({ sessionId: "mock-session-1" });
const promptResult = yield* conn.request("session/prompt", {
sessionId: "mock-session-1",

Comment threadapps/server/src/orchestration/Layers/ProviderCommandReactor.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.test.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
- Introduce Cursor ACP adapter and model selection probe
- Preserve cursor session resume state across model changes
- Propagate provider and runtime tool metadata through orchestration and UI
Made-with: Cursor
Replace the hardcoded client-side CURSOR_MODEL_CAPABILITY_BY_FAMILY map
with server-provided ModelCapabilities, matching the Codex/Claude pattern.
- Add CursorProvider snapshot service with BUILT_IN_MODELS and per-model
capabilities; register it in ProviderRegistry alongside Codex/Claude.
- Delete CursorTraitsPicker and route Cursor through the generic
TraitsPicker, adding cursor support for the reasoning/effort key.
- Add normalizeCursorModelOptionsWithCapabilities to providerModels.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadpackages/shared/src/model.ts Outdated
Comment threadapps/web/src/composerDraftStore.ts
…tion
Instead of restarting the ACP process when the model changes mid-thread,
use session/set_config_option to switch models within a live session.
Update sessionModelSwitch to "in-session" and add probe tests to verify
the real agent supports this method.
Made-with: Cursor
Made-with: Cursor
# Conflicts:
#	apps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.tsx
#	apps/web/src/components/chat/TraitsPicker.tsx
#	apps/web/src/components/chat/composerProviderRegistry.test.tsx
#	apps/web/src/composerDraftStore.ts
#	packages/contracts/src/model.ts
#	packages/shared/src/model.test.ts
#	packages/shared/src/model.ts
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/web/src/composerDraftStore.ts Outdated
- Removed unused CursorModelOptions and related logic from ChatView.
- Updated model selection handling to map concrete Cursor slugs to server-provided options.
- Simplified ProviderModelPicker by eliminating unnecessary cursor-related state and logic.
- Adjusted tests to reflect changes in model selection behavior for Cursor provider.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
- Add a standalone ACP probe script for initialize/auth/session/new
- Switch Cursor provider status checks to `agent about` for version and auth
- Log the ACP session/new result in the probe test
Comment threadapps/server/src/provider/Layers/CursorProvider.ts
- Canonicalize Claude and Cursor dispatch model slugs
- Update provider model selection, defaults, and tests
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
- route Cursor commit/PR/branch generation through the agent CLI
- resolve separate ACP and agent model IDs for Cursor models
- improve git action failure logging and surface command output
Comment threadapps/server/src/provider/Layers/CursorProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/git/Layers/RoutingTextGeneration.ts
- Apply model and mode configuration during session start
- Avoid repeating no-op config writes on subsequent turns

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Redundant Schema.is check after findProviderAdapterRequestError
    • Replaced the redundant Schema.is(ProviderAdapterRequestError) checks with simple truthy checks since findProviderAdapterRequestError already validates and returns the typed result.
  • ✅ Fixed: formatFailureDetail uses .message instead of .detail
    • Changed providerError.message to providerError.detail in formatFailureDetail to produce the specific human-readable error description consistent with the rest of the file.

Create PR

Or push these changes by commenting:

@cursor push 0416bda917
Preview (0416bda917)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -98,7 +98,7 @@
function isUnknownPendingApprovalRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
const detail = error.detail.toLowerCase();
return (
detail.includes("unknown pending approval request") ||
@@ -114,7 +114,7 @@
function isUnknownPendingUserInputRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
return error.detail.toLowerCase().includes("unknown pending user-input request");
}
return Cause.pretty(cause).toLowerCase().includes("unknown pending user-input request");
@@ -211,7 +211,7 @@
? failReason.error
: undefined;
if (providerError) {
- return providerError.message;+ return providerError.detail;
}
return Cause.pretty(cause);
};

You can send follow-ups to the cloud agent here.

- Lazily create the event stream from the shared queue
- Co-authored-by: codex <codex@users.noreply.github.com>
- annotate ACP probe spans with the active option id when the probe option is missing
- preserves model capability discovery metadata
- Switch CursorAdapter to `acp.getEvents()`
- Update ACP session tests to read from the accessor
- Match unknown approval and user-input errors from any provider adapter error
- Surface provider error detail instead of the generic message

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Stale model override after session restart for unsupported switch
    • When sessionModelSwitch is 'unsupported' and the user explicitly requested a model change (input.modelSelection is defined), the fix now passes through the user's requested model directly instead of overriding it with the stale activeSession.model, while preserving the session-model fallback for subsequent turns without an explicit model change.

Create PR

Or push these changes by commenting:

@cursor push 245526b0fa
Preview (245526b0fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -428,12 +428,14 @@
input.modelSelection ?? threadModelSelections.get(input.threadId) ?? thread.modelSelection;
const modelForTurn =
sessionModelSwitch === "unsupported"
- ? activeSession?.model !== undefined- ? {- ...requestedModelSelection,- model: activeSession.model,- }- : requestedModelSelection+ ? input.modelSelection !== undefined+ ? input.modelSelection+ : activeSession?.model !== undefined+ ? {+ ...requestedModelSelection,+ model: activeSession.model,+ }+ : requestedModelSelection
: input.modelSelection;
return {

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 1753bc6. Configure here.

- Set cursor.enabled default to false in shared settings schema
- Render optional provider badge on install cards (Cursor: Early Access)
- Align server tests with settings-based Cursor disable and drop stale set_config assertion
- Only reuse the active session model if the turn omits modelSelection
- Add regression test for restart with an explicit model override
- Drop ProviderCommandReactor case covering explicit model override when restarting with sessionModelSwitch unsupported
@juliusmarminge
juliusmarminge merged commit 9c64f12 into mainApr 17, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the t3code/greeting branch April 17, 2026 23:21
orlaya added a commit to orlaya/t3code that referenced this pull request Apr 18, 2026
Integrates 7 upstream commits, headlined by Cursor provider via ACP
(pingdotgg#1355, new effect-acp package + AcpSessionRuntime) and Claude Opus 4.5.
Conflicts resolved (see untangle.md for full policy/playbook):
- ClaudeAdapter.ts queryOptions — took upstream's effort type cast +
kept our isOpus47 thinking-adaptive line.
- MessagesTimeline.tsx SimpleWorkEntryRow — took upstream's cleaner
outer rawCommand ternary (ours had dead inner checks).
- ProviderRuntimeIngestion.ts assistant-delta flow — adopted upstream's
new getOrCreateAssistantMessageId / flushBufferedAssistantMessagesForTurn
/ finalizeActiveAssistantSegmentForTurn helpers + pauseForUserTurnId
block; re-injected our timed 150ms streaming flush, reasoningDelta/
reasoningCompletion dispatch, agentKind plumbing on top.
Downstream adaptations required by upstream's new code:
- Cursor/ACP agentKind plumbing — upstream emitted ProviderRuntimeEvent
values without agentKind; our thinking-blocks tweak made it required.
Fixed via a single makeEventStamp helper change in CursorAdapter
(hard-codes "primary") + AcpEventStamp interface extension. Mirrors
the OpenCode pattern; ~14 event constructions cascade.
- Session reaper — removed dead Effect.catch on a reconcile effect whose
error channel is now `never` (lint hint in our own tweak code).
Test adaptations:
- Fast-mode tests in ClaudeAdapter.test.ts + ClaudeTextGeneration.test.ts
migrated from claude-opus-4-6 (fast mode disabled by our tweak) to
claude-opus-4-5 (upstream's new model, currently the only one that
still supports fast mode).
- Buffered-streaming tests in ProviderRuntimeIngestion.test.ts updated
to pass enableAssistantStreaming: false explicitly, since our tweak
flipped the default to true.
- dev-runner.test.ts — T3CODE_NO_BROWSER assertion updated from
undefined to "1" to match our previously-undocumented tweak.
Docs:
- tweakings.md — added T3CODE_NO_BROWSER + Cursor/ACP agentKind entries.
- untangle.md — added Policy + Active resolution entries for the three
conflicted files, plus reconciliation pattern for future upstream
restructures of the ingestion flow.
@pompydevpompydev mentioned this pull request Apr 18, 2026
2 tasks
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 18, 2026
Integrates upstream/main (9df3c64) on top of fork's main (9602c18).
Upstream features adopted:
- Claude Opus 4.5 and 4.7 built-in models (pingdotgg#2072, pingdotgg#2143)
- Node-native TypeScript migration across desktop/server (pingdotgg#2098)
- Configurable project grouping with client-settings overrides (pingdotgg#2055, pingdotgg#2099)
- Thread status in command palette (pingdotgg#2107)
- Responsive composer / plan sidebar on narrow windows (pingdotgg#1198)
- Capture-phase CTRL+J keydown for Windows terminal toggle (pingdotgg#2113/pingdotgg#2142)
- Bypass xterm for global terminal shortcuts (pingdotgg#1580)
- Windows ARM build target (pingdotgg#2080)
- Windows PATH hydration + repair (pingdotgg#1729)
- Gitignore-aware workspace search (pingdotgg#2078)
- Claude process leak fix + stale session monitoring (pingdotgg#2042)
- Preserve provider bindings when stopping sessions (pingdotgg#2084)
- Clean up invalid pending-approval projections (pingdotgg#2106) — new migration
- Extract backend startup readiness coordination
- Drop stale text-gen options on reset (pingdotgg#2076)
- Extend negative repository identity cache TTL (pingdotgg#2083)
- Allow deleting non-empty projects from warning toast (pingdotgg#1264)
- Restore defaults only on General settings (pingdotgg#1710)
- Release workflow modernization (blacksmith runners, GitHub App token guards, v0.0.20 version bump)
Fork features preserved:
- All 8 providers (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) with their adapters, services, and tests
- Fork's custom OpenCode protocol impl in apps/server/src/opencode/ (kept
over upstream's @opencode-ai/sdk-based provider added in pingdotgg#1758 — fork's
version is tested and integrated; upstream's parallel files deleted)
- Fork's direct-CLI Cursor adapter (kept over upstream's new ACP-based
CursorProvider added in pingdotgg#1355 — upstream's parallel files deleted)
- Fork's ProviderRegistry aggregates only codex + claudeAgent snapshots;
the other 6 providers register via ProviderAdapterRegistry
- PROVIDER_CACHE_IDS stays at [codex, claudeAgent] matching what the
registry actually caches
- Migration IDs preserved (fork 23/24/25/26; upstream's new 025 lands at
ID 27 to avoid re-applying on deployed fork DBs)
- Fork's generic per-provider settings (enabled/binaryPath/configDir/
customModels) kept over upstream's opencode-specific serverUrl/password
- Log directory IPC channels, updateInstallInFlight tracking, icon
composer pipeline all preserved
- Fork's simplified release.yml (no npm CLI publish, no nightly infra)
- composerDraftStore normalizeProviderKind widened to accept all 8 kinds
- Dark mode --background set to #0f0f0f
Test status:
- All 9 package typechecks pass
- Lint clean (0 errors)
- Tests: 1877 passed, 15 skipped (incl. 4 historically-flaky GitManager
cross-repo PR selector tests newly gated with TODO for Node-native-TS
follow-up)
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
…kends
Replaces fork's hand-rolled Cursor (direct-CLI) and OpenCode (custom
protocol) backends with upstream's implementations while keeping fork's
8-provider model picker UI flow intact.
## Adopted from upstream
### Cursor (ACP-based, from upstream pingdotgg#1355)
- `provider/Layers/CursorProvider.ts` + test
- `provider/Services/CursorProvider.ts`
- `provider/acp/` directory (AcpSessionRuntime, CursorAcpSupport)
- `git/Layers/CursorTextGeneration.ts` + test
- Upstream's `Layers/CursorAdapter.ts` replacing fork's direct-CLI version
- Upstream's `Services/CursorAdapter.ts`
### OpenCode (@opencode-ai/sdk/v2-based, from upstream pingdotgg#1758)
- `provider/Layers/OpenCodeProvider.ts` + test
- `provider/Services/OpenCodeProvider.ts`
- `provider/opencodeRuntime.ts` + test
- `git/Layers/OpenCodeTextGeneration.ts` + test
- Upstream's `Layers/OpenCodeAdapter.ts` replacing fork's thin wrapper
- Upstream's `Services/OpenCodeAdapter.ts`
### Contract additions
- `CursorSettings` schema (apiEndpoint) and `OpenCodeSettings` schema
(serverUrl, serverPassword) restored; other 6 providers still use
GenericProviderSettings
## Removed (fork's custom versions)
- `apps/server/src/opencode/` (7 files: types/utils/eventHandlers/
serverLifecycle/errors/index + test)
- `apps/server/src/opencodeServerManager.ts` + test
- `apps/server/src/provider/Layers/CursorUsage.ts` + test
## Wiring changes
- `ProviderRegistry.ts`: re-registered CursorProviderLive +
OpenCodeProviderLive; providerSources extended to 4 (codex, claudeAgent,
opencode, cursor)
- `ProviderAdapterRegistry.ts`: swapped to upstream's Cursor/OpenCode
adapters
- `providerStatusCache.ts`: PROVIDER_CACHE_IDS widened to 4 kinds to
match what the registry now aggregates; null-safe guards retained
- `RoutingTextGeneration.ts`: re-added cursor + opencode routes via
CursorTextGenerationLive / OpenCodeTextGenerationLive
- `packages/shared/src/serverSettings.ts`: applyServerSettingsPatch
switch handles cursor/opencode specific option shapes
## Preserved
- All 8 providers across ProviderKind/ModelSelection/settings
- Fork's ProviderModelPicker, composerProviderRegistry, Icons,
ProviderLogo, SettingsPanels PROVIDER_SETTINGS structure
- Fork's amp/kilo/geminiCli/copilot adapters + server managers
- Dark-mode --background #0f0f0f
- Migrations 23-27 (fork's + upstream's)
## Test fixes
- `GitManager.test.ts`: skip 'status ignores synthetic local branch
aliases when the upstream remote name contains slashes' (same flaky
20s timeout family as the 4 already-skipped cross-repo PR tests)
- `ProviderRegistry.test.ts`: update 'returns snapshots for all
supported providers' expectation from [codex,claudeAgent] to
[codex,claudeAgent,opencode,cursor] to match 4-provider registry
## Status
- bun typecheck: 9/9 packages clean
- bun run lint: 0 errors, 32 warnings
- bun fmt: clean
- bun run test: all packages pass
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 20, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 25, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MuneerAhmed03 pushed a commit to MuneerAhmed03/t3code that referenced this pull request Apr 26, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
@DerpedyeaDerpedyea mentioned this pull request Jul 1, 2026
4 tasks
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add ACP support with Cursor provider - #1355

Merged
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting
Apr 17, 2026
Merged

Add ACP support with Cursor provider#1355
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Mar 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds Cursor as a first-class provider with ACP session lifecycle support, health checks, and adapter wiring in the server.
  • Implements Cursor model selection, including fast/plan mode mapping and session restart behavior when model options change.
  • Preserves provider/thread model state through orchestration, projection, and turn dispatch paths.
  • Updates the web app to surface Cursor traits, provider/model selection, and session drafting behavior.
  • Expands runtime ingestion so completed tool events retain structured tool metadata.

Testing

  • bun fmt
  • bun lint
  • bun typecheck
  • Added and updated tests across server, contracts, shared, and web layers for Cursor adapter behavior, orchestration routing, session model changes, and UI state handling.
  • Not run: bun run test

Note

High Risk
High risk because it introduces a new Cursor ACP provider/agent integration and significantly changes orchestration/runtime-ingestion behavior around turn starts, tool/approval boundaries, and assistant message buffering/segmentation.

Overview
Adds Cursor as a first-class provider using ACP (stdio JSON-RPC), including a new CursorTextGenerationLive path for git text generation that spawns an ACP runtime, applies ACP-configured model options, and tolerates noisy JSON responses.

Extends server orchestration to route text generation to Cursor and refines provider turn start handling to better surface/record start failures without crashing. Runtime ingestion is reworked to segment assistant messages across approval/user-input boundaries, flush buffered text deterministically, avoid whitespace-only artifacts/duplicate completions, and preserve structured tool-call metadata for completed tool activities.

Also updates Claude model-id resolution to use provider-specific resolveClaudeApiModelId, raises the checkpoint diff git output cap, and adds effect-acp wiring/build config so ACP code can be bundled and tested.

Reviewed by Cursor Bugbot for commit aa696b5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Cursor as a provider with ACP-backed sessions, text generation, and UI support

  • Introduces a new effect-acp workspace package implementing a typed JSON-RPC client/agent transport over stdio, matching the ACP protocol (v0.11.3), with schema-generated types and Effect-native error handling.
  • Adds CursorAdapterLive and CursorProviderLive server layers that launch the Cursor ACP agent subprocess, manage session lifecycle (start, send, interrupt, approve, stop), discover models/capabilities, and stream provider snapshots.
  • Extends contracts (ProviderKind, ModelSelection, ProviderModelOptions, ServerSettings) and shared utilities to include Cursor-specific types: CursorModelOptions, CursorModelSelection, CursorSettings, and CursorSettingsPatch.
  • Wires Cursor into the composer UI: model picker, TraitsPicker (fast mode, reasoning, context window), settings panel with 'Early Access' badge, and composerProviderRegistry.
  • Adds CursorTextGenerationLive for ACP-backed git text generation (commit messages, PR content, branch names, thread titles) with a 180s timeout and JSON extraction.
  • Improves ProviderRuntimeIngestion with segment-aware assistant message streaming, buffered flush on pause events, and suppression of empty completions.
  • Improves ProviderCommandReactor turn-start failure handling: sets lastError on the thread session, appends a provider.turn.start.failed activity, and forks the send with recovery logging.
  • Risk: ProviderSessionModelSwitchMode removes the 'restart-session' value; any persisted or in-flight state using that string will no longer match the type union.

Macroscope summarized aa696b5.

@coderabbitai

coderabbitaiBot commented Mar 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c2d0780d-752d-49d8-b364-1135b6096558

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/greeting

Comment @coderabbitai help to get the list of available commands and usage tips.

@juliusmarminge
juliusmarminge marked this pull request as draft March 24, 2026 07:29
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Mar 24, 2026

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Merge never clears cached provider model options
    • Replaced ?? fallback with key in incoming check so explicitly-present-but-undefined provider keys now clear cached values, and added cache deletion when merge produces undefined.
  • ✅ Fixed: Mock agent test uses strict equal with extra fields
    • Changed toEqual to toMatchObject so the assertion tolerates the extra modes field returned by the mock agent.

Create PR

Or push these changes by commenting:

@cursor push beb68c40d7
Preview (beb68c40d7)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -50,20 +50,17 @@
cached: ProviderModelOptions | undefined,
incoming: ProviderModelOptions | undefined,
): ProviderModelOptions | undefined {
- if (!cached && !incoming) {- return undefined;+ if (incoming === undefined) return cached;+ if (cached === undefined) return incoming;++ const providerKeys = ["codex", "claudeAgent", "cursor"] as const;+ const next: Record<string, unknown> = {};+ for (const key of providerKeys) {+ const value = key in incoming ? incoming[key] : cached[key];+ if (value !== undefined) {+ next[key] = value;+ }
}
- const next = {- ...(incoming?.codex !== undefined || cached?.codex !== undefined- ? { codex: incoming?.codex ?? cached?.codex }- : {}),- ...(incoming?.claudeAgent !== undefined || cached?.claudeAgent !== undefined- ? { claudeAgent: incoming?.claudeAgent ?? cached?.claudeAgent }- : {}),- ...(incoming?.cursor !== undefined || cached?.cursor !== undefined- ? { cursor: incoming?.cursor ?? cached?.cursor }- : {}),- } satisfies Partial<ProviderModelOptions>;
return Object.keys(next).length > 0 ? (next as ProviderModelOptions) : undefined;
}
@@ -405,8 +402,12 @@
threadModelOptions.get(input.threadId),
input.modelOptions,
);
- if (mergedModelOptions !== undefined) {- threadModelOptions.set(input.threadId, mergedModelOptions);+ if (input.modelOptions !== undefined) {+ if (mergedModelOptions !== undefined) {+ threadModelOptions.set(input.threadId, mergedModelOptions);+ } else {+ threadModelOptions.delete(input.threadId);+ }
}
const normalizedInput = toNonEmptyProviderInput(input.messageText);
const normalizedAttachments = input.attachments ?? [];
diff --git a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts--- a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts+++ b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts@@ -32,7 +32,7 @@
cwd: process.cwd(),
mcpServers: [],
});
- expect(newResult).toEqual({ sessionId: "mock-session-1" });+ expect(newResult).toMatchObject({ sessionId: "mock-session-1" });
const promptResult = yield* conn.request("session/prompt", {
sessionId: "mock-session-1",

Comment threadapps/server/src/orchestration/Layers/ProviderCommandReactor.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.test.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
- Introduce Cursor ACP adapter and model selection probe
- Preserve cursor session resume state across model changes
- Propagate provider and runtime tool metadata through orchestration and UI
Made-with: Cursor
Replace the hardcoded client-side CURSOR_MODEL_CAPABILITY_BY_FAMILY map
with server-provided ModelCapabilities, matching the Codex/Claude pattern.
- Add CursorProvider snapshot service with BUILT_IN_MODELS and per-model
capabilities; register it in ProviderRegistry alongside Codex/Claude.
- Delete CursorTraitsPicker and route Cursor through the generic
TraitsPicker, adding cursor support for the reasoning/effort key.
- Add normalizeCursorModelOptionsWithCapabilities to providerModels.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadpackages/shared/src/model.ts Outdated
Comment threadapps/web/src/composerDraftStore.ts
…tion
Instead of restarting the ACP process when the model changes mid-thread,
use session/set_config_option to switch models within a live session.
Update sessionModelSwitch to "in-session" and add probe tests to verify
the real agent supports this method.
Made-with: Cursor
Made-with: Cursor
# Conflicts:
#	apps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.tsx
#	apps/web/src/components/chat/TraitsPicker.tsx
#	apps/web/src/components/chat/composerProviderRegistry.test.tsx
#	apps/web/src/composerDraftStore.ts
#	packages/contracts/src/model.ts
#	packages/shared/src/model.test.ts
#	packages/shared/src/model.ts
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/web/src/composerDraftStore.ts Outdated
- Removed unused CursorModelOptions and related logic from ChatView.
- Updated model selection handling to map concrete Cursor slugs to server-provided options.
- Simplified ProviderModelPicker by eliminating unnecessary cursor-related state and logic.
- Adjusted tests to reflect changes in model selection behavior for Cursor provider.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
- Add a standalone ACP probe script for initialize/auth/session/new
- Switch Cursor provider status checks to `agent about` for version and auth
- Log the ACP session/new result in the probe test
Comment threadapps/server/src/provider/Layers/CursorProvider.ts
- Canonicalize Claude and Cursor dispatch model slugs
- Update provider model selection, defaults, and tests
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
- route Cursor commit/PR/branch generation through the agent CLI
- resolve separate ACP and agent model IDs for Cursor models
- improve git action failure logging and surface command output
Comment threadapps/server/src/provider/Layers/CursorProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/git/Layers/RoutingTextGeneration.ts
- Apply model and mode configuration during session start
- Avoid repeating no-op config writes on subsequent turns

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Redundant Schema.is check after findProviderAdapterRequestError
    • Replaced the redundant Schema.is(ProviderAdapterRequestError) checks with simple truthy checks since findProviderAdapterRequestError already validates and returns the typed result.
  • ✅ Fixed: formatFailureDetail uses .message instead of .detail
    • Changed providerError.message to providerError.detail in formatFailureDetail to produce the specific human-readable error description consistent with the rest of the file.

Create PR

Or push these changes by commenting:

@cursor push 0416bda917
Preview (0416bda917)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -98,7 +98,7 @@
function isUnknownPendingApprovalRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
const detail = error.detail.toLowerCase();
return (
detail.includes("unknown pending approval request") ||
@@ -114,7 +114,7 @@
function isUnknownPendingUserInputRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
return error.detail.toLowerCase().includes("unknown pending user-input request");
}
return Cause.pretty(cause).toLowerCase().includes("unknown pending user-input request");
@@ -211,7 +211,7 @@
? failReason.error
: undefined;
if (providerError) {
- return providerError.message;+ return providerError.detail;
}
return Cause.pretty(cause);
};

You can send follow-ups to the cloud agent here.

- Lazily create the event stream from the shared queue
- Co-authored-by: codex <codex@users.noreply.github.com>
- annotate ACP probe spans with the active option id when the probe option is missing
- preserves model capability discovery metadata
- Switch CursorAdapter to `acp.getEvents()`
- Update ACP session tests to read from the accessor
- Match unknown approval and user-input errors from any provider adapter error
- Surface provider error detail instead of the generic message

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Stale model override after session restart for unsupported switch
    • When sessionModelSwitch is 'unsupported' and the user explicitly requested a model change (input.modelSelection is defined), the fix now passes through the user's requested model directly instead of overriding it with the stale activeSession.model, while preserving the session-model fallback for subsequent turns without an explicit model change.

Create PR

Or push these changes by commenting:

@cursor push 245526b0fa
Preview (245526b0fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -428,12 +428,14 @@
input.modelSelection ?? threadModelSelections.get(input.threadId) ?? thread.modelSelection;
const modelForTurn =
sessionModelSwitch === "unsupported"
- ? activeSession?.model !== undefined- ? {- ...requestedModelSelection,- model: activeSession.model,- }- : requestedModelSelection+ ? input.modelSelection !== undefined+ ? input.modelSelection+ : activeSession?.model !== undefined+ ? {+ ...requestedModelSelection,+ model: activeSession.model,+ }+ : requestedModelSelection
: input.modelSelection;
return {

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 1753bc6. Configure here.

- Set cursor.enabled default to false in shared settings schema
- Render optional provider badge on install cards (Cursor: Early Access)
- Align server tests with settings-based Cursor disable and drop stale set_config assertion
- Only reuse the active session model if the turn omits modelSelection
- Add regression test for restart with an explicit model override
- Drop ProviderCommandReactor case covering explicit model override when restarting with sessionModelSwitch unsupported
@juliusmarminge
juliusmarminge merged commit 9c64f12 into mainApr 17, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the t3code/greeting branch April 17, 2026 23:21
orlaya added a commit to orlaya/t3code that referenced this pull request Apr 18, 2026
Integrates 7 upstream commits, headlined by Cursor provider via ACP
(pingdotgg#1355, new effect-acp package + AcpSessionRuntime) and Claude Opus 4.5.
Conflicts resolved (see untangle.md for full policy/playbook):
- ClaudeAdapter.ts queryOptions — took upstream's effort type cast +
kept our isOpus47 thinking-adaptive line.
- MessagesTimeline.tsx SimpleWorkEntryRow — took upstream's cleaner
outer rawCommand ternary (ours had dead inner checks).
- ProviderRuntimeIngestion.ts assistant-delta flow — adopted upstream's
new getOrCreateAssistantMessageId / flushBufferedAssistantMessagesForTurn
/ finalizeActiveAssistantSegmentForTurn helpers + pauseForUserTurnId
block; re-injected our timed 150ms streaming flush, reasoningDelta/
reasoningCompletion dispatch, agentKind plumbing on top.
Downstream adaptations required by upstream's new code:
- Cursor/ACP agentKind plumbing — upstream emitted ProviderRuntimeEvent
values without agentKind; our thinking-blocks tweak made it required.
Fixed via a single makeEventStamp helper change in CursorAdapter
(hard-codes "primary") + AcpEventStamp interface extension. Mirrors
the OpenCode pattern; ~14 event constructions cascade.
- Session reaper — removed dead Effect.catch on a reconcile effect whose
error channel is now `never` (lint hint in our own tweak code).
Test adaptations:
- Fast-mode tests in ClaudeAdapter.test.ts + ClaudeTextGeneration.test.ts
migrated from claude-opus-4-6 (fast mode disabled by our tweak) to
claude-opus-4-5 (upstream's new model, currently the only one that
still supports fast mode).
- Buffered-streaming tests in ProviderRuntimeIngestion.test.ts updated
to pass enableAssistantStreaming: false explicitly, since our tweak
flipped the default to true.
- dev-runner.test.ts — T3CODE_NO_BROWSER assertion updated from
undefined to "1" to match our previously-undocumented tweak.
Docs:
- tweakings.md — added T3CODE_NO_BROWSER + Cursor/ACP agentKind entries.
- untangle.md — added Policy + Active resolution entries for the three
conflicted files, plus reconciliation pattern for future upstream
restructures of the ingestion flow.
@pompydevpompydev mentioned this pull request Apr 18, 2026
2 tasks
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 18, 2026
Integrates upstream/main (9df3c64) on top of fork's main (9602c18).
Upstream features adopted:
- Claude Opus 4.5 and 4.7 built-in models (pingdotgg#2072, pingdotgg#2143)
- Node-native TypeScript migration across desktop/server (pingdotgg#2098)
- Configurable project grouping with client-settings overrides (pingdotgg#2055, pingdotgg#2099)
- Thread status in command palette (pingdotgg#2107)
- Responsive composer / plan sidebar on narrow windows (pingdotgg#1198)
- Capture-phase CTRL+J keydown for Windows terminal toggle (pingdotgg#2113/pingdotgg#2142)
- Bypass xterm for global terminal shortcuts (pingdotgg#1580)
- Windows ARM build target (pingdotgg#2080)
- Windows PATH hydration + repair (pingdotgg#1729)
- Gitignore-aware workspace search (pingdotgg#2078)
- Claude process leak fix + stale session monitoring (pingdotgg#2042)
- Preserve provider bindings when stopping sessions (pingdotgg#2084)
- Clean up invalid pending-approval projections (pingdotgg#2106) — new migration
- Extract backend startup readiness coordination
- Drop stale text-gen options on reset (pingdotgg#2076)
- Extend negative repository identity cache TTL (pingdotgg#2083)
- Allow deleting non-empty projects from warning toast (pingdotgg#1264)
- Restore defaults only on General settings (pingdotgg#1710)
- Release workflow modernization (blacksmith runners, GitHub App token guards, v0.0.20 version bump)
Fork features preserved:
- All 8 providers (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) with their adapters, services, and tests
- Fork's custom OpenCode protocol impl in apps/server/src/opencode/ (kept
over upstream's @opencode-ai/sdk-based provider added in pingdotgg#1758 — fork's
version is tested and integrated; upstream's parallel files deleted)
- Fork's direct-CLI Cursor adapter (kept over upstream's new ACP-based
CursorProvider added in pingdotgg#1355 — upstream's parallel files deleted)
- Fork's ProviderRegistry aggregates only codex + claudeAgent snapshots;
the other 6 providers register via ProviderAdapterRegistry
- PROVIDER_CACHE_IDS stays at [codex, claudeAgent] matching what the
registry actually caches
- Migration IDs preserved (fork 23/24/25/26; upstream's new 025 lands at
ID 27 to avoid re-applying on deployed fork DBs)
- Fork's generic per-provider settings (enabled/binaryPath/configDir/
customModels) kept over upstream's opencode-specific serverUrl/password
- Log directory IPC channels, updateInstallInFlight tracking, icon
composer pipeline all preserved
- Fork's simplified release.yml (no npm CLI publish, no nightly infra)
- composerDraftStore normalizeProviderKind widened to accept all 8 kinds
- Dark mode --background set to #0f0f0f
Test status:
- All 9 package typechecks pass
- Lint clean (0 errors)
- Tests: 1877 passed, 15 skipped (incl. 4 historically-flaky GitManager
cross-repo PR selector tests newly gated with TODO for Node-native-TS
follow-up)
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
…kends
Replaces fork's hand-rolled Cursor (direct-CLI) and OpenCode (custom
protocol) backends with upstream's implementations while keeping fork's
8-provider model picker UI flow intact.
## Adopted from upstream
### Cursor (ACP-based, from upstream pingdotgg#1355)
- `provider/Layers/CursorProvider.ts` + test
- `provider/Services/CursorProvider.ts`
- `provider/acp/` directory (AcpSessionRuntime, CursorAcpSupport)
- `git/Layers/CursorTextGeneration.ts` + test
- Upstream's `Layers/CursorAdapter.ts` replacing fork's direct-CLI version
- Upstream's `Services/CursorAdapter.ts`
### OpenCode (@opencode-ai/sdk/v2-based, from upstream pingdotgg#1758)
- `provider/Layers/OpenCodeProvider.ts` + test
- `provider/Services/OpenCodeProvider.ts`
- `provider/opencodeRuntime.ts` + test
- `git/Layers/OpenCodeTextGeneration.ts` + test
- Upstream's `Layers/OpenCodeAdapter.ts` replacing fork's thin wrapper
- Upstream's `Services/OpenCodeAdapter.ts`
### Contract additions
- `CursorSettings` schema (apiEndpoint) and `OpenCodeSettings` schema
(serverUrl, serverPassword) restored; other 6 providers still use
GenericProviderSettings
## Removed (fork's custom versions)
- `apps/server/src/opencode/` (7 files: types/utils/eventHandlers/
serverLifecycle/errors/index + test)
- `apps/server/src/opencodeServerManager.ts` + test
- `apps/server/src/provider/Layers/CursorUsage.ts` + test
## Wiring changes
- `ProviderRegistry.ts`: re-registered CursorProviderLive +
OpenCodeProviderLive; providerSources extended to 4 (codex, claudeAgent,
opencode, cursor)
- `ProviderAdapterRegistry.ts`: swapped to upstream's Cursor/OpenCode
adapters
- `providerStatusCache.ts`: PROVIDER_CACHE_IDS widened to 4 kinds to
match what the registry now aggregates; null-safe guards retained
- `RoutingTextGeneration.ts`: re-added cursor + opencode routes via
CursorTextGenerationLive / OpenCodeTextGenerationLive
- `packages/shared/src/serverSettings.ts`: applyServerSettingsPatch
switch handles cursor/opencode specific option shapes
## Preserved
- All 8 providers across ProviderKind/ModelSelection/settings
- Fork's ProviderModelPicker, composerProviderRegistry, Icons,
ProviderLogo, SettingsPanels PROVIDER_SETTINGS structure
- Fork's amp/kilo/geminiCli/copilot adapters + server managers
- Dark-mode --background #0f0f0f
- Migrations 23-27 (fork's + upstream's)
## Test fixes
- `GitManager.test.ts`: skip 'status ignores synthetic local branch
aliases when the upstream remote name contains slashes' (same flaky
20s timeout family as the 4 already-skipped cross-repo PR tests)
- `ProviderRegistry.test.ts`: update 'returns snapshots for all
supported providers' expectation from [codex,claudeAgent] to
[codex,claudeAgent,opencode,cursor] to match 4-provider registry
## Status
- bun typecheck: 9/9 packages clean
- bun run lint: 0 errors, 32 warnings
- bun fmt: clean
- bun run test: all packages pass
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 20, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 25, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MuneerAhmed03 pushed a commit to MuneerAhmed03/t3code that referenced this pull request Apr 26, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
@DerpedyeaDerpedyea mentioned this pull request Jul 1, 2026
4 tasks
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add ACP support with Cursor provider - #1355

Merged
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting
Apr 17, 2026
Merged

Add ACP support with Cursor provider#1355
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Mar 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds Cursor as a first-class provider with ACP session lifecycle support, health checks, and adapter wiring in the server.
  • Implements Cursor model selection, including fast/plan mode mapping and session restart behavior when model options change.
  • Preserves provider/thread model state through orchestration, projection, and turn dispatch paths.
  • Updates the web app to surface Cursor traits, provider/model selection, and session drafting behavior.
  • Expands runtime ingestion so completed tool events retain structured tool metadata.

Testing

  • bun fmt
  • bun lint
  • bun typecheck
  • Added and updated tests across server, contracts, shared, and web layers for Cursor adapter behavior, orchestration routing, session model changes, and UI state handling.
  • Not run: bun run test

Note

High Risk
High risk because it introduces a new Cursor ACP provider/agent integration and significantly changes orchestration/runtime-ingestion behavior around turn starts, tool/approval boundaries, and assistant message buffering/segmentation.

Overview
Adds Cursor as a first-class provider using ACP (stdio JSON-RPC), including a new CursorTextGenerationLive path for git text generation that spawns an ACP runtime, applies ACP-configured model options, and tolerates noisy JSON responses.

Extends server orchestration to route text generation to Cursor and refines provider turn start handling to better surface/record start failures without crashing. Runtime ingestion is reworked to segment assistant messages across approval/user-input boundaries, flush buffered text deterministically, avoid whitespace-only artifacts/duplicate completions, and preserve structured tool-call metadata for completed tool activities.

Also updates Claude model-id resolution to use provider-specific resolveClaudeApiModelId, raises the checkpoint diff git output cap, and adds effect-acp wiring/build config so ACP code can be bundled and tested.

Reviewed by Cursor Bugbot for commit aa696b5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Cursor as a provider with ACP-backed sessions, text generation, and UI support

  • Introduces a new effect-acp workspace package implementing a typed JSON-RPC client/agent transport over stdio, matching the ACP protocol (v0.11.3), with schema-generated types and Effect-native error handling.
  • Adds CursorAdapterLive and CursorProviderLive server layers that launch the Cursor ACP agent subprocess, manage session lifecycle (start, send, interrupt, approve, stop), discover models/capabilities, and stream provider snapshots.
  • Extends contracts (ProviderKind, ModelSelection, ProviderModelOptions, ServerSettings) and shared utilities to include Cursor-specific types: CursorModelOptions, CursorModelSelection, CursorSettings, and CursorSettingsPatch.
  • Wires Cursor into the composer UI: model picker, TraitsPicker (fast mode, reasoning, context window), settings panel with 'Early Access' badge, and composerProviderRegistry.
  • Adds CursorTextGenerationLive for ACP-backed git text generation (commit messages, PR content, branch names, thread titles) with a 180s timeout and JSON extraction.
  • Improves ProviderRuntimeIngestion with segment-aware assistant message streaming, buffered flush on pause events, and suppression of empty completions.
  • Improves ProviderCommandReactor turn-start failure handling: sets lastError on the thread session, appends a provider.turn.start.failed activity, and forks the send with recovery logging.
  • Risk: ProviderSessionModelSwitchMode removes the 'restart-session' value; any persisted or in-flight state using that string will no longer match the type union.

Macroscope summarized aa696b5.

@coderabbitai

coderabbitaiBot commented Mar 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c2d0780d-752d-49d8-b364-1135b6096558

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/greeting

Comment @coderabbitai help to get the list of available commands and usage tips.

@juliusmarminge
juliusmarminge marked this pull request as draft March 24, 2026 07:29
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Mar 24, 2026

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Merge never clears cached provider model options
    • Replaced ?? fallback with key in incoming check so explicitly-present-but-undefined provider keys now clear cached values, and added cache deletion when merge produces undefined.
  • ✅ Fixed: Mock agent test uses strict equal with extra fields
    • Changed toEqual to toMatchObject so the assertion tolerates the extra modes field returned by the mock agent.

Create PR

Or push these changes by commenting:

@cursor push beb68c40d7
Preview (beb68c40d7)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -50,20 +50,17 @@
cached: ProviderModelOptions | undefined,
incoming: ProviderModelOptions | undefined,
): ProviderModelOptions | undefined {
- if (!cached && !incoming) {- return undefined;+ if (incoming === undefined) return cached;+ if (cached === undefined) return incoming;++ const providerKeys = ["codex", "claudeAgent", "cursor"] as const;+ const next: Record<string, unknown> = {};+ for (const key of providerKeys) {+ const value = key in incoming ? incoming[key] : cached[key];+ if (value !== undefined) {+ next[key] = value;+ }
}
- const next = {- ...(incoming?.codex !== undefined || cached?.codex !== undefined- ? { codex: incoming?.codex ?? cached?.codex }- : {}),- ...(incoming?.claudeAgent !== undefined || cached?.claudeAgent !== undefined- ? { claudeAgent: incoming?.claudeAgent ?? cached?.claudeAgent }- : {}),- ...(incoming?.cursor !== undefined || cached?.cursor !== undefined- ? { cursor: incoming?.cursor ?? cached?.cursor }- : {}),- } satisfies Partial<ProviderModelOptions>;
return Object.keys(next).length > 0 ? (next as ProviderModelOptions) : undefined;
}
@@ -405,8 +402,12 @@
threadModelOptions.get(input.threadId),
input.modelOptions,
);
- if (mergedModelOptions !== undefined) {- threadModelOptions.set(input.threadId, mergedModelOptions);+ if (input.modelOptions !== undefined) {+ if (mergedModelOptions !== undefined) {+ threadModelOptions.set(input.threadId, mergedModelOptions);+ } else {+ threadModelOptions.delete(input.threadId);+ }
}
const normalizedInput = toNonEmptyProviderInput(input.messageText);
const normalizedAttachments = input.attachments ?? [];
diff --git a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts--- a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts+++ b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts@@ -32,7 +32,7 @@
cwd: process.cwd(),
mcpServers: [],
});
- expect(newResult).toEqual({ sessionId: "mock-session-1" });+ expect(newResult).toMatchObject({ sessionId: "mock-session-1" });
const promptResult = yield* conn.request("session/prompt", {
sessionId: "mock-session-1",

Comment threadapps/server/src/orchestration/Layers/ProviderCommandReactor.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.test.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
- Introduce Cursor ACP adapter and model selection probe
- Preserve cursor session resume state across model changes
- Propagate provider and runtime tool metadata through orchestration and UI
Made-with: Cursor
Replace the hardcoded client-side CURSOR_MODEL_CAPABILITY_BY_FAMILY map
with server-provided ModelCapabilities, matching the Codex/Claude pattern.
- Add CursorProvider snapshot service with BUILT_IN_MODELS and per-model
capabilities; register it in ProviderRegistry alongside Codex/Claude.
- Delete CursorTraitsPicker and route Cursor through the generic
TraitsPicker, adding cursor support for the reasoning/effort key.
- Add normalizeCursorModelOptionsWithCapabilities to providerModels.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadpackages/shared/src/model.ts Outdated
Comment threadapps/web/src/composerDraftStore.ts
…tion
Instead of restarting the ACP process when the model changes mid-thread,
use session/set_config_option to switch models within a live session.
Update sessionModelSwitch to "in-session" and add probe tests to verify
the real agent supports this method.
Made-with: Cursor
Made-with: Cursor
# Conflicts:
#	apps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.tsx
#	apps/web/src/components/chat/TraitsPicker.tsx
#	apps/web/src/components/chat/composerProviderRegistry.test.tsx
#	apps/web/src/composerDraftStore.ts
#	packages/contracts/src/model.ts
#	packages/shared/src/model.test.ts
#	packages/shared/src/model.ts
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/web/src/composerDraftStore.ts Outdated
- Removed unused CursorModelOptions and related logic from ChatView.
- Updated model selection handling to map concrete Cursor slugs to server-provided options.
- Simplified ProviderModelPicker by eliminating unnecessary cursor-related state and logic.
- Adjusted tests to reflect changes in model selection behavior for Cursor provider.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
- Add a standalone ACP probe script for initialize/auth/session/new
- Switch Cursor provider status checks to `agent about` for version and auth
- Log the ACP session/new result in the probe test
Comment threadapps/server/src/provider/Layers/CursorProvider.ts
- Canonicalize Claude and Cursor dispatch model slugs
- Update provider model selection, defaults, and tests
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
- route Cursor commit/PR/branch generation through the agent CLI
- resolve separate ACP and agent model IDs for Cursor models
- improve git action failure logging and surface command output
Comment threadapps/server/src/provider/Layers/CursorProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/git/Layers/RoutingTextGeneration.ts
- Apply model and mode configuration during session start
- Avoid repeating no-op config writes on subsequent turns

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Redundant Schema.is check after findProviderAdapterRequestError
    • Replaced the redundant Schema.is(ProviderAdapterRequestError) checks with simple truthy checks since findProviderAdapterRequestError already validates and returns the typed result.
  • ✅ Fixed: formatFailureDetail uses .message instead of .detail
    • Changed providerError.message to providerError.detail in formatFailureDetail to produce the specific human-readable error description consistent with the rest of the file.

Create PR

Or push these changes by commenting:

@cursor push 0416bda917
Preview (0416bda917)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -98,7 +98,7 @@
function isUnknownPendingApprovalRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
const detail = error.detail.toLowerCase();
return (
detail.includes("unknown pending approval request") ||
@@ -114,7 +114,7 @@
function isUnknownPendingUserInputRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
return error.detail.toLowerCase().includes("unknown pending user-input request");
}
return Cause.pretty(cause).toLowerCase().includes("unknown pending user-input request");
@@ -211,7 +211,7 @@
? failReason.error
: undefined;
if (providerError) {
- return providerError.message;+ return providerError.detail;
}
return Cause.pretty(cause);
};

You can send follow-ups to the cloud agent here.

- Lazily create the event stream from the shared queue
- Co-authored-by: codex <codex@users.noreply.github.com>
- annotate ACP probe spans with the active option id when the probe option is missing
- preserves model capability discovery metadata
- Switch CursorAdapter to `acp.getEvents()`
- Update ACP session tests to read from the accessor
- Match unknown approval and user-input errors from any provider adapter error
- Surface provider error detail instead of the generic message

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Stale model override after session restart for unsupported switch
    • When sessionModelSwitch is 'unsupported' and the user explicitly requested a model change (input.modelSelection is defined), the fix now passes through the user's requested model directly instead of overriding it with the stale activeSession.model, while preserving the session-model fallback for subsequent turns without an explicit model change.

Create PR

Or push these changes by commenting:

@cursor push 245526b0fa
Preview (245526b0fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -428,12 +428,14 @@
input.modelSelection ?? threadModelSelections.get(input.threadId) ?? thread.modelSelection;
const modelForTurn =
sessionModelSwitch === "unsupported"
- ? activeSession?.model !== undefined- ? {- ...requestedModelSelection,- model: activeSession.model,- }- : requestedModelSelection+ ? input.modelSelection !== undefined+ ? input.modelSelection+ : activeSession?.model !== undefined+ ? {+ ...requestedModelSelection,+ model: activeSession.model,+ }+ : requestedModelSelection
: input.modelSelection;
return {

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 1753bc6. Configure here.

- Set cursor.enabled default to false in shared settings schema
- Render optional provider badge on install cards (Cursor: Early Access)
- Align server tests with settings-based Cursor disable and drop stale set_config assertion
- Only reuse the active session model if the turn omits modelSelection
- Add regression test for restart with an explicit model override
- Drop ProviderCommandReactor case covering explicit model override when restarting with sessionModelSwitch unsupported
@juliusmarminge
juliusmarminge merged commit 9c64f12 into mainApr 17, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the t3code/greeting branch April 17, 2026 23:21
orlaya added a commit to orlaya/t3code that referenced this pull request Apr 18, 2026
Integrates 7 upstream commits, headlined by Cursor provider via ACP
(pingdotgg#1355, new effect-acp package + AcpSessionRuntime) and Claude Opus 4.5.
Conflicts resolved (see untangle.md for full policy/playbook):
- ClaudeAdapter.ts queryOptions — took upstream's effort type cast +
kept our isOpus47 thinking-adaptive line.
- MessagesTimeline.tsx SimpleWorkEntryRow — took upstream's cleaner
outer rawCommand ternary (ours had dead inner checks).
- ProviderRuntimeIngestion.ts assistant-delta flow — adopted upstream's
new getOrCreateAssistantMessageId / flushBufferedAssistantMessagesForTurn
/ finalizeActiveAssistantSegmentForTurn helpers + pauseForUserTurnId
block; re-injected our timed 150ms streaming flush, reasoningDelta/
reasoningCompletion dispatch, agentKind plumbing on top.
Downstream adaptations required by upstream's new code:
- Cursor/ACP agentKind plumbing — upstream emitted ProviderRuntimeEvent
values without agentKind; our thinking-blocks tweak made it required.
Fixed via a single makeEventStamp helper change in CursorAdapter
(hard-codes "primary") + AcpEventStamp interface extension. Mirrors
the OpenCode pattern; ~14 event constructions cascade.
- Session reaper — removed dead Effect.catch on a reconcile effect whose
error channel is now `never` (lint hint in our own tweak code).
Test adaptations:
- Fast-mode tests in ClaudeAdapter.test.ts + ClaudeTextGeneration.test.ts
migrated from claude-opus-4-6 (fast mode disabled by our tweak) to
claude-opus-4-5 (upstream's new model, currently the only one that
still supports fast mode).
- Buffered-streaming tests in ProviderRuntimeIngestion.test.ts updated
to pass enableAssistantStreaming: false explicitly, since our tweak
flipped the default to true.
- dev-runner.test.ts — T3CODE_NO_BROWSER assertion updated from
undefined to "1" to match our previously-undocumented tweak.
Docs:
- tweakings.md — added T3CODE_NO_BROWSER + Cursor/ACP agentKind entries.
- untangle.md — added Policy + Active resolution entries for the three
conflicted files, plus reconciliation pattern for future upstream
restructures of the ingestion flow.
@pompydevpompydev mentioned this pull request Apr 18, 2026
2 tasks
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 18, 2026
Integrates upstream/main (9df3c64) on top of fork's main (9602c18).
Upstream features adopted:
- Claude Opus 4.5 and 4.7 built-in models (pingdotgg#2072, pingdotgg#2143)
- Node-native TypeScript migration across desktop/server (pingdotgg#2098)
- Configurable project grouping with client-settings overrides (pingdotgg#2055, pingdotgg#2099)
- Thread status in command palette (pingdotgg#2107)
- Responsive composer / plan sidebar on narrow windows (pingdotgg#1198)
- Capture-phase CTRL+J keydown for Windows terminal toggle (pingdotgg#2113/pingdotgg#2142)
- Bypass xterm for global terminal shortcuts (pingdotgg#1580)
- Windows ARM build target (pingdotgg#2080)
- Windows PATH hydration + repair (pingdotgg#1729)
- Gitignore-aware workspace search (pingdotgg#2078)
- Claude process leak fix + stale session monitoring (pingdotgg#2042)
- Preserve provider bindings when stopping sessions (pingdotgg#2084)
- Clean up invalid pending-approval projections (pingdotgg#2106) — new migration
- Extract backend startup readiness coordination
- Drop stale text-gen options on reset (pingdotgg#2076)
- Extend negative repository identity cache TTL (pingdotgg#2083)
- Allow deleting non-empty projects from warning toast (pingdotgg#1264)
- Restore defaults only on General settings (pingdotgg#1710)
- Release workflow modernization (blacksmith runners, GitHub App token guards, v0.0.20 version bump)
Fork features preserved:
- All 8 providers (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) with their adapters, services, and tests
- Fork's custom OpenCode protocol impl in apps/server/src/opencode/ (kept
over upstream's @opencode-ai/sdk-based provider added in pingdotgg#1758 — fork's
version is tested and integrated; upstream's parallel files deleted)
- Fork's direct-CLI Cursor adapter (kept over upstream's new ACP-based
CursorProvider added in pingdotgg#1355 — upstream's parallel files deleted)
- Fork's ProviderRegistry aggregates only codex + claudeAgent snapshots;
the other 6 providers register via ProviderAdapterRegistry
- PROVIDER_CACHE_IDS stays at [codex, claudeAgent] matching what the
registry actually caches
- Migration IDs preserved (fork 23/24/25/26; upstream's new 025 lands at
ID 27 to avoid re-applying on deployed fork DBs)
- Fork's generic per-provider settings (enabled/binaryPath/configDir/
customModels) kept over upstream's opencode-specific serverUrl/password
- Log directory IPC channels, updateInstallInFlight tracking, icon
composer pipeline all preserved
- Fork's simplified release.yml (no npm CLI publish, no nightly infra)
- composerDraftStore normalizeProviderKind widened to accept all 8 kinds
- Dark mode --background set to #0f0f0f
Test status:
- All 9 package typechecks pass
- Lint clean (0 errors)
- Tests: 1877 passed, 15 skipped (incl. 4 historically-flaky GitManager
cross-repo PR selector tests newly gated with TODO for Node-native-TS
follow-up)
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
…kends
Replaces fork's hand-rolled Cursor (direct-CLI) and OpenCode (custom
protocol) backends with upstream's implementations while keeping fork's
8-provider model picker UI flow intact.
## Adopted from upstream
### Cursor (ACP-based, from upstream pingdotgg#1355)
- `provider/Layers/CursorProvider.ts` + test
- `provider/Services/CursorProvider.ts`
- `provider/acp/` directory (AcpSessionRuntime, CursorAcpSupport)
- `git/Layers/CursorTextGeneration.ts` + test
- Upstream's `Layers/CursorAdapter.ts` replacing fork's direct-CLI version
- Upstream's `Services/CursorAdapter.ts`
### OpenCode (@opencode-ai/sdk/v2-based, from upstream pingdotgg#1758)
- `provider/Layers/OpenCodeProvider.ts` + test
- `provider/Services/OpenCodeProvider.ts`
- `provider/opencodeRuntime.ts` + test
- `git/Layers/OpenCodeTextGeneration.ts` + test
- Upstream's `Layers/OpenCodeAdapter.ts` replacing fork's thin wrapper
- Upstream's `Services/OpenCodeAdapter.ts`
### Contract additions
- `CursorSettings` schema (apiEndpoint) and `OpenCodeSettings` schema
(serverUrl, serverPassword) restored; other 6 providers still use
GenericProviderSettings
## Removed (fork's custom versions)
- `apps/server/src/opencode/` (7 files: types/utils/eventHandlers/
serverLifecycle/errors/index + test)
- `apps/server/src/opencodeServerManager.ts` + test
- `apps/server/src/provider/Layers/CursorUsage.ts` + test
## Wiring changes
- `ProviderRegistry.ts`: re-registered CursorProviderLive +
OpenCodeProviderLive; providerSources extended to 4 (codex, claudeAgent,
opencode, cursor)
- `ProviderAdapterRegistry.ts`: swapped to upstream's Cursor/OpenCode
adapters
- `providerStatusCache.ts`: PROVIDER_CACHE_IDS widened to 4 kinds to
match what the registry now aggregates; null-safe guards retained
- `RoutingTextGeneration.ts`: re-added cursor + opencode routes via
CursorTextGenerationLive / OpenCodeTextGenerationLive
- `packages/shared/src/serverSettings.ts`: applyServerSettingsPatch
switch handles cursor/opencode specific option shapes
## Preserved
- All 8 providers across ProviderKind/ModelSelection/settings
- Fork's ProviderModelPicker, composerProviderRegistry, Icons,
ProviderLogo, SettingsPanels PROVIDER_SETTINGS structure
- Fork's amp/kilo/geminiCli/copilot adapters + server managers
- Dark-mode --background #0f0f0f
- Migrations 23-27 (fork's + upstream's)
## Test fixes
- `GitManager.test.ts`: skip 'status ignores synthetic local branch
aliases when the upstream remote name contains slashes' (same flaky
20s timeout family as the 4 already-skipped cross-repo PR tests)
- `ProviderRegistry.test.ts`: update 'returns snapshots for all
supported providers' expectation from [codex,claudeAgent] to
[codex,claudeAgent,opencode,cursor] to match 4-provider registry
## Status
- bun typecheck: 9/9 packages clean
- bun run lint: 0 errors, 32 warnings
- bun fmt: clean
- bun run test: all packages pass
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 20, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 25, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MuneerAhmed03 pushed a commit to MuneerAhmed03/t3code that referenced this pull request Apr 26, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
@DerpedyeaDerpedyea mentioned this pull request Jul 1, 2026
4 tasks
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@juliusmarminge@cursoragent
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add ACP support with Cursor provider - #1355

Merged
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting
Apr 17, 2026
Merged

Add ACP support with Cursor provider#1355
juliusmarminge merged 101 commits into
mainfrom
t3code/greeting

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Mar 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds Cursor as a first-class provider with ACP session lifecycle support, health checks, and adapter wiring in the server.
  • Implements Cursor model selection, including fast/plan mode mapping and session restart behavior when model options change.
  • Preserves provider/thread model state through orchestration, projection, and turn dispatch paths.
  • Updates the web app to surface Cursor traits, provider/model selection, and session drafting behavior.
  • Expands runtime ingestion so completed tool events retain structured tool metadata.

Testing

  • bun fmt
  • bun lint
  • bun typecheck
  • Added and updated tests across server, contracts, shared, and web layers for Cursor adapter behavior, orchestration routing, session model changes, and UI state handling.
  • Not run: bun run test

Note

High Risk
High risk because it introduces a new Cursor ACP provider/agent integration and significantly changes orchestration/runtime-ingestion behavior around turn starts, tool/approval boundaries, and assistant message buffering/segmentation.

Overview
Adds Cursor as a first-class provider using ACP (stdio JSON-RPC), including a new CursorTextGenerationLive path for git text generation that spawns an ACP runtime, applies ACP-configured model options, and tolerates noisy JSON responses.

Extends server orchestration to route text generation to Cursor and refines provider turn start handling to better surface/record start failures without crashing. Runtime ingestion is reworked to segment assistant messages across approval/user-input boundaries, flush buffered text deterministically, avoid whitespace-only artifacts/duplicate completions, and preserve structured tool-call metadata for completed tool activities.

Also updates Claude model-id resolution to use provider-specific resolveClaudeApiModelId, raises the checkpoint diff git output cap, and adds effect-acp wiring/build config so ACP code can be bundled and tested.

Reviewed by Cursor Bugbot for commit aa696b5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Cursor as a provider with ACP-backed sessions, text generation, and UI support

  • Introduces a new effect-acp workspace package implementing a typed JSON-RPC client/agent transport over stdio, matching the ACP protocol (v0.11.3), with schema-generated types and Effect-native error handling.
  • Adds CursorAdapterLive and CursorProviderLive server layers that launch the Cursor ACP agent subprocess, manage session lifecycle (start, send, interrupt, approve, stop), discover models/capabilities, and stream provider snapshots.
  • Extends contracts (ProviderKind, ModelSelection, ProviderModelOptions, ServerSettings) and shared utilities to include Cursor-specific types: CursorModelOptions, CursorModelSelection, CursorSettings, and CursorSettingsPatch.
  • Wires Cursor into the composer UI: model picker, TraitsPicker (fast mode, reasoning, context window), settings panel with 'Early Access' badge, and composerProviderRegistry.
  • Adds CursorTextGenerationLive for ACP-backed git text generation (commit messages, PR content, branch names, thread titles) with a 180s timeout and JSON extraction.
  • Improves ProviderRuntimeIngestion with segment-aware assistant message streaming, buffered flush on pause events, and suppression of empty completions.
  • Improves ProviderCommandReactor turn-start failure handling: sets lastError on the thread session, appends a provider.turn.start.failed activity, and forks the send with recovery logging.
  • Risk: ProviderSessionModelSwitchMode removes the 'restart-session' value; any persisted or in-flight state using that string will no longer match the type union.

Macroscope summarized aa696b5.

@coderabbitai

coderabbitaiBot commented Mar 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c2d0780d-752d-49d8-b364-1135b6096558

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/greeting

Comment @coderabbitai help to get the list of available commands and usage tips.

@juliusmarminge
juliusmarminge marked this pull request as draft March 24, 2026 07:29
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Mar 24, 2026

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Merge never clears cached provider model options
    • Replaced ?? fallback with key in incoming check so explicitly-present-but-undefined provider keys now clear cached values, and added cache deletion when merge produces undefined.
  • ✅ Fixed: Mock agent test uses strict equal with extra fields
    • Changed toEqual to toMatchObject so the assertion tolerates the extra modes field returned by the mock agent.

Create PR

Or push these changes by commenting:

@cursor push beb68c40d7
Preview (beb68c40d7)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -50,20 +50,17 @@
cached: ProviderModelOptions | undefined,
incoming: ProviderModelOptions | undefined,
): ProviderModelOptions | undefined {
- if (!cached && !incoming) {- return undefined;+ if (incoming === undefined) return cached;+ if (cached === undefined) return incoming;++ const providerKeys = ["codex", "claudeAgent", "cursor"] as const;+ const next: Record<string, unknown> = {};+ for (const key of providerKeys) {+ const value = key in incoming ? incoming[key] : cached[key];+ if (value !== undefined) {+ next[key] = value;+ }
}
- const next = {- ...(incoming?.codex !== undefined || cached?.codex !== undefined- ? { codex: incoming?.codex ?? cached?.codex }- : {}),- ...(incoming?.claudeAgent !== undefined || cached?.claudeAgent !== undefined- ? { claudeAgent: incoming?.claudeAgent ?? cached?.claudeAgent }- : {}),- ...(incoming?.cursor !== undefined || cached?.cursor !== undefined- ? { cursor: incoming?.cursor ?? cached?.cursor }- : {}),- } satisfies Partial<ProviderModelOptions>;
return Object.keys(next).length > 0 ? (next as ProviderModelOptions) : undefined;
}
@@ -405,8 +402,12 @@
threadModelOptions.get(input.threadId),
input.modelOptions,
);
- if (mergedModelOptions !== undefined) {- threadModelOptions.set(input.threadId, mergedModelOptions);+ if (input.modelOptions !== undefined) {+ if (mergedModelOptions !== undefined) {+ threadModelOptions.set(input.threadId, mergedModelOptions);+ } else {+ threadModelOptions.delete(input.threadId);+ }
}
const normalizedInput = toNonEmptyProviderInput(input.messageText);
const normalizedAttachments = input.attachments ?? [];
diff --git a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts--- a/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts+++ b/apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts@@ -32,7 +32,7 @@
cwd: process.cwd(),
mcpServers: [],
});
- expect(newResult).toEqual({ sessionId: "mock-session-1" });+ expect(newResult).toMatchObject({ sessionId: "mock-session-1" });
const promptResult = yield* conn.request("session/prompt", {
sessionId: "mock-session-1",

Comment threadapps/server/src/orchestration/Layers/ProviderCommandReactor.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.test.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
Comment threadapps/server/src/provider/acp/AcpJsonRpcConnection.ts Outdated
- Introduce Cursor ACP adapter and model selection probe
- Preserve cursor session resume state across model changes
- Propagate provider and runtime tool metadata through orchestration and UI
Made-with: Cursor
Replace the hardcoded client-side CURSOR_MODEL_CAPABILITY_BY_FAMILY map
with server-provided ModelCapabilities, matching the Codex/Claude pattern.
- Add CursorProvider snapshot service with BUILT_IN_MODELS and per-model
capabilities; register it in ProviderRegistry alongside Codex/Claude.
- Delete CursorTraitsPicker and route Cursor through the generic
TraitsPicker, adding cursor support for the reasoning/effort key.
- Add normalizeCursorModelOptionsWithCapabilities to providerModels.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
Comment threadpackages/shared/src/model.ts Outdated
Comment threadapps/web/src/composerDraftStore.ts
…tion
Instead of restarting the ACP process when the model changes mid-thread,
use session/set_config_option to switch models within a live session.
Update sessionModelSwitch to "in-session" and add probe tests to verify
the real agent supports this method.
Made-with: Cursor
Made-with: Cursor
# Conflicts:
#	apps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.browser.tsx
#	apps/web/src/components/chat/ProviderModelPicker.tsx
#	apps/web/src/components/chat/TraitsPicker.tsx
#	apps/web/src/components/chat/composerProviderRegistry.test.tsx
#	apps/web/src/composerDraftStore.ts
#	packages/contracts/src/model.ts
#	packages/shared/src/model.test.ts
#	packages/shared/src/model.ts
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
Comment threadapps/web/src/composerDraftStore.ts Outdated
- Removed unused CursorModelOptions and related logic from ChatView.
- Updated model selection handling to map concrete Cursor slugs to server-provided options.
- Simplified ProviderModelPicker by eliminating unnecessary cursor-related state and logic.
- Adjusted tests to reflect changes in model selection behavior for Cursor provider.
Made-with: Cursor
Comment threadapps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx Outdated
- Add a standalone ACP probe script for initialize/auth/session/new
- Switch Cursor provider status checks to `agent about` for version and auth
- Log the ACP session/new result in the probe test
Comment threadapps/server/src/provider/Layers/CursorProvider.ts
- Canonicalize Claude and Cursor dispatch model slugs
- Update provider model selection, defaults, and tests
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts Outdated
- route Cursor commit/PR/branch generation through the agent CLI
- resolve separate ACP and agent model IDs for Cursor models
- improve git action failure logging and surface command output
Comment threadapps/server/src/provider/Layers/CursorProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/git/Layers/RoutingTextGeneration.ts
- Apply model and mode configuration during session start
- Avoid repeating no-op config writes on subsequent turns

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Redundant Schema.is check after findProviderAdapterRequestError
    • Replaced the redundant Schema.is(ProviderAdapterRequestError) checks with simple truthy checks since findProviderAdapterRequestError already validates and returns the typed result.
  • ✅ Fixed: formatFailureDetail uses .message instead of .detail
    • Changed providerError.message to providerError.detail in formatFailureDetail to produce the specific human-readable error description consistent with the rest of the file.

Create PR

Or push these changes by commenting:

@cursor push 0416bda917
Preview (0416bda917)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -98,7 +98,7 @@
function isUnknownPendingApprovalRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
const detail = error.detail.toLowerCase();
return (
detail.includes("unknown pending approval request") ||
@@ -114,7 +114,7 @@
function isUnknownPendingUserInputRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
const error = findProviderAdapterRequestError(cause);
- if (Schema.is(ProviderAdapterRequestError)(error)) {+ if (error) {
return error.detail.toLowerCase().includes("unknown pending user-input request");
}
return Cause.pretty(cause).toLowerCase().includes("unknown pending user-input request");
@@ -211,7 +211,7 @@
? failReason.error
: undefined;
if (providerError) {
- return providerError.message;+ return providerError.detail;
}
return Cause.pretty(cause);
};

You can send follow-ups to the cloud agent here.

- Lazily create the event stream from the shared queue
- Co-authored-by: codex <codex@users.noreply.github.com>
- annotate ACP probe spans with the active option id when the probe option is missing
- preserves model capability discovery metadata
- Switch CursorAdapter to `acp.getEvents()`
- Update ACP session tests to read from the accessor
- Match unknown approval and user-input errors from any provider adapter error
- Surface provider error detail instead of the generic message

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Stale model override after session restart for unsupported switch
    • When sessionModelSwitch is 'unsupported' and the user explicitly requested a model change (input.modelSelection is defined), the fix now passes through the user's requested model directly instead of overriding it with the stale activeSession.model, while preserving the session-model fallback for subsequent turns without an explicit model change.

Create PR

Or push these changes by commenting:

@cursor push 245526b0fa
Preview (245526b0fa)
diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts--- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts@@ -428,12 +428,14 @@
input.modelSelection ?? threadModelSelections.get(input.threadId) ?? thread.modelSelection;
const modelForTurn =
sessionModelSwitch === "unsupported"
- ? activeSession?.model !== undefined- ? {- ...requestedModelSelection,- model: activeSession.model,- }- : requestedModelSelection+ ? input.modelSelection !== undefined+ ? input.modelSelection+ : activeSession?.model !== undefined+ ? {+ ...requestedModelSelection,+ model: activeSession.model,+ }+ : requestedModelSelection
: input.modelSelection;
return {

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 1753bc6. Configure here.

- Set cursor.enabled default to false in shared settings schema
- Render optional provider badge on install cards (Cursor: Early Access)
- Align server tests with settings-based Cursor disable and drop stale set_config assertion
- Only reuse the active session model if the turn omits modelSelection
- Add regression test for restart with an explicit model override
- Drop ProviderCommandReactor case covering explicit model override when restarting with sessionModelSwitch unsupported
@juliusmarminge
juliusmarminge merged commit 9c64f12 into mainApr 17, 2026
12 checks passed
@juliusmarminge
juliusmarminge deleted the t3code/greeting branch April 17, 2026 23:21
orlaya added a commit to orlaya/t3code that referenced this pull request Apr 18, 2026
Integrates 7 upstream commits, headlined by Cursor provider via ACP
(pingdotgg#1355, new effect-acp package + AcpSessionRuntime) and Claude Opus 4.5.
Conflicts resolved (see untangle.md for full policy/playbook):
- ClaudeAdapter.ts queryOptions — took upstream's effort type cast +
kept our isOpus47 thinking-adaptive line.
- MessagesTimeline.tsx SimpleWorkEntryRow — took upstream's cleaner
outer rawCommand ternary (ours had dead inner checks).
- ProviderRuntimeIngestion.ts assistant-delta flow — adopted upstream's
new getOrCreateAssistantMessageId / flushBufferedAssistantMessagesForTurn
/ finalizeActiveAssistantSegmentForTurn helpers + pauseForUserTurnId
block; re-injected our timed 150ms streaming flush, reasoningDelta/
reasoningCompletion dispatch, agentKind plumbing on top.
Downstream adaptations required by upstream's new code:
- Cursor/ACP agentKind plumbing — upstream emitted ProviderRuntimeEvent
values without agentKind; our thinking-blocks tweak made it required.
Fixed via a single makeEventStamp helper change in CursorAdapter
(hard-codes "primary") + AcpEventStamp interface extension. Mirrors
the OpenCode pattern; ~14 event constructions cascade.
- Session reaper — removed dead Effect.catch on a reconcile effect whose
error channel is now `never` (lint hint in our own tweak code).
Test adaptations:
- Fast-mode tests in ClaudeAdapter.test.ts + ClaudeTextGeneration.test.ts
migrated from claude-opus-4-6 (fast mode disabled by our tweak) to
claude-opus-4-5 (upstream's new model, currently the only one that
still supports fast mode).
- Buffered-streaming tests in ProviderRuntimeIngestion.test.ts updated
to pass enableAssistantStreaming: false explicitly, since our tweak
flipped the default to true.
- dev-runner.test.ts — T3CODE_NO_BROWSER assertion updated from
undefined to "1" to match our previously-undocumented tweak.
Docs:
- tweakings.md — added T3CODE_NO_BROWSER + Cursor/ACP agentKind entries.
- untangle.md — added Policy + Active resolution entries for the three
conflicted files, plus reconciliation pattern for future upstream
restructures of the ingestion flow.
@pompydevpompydev mentioned this pull request Apr 18, 2026
2 tasks
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 18, 2026
Integrates upstream/main (9df3c64) on top of fork's main (9602c18).
Upstream features adopted:
- Claude Opus 4.5 and 4.7 built-in models (pingdotgg#2072, pingdotgg#2143)
- Node-native TypeScript migration across desktop/server (pingdotgg#2098)
- Configurable project grouping with client-settings overrides (pingdotgg#2055, pingdotgg#2099)
- Thread status in command palette (pingdotgg#2107)
- Responsive composer / plan sidebar on narrow windows (pingdotgg#1198)
- Capture-phase CTRL+J keydown for Windows terminal toggle (pingdotgg#2113/pingdotgg#2142)
- Bypass xterm for global terminal shortcuts (pingdotgg#1580)
- Windows ARM build target (pingdotgg#2080)
- Windows PATH hydration + repair (pingdotgg#1729)
- Gitignore-aware workspace search (pingdotgg#2078)
- Claude process leak fix + stale session monitoring (pingdotgg#2042)
- Preserve provider bindings when stopping sessions (pingdotgg#2084)
- Clean up invalid pending-approval projections (pingdotgg#2106) — new migration
- Extract backend startup readiness coordination
- Drop stale text-gen options on reset (pingdotgg#2076)
- Extend negative repository identity cache TTL (pingdotgg#2083)
- Allow deleting non-empty projects from warning toast (pingdotgg#1264)
- Restore defaults only on General settings (pingdotgg#1710)
- Release workflow modernization (blacksmith runners, GitHub App token guards, v0.0.20 version bump)
Fork features preserved:
- All 8 providers (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) with their adapters, services, and tests
- Fork's custom OpenCode protocol impl in apps/server/src/opencode/ (kept
over upstream's @opencode-ai/sdk-based provider added in pingdotgg#1758 — fork's
version is tested and integrated; upstream's parallel files deleted)
- Fork's direct-CLI Cursor adapter (kept over upstream's new ACP-based
CursorProvider added in pingdotgg#1355 — upstream's parallel files deleted)
- Fork's ProviderRegistry aggregates only codex + claudeAgent snapshots;
the other 6 providers register via ProviderAdapterRegistry
- PROVIDER_CACHE_IDS stays at [codex, claudeAgent] matching what the
registry actually caches
- Migration IDs preserved (fork 23/24/25/26; upstream's new 025 lands at
ID 27 to avoid re-applying on deployed fork DBs)
- Fork's generic per-provider settings (enabled/binaryPath/configDir/
customModels) kept over upstream's opencode-specific serverUrl/password
- Log directory IPC channels, updateInstallInFlight tracking, icon
composer pipeline all preserved
- Fork's simplified release.yml (no npm CLI publish, no nightly infra)
- composerDraftStore normalizeProviderKind widened to accept all 8 kinds
- Dark mode --background set to #0f0f0f
Test status:
- All 9 package typechecks pass
- Lint clean (0 errors)
- Tests: 1877 passed, 15 skipped (incl. 4 historically-flaky GitManager
cross-repo PR selector tests newly gated with TODO for Node-native-TS
follow-up)
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
…kends
Replaces fork's hand-rolled Cursor (direct-CLI) and OpenCode (custom
protocol) backends with upstream's implementations while keeping fork's
8-provider model picker UI flow intact.
## Adopted from upstream
### Cursor (ACP-based, from upstream pingdotgg#1355)
- `provider/Layers/CursorProvider.ts` + test
- `provider/Services/CursorProvider.ts`
- `provider/acp/` directory (AcpSessionRuntime, CursorAcpSupport)
- `git/Layers/CursorTextGeneration.ts` + test
- Upstream's `Layers/CursorAdapter.ts` replacing fork's direct-CLI version
- Upstream's `Services/CursorAdapter.ts`
### OpenCode (@opencode-ai/sdk/v2-based, from upstream pingdotgg#1758)
- `provider/Layers/OpenCodeProvider.ts` + test
- `provider/Services/OpenCodeProvider.ts`
- `provider/opencodeRuntime.ts` + test
- `git/Layers/OpenCodeTextGeneration.ts` + test
- Upstream's `Layers/OpenCodeAdapter.ts` replacing fork's thin wrapper
- Upstream's `Services/OpenCodeAdapter.ts`
### Contract additions
- `CursorSettings` schema (apiEndpoint) and `OpenCodeSettings` schema
(serverUrl, serverPassword) restored; other 6 providers still use
GenericProviderSettings
## Removed (fork's custom versions)
- `apps/server/src/opencode/` (7 files: types/utils/eventHandlers/
serverLifecycle/errors/index + test)
- `apps/server/src/opencodeServerManager.ts` + test
- `apps/server/src/provider/Layers/CursorUsage.ts` + test
## Wiring changes
- `ProviderRegistry.ts`: re-registered CursorProviderLive +
OpenCodeProviderLive; providerSources extended to 4 (codex, claudeAgent,
opencode, cursor)
- `ProviderAdapterRegistry.ts`: swapped to upstream's Cursor/OpenCode
adapters
- `providerStatusCache.ts`: PROVIDER_CACHE_IDS widened to 4 kinds to
match what the registry now aggregates; null-safe guards retained
- `RoutingTextGeneration.ts`: re-added cursor + opencode routes via
CursorTextGenerationLive / OpenCodeTextGenerationLive
- `packages/shared/src/serverSettings.ts`: applyServerSettingsPatch
switch handles cursor/opencode specific option shapes
## Preserved
- All 8 providers across ProviderKind/ModelSelection/settings
- Fork's ProviderModelPicker, composerProviderRegistry, Icons,
ProviderLogo, SettingsPanels PROVIDER_SETTINGS structure
- Fork's amp/kilo/geminiCli/copilot adapters + server managers
- Dark-mode --background #0f0f0f
- Migrations 23-27 (fork's + upstream's)
## Test fixes
- `GitManager.test.ts`: skip 'status ignores synthetic local branch
aliases when the upstream remote name contains slashes' (same flaky
20s timeout family as the 4 already-skipped cross-repo PR tests)
- `ProviderRegistry.test.ts`: update 'returns snapshots for all
supported providers' expectation from [codex,claudeAgent] to
[codex,claudeAgent,opencode,cursor] to match 4-provider registry
## Status
- bun typecheck: 9/9 packages clean
- bun run lint: 0 errors, 32 warnings
- bun fmt: clean
- bun run test: all packages pass
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 20, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
hrishikeshmane pushed a commit to hrishikeshmane/t3code that referenced this pull request Apr 25, 2026
…, and Opus 4.7
Adds Kiro as a first-class ACP provider layered on top of upstream's shared ACP
infrastructure (PR pingdotgg#1355). Kiro is an Amazon CLI (`kiro-cli acp`) speaking the
Agent Communication Protocol over stdio; authentication is OIDC via
`kiro-cli login` (out-of-band).
Highlights:
- Full ACP lifecycle: initialize → session/new → session/prompt/cancel, with
streaming `session/update` notifications and `{stopReason: "end_turn"}` turn
end via RPC response.
- Agent discovery via `kiro-cli agent list`, cached at `~/.t3/caches/kiro.json`
and surfaced through `ModelCapabilities.agentOptions`. Agents are a spawn-time
CLI flag (`--agent <name>`) so `sendTurn` respawns the child process when the
selected agent changes mid-session.
- `/agent` slash command opens the TraitsPicker, mirroring `/model`. Gated on
whether the current model exposes `agentOptions`.
- TraitsPicker now closes on agent selection (`closeOnClick` MenuRadioItem).
- `normalizeProviderModelOptionsWithCapabilities` gains a `case "kiro"` —
previously the kiro dispatch path dropped `{ agent }` silently because the
switch fell through to `undefined`, so the server never received the agent
selection even though the composer store held it.
- `_kiro.dev/commands/available` notifications runtime-patch slash commands;
`_kiro.dev/metadata` surfaces context window usage.
- Built-in Kiro models include Opus 4.7 (aliased as `opus`), Sonnet 4.6, Haiku
4.5, Deepseek 3.2.
Hidden traps documented in PATCH.md:
- Three hardcoded ProviderKind arrays in `composerDraftStore.ts` all need
`"kiro"` or model selection silently reverts to previous provider.
- `normalizeProviderModelOptionsWithCapabilities` switch needs an explicit
`case "kiro"` or agent selection never reaches the server.
- ACP `authMethodId` is made optional: Kiro returns empty `authMethods` and per
spec the client must skip `authenticate`.
- `_kiro.dev/*` ext requests the adapter doesn't handle must return JSON-RPC
error `-32601` (not empty-object success).
- `mcpServers: []` is required in `session/new`; omission exits kiro-cli
silently.
Test coverage:
- `KiroAdapter.integration.test.ts` — 8 tests covering start/stop/listSessions,
streaming, runtime events, agent flag propagation, respawn on agent change.
- `KiroAdapter.parsing.test.ts` — ACP message parsing.
- `packages/shared/src/model.test.ts` — 4 new tests for `normalizeKiro*` and
provider-switch wiring.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MuneerAhmed03 pushed a commit to MuneerAhmed03/t3code that referenced this pull request Apr 26, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
@DerpedyeaDerpedyea mentioned this pull request Jul 1, 2026
4 tasks
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@macmini.local>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@juliusmarminge@cursoragent