Skip to content

fix(server): Claude adapter v2 fixes (upstream G2) - #1005

Merged
rynfar merged 7 commits into
pylonfrom
upstream/2026-10-03-g2-claude-adapter
Oct 4, 2026
Merged

rynfar merged 7 commits into
pylonfrom
upstream/2026-10-03-g2-claude-adapter

Conversation

@rynfar

@rynfar rynfar commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Ports upstream T3 group G2 (Claude adapter v2 fixes) into Pylon. Part of upstream cycle #996.

Sources

Upstream SHA Behavior Outcome
1e7c8e0f24 Claude MCP tools show their names and icons (tool_use_meta → title + toolSource) Adopted, clean cherry-pick -x (includes claude_mcp_tool_presentation replay fixture)
b4d3d51ac9 Claude model/setting changes no longer kill running background agents (refuse replacement with ClaudeBackgroundWorkBlocksQueryReplacementError; continuations keep the live process) Adopted, clean
8283b481a3 Claude V2 turns start on Windows with the default binary path (resolveClaudeSdkExecutablePath) Adopted, clean (helper already exists in Pylon)
5bf19d12b0 Threads stay working while Claude starts a wake turn (init counts as wake evidence) Adopted, clean
ce90eec1ff A Claude command you stop shows as interrupted, not failed Adopted, clean
aad732901e Claude threads no longer stuck in plan mode Claude entered itself (setPermissionMode restore on reuse) Adopted, clean
6414268859 Fake Claude CLI exits with its parent Already covered: Pylon's fake never had the keep-alive setInterval (Pylon's probe only sends initialize, no get_usage), so it already exits when stdin closes. Intent folded into the adapted fixture below.
858b98b8fa Fake Claude CLI is a fixture file, not a generated string Adapted: moved Pylon's own fake (initialize-only) to apps/server/src/provider/Layers/testing/ClaudeCapabilitiesProbe.fixture.mjs; upstream's get_usage handler and keep-alive not carried since Pylon's probe does not request usage.

Pylon adaptations / interactions

  • fix(provider): harden OpenCode session titles, v2 serve line, and Claude interrupt grace #916 Claude interrupt grace: that grace (settleInterruptedTurn / CLAUDE_INTERRUPT_GRACE) lived in the v1 apps/server/src/provider/Layers/ClaudeAdapter.ts, which was removed when Pylon adopted orchestrator v2 (eed7e978f6). None of these sources touch v1 or the v2 interruptTurn path; v2 interruptTurn still awaits query.interrupt acknowledgement before close. b4d3d51ac9 only adds a stopping = true mark in closeLiveQueryForNativeThread (Stop/rollback/fork), so Stop still always closes the process. Behavior otherwise unchanged; whether the v1 "wait for the turn to settle before kill" grace should be re-ported to v2 is a separate follow-up (not in scope here).
  • The new user-facing error message carries no T3 branding. ProviderFailure.ts maps the new tag to its own message.
  • Rebased onto feat: subagent and tool presentation fixes (upstream G3) #999 (G3, merged first). The one conflict was the tool-item title chain: kept G3's dynamicToolTitle(...) and added the MCP presentation.title after it, matching upstream's final order (searchTitle ?? dynamicToolTitle ?? presentation.title ?? null).

Applicability to other adapters (follow-ups, not ported)

  • MCP name/icon (1e7c8e0f24): Claude-specific tool_use_meta. No other v2 adapter sets toolSource; Codex/OpenCode MCP presentation is a possible follow-up if their protocols expose server names/icons.
  • Model change kills background work (b4d3d51ac9): Claude-specific (selection change replaces the CLI process). Codex/OpenCode take per-turn model selection without process replacement; Prime not checked in depth — follow-up.
  • Windows binary path, wake init, self-entered plan mode: Claude CLI/SDK-specific; no equivalent in Codex/OpenCode/Prime.
  • Stopped command shows interrupted (ce90eec1ff): Codex, Cursor, Pi and OpenCode2 already assert interrupted in turn_interrupt_mid_tool/opencode2_interrupt. OpenCode v1 (OpenCodeAdapterV2.ts maps tool part error → failed regardless of turn.interrupted) likely has the same bug — follow-up. Prime: not verified — follow-up.

Verification

  • vp run -F t3 typecheck — exit 0, 0 error TS (ran tsc --noEmit in apps/server).
  • vp test run src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts src/provider/Layers/ClaudeCapabilitiesProbe.test.ts — 2 files, 131 tests passed.
  • vp test run src/orchestration-v2/testkit/ClaudeReplayFixtures.integration.test.ts src/orchestration-v2/testkit/OrchestratorReplayFixtures.contract.test.ts src/orchestration-v2/testkit/OrchestratorReplayFixtures.integration.test.ts — 3 files, 129 tests passed (incl. claude_mcp_tool_presentation, claude_background_task_interrupt, turn_interrupt_mid_tool/claudeAgent).
  • Tests run with CLAUDE_CONFIG_DIR unset (known local env issue for claude_result_is_error).
  • vp lint / vp fmt --check on changed files — format clean; only two pre-existing no-unused-vars warnings in ClaudeAdapterV2.ts/.testkit.ts.

Re-run after the rebase onto #999: typecheck exit 0; the five test files above together pass (260 tests).

Unverified

  • Windows binary path behavior (no Windows host).
  • Live Claude CLI behavior for tool_use_meta, plan-mode restore, and background-work refusal beyond the recorded replay fixtures and unit tests.

🤖 Generated with Claude Code

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Oct 3, 2026
@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 4.9 KiB 4.9 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 3.7 KiB 3.7 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 20.4 KiB 20.4 KiB 0 B (0.0%) 29.3 KiB ✅
Codex Live turn messages 2 2 0 (0.0%) 8 ✅
Claude Total thread wire 4.9 KiB 4.9 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 3.7 KiB 3.7 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 20.8 KiB 20.8 KiB 0 B (0.0%) 29.3 KiB ✅
Claude Live turn messages 2 2 0 (0.0%) 8 ✅

Baseline: cda6633 · PR result: a1175cb · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 106.1 KiB
  • Claude decoded thread snapshot: 106.4 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

scratchyone and others added 7 commits October 3, 2026 17:02
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 1e7c8e0f24c217a3229615fa1de1e6ed85d7e835)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…gents (#14726)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit b4d3d51ac99d4306d754afb5c78c49845bfac3c1)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… path (#15021)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>
(cherry picked from commit 8283b481a34f5cc6f984f290e7cb93cc35b4dc56)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…5055)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 5bf19d12b0fd54fc9999579869bcf264bc555874)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit ce90eec1ffc2087395227a610843091f4b260cf7)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…entered itself (#15224)

(cherry picked from commit aad732901e4b7d485574eaef5a9c1fb388c4291a)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…string

Adapted from upstream 858b98b8fa618cf9b9528b5415493fcf0572ac88 (and
6414268859 for the exit-with-parent intent). Pylon's capability probe
only sends initialize, and its fake CLI never had a keep-alive
interval, so the fixture keeps Pylon's initialize-only behavior and
exits when stdin closes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@rynfar
rynfar force-pushed the upstream/2026-10-03-g2-claude-adapter branch from 4197c0a to a1175cb Compare October 3, 2026 23:04
@rynfar

rynfar commented Oct 3, 2026

Copy link
Copy Markdown
Collaborator Author

CI note: on head a1175cb, Test Server 2 failed once in src/provider/acp/AcpSessionRuntime.processTree.test.ts > terminatePosixOwnedProcessTree > rotates more than 64 live parents without scanning retained tombstones. This PR does not touch that code. It passed when only the failed job was re-run, and the same job passed on the pre-rebase head, so I'm treating it as flaky. All checks are now green.

@rynfar
rynfar merged commit ec5bf96 into pylon Oct 4, 2026
36 of 38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants