From 47d03de3079678f851cee751d02e94900c77d685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Mon, 3 Aug 2026 00:28:39 +0000 Subject: [PATCH] chat: carry claude's own session uuid on the result event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sidecar knew which transcript file a turn had landed in and kept it to itself — setClaudeSession fed --resume and nothing else. A session officer started was therefore unaddressable from the platform side. Put it on the result event so it crosses the wire. Co-Authored-By: Claude Opus 5 --- src/servers/api/chat/types.ts | 7 +++++++ src/servers/sidecar/claude/stream-parser.ts | 4 +++- src/servers/sidecar/claude/turn-stream.ts | 8 +++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/servers/api/chat/types.ts b/src/servers/api/chat/types.ts index feb38dd2..b383e37d 100644 --- a/src/servers/api/chat/types.ts +++ b/src/servers/api/chat/types.ts @@ -115,6 +115,12 @@ export type ServerMessage = type: 'result'; sessionId: string; cost: MessageCost; + // Claude's OWN session uuid — the name of the transcript file under ~/.claude/projects//. + // Distinct from `sessionId`, which is the key officer made up. Until this crossed the wire the + // platform had no way to address a session it had started: the mapping was captured inside the + // sidecar (claude-manager's setClaudeSession) and never left it. Absent if the harness didn't + // report one. + claudeSessionId?: string; } | { type: 'sync:messages'; @@ -177,6 +183,7 @@ export type ChatEvent = | { type: 'result'; cost: MessageCost; + claudeSessionId?: string; } | { type: 'error'; message: string } | { type: 'stopped' } diff --git a/src/servers/sidecar/claude/stream-parser.ts b/src/servers/sidecar/claude/stream-parser.ts index 2790ff4a..ae35bb5c 100644 --- a/src/servers/sidecar/claude/stream-parser.ts +++ b/src/servers/sidecar/claude/stream-parser.ts @@ -115,7 +115,9 @@ function handleResult( callbacks.onSessionId(sessionId); } - callbacks.onEvent({ type: 'result', cost }); + // Carried on the event as well as into sidecar-local state: the callback only feeds `--resume` here, + // so without this the platform never learns which transcript file a session it started ended up in. + callbacks.onEvent({ type: 'result', cost, claudeSessionId: sessionId }); } function handleSystem(msg: Record, callbacks: StreamParserCallbacks): void { diff --git a/src/servers/sidecar/claude/turn-stream.ts b/src/servers/sidecar/claude/turn-stream.ts index 51bd79b9..31032324 100644 --- a/src/servers/sidecar/claude/turn-stream.ts +++ b/src/servers/sidecar/claude/turn-stream.ts @@ -67,7 +67,13 @@ export function createTurnStream(sessionId: string): TurnStream { ]; case 'result': - return [...flush(), { msg: { type: 'result', sessionId, cost: event.cost }, durable: true }]; + return [ + ...flush(), + { + msg: { type: 'result', sessionId, cost: event.cost, claudeSessionId: event.claudeSessionId }, + durable: true, + }, + ]; case 'error': return [{ msg: { type: 'error', message: event.message }, durable: true }];