Persistent Subagent Lifecycle
This page documents the current actor-runtime lifecycle for persistent_session subagents (for example, ask_openclaw in examples/openclaw/openclaw-demo.ts).
Where It Is Configured
ask_openclawis wired to a persistent config viacreatePersistentOpenClawSubagentConfig(...).- That config sets:
lifetime: 'persistent_session'persistentFactory: (...) => new PersistentOpenClawSubagent(...)
End-to-End Sequence
Persistent Instance State
Ownership Boundaries
ToolRouterActor: decides inline vs background; emitssubagent.spawn_requested.SubagentSupervisorActor: owns workflow state (running,waiting_input,completed,failed,cancelled).VoiceSession.backgroundExecutor: picks persistent vs fallback handoff execution path.PersistentSubagentManager: owns persistent instance registry and reuse by key.PersistentOpenClawSubagent: owns provider call loop (chatSend+ streamednextChatEvent).
Key Behavior Notes
One persistent instance per
(VoiceSession, subagent key); current key isconfigName(forask_openclaw, key isask_openclaw).Persistent instances are disposed when
VoiceSession.close()runs.For tools with
pendingMessage, completion/failure updates are queued as system notifications so the main LLM can reliably speak progress back. A completion whose result isscheduling: 'silent'(below) publishes no such notification: the call was already answered by its pending message and there is nothing new to say.An instance may implement the optional
invokeWithScheduling, returning{ text, scheduling: 'silent' }(PersistentSubagentResult); the session then calls it instead ofinvoke. The result is added to the model's context without prompting a response, for a call with nothing new to say, such as a NON_BLOCKING call the model re-issued after its result was already returned. Gemini honours it for NON_BLOCKING tools only. It is supported on this actor-mode persistent path only, not on legacyToolCallRouterhandoffs.PersistentSubagentManager.invokestill returns the text;invokeWithSchedulingreturns both.
Routing Precedence (OpenClaw Demo)
In examples/openclaw/openclaw-demo.ts, explicit mentions of OpenClaw route to ask_openclaw, but media generation has higher precedence:
- Image/visual generation requests must route to
generate_image. - Video/motion generation requests must route to
generate_video. - OpenClaw is not used for image/video generation in this demo configuration.
This prevents explicit phrases like "use OpenClaw" from accidentally bypassing media tools for image/video tasks.
Code Map
examples/openclaw/openclaw-demo.tsexamples/lib/openclaw-tools.tsexamples/lib/persistent-openclaw-subagent.tssrc/core/voice-session.tssrc/agent/persistent-subagent-manager.tssrc/runtime/actors/tool-router-actor.tssrc/runtime/actors/subagent-supervisor-actor.tssrc/transport/gemini-live-transport.ts