[release/0.1.9] fix(trajectory): record subagent runs under their own agent_id (#33)#112
Merged
justrach merged 1 commit intoMay 20, 2026
Conversation
Closes #33. Before this change, the `/trace` command (and any tooling that queries `trajectory_events`) saw only the root agent's tool calls. Every Task dispatch that ran inside `AgentExecutor::execute` constructed a fresh `ForgeApp` *without* a recorder, so the child orchestrator silently bypassed the trajectory pipeline. The acceptance criterion was: SELECT DISTINCT agent_id FROM trajectory_events WHERE conversation_id = ? …should return parent + every dispatched child, with child rows linked back via `parent_agent_id`. It returned only the parent. Fix: thread the raw `Arc<dyn TrajectoryRepo>` from `ForgeAPI::chat` through `ForgeApp -> ToolRegistry -> AgentExecutor` via a constructor injection (`with_trajectory_repo`), then have `AgentExecutor::execute` build a *child* `TrajectoryRecorder` scoped to `(conversation_id, child_agent_id, Some(parent_agent_id))` before spinning up the child's `ForgeApp`. Recursive dispatches inherit the repo, so grandchild runs build their own recorders against the same backend and the `/trace` tree walks naturally. Plumbing notes: - Added `AgentExecutor::with_trajectory_repo(...)` and a new `parent_agent_id` parameter on `AgentExecutor::execute(...)` - Updated both Task-tool + agent-delegation callsites in `ToolRegistry` to capture `agent.id` and pass it through - Added `ForgeApp::with_trajectory_repo(...)` mirroring the existing `with_trajectory_recorder(...)` chain; both are wired together in `ForgeAPI::chat` - Recording stays best-effort: every recorder error is swallowed with a `tracing::warn!`; a telemetry failure never aborts an agent run Tests: added `parent_and_child_recorders_share_conversation_trajectory` to `trajectory_recorder::tests` which asserts the exact acceptance criterion at the recorder layer (distinct agent_ids in the conversation, all child rows reference the parent, root rows have no parent_agent_id). Full `cargo test -p forge_app` is green (736 tests). Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: blackfloofie-a codegraff agent <265516171+blackfloofie@users.noreply.github.com> Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This was referenced May 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Backports #111 (closes #33) to
release/0.1.9. Clean cherry-pick of51f1897, no merge conflicts.
Fixes the case where subagent runs dispatched via the Task tool
silently bypassed the
TrajectoryRecorder, leaving/traceblindto anything below the root agent. After this, every dispatched
(conversation_id, child_agent_id)pair gets its own recorder andchild rows carry
parent_agent_idlinking back to the dispatcher.See #111 for the full rationale and design notes.
Test plan
release/0.1.9cargo test -p forge_app trajectory_recorder— all 5 tests pass,including the new
parent_and_child_recorders_share_conversation_trajectoryregression test
Generated with Devin