Skip to content

Commit 9b1d8b4

Browse files
jeremyederclaude
authored andcommitted
fix(runner): restore tool error reporting on ToolCallEndEvent (#1100)
## Summary - Restores `is_error` forwarding from `ToolResultBlock` to `ToolCallEndEvent` in the AG-UI handler - PR #613 (Feb 18) refactored to event-driven architecture but dropped this field, breaking Langfuse tool error tracking since Feb 24 - 3-line fix matching the old `adapter.py` behavior (lines 836-846) ## Root Cause `handle_tool_result_block()` in `handlers.py` reads `is_error` from the Claude SDK's `ToolResultBlock` but never forwards it to `ToolCallEndEvent`. The observability layer (`track_agui_event` in `observability.py`) checks `getattr(event, "error", None)` on `TOOL_CALL_END` events and always gets `None`, so all tool spans are tagged `level=DEFAULT` instead of `level=ERROR`. ## Impact - Langfuse tool error tracking broken for ~5 weeks (since Feb 24) - Cockpit dashboard correction rate dropped from ~8% to 0.01% - Session metrics `tool_failures_total` always reports 0 - `tool_log_correction` MCP tool still works (separate path) but only captures explicit human corrections, not tool execution failures ## Test plan - [ ] Verify `ToolCallEndEvent` accepts `result` and `error` fields (confirmed via test fixtures in `conftest.py`) - [ ] Run `pytest components/runners/ambient-runner/tests/` - [ ] After deploy: verify Langfuse observations show `level=ERROR` on tool failures - [ ] Cockpit correction rate dashboard should show non-zero values again 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2865d58 commit 9b1d8b4

1 file changed

Lines changed: 3 additions & 0 deletions

File tree

  • components/runners/ambient-runner/ag_ui_claude_sdk

components/runners/ambient-runner/ag_ui_claude_sdk/handlers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ async def handle_tool_result_block(
154154
"""
155155
tool_use_id = getattr(block, "tool_use_id", None)
156156
content = getattr(block, "content", None)
157+
is_error = getattr(block, "is_error", None)
157158

158159
# Parse tool result content for frontend rendering
159160
# Claude SDK tools return: [{"type": "text", "text": "{json_data}"}]
@@ -191,6 +192,8 @@ async def handle_tool_result_block(
191192
thread_id=thread_id,
192193
run_id=run_id,
193194
tool_call_id=tool_use_id,
195+
result=result_str if not is_error else None,
196+
error=result_str if is_error else None,
194197
timestamp=now_ms(),
195198
)
196199

0 commit comments

Comments
 (0)