Repository navigation
Conversation
The Copilot plugin registers subagentStop in camelCase, so Copilot CLI sends agentId, agentType and response. The hook read only agent_id, agent_type and last_assistant_message: the subagent's report was stored empty, agent_id held the agent name, and without agent_id the event id fell back to the hook time, so a repeat delivery was stored twice. The hook now falls back to the camelCase fields, and agentId makes the event id stable the same way agent_id does. Signed-off-by: Dmitrii Zhukov <dmitry0983@gmail.com>
stripPrivateData only matches a closed <private> block, and the server redacts after the hook has already cut the reply, so a block that crossed the 4000-character limit was stored with its opening tag and the start of the secret. Copilot's response now reaches the same cut. The hook redacts the whole reply first, as stop.ts does. Signed-off-by: Dmitrii Zhukov <dmitry0983@gmail.com>
|
@dmazhukov is attempting to deploy a commit to the rohitg00's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
| {}, | ||
| { ...body.data, stop_hook_active: data.stop_hook_active === true }, | ||
| { stable: Boolean(data.agent_id) }, | ||
| { stable: Boolean(data.agent_id || data.agentId) }, |
There was a problem hiding this comment.
🟡 Long subagent updates disappear as duplicates
When one Copilot agentId sends distinct replies sharing their first 4,000 characters, withEventId gives both the same ID. capture discards the later report as a duplicate.
Learn more
The hook converts each subagent stop into an observation. For Copilot payloads, agentId makes the event ID stable across repeated delivery, so withEventId hashes the supplied content without a timestamp. That content contains only the first 4,000 characters of the redacted reply. Two legitimate stops from the same agent with a common report prefix therefore have identical IDs, and capture ignores the later one.
Example: A Copilot subagent reports "A".repeat(4000) + "draft", then stops again with "A".repeat(4000) + "finished". Both requests carry the same last_message and event ID, so only the draft observation survives.
Recommended fix: Keep the redacted 4,000-character reply in body.data, but derive the stable event ID using a digest of the full redacted reply as additional content. Identical retries then share an ID while distinct long reports do not.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Both stops store the same last_message: the reply is cut to 4000 characters (src/hooks/subagent-stop.ts:35) before it is hashed and stored, so the later event would repeat the first one except for its timestamp. Hashing the full reply would only add that copy. Snake_case payloads with agent_id already behave this way on main: "A".repeat(4000) + "draft" and + "finished" give one event id and an identical last_message there and on this head.
subagent-stopnow reads the camelCase payload Copilot CLI sends forsubagentStop:responsebecomeslast_message,agentIdbecomesagent_idand keeps the event id stable,agentTypebecomesagent_type. Fixes #1596.hooks.copilot.jsonregisterssubagentStopin camelCase and the hook read only snake_case names, so on Copilot every subagent report was stored empty, and a retry was stored twice.The reply is now redacted before the 4000-character cut, like
stop.ts: a<private>block across the limit kept its secret.Not covered: Copilot's
subagentStartsends noagentId, so start events keep the agent name.Not covered: field names follow the Copilot CLI hooks reference, not a captured payload.
Not covered: an unclosed
<private>tag, or one with attributes, stays unredacted here and on the server.Summary by CodeRabbit
Bug Fixes
Tests