Skip to content

fix(agent): stamp tool request with originating response timestamp - #9479

Closed
jpatel3 wants to merge 1 commit into
aaif-goose:mainfrom
jpatel3:fix/9461-tool-request-timestamp-ordering
Closed

fix(agent): stamp tool request with originating response timestamp#9479
jpatel3 wants to merge 1 commit into
aaif-goose:mainfrom
jpatel3:fix/9461-tool-request-timestamp-ordering

Conversation

@jpatel3

@jpatel3 jpatel3 commented May 29, 2026

Copy link
Copy Markdown

Summary

Fixes #9461.

Tool request messages (assistant/tool_use) were being assigned a created timestamp after tool execution, while their paired tool response messages (user/tool_result) were stamped before execution. When a tool ran long enough to cross a one-second boundary, the request ended up with a later timestamp than its response.

The session DB retrieves messages with ORDER BY created_timestamp, id (crates/goose/src/session/session_manager.rs). The id auto-increment tiebreaker only matters when timestamps are equal — so an out-of-order pair causes the tool_result to sort ahead of its tool_use, and the Claude API rejects the conversation with:

messages.0.content.0: unexpected tool_use_id in tool_result blocks

Fix

In the tool-request construction loop in crates/goose/src/agents/agent.rs, carry the originating provider response's created timestamp onto the tool-request message. This mirrors how thinking/reasoning content is already stamped (thinking_msg uses response.created). The request and response now share a timestamp, so the insertion-order id tiebreaker preserves the correct request-before-response ordering.

Test

Added test_tool_request_not_stamped_after_response in crates/goose/tests/agent.rs. A mock provider emits a tool request stamped well in the past; the test drives the agent through one tool turn and asserts the persisted tool-request keeps that timestamp and is never stamped after its response. Verified the test fails without the fix (the request gets the wall-clock time) and passes with it.

cargo test -p goose --features rustls-tls --test agent max_turns_tests

Tool requests (assistant/tool_use) were created after tool execution
while their paired tool responses (user/tool_result) were created before
it. When execution crossed a one-second boundary, the request received a
later created_timestamp than the response. The session DB returns
messages ORDER BY created_timestamp, id, so the response sorted ahead of
its request and the Claude API rejected the conversation with
"unexpected tool_use_id in tool_result blocks".

Carry the originating response's timestamp onto the tool request message
(mirroring how thinking content is already stamped) so the request and
response share a timestamp and the auto-increment id tiebreaker preserves
insertion order.

Fixes aaif-goose#9461

Signed-off-by: Jaimin Patel <jpatel@tuvalabs.com>
@DOsinga

DOsinga commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Thanks for digging into this and the clear write-up in #9461! This turned out to be a popular bug — the same fix landed in #9462, which clamps the tool request timestamp to its response so the session ordering stays correct. Since that's now merged on main, I'm going to close this as a duplicate. Really appreciate the contribution, and hope you'll send more our way! 🙏

@DOsinga DOsinga closed this Jun 15, 2026
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.

Tool request messages get later timestamps than tool responses, breaking Claude API message ordering

2 participants