Skip to content

multiagent/

Multi-agent runtime: run multiple independent sygen agents in one process.

Files

  • multiagent/supervisor.py: AgentSupervisor lifecycle, health, crash recovery, agents watcher
  • multiagent/stack.py: AgentStack container (config + bot + orchestrator)
  • multiagent/bus.py: InterAgentBus (sync + async inter-agent messaging)
  • multiagent/internal_api.py: localhost HTTP bridge for tool scripts (/interagent/*, /tasks/*)
  • multiagent/models.py: SubAgentConfig, merge helpers
  • multiagent/registry.py: agents.json read/write
  • multiagent/health.py: per-agent health model
  • multiagent/shared_knowledge.py: shared knowledge sync (SHAREDMEMORY.md)
  • multiagent/commands.py: Telegram commands (/agents, /agent_start, /agent_stop, /agent_restart)

Runtime model

AgentSupervisor
  +-- AgentStack "main"
  +-- AgentStack "sub-*" (0..n)
  +-- InterAgentBus
  +-- InternalAgentAPI (localhost bridge)
  +-- optional TaskHub (shared)
  +-- SharedKnowledgeSync
  +-- FileWatcher(agents.json)

Each stack is isolated (token/workspace/sessions), but shares process/event-loop infrastructure.

Startup sequence (AgentSupervisor.start)

  1. start inter-agent bus
  2. start internal API
  3. optional shared task hub
  4. create/start main stack
  5. wait for main readiness
  6. start sub-agents from agents.json
  7. start shared knowledge sync
  8. start agents.json watcher

Dynamic agent changes

Watcher polls agents.json every 5s.

  • added entry -> start sub-agent
  • removed entry -> stop sub-agent
  • restart triggers for running sub-agents:
  • transport changed
  • Telegram identity changed (telegram_token)
  • Matrix identity changed (matrix.homeserver or matrix.user_id)
  • other field changes do not auto-restart running agent

Crash/restart policy

Per agent _supervised_run behavior:

  • clean exit -> stop
  • exit code 42:
  • main -> propagate full process/service restart
  • sub-agent -> in-process hot-reload
  • crash -> exponential backoff retries (5 attempts max), then mark crashed

Sub-agent config (agents.json)

Minimal entry:

{
  "name": "coder",
  "telegram_token": "123456:ABC...",
  "allowed_user_ids": [12345678],
  "allowed_group_ids": [],
  "provider": "codex",
  "model": "o3"
}

Merge behavior:

  • base: main AgentConfig
  • override: non-null SubAgentConfig fields
  • always forced:
  • sygen_home=~/.sygen/agents/<name>/
  • sub-agent telegram_token, allowed_user_ids, allowed_group_ids
  • api.enabled=false unless explicitly provided for sub-agent

Shared vs isolated

Isolated per sub-agent:

  • transport credentials and auth (Telegram token or Matrix account)
  • workspace and files under ~/.sygen/agents/<name>/
  • sessions.json, named_sessions.json, cron/webhook state

Shared across process:

  • InterAgentBus
  • InternalAgentAPI
  • optional shared TaskHub
  • central log file (~/.sygen/logs/agent.log)
  • shared knowledge source (~/.sygen/SHAREDMEMORY.md)

Inter-agent communication

In-memory bus

  • sync: waits for target response (send)
  • async: returns task ID immediately (send_async)

Recipient processing uses deterministic named session ia-<sender>.

Provider-switch safeguard:

  • if recipient provider changed since prior ia-<sender> session, old session is ended and recreated
  • provider-switch notice is surfaced back to sender side

Activity log

Each agent automatically maintains AGENT_ACTIVITY.md in its workspace — a rolling log of inter-agent interactions it handled. When a user opens a direct chat, the agent reads this file and has context about recent delegated work.

Format: - [MM-DD HH:MM] from:<sender> [ok (Ns)] <message> → <result>

Cleanup:

  • FIFO cap: 15 entries (oldest evicted on write)
  • Age expiry: entries older than 7 days are dropped on write
  • Memory cleanup cron covers this file for all agents

Async timeout behavior

Async inter-agent tasks are fire-and-forget. If a task times out, the timeout is logged but not delivered to the user's chat. This prevents confusing "Inter-Agent Request Failed" messages for tasks that may have been resolved by other means.

Local HTTP bridge for tool scripts

InternalAgentAPI runs on config.interagent_port (default 8799):

  • host mode: 127.0.0.1:<port>
  • Docker mode: 0.0.0.0:<port>

Inter-agent endpoints:

  • POST /interagent/send
  • POST /interagent/send_async
  • GET /interagent/agents
  • GET /interagent/health

Task endpoints (shared hub):

  • POST /tasks/create
  • POST /tasks/resume
  • POST /tasks/ask_parent
  • GET /tasks/list
  • POST /tasks/cancel
  • POST /tasks/delete

Ownership checks apply for resume/cancel/delete when from=<agent> is present.

TaskHub integration

When enabled, supervisor wires each stack into shared TaskHub:

  • per-agent CLI service
  • per-agent paths (tasks_dir)
  • task result callback
  • task question callback
  • agent primary chat ID mapping

This enables task submission from any agent while preserving owner routing.

Shared knowledge sync

SharedKnowledgeSync watches ~/.sygen/SHAREDMEMORY.md and mirrors content into each agent's MAINMEMORY.md block.

Legacy HTML marker format is migrated to current block markers when rewritten.

Chat and CLI commands

Main-agent chat commands:

  • Telegram: /agents, /agent_start <name>, /agent_stop <name>, /agent_restart <name>
  • Matrix: !agents, !agent_start <name>, !agent_stop <name>, !agent_restart <name> (/ prefix also works)

CLI:

  • sygen agents
  • sygen agents list
  • sygen agents add <name>
  • sygen agents remove <name>

sygen agents list fetches live health from internal API when main bot is running.

Important CLI nuance:

  • sygen agents add <name> currently prompts for Telegram token/user/group data only.
  • Matrix sub-agents are supported by the runtime and merge logic, but are created via manual agents.json editing or the bundled create_agent.py --transport matrix tool script.