mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
fix(agent-hooks): stop Claude agent-hook runs from minting phantom subagent rows (#33298)
Claude tool events from agent-hook runs (`hook-agent-<uuid>` ids, which never send SubagentStop) no longer mint phantom "Working - Agent" subagent rows. Fixes #27775. Supersedes #27776, #15326. Co-authored-by: DamHV <251416543+DamHV@users.noreply.github.com>
This commit is contained in:
@@ -221,6 +221,35 @@ describe('shared agent-hook-listener', () => {
|
||||
expect(stopped?.payload.state).toBe('done')
|
||||
})
|
||||
|
||||
it('does not mint rows for agent-hook runs on the lead or inside a subagent', () => {
|
||||
claudeEvent({ hook_event_name: 'UserPromptSubmit', prompt: 'go' })
|
||||
// Why: payloads captured from Claude Code 2.1.310; a hook run inside a subagent inherits its agent_type.
|
||||
const leadHook = claudeEvent({
|
||||
hook_event_name: 'PreToolUse',
|
||||
agent_id: 'hook-agent-f91f48da-b4db-45e3-a8a1-3debdaa4f2f5',
|
||||
tool_name: 'Read',
|
||||
tool_input: { file_path: '/tmp/README.md' }
|
||||
})
|
||||
expect(leadHook?.payload.state).toBe('working')
|
||||
expect(leadHook?.payload.subagents ?? []).toEqual([])
|
||||
|
||||
claudeEvent({
|
||||
hook_event_name: 'SubagentStart',
|
||||
agent_id: 'aa34e9e23451d1f6b',
|
||||
agent_type: 'general-purpose'
|
||||
})
|
||||
const childHook = claudeEvent({
|
||||
hook_event_name: 'PreToolUse',
|
||||
agent_id: 'hook-agent-5179ea04-58c0-440a-b861-04ead9f87aaa',
|
||||
agent_type: 'general-purpose',
|
||||
tool_name: 'Read',
|
||||
tool_input: { file_path: '/tmp/README.md' }
|
||||
})
|
||||
expect(childHook?.payload.subagents).toEqual([
|
||||
expect.objectContaining({ id: 'aa34e9e23451d1f6b' })
|
||||
])
|
||||
})
|
||||
|
||||
it('parks a teammate as a persistent idle row across its stop/idle/lead-Stop cycle', () => {
|
||||
// Why: the interactive agent-teams shape observed live on 2.1.217 —
|
||||
// lifecycle events use `a<name>-<hex>` agent ids while background_tasks
|
||||
|
||||
@@ -33,6 +33,8 @@ import { buildClaudeStatusPayload } from './claude-status-build'
|
||||
import { trackClaudeTaskNotificationDelivery } from './claude-task-notification-delivery'
|
||||
import { recordClaudeTeammateSpawn } from './claude-teammate-spawn'
|
||||
|
||||
const CLAUDE_HOOK_AGENT_ID_PREFIX = 'hook-agent-'
|
||||
|
||||
export function normalizeClaudeEvent(
|
||||
state: HookListenerState,
|
||||
eventName: unknown,
|
||||
@@ -179,7 +181,9 @@ export function normalizeClaudeEvent(
|
||||
eventName === 'PostToolUseFailure')
|
||||
? eventAgentId
|
||||
: undefined
|
||||
if (eventAgentId && (subagentOriginId || isWaitingInducing)) {
|
||||
// Why: `"type": "agent"` hook runs emit tool hooks (agent_type only if inherited) but never SubagentStop, so their row would stay working forever; real children may be untyped and start-less.
|
||||
const isClaudeHookAgent = eventAgentId?.startsWith(CLAUDE_HOOK_AGENT_ID_PREFIX) === true
|
||||
if (eventAgentId && (subagentOriginId || isWaitingInducing) && !isClaudeHookAgent) {
|
||||
upsertWorkingClaudeSubagent(
|
||||
getOrCreateClaudeSubagentRoster(state, paneKey),
|
||||
eventAgentId,
|
||||
|
||||
Reference in New Issue
Block a user