fix: address tool_result dedup, SDK task ID collision, and doc accuracy
P1: tool_result dedup changed from "first wins" to "last wins"
- claude-client.ts: remove emittedToolResultIds Set, both PostToolUse and
user message handler emit freely. PostToolUse provides immediate UI feedback;
user handler's potentially more complete result arrives second.
- route.ts: collectStreamResponse replaces existing contentBlock entry when
duplicate tool_use_id arrives (last wins for DB persistence).
- ChatView.tsx: onToolResult replaces existing state entry by tool_use_id
instead of skipping, ensuring most complete result is displayed.
P2: SDK task ID collision risk eliminated
- db.ts: syncSdkTasks now uses full sessionId in task ID
(`sdk-{fullSessionId}-{index}`) instead of truncated 8-char prefix,
eliminating cross-session primary key collisions.
P2: Todo ordering stabilized
- db.ts: add sort_order column migration, syncSdkTasks writes array index
as sort_order. getTasksBySession sorts by sort_order ASC, created_at ASC
so tasks with identical timestamps maintain insertion order.
P3: Documentation field mapping corrected
- agent-tooling-todo-bridge.md: fix field mapping table — actual implementation
maps activeForm (not priority) to description column. Updated dedup strategy
docs from "three-layer skip" to "two-layer last-wins replace".
Lint: fix prefer-const for finalPrompt in claude-client.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
c13ff54638
commit
0c379e5607
5 files changed
+64
-54
No files matched your search
@@ -272,15 +272,24 @@ async function collectStreamResponse(stream: ReadableStream<string>, sessionId:
|
||||
} else if (event.type === 'tool_result') {
|
||||
try {
|
||||
const resultData = JSON.parse(event.data);
|
||||
// Dedup: skip if already seen
|
||||
if (!seenToolResultIds.has(resultData.tool_use_id)) {
|
||||
const newBlock = {
|
||||
type: 'tool_result' as const,
|
||||
tool_use_id: resultData.tool_use_id,
|
||||
content: resultData.content,
|
||||
is_error: resultData.is_error || false,
|
||||
};
|
||||
// Last-wins: if same tool_use_id already exists, replace it
|
||||
// (user handler's result may be more complete than PostToolUse's)
|
||||
if (seenToolResultIds.has(resultData.tool_use_id)) {
|
||||
const idx = contentBlocks.findIndex(
|
||||
(b) => b.type === 'tool_result' && 'tool_use_id' in b && b.tool_use_id === resultData.tool_use_id
|
||||
);
|
||||
if (idx >= 0) {
|
||||
contentBlocks[idx] = newBlock;
|
||||
}
|
||||
} else {
|
||||
seenToolResultIds.add(resultData.tool_use_id);
|
||||
contentBlocks.push({
|
||||
type: 'tool_result',
|
||||
tool_use_id: resultData.tool_use_id,
|
||||
content: resultData.content,
|
||||
is_error: resultData.is_error || false,
|
||||
});
|
||||
contentBlocks.push(newBlock);
|
||||
}
|
||||
} catch {
|
||||
// skip malformed tool_result data
|
||||
|
||||
Reference in new issue
Block a user