Skip to content

Conversation

@shentongmartin
Copy link
Contributor

@shentongmartin shentongmartin commented Dec 26, 2025

fix(adk): emit tool result AgentEvent after tool middlewares

Problem

Tool results emitted in AgentEvent were 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 OnToolEnd callbacks, 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.

// Prepend collector middleware so it wraps all user middlewares
config.ToolCallMiddlewares = append(
    []compose.ToolMiddleware{newToolResultCollectorMiddleware()},
    config.ToolCallMiddlewares...,
)

The collector receives the tool result sender via context (set in graph's OnStartFn), and emits the result after next() returns.

Key Design Decisions

Why context instead of state for sender passing?

In interrupt/resume scenarios, OnStartFn is called before state is restored from checkpoint. Using context ensures the sender is available regardless of state restoration timing.

Scope

Both adk.ChatModelAgent and flow/agent/react.MessageFuture are fixed with the same pattern. Tests cover both Invoke and Stream paths, verifying that middleware-modified results are correctly emitted.

@codecov
Copy link

codecov bot commented Dec 26, 2025

Codecov Report

❌ Patch coverage is 91.09589% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.28%. Comparing base (47ddc7e) to head (72a8ab5).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
adk/chatmodel.go 83.72% 2 Missing and 5 partials ⚠️
flow/agent/react/react.go 87.87% 2 Missing and 2 partials ⚠️
adk/react.go 95.91% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #649      +/-   ##
==========================================
+ Coverage   80.23%   80.28%   +0.04%     
==========================================
  Files         124      124              
  Lines       11829    11904      +75     
==========================================
+ Hits         9491     9557      +66     
- Misses       1612     1616       +4     
- Partials      726      731       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Change-Id: I66be0601edbde456119edd164f1442a93eef9b21
- Add tool result collector middleware to emit final tool results after all middlewares
- Migrate flow/agent/react from State to Context for sender passing (resume compatibility)
- Add address depth constants and isAddressAtDepth helper for clearer address checks
- Use stream.Copy(2) instead of goroutine for stream tool result handling
- Add comprehensive tests for both Invoke and Stream paths

Change-Id: I3fba18f63c33cb6129cdf23c4832871b7582b836
@shentongmartin shentongmartin merged commit e825e71 into main Dec 30, 2025
19 checks passed
@shentongmartin shentongmartin deleted the fix/tool_result branch December 30, 2025 06:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants