Assistant Delegation and Zombie Contexts
The assistant module supports complex multi-agent collaboration via delegation, allowing a primary agent to assign tasks to specialized sub-agents.
Delegation Mechanisms
1. Synchronous Delegation (call_agent)
The primary agent waits for the sub-agent to complete its task and provide a result within the same session. This is best for quick, direct sub-tasks.
2. Asynchronous Delegation (call_agent_async)
The primary agent assigns a task to a sub-agent and continues its own execution or ends its session. The result is delivered later via a notification. This is essential for long-running tasks.
Zombie Contexts
"Zombie Contexts" are a robust persistence mechanism designed to handle asynchronous results when the original (parent) session is no longer active (e.g., after a restart or session timeout).
How it Works
- Registration: When
call_agent_asyncis invoked, theZombieParentRegistrycaptures critical metadata about the parent session (ChatID, Platform, UserRole, AgentName). - Execution: The sub-agent runs in a background goroutine.
- Completion: When the sub-agent finishes, the system checks if the parent session is still active.
- Fallback: If the parent session is gone, the system retrieves the "Zombie" metadata and uses it to send a persona-aware notification to the user (via WhatsApp or Discord) informing them of the result.
WhatsApp LID→JID Resolution Fix (April 2026)
Issue: WhatsApp async delegation notifications failed because LID (Login ID) format wasn't being resolved to JID (Jabber ID) format.
Example:
- LID:
123456789(phone number only) - JID:
123456789@s.whatsapp.net(full WhatsApp address format)
Fix: Implemented 3-tier fallback in resolveWhatsAppChatID:
| Tier | Check | Action |
|---|---|---|
| 1 | Already JID format? | Use directly |
| 2 | Phone number extractable? | Append @s.whatsapp.net |
| 3 | Fallback | Use stored ZombieParent ChatID |
Files: assistant/planner.go, assistant/scheduler.go, assistant/wakeup.go
Empty ChatID Bug: ZombieParent registration could capture empty ChatID. Fixed with fallback to use stored parent ChatID when current is empty.
Sequence Diagram: Async Delegation & Zombie Recovery
sequenceDiagram
participant N as Nikki (Parent)
participant Z as Zombie Registry
participant S as Sasha (Sub-Agent)
participant W as WhatsApp Notifier
N->>S: call_agent_async(task)
N->>Z: RegisterZombieParent(ChatID, Meta)
N-->>N: Session Ends/Saves
Note over S: Sasha works on task...
S->>S: Task Complete
S->>Z: Retrieve Zombie Metadata
Z-->>S: Meta (ChatID, User, etc.)
S->>W: Send Notification ("Hey, Sasha here. I finished X...")
Key Files & Functions
assistant/planner.go: ContainsAsyncCallAgentwhich initiates async delegation.assistant/chat_persistence.go: Manages the storage and rehydration of ParentFacts.NotifyUserAsyncComplete(): The fallback function that uses zombie contexts to deliver results.kill_async_agent: A tool for manually terminating hanging sub-agents.
Guidance for AI Agents
- Use Async for Long Tasks: If a task involves deep research or long-running scripts, use
call_agent_asyncto avoid blocking the user. - Provide Task IDs: Always reference the unique Task ID in your initial delegation and final report.
- Check Pending Tasks: Use
list_pending_async_agentsto see what your sub-agents are currently working on.