Skip to content

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_openclaw is wired to a persistent config via createPersistentOpenClawSubagentConfig(...).
  • That config sets:
    • lifetime: 'persistent_session'
    • persistentFactory: (...) => new PersistentOpenClawSubagent(...)

End-to-End Sequence ​

Persistent Instance State ​

Ownership Boundaries ​

  • ToolRouterActor: decides inline vs background; emits subagent.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 + streamed nextChatEvent).

Key Behavior Notes ​

  • One persistent instance per (VoiceSession, subagent key); current key is configName (for ask_openclaw, key is ask_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 is scheduling: '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 of invoke. 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 legacy ToolCallRouter handoffs. PersistentSubagentManager.invoke still returns the text; invokeWithScheduling returns 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.ts
  • examples/lib/openclaw-tools.ts
  • examples/lib/persistent-openclaw-subagent.ts
  • src/core/voice-session.ts
  • src/agent/persistent-subagent-manager.ts
  • src/runtime/actors/tool-router-actor.ts
  • src/runtime/actors/subagent-supervisor-actor.ts
  • src/transport/gemini-live-transport.ts

Built with VitePress