fix(run-events): tool results carry parentMessageId like tool call starts - #4494
Conversation
…arts The conversation run event encoder named the assistant message on TOOL_CALL_START but not on TOOL_CALL_RESULT, so a consumer had to recover a result's turn from the synthetic `<assistantMessageId>:tool:<toolCallId>` message id. State it explicitly instead: the tool-result payload schema gains an optional non-empty `parentMessageId`, and all four result branches (tool-input-error, tool-output-available, tool-output-error, tool-output-denied) set it to the active message id when one is open. The synthetic messageId is unchanged. The schema's JSDoc and the generated API reference describe the field. The native run events contract fixture has no TOOL_CALL_RESULT sample, so it and its pinned hash are unchanged. Claude-Session: https://claude.ai/code/session_01CqY82FYm9aUkyawWmh4T9n
|
@codex review |
|
You have reached your Codex usage limits for security reviews. Please try again later. |
|
Warning Review limit reachedNext included review available in 22 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (5)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
📦 Client bundle boundary
A server module in a client graph aborts hydration in the browser. New leaks fail CI; known leaks are tracked in |
Review: 92/100 — excellentSmall, well-scoped bugfix that does exactly what it says: Strengths
Minor nit (non-blocking)
No security, design, or test-coverage concerns. CI was still running several jobs at review time (coverage shards, lint, typecheck, integration/e2e) with everything completed so far green — worth a final glance before merge, but nothing in the diff itself suggests risk there. Generated by Claude Code |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|



Why
The conversation run event encoder already names the assistant message on
TOOL_CALL_START(parentMessageId). It did not do the same onTOOL_CALL_RESULT, so the API had to work out a tool result's turn from the made-up message id<assistantMessageId>:tool:<toolCallId>when it ingests the event. Recovering it that way is a stopgap. The encoder should state the parent directly, the same way it does for starts.What changed
getToolCallResultPayloadSchema(src/run-events/payload.ts) now has an optionalparentMessageIdfield. It must be a non-empty string, the same ruleTOOL_CALL_STARTuses.ConversationRunEventEncoder(src/agent/conversation/run-events.ts) setsparentMessageIdto the active assistant message id on all four places that emit a tool result:tool-input-error,tool-output-available,tool-output-errorandtool-output-denied. When no message is open, the key is left out, which matchesTOOL_CALL_START.getToolCallResultPayloadSchemaand the generateddocs/api-reference/veryfront/run-events.mdnow describeparentMessageId.messageIdis unchanged, because consumers and the API's ingest-time recovery depend on its format.Contract fixture
No change.
tests/fixtures/contracts/native-run-events.jsononly covers the native frame types (for tool calls, that isTOOL_CALL_STATUS_CHANGED) and has noTOOL_CALL_RESULTsample. The fixture and its SHA-256 hash stay as they are, so veryfront-api needs no companion fixture PR. The API's typedTOOL_CALL_RESULTschema on its main branch already accepts an optionalparentMessageId.Tests
src/agent/conversation/run-events.test.ts: for each of the four branches, one test checks thatparentMessageIdequals the active message id inside an open message, and another checks that the key is missing when no message is open. Both tests also pin the made-upmessageId. These failed before the change and pass after it. The existing exact-shape test now includes the new key.src/run-events/payload.test.ts: the schema accepts a stringparentMessageIdand rejects a number or an empty string. This failed before the change, because the passthrough schema let a number through.Out of scope
lifecycle-run-event-adapter.tsbuilds its own tool records and uses a different shape:messageIdon starts and no parent on results. This PR leaves it unchanged; any change there is a separate piece of work.https://claude.ai/code/session_01CqY82FYm9aUkyawWmh4T9n