Repository navigation
Conversation
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.
Fixes #158
Copilot CLI runs the user's hooks inside subagents too, and it fills in
sessionIdwith the subagent's agent id (for exampleexplore-0) in place of the root session id. A subagent hook payload has no other marker:agentNameandagentIdonly appear insubagentStartandsubagentStop, and tool payloads have no transcript path. So when a subagent rancargo testand it failed with an error a procedure was learned from,postToolUseserved that procedure to the subagent and recorded the injection underexplore-0. Copilot writes the subagent's events into the parent'ssession-state/<root id>/events.jsonl, tagged withagentId, and the parser leaves them out of the parent's trace. No trace with the agent id is ever learned, so nothing settled that injection: its outcome was never scored and the row stayed in the store for good.Now a shell failure from
postToolUseorpostToolUseFailureis only recalled when the session has its ownevents.jsonlunder Copilot'ssession-statedirectory. That is exactly the condition for an injection to be settled later. A subagent never gets a directory of its own, since its agent id is made from the task name or the tool call id and session directories are named by the root session's UUID. A root session always has one by the time a tool finishes: Copilot starts writingevents.jsonlas soon as the firstuser.messageis emitted (with a 100 ms debounce), and a tool can only run after a model round trip that follows it. Other subagent events already do nothing:agentStopandpreCompactfrom a subagent have no transcript, so their ingest and reminder are skipped, andsessionStart/sessionEnddon't fire in subagents.I didn't use the shape of the session id as the signal. Root ids are UUIDs and agent ids aren't today, but agent ids come from tool call ids whose format depends on the model provider, and SDK hosts can pick their own session ids, so that check would be guessing. The trade-off of the transcript check is that someone who moves Copilot's config with
--config-dirbut doesn't setCOPILOT_HOMEgets no failure recalls, because their transcripts aren't where Trodden looks. In that setup nothing is recorded wrongly, they just miss the recall.I left
userPromptSubmittedalone on purpose. Subagents fire it too, with the agent id, so their task prompt can get a recall the same way. But the transcript check can't tell the two apart there: in a new root session Copilot fires the hook before the firstuser.message, soevents.jsonldoesn't exist yet and the check would drop the recall for the first prompt of every new session, which is the most useful one. That needs its own fix.To reproduce, I built the binary, used a scratch
TRODDEN_HOMEandCOPILOT_HOME, learned a procedure by ingesting a Copilotevents.jsonlwherecargo testfailed with E0425, the file was edited and the test then passed, and fedtrodden hook copilottwopostToolUsepayloads with the same failing output: one with the root session id and one with a subagent id. Before the fix both got the procedure back, and theinjectionstable had a row for the subagent id next to the root one. After the fix the subagent payload gets no reply and only the root session's injection is recorded.The new test sends a failing shell result through
postToolUse,postToolUseFailureand the PascalCasePostToolUse, checks each is recalled for the root session, then swaps in a subagent id and checks it is ignored. It fails before the fix and passes after. The existing failure test now sets up the root session'sevents.jsonlfirst.