fix(adk): emit tool result AgentEvent after tool middlewares #649
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
fix(adk): emit tool result AgentEvent after tool middlewares
Problem
Tool results emitted in
AgentEventwere captured before middleware processing. When middlewares modify tool outputs (e.g., content filtering, format transformation), users received the raw results instead of the processed ones.This happened because tool results were emitted via
OnToolEndcallbacks, which fire at the component boundary—before the middleware chain processes the output.Solution
Move tool result emission from callbacks into a collector middleware that sits at the outermost position of the middleware chain. This ensures it captures the final result after all other middlewares have processed it.
The collector receives the tool result sender via context (set in graph's
OnStartFn), and emits the result afternext()returns.Key Design Decisions
Why context instead of state for sender passing?
In interrupt/resume scenarios,
OnStartFnis called before state is restored from checkpoint. Using context ensures the sender is available regardless of state restoration timing.Scope
Both
adk.ChatModelAgentandflow/agent/react.MessageFutureare fixed with the same pattern. Tests cover both Invoke and Stream paths, verifying that middleware-modified results are correctly emitted.