Skip to content

Conversation

@zastrowm
Copy link
Member

@zastrowm zastrowm commented Sep 3, 2025

Description

Enable decorated tools to be an async generator, enabling streaming of tool events back to to the caller. Assuming #773 is merged, the changes needed are fairly minor, as currently we're just swallowing tool stream events.

Implements #543

Api Bar-raising

The tool event being emitted (as a dictionary) needs to go through bar-raising. The event name should not matter, as it's an internal name-only (TypedEvents are not exposed; only the dictionary)

Proposed new Event

ToolStreamEvent:

  • tool_stream_event:
    • tool_use: ToolUse - the tool use that emitted the event
    • data: Any - the data that was streamed/yielded from the tool

Example tool yielding:

@strands.tool
async def streaming_tool():
    yield {"tool_streaming": True}
    yield {"another_data": 13}
    yield "Final result"

Example Consumption:

def my_callback(kwargs: dict[str, any]):
   if "tool_stream_event" in kwargs:
      tool_use = kwargs["kwargs"]["tool_stream_event"]["tool_use"]
      data = kwargs["kwargs"]["tool_stream_event"]["data"]

      print(data) 
      # Prints 3 times
      #     "{"tool_streaming": True}"
      #     "{"another_data": 13}"
      #     "Final result"
      ...

Existing Events

Our existing events are as follows and the proposed names must not conflict with any of the existing events:

Event Type Dictionary Properties
InitEventLoopEvent init_event_loop: bool
StartEvent start: bool
StartEventLoopEvent start_event_loop: bool
ModelStreamChunkEvent event: StreamEvent
ToolUseStreamEvent delta: ContentBlockDelta
current_tool_use: dict[str, Any]
TextStreamEvent data: str,
delta: ContentBlockDelta
ReasoningTextStreamEvent reasoningText: str | None
delta: ContentBlockDelta
reasoning: bool
ReasoningSignatureStreamEvent reasoning_signature: str | None,
delta: ContentBlockDelta,
reasoning: bool
EventLoopThrottleEvent event_loop_throttled_delay: int
ModelMessageEvent message: Message
ToolResultMessageEvent message: Any
ForceStopEvent force_stop: bool,
force_stop_reason: str
AgentResultEvent result: AgentResult

Related Issues

#543

Documentation PR

Type of Change

New feature

Testing

How have you tested the change? Verify that the changes do not break functionality or introduce warnings in consuming repositories: agents-docs, agents-tools, agents-cli

  • I ran hatch run prepare

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Enable decorated tools to be an async generator, enabling streaming of tool events back to to the caller.
pgrayy
pgrayy previously approved these changes Sep 3, 2025
@pgrayy pgrayy self-requested a review September 3, 2025 19:08
@zastrowm zastrowm merged commit d07629f into strands-agents:main Sep 4, 2025
12 checks passed
This was referenced Sep 17, 2025
Unshure pushed a commit to Unshure/sdk-python that referenced this pull request Sep 24, 2025
Enable decorated tools to be an async generator, enabling streaming of tool events back to to the caller.

---------

Co-authored-by: Mackenzie Zastrow <[email protected]>
@zastrowm zastrowm mentioned this pull request Oct 6, 2025
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants