Skip to content

ACP (acpx) sessions don't trigger subagent_ended hook or announce pipeline #46439

@worldofgeese

Description

@worldofgeese

Summary

ACP sessions spawned via sessions_spawn(runtime: "acp") complete successfully but never trigger the subagent_ended hook or the subagent announce pipeline. The orchestrator/parent session never receives a completion announcement, creating a silent stall.

Expected Behavior

When an ACP session finishes, the parent session should receive a completion announcement (same as embedded/Pi subagent runs), and the subagent_ended hook should fire.

Actual Behavior

  • ACP session completes and emits done event internally
  • Stream log shows :start:stall (60s idle) — but no lifecycle event reaches the agent event bus
  • subagent_ended hook never fires
  • Announce pipeline never triggers
  • Parent session waiting via sessions_yield is never woken

Root Cause (from source investigation)

The embedded Pi runtime (pi-embedded-subscribe.handlers.lifecycle.ts) calls emitAgentEvent({ stream: "lifecycle", data: { phase: "end" } }) on completion, which the subagent registry listener picks up → completeSubagentRunemitSubagentEndedHookForRun → announce flow.

The ACPX plugin runtime (runtime.ts) yields { type: "done" } to its caller but this is not bridged into the gateway's emitAgentEvent bus. ACPX manages its own lifecycle internally (service.ts:lifecycleRevision) without emitting to the shared agent event system.

So the announce pipeline is architecturally sound — it just never receives the signal from ACP runs.

Proposed Fix

When an ACP run yields { type: "done" }, the gateway's ACP handler should call:

emitAgentEvent({
  runId,
  stream: "lifecycle",
  data: { phase: "end", endedAt: Date.now() }
});

This would make all existing infrastructure work: subagent_ended hook fires, announce pipeline delivers results to requester session, sessions_yield wakes up.

Workaround

Currently using a background stream-log watcher that polls .acp-stream.jsonl files for :stall events every 10s and cross-references active-tasks.json for git branch changes. Works but adds ~70s latency (60s stall + 10s scan).

Environment

  • OpenClaw v2026.3.13 (commit f6e5b67)
  • acpx v0.1.16
  • ACP backend: claude (via Anthropic proxy)

Relevant Source Locations

  • auth-profiles-*.js:92532onAgentEvent listener for lifecycle events
  • auth-profiles-*.js:92344completeSubagentRun
  • auth-profiles-*.js:92375emitSubagentEndedHookForRun
  • ACPX runtime.ts:409 — yields { type: "done" } (not bridged to agent event bus)
  • ACPX service.ts:39-100 — internal lifecycle management
  • Pi runtime: pi-embedded-subscribe.handlers.lifecycle.ts — correctly emits lifecycle events

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions