Skip to content

Commit 69df320

Browse files
FL4TLiN3claude
andauthored
fix: handle resolveToolResults event in delegation tree builder (#748)
Add explicit handling for the resolveToolResults event type in buildRunTreeFromEvents. This event fires after MCP tool execution and after resumeFromStop when all tool results are resolved. Without this handler, these events were silently ignored in the switch statement. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 568a2b8 commit 69df320

File tree

3 files changed

+48
-0
lines changed

3 files changed

+48
-0
lines changed

.changeset/resolve-tool-results.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@perstack/tui-components": patch
3+
---
4+
5+
Handle resolveToolResults event type in delegation tree builder

packages/tui-components/src/log-viewer/build-run-tree.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,43 @@ describe("buildRunTreeFromEvents", () => {
503503
expect(gd1Flat.depth).toBe(4) // root > build > te1 > bg1 > gd1
504504
})
505505

506+
it("handles resolveToolResults events without affecting tree structure", () => {
507+
// resolveToolResults fires after MCP tool execution and after resumeFromStop.
508+
// It should be handled gracefully without creating spurious nodes or breaking merges.
509+
const events = [
510+
startRun("root", "coordinator"),
511+
makeEvent("callTools", "root", "coordinator", {
512+
newMessage: {},
513+
toolCalls: [],
514+
usage: baseUsage,
515+
}),
516+
// resolveToolResults after MCP tool execution
517+
makeEvent("resolveToolResults", "root", "coordinator", {
518+
toolResults: [{ id: "tr-1", skillName: "read_file", toolName: "read_file", result: [] }],
519+
}),
520+
stopByDelegate("root", "coordinator"),
521+
startRun("child", "@coordinator/worker", "root"),
522+
completeRun("child", "@coordinator/worker"),
523+
// Resume and immediately resolveToolResults (same timestamp pattern from real data)
524+
resumeFromStop("root-resume", "coordinator"),
525+
makeEvent("resolveToolResults", "root-resume", "coordinator", {
526+
toolResults: [{ id: "tr-2", skillName: "delegate/worker", toolName: "worker", result: [] }],
527+
}),
528+
completeRun("root-resume", "coordinator"),
529+
]
530+
531+
const { treeState, runStats } = buildRunTreeFromEvents(events)
532+
533+
// Resume merged correctly
534+
expect(treeState.nodes.size).toBe(2) // root, child
535+
expect(treeState.nodes.get("root")?.status).toBe("completed")
536+
expect(treeState.nodes.get("child")?.parentRunId).toBe("root")
537+
538+
// resolveToolResults events counted in stats
539+
const rootStats = runStats.get("root")!
540+
expect(rootStats.eventCount).toBeGreaterThanOrEqual(6) // start, callTools, resolve, stop, resume, resolve, complete
541+
})
542+
506543
it("shows failed delegates as error nodes (startRun + stopRunByError)", () => {
507544
// With the runtime fix, failed delegates now emit startRun + stopRunByError events.
508545
// design-roles delegates to 4x find-skill, all fail immediately.

packages/tui-components/src/log-viewer/build-run-tree.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,12 @@ export function buildRunTreeFromEvents(events: RunEvent[]): RunTreeResult {
296296
}
297297
break
298298
}
299+
300+
case "resolveToolResults": {
301+
// Tool results resolved — no node state change needed.
302+
// Stats are already recorded at the top of the loop.
303+
break
304+
}
299305
}
300306
}
301307

0 commit comments

Comments
 (0)