Emit custom tool_result SSE event in Anthropic stream

Adds a non-standard tool_result event between the tool_use block close
and the next text block, so clients can see server-side tool execution
results. Anthropic SDKs ignore unknown event types.
This commit is contained in:
Roland Tannous 2026-04-11 22:30:46 +04:00
commit 10edb46f80
2 changed files with 14 additions and 4 deletions

View file

@ -224,6 +224,12 @@ class AnthropicStreamEmitter:
events = []
# Close the tool_use block
events.append(self._close_block())
# Emit custom tool_result event (non-standard, ignored by SDKs)
events.append(build_anthropic_sse_event("tool_result", {
"type": "tool_result",
"tool_use_id": event.get("tool_call_id", ""),
"content": event.get("result", ""),
}))
# Open a new text block for the model's next response
self.block_index += 1
events.extend(self._open_text_block())

View file

@ -328,11 +328,15 @@ class TestAnthropicStreamEmitter:
e.start("msg_1", "m")
e.feed({"type": "tool_start", "tool_name": "t", "tool_call_id": "tc_1", "arguments": {}})
events = e.feed({"type": "tool_end", "tool_name": "t", "tool_call_id": "tc_1", "result": "done"})
# content_block_stop (tool) + content_block_start (new text)
assert len(events) == 2
# content_block_stop (tool) + tool_result + content_block_start (new text)
assert len(events) == 3
assert "content_block_stop" in events[0]
assert "content_block_start" in events[1]
assert '"type": "text"' in events[1]
assert "tool_result" in events[1]
parsed = json.loads(events[1].split("data: ")[1])
assert parsed["content"] == "done"
assert parsed["tool_use_id"] == "tc_1"
assert "content_block_start" in events[2]
assert '"type": "text"' in events[2]
def test_finish_emits_stop_events(self):
e = AnthropicStreamEmitter()