docs: add C4 architecture diagrams for multi-agent framework

Mermaid-based C4 model documentation covering:
- C1 System Context: picoclaw in its ecosystem
- C2 Container: runtime containers and responsibilities
- C3 Component: multi-agent internals (blackboard, handoff, routing, fallback, provider protocol)
- C4 Code Detail: interfaces, tool loop flow, blackboard lifecycle, fallback decision tree
- Sequence Diagrams: handoff, blackboard sync, fallback chain, route resolution, config lifecycle
- Roadmap: phased plan with dependency graph and status tracking

Relates to #294, #283
This commit is contained in:
Leandro Barbosa 2026-02-18 12:04:07 -03:00
parent c9a5769576
commit 38ff3b8aa5
7 changed files with 865 additions and 0 deletions

View file

@ -0,0 +1,28 @@
# PicoClaw Multi-Agent Architecture
This directory contains C4 model diagrams (rendered with Mermaid) documenting the multi-agent collaboration framework for PicoClaw.
## Documents
| Document | Scope | Description |
|----------|-------|-------------|
| [C1 - System Context](./c1-system-context.md) | Highest level | PicoClaw in its ecosystem: users, channels, LLM providers |
| [C2 - Container](./c2-container.md) | Runtime containers | Gateway, Agent Loop, Provider Layer, Channels |
| [C3 - Component](./c3-component-multi-agent.md) | Multi-agent internals | Blackboard, Handoff, Routing, Registry, Fallback |
| [C4 - Code](./c4-code-detail.md) | Key structs/interfaces | Go interfaces, data flow, tool execution |
| [Sequence Diagrams](./sequences.md) | Runtime flows | Handoff, Blackboard sync, Fallback chain |
| [Roadmap](./roadmap.md) | Phased plan | What's done, what's next, dependencies |
## Related Issues
- [#294 - Base Multi-agent Collaboration Framework & Shared Context](https://github.com/sipeed/picoclaw/issues/294)
- [#283 - Refactor Provider Architecture: By Protocol Instead of By Vendor](https://github.com/sipeed/picoclaw/issues/283)
- [Discussion #122 - Provider Architecture Proposal](https://github.com/sipeed/picoclaw/discussions/122)
## Status
| Phase | Status | PR |
|-------|--------|----|
| Provider Protocol Refactor | Merged | [#213](https://github.com/sipeed/picoclaw/pull/213) |
| Model Fallback + Multi-agent Routing | Merged | [#131](https://github.com/sipeed/picoclaw/pull/131) |
| Multi-agent Collaboration Framework | WIP | [#423](https://github.com/sipeed/picoclaw/pull/423) |

View file

@ -0,0 +1,59 @@
# C1 - System Context Diagram
PicoClaw as a multi-agent platform within its ecosystem.
```mermaid
C4Context
title System Context - PicoClaw Multi-Agent Platform
Person(user, "User", "Interacts via messaging channels or CLI")
Person(dev, "Developer", "Configures agents, skills, and providers")
System(picoclaw, "PicoClaw", "Multi-agent AI platform that routes user messages to specialized agents backed by multiple LLM providers")
System_Ext(discord, "Discord", "Chat platform")
System_Ext(telegram, "Telegram", "Chat platform")
System_Ext(slack, "Slack", "Workspace messaging")
System_Ext(whatsapp, "WhatsApp", "Messaging")
System_Ext(cli, "CLI", "Direct terminal access")
System_Ext(openai, "OpenAI API", "GPT models, Codex")
System_Ext(anthropic, "Anthropic API", "Claude models")
System_Ext(gemini, "Google Gemini", "Gemini models")
System_Ext(openrouter, "OpenRouter", "Multi-model gateway")
System_Ext(groq, "Groq", "Fast inference")
System_Ext(ollama, "Ollama", "Local LLM")
System_Ext(claude_cli, "Claude Code CLI", "Subprocess provider")
System_Ext(codex_cli, "Codex CLI", "Subprocess provider")
Rel(user, discord, "Sends messages")
Rel(user, telegram, "Sends messages")
Rel(user, slack, "Sends messages")
Rel(user, whatsapp, "Sends messages")
Rel(user, cli, "Direct input")
Rel(dev, picoclaw, "Configures via config.json")
Rel(discord, picoclaw, "Webhook/Bot events")
Rel(telegram, picoclaw, "Bot API")
Rel(slack, picoclaw, "Events API")
Rel(whatsapp, picoclaw, "Webhook")
Rel(cli, picoclaw, "Stdin/Stdout")
Rel(picoclaw, openai, "HTTPS/REST")
Rel(picoclaw, anthropic, "HTTPS/REST")
Rel(picoclaw, gemini, "HTTPS/REST")
Rel(picoclaw, openrouter, "HTTPS/REST")
Rel(picoclaw, groq, "HTTPS/REST")
Rel(picoclaw, ollama, "HTTP localhost")
Rel(picoclaw, claude_cli, "Subprocess stdio")
Rel(picoclaw, codex_cli, "Subprocess stdio")
```
## Key interactions
| Boundary | Protocol | Direction |
|----------|----------|-----------|
| User -> Channels | Platform-native (Discord bot, Telegram bot, etc.) | Inbound |
| Channels -> PicoClaw | Go channel bus (`pkg/bus`) | Internal |
| PicoClaw -> LLM Providers | HTTPS REST / Subprocess stdio | Outbound |
| Developer -> PicoClaw | `~/.picoclaw/config.json` + workspace files | Config |

View file

@ -0,0 +1,58 @@
# C2 - Container Diagram
Runtime containers inside PicoClaw.
```mermaid
C4Container
title Container Diagram - PicoClaw Runtime
Person(user, "User")
System_Boundary(picoclaw, "PicoClaw Process") {
Container(gateway, "Gateway", "Go HTTP server", "Exposes health/ready endpoints, manages lifecycle")
Container(channel_mgr, "Channel Manager", "pkg/channels", "Manages Discord, Telegram, Slack, WhatsApp, CLI connections")
Container(msg_bus, "Message Bus", "pkg/bus", "Pub/sub event bus routing messages between channels and agents")
Container(agent_loop, "Agent Loop", "pkg/agent", "Core orchestrator: routes messages to agents, manages tool loops, sessions")
Container(registry, "Agent Registry", "pkg/agent", "Stores AgentInstance configs, resolves agent by ID or route")
Container(router, "Route Resolver", "pkg/routing", "Matches incoming messages to agents based on channel/chat/peer bindings")
Container(multiagent, "Multi-Agent Framework", "pkg/multiagent", "Blackboard shared context, Handoff mechanism, Agent discovery tools")
Container(tools, "Tool Registry", "pkg/tools", "Shell, file, web, session, message, spawn, exec tools")
Container(providers, "Provider Layer", "pkg/providers", "LLM provider abstraction: HTTP, CLI, OAuth, Fallback chain")
Container(session, "Session Store", "pkg/session", "Per-agent session persistence with conversation history")
Container(skills, "Skills Engine", "pkg/skills", "Loads SKILL.md files, provides skill tools to agents")
Container(config, "Config", "pkg/config", "Loads config.json, agent definitions, model_list")
}
System_Ext(llm, "LLM Providers", "OpenAI, Anthropic, Gemini, Groq, Ollama, Claude CLI, Codex CLI")
System_Ext(channels_ext, "Messaging Platforms", "Discord, Telegram, Slack, WhatsApp")
Rel(user, channels_ext, "Sends message")
Rel(channels_ext, channel_mgr, "Delivers event")
Rel(channel_mgr, msg_bus, "Publishes message")
Rel(msg_bus, agent_loop, "Delivers to agent")
Rel(agent_loop, router, "Resolves target agent")
Rel(agent_loop, registry, "Gets AgentInstance")
Rel(agent_loop, multiagent, "Blackboard sync, Handoff")
Rel(agent_loop, tools, "Executes tool calls")
Rel(agent_loop, session, "Load/save history")
Rel(agent_loop, skills, "Resolves skill tools")
Rel(agent_loop, providers, "LLM Chat()")
Rel(providers, llm, "API calls")
Rel(gateway, agent_loop, "Lifecycle management")
Rel(config, agent_loop, "Agent definitions")
Rel(config, providers, "Provider config")
Rel(config, registry, "AgentConfig list")
```
## Container responsibilities
| Container | Package | Key types |
|-----------|---------|-----------|
| Agent Loop | `pkg/agent` | `AgentLoop`, `RunToolLoop()` |
| Agent Registry | `pkg/agent` | `AgentRegistry`, `AgentInstance` |
| Route Resolver | `pkg/routing` | `RouteResolver`, `SessionKeyBuilder` |
| Multi-Agent | `pkg/multiagent` | `Blackboard`, `HandoffTool`, `ListAgentsTool` |
| Provider Layer | `pkg/providers` | `LLMProvider`, `FallbackChain`, `HTTPProvider` |
| Tool Registry | `pkg/tools` | `Tool`, `ContextualTool`, `AsyncTool` |
| Session Store | `pkg/session` | `SessionStore`, conversation history |
| Config | `pkg/config` | `Config`, `AgentConfig`, `ModelConfig` |

View file

@ -0,0 +1,264 @@
# C3 - Component Diagram: Multi-Agent Framework
Detailed view of the multi-agent collaboration components.
## Core Multi-Agent Components
```mermaid
C4Component
title Component Diagram - Multi-Agent Collaboration (pkg/multiagent + pkg/agent)
Container_Boundary(agent_pkg, "pkg/agent") {
Component(loop, "AgentLoop", "loop.go", "Core orchestrator: tool loop, LLM calls, session management")
Component(registry, "AgentRegistry", "registry.go", "Stores AgentInstance map, resolves by ID, lists all agents")
Component(instance, "AgentInstance", "instance.go", "Per-agent config: ID, Name, Role, SystemPrompt, tools, workspace")
Component(resolver_adapter, "registryResolver", "loop.go", "Adapter: bridges AgentRegistry to multiagent.AgentResolver interface")
}
Container_Boundary(multiagent_pkg, "pkg/multiagent") {
Component(blackboard, "Blackboard", "blackboard.go", "Thread-safe shared key-value store with author/scope/timestamp metadata")
Component(bb_tool, "BlackboardTool", "blackboard_tool.go", "LLM tool: read/write/list/delete on shared context")
Component(handoff, "ExecuteHandoff", "handoff.go", "Resolves target agent, writes context to blackboard, delegates via RunToolLoop")
Component(handoff_tool, "HandoffTool", "handoff_tool.go", "LLM tool: delegates sub-task to another agent with optional context")
Component(list_tool, "ListAgentsTool", "list_agents_tool.go", "LLM tool: returns all registered agents with ID/Name/Role")
Component(agent_resolver, "AgentResolver", "handoff.go", "Interface: GetAgentInfo(id), ListAgents() - decouples from pkg/agent")
}
Container_Boundary(routing_pkg, "pkg/routing") {
Component(route_resolver, "RouteResolver", "route.go", "Matches message to agent based on channel/chat/peer bindings")
Component(session_key, "SessionKeyBuilder", "session_key.go", "Builds per-agent session keys from channel+chat+agent")
Component(agent_id, "AgentID", "agent_id.go", "Normalizes agent identifiers")
}
Container_Boundary(providers_pkg, "pkg/providers") {
Component(fallback, "FallbackChain", "fallback.go", "Tries candidates in order, skips cooled-down, classifies errors")
Component(cooldown, "CooldownTracker", "cooldown.go", "Per-model failure tracking with exponential backoff")
Component(error_cls, "ErrorClassifier", "error_classifier.go", "Maps HTTP errors to FailoverReason: rate_limit, billing, auth, etc.")
Component(factory, "CreateProvider", "factory.go", "Resolves config to provider: HTTP, CLI, OAuth, Fallback")
}
Rel(loop, registry, "GetInstance(agentID)")
Rel(loop, resolver_adapter, "Creates on init")
Rel(resolver_adapter, registry, "Delegates to")
Rel(resolver_adapter, agent_resolver, "Implements")
Rel(loop, blackboard, "getOrCreateBlackboard(sessionKey)")
Rel(loop, bb_tool, "Registers when >1 agent")
Rel(loop, handoff_tool, "Registers when >1 agent")
Rel(loop, list_tool, "Registers when >1 agent")
Rel(handoff_tool, handoff, "Calls ExecuteHandoff()")
Rel(handoff, agent_resolver, "GetAgentInfo(targetID)")
Rel(handoff, blackboard, "Writes handoff context")
Rel(handoff, loop, "Calls RunToolLoop() for target agent")
Rel(bb_tool, blackboard, "CRUD operations")
Rel(list_tool, agent_resolver, "ListAgents()")
Rel(loop, route_resolver, "ResolveAgent(msg)")
Rel(loop, session_key, "BuildKey(channel, chat, agent)")
Rel(loop, fallback, "Chat() with fallback")
Rel(fallback, cooldown, "Check/update cooldown")
Rel(fallback, error_cls, "ClassifyError()")
```
## Blackboard Data Model
```mermaid
classDiagram
class Blackboard {
-entries map[string]BlackboardEntry
-mu sync.RWMutex
+Set(key, value, author, scope)
+Get(key) string
+GetEntry(key) BlackboardEntry
+Delete(key)
+List() []BlackboardEntry
+Snapshot() string
+Size() int
+MarshalJSON() []byte
+UnmarshalJSON([]byte)
}
class BlackboardEntry {
+Key string
+Value string
+Author string
+Scope string
+Timestamp time.Time
}
class BlackboardTool {
-board *Blackboard
-agentID string
+Name() string
+Execute(args) string
}
class HandoffRequest {
+TargetAgentID string
+Task string
+Context map[string]string
+SessionKey string
}
class HandoffResult {
+AgentID string
+Response string
+Success bool
+Error string
}
class AgentResolver {
<<interface>>
+GetAgentInfo(agentID) *AgentInfo
+ListAgents() []AgentInfo
}
class AgentInfo {
+ID string
+Name string
+Role string
+SystemPrompt string
}
Blackboard "1" --> "*" BlackboardEntry : stores
BlackboardTool --> Blackboard : operates on
HandoffRequest ..> AgentResolver : resolved via
AgentResolver --> AgentInfo : returns
```
## Agent Registry & Instance Model
```mermaid
classDiagram
class AgentRegistry {
-agents map[string]*AgentInstance
-defaultID string
+Register(instance)
+GetInstance(id) *AgentInstance
+GetDefault() *AgentInstance
+ListAgentIDs() []string
}
class AgentInstance {
+ID string
+Name string
+Role string
+SystemPrompt string
+Workspace string
+Model string
+Skills []string
+Tools []Tool
+AllowedSubagents []string
}
class AgentConfig {
+ID string
+Default bool
+Name string
+Role string
+SystemPrompt string
+Workspace string
+Model *AgentModelConfig
+Skills []string
+Subagents *SubagentsConfig
}
class RouteResolver {
-bindings []AgentBinding
+ResolveAgent(channel, chatID, peerKind, peerID) string
}
class FallbackChain {
-primary ModelRef
-fallbacks []ModelRef
-cooldown *CooldownTracker
+Chat(ctx, messages, tools, model, opts) *LLMResponse
}
AgentRegistry "1" --> "*" AgentInstance : manages
AgentConfig ..> AgentInstance : creates
AgentInstance --> FallbackChain : uses for LLM calls
RouteResolver --> AgentRegistry : resolves agent from
```
## Provider Protocol Architecture (PR #213 + #283)
```mermaid
graph TB
subgraph "Config Layer"
CFG[config.json]
ML[model_list - future]
end
subgraph "Factory (factory.go)"
RS[resolveProviderSelection]
CP[CreateProvider]
end
subgraph "Protocol Families"
subgraph "OpenAI-Compatible"
OC[openai_compat/provider.go]
HTTP[HTTPProvider - thin delegate]
end
subgraph "Anthropic"
ANT[anthropic/provider.go]
CP2[ClaudeProvider]
end
subgraph "CLI-Based"
CC[ClaudeCliProvider]
CX[CodexCliProvider]
end
subgraph "OAuth/Token"
CA[CodexProvider - OAuth]
CL[ClaudeProvider - OAuth]
end
subgraph "Resilience"
FB[FallbackChain]
CD[CooldownTracker]
EC[ErrorClassifier]
end
end
subgraph "External LLMs"
OPENAI[OpenAI]
GROQ[Groq]
DEEP[DeepSeek]
OR[OpenRouter]
ANTH[Anthropic]
GEM[Gemini]
OLL[Ollama]
CLICLI[claude CLI]
CODCLI[codex CLI]
end
CFG --> RS
ML -.-> RS
RS --> CP
CP --> HTTP
CP --> ANT
CP --> CC
CP --> CX
CP --> CA
CP --> CL
HTTP --> OC
OC --> OPENAI
OC --> GROQ
OC --> DEEP
OC --> OR
OC --> OLL
ANT --> ANTH
CP2 --> ANTH
OC --> GEM
CC --> CLICLI
CX --> CODCLI
CA --> OPENAI
FB --> CD
FB --> EC
FB -.-> HTTP
FB -.-> ANT
```

View file

@ -0,0 +1,148 @@
# C4 - Code Detail
Key interfaces, structs, and data flows at the code level.
## Core Interfaces
```mermaid
classDiagram
class LLMProvider {
<<interface>>
+Chat(ctx, messages, tools, model, opts) *LLMResponse
+GetDefaultModel() string
}
class Tool {
<<interface>>
+Name() string
+Description() string
+Parameters() map[string]any
+Execute(args map[string]any) (string, error)
}
class ContextualTool {
<<interface>>
+SetContext(ctx ToolContext)
}
class AsyncTool {
<<interface>>
+ExecuteAsync(ctx, args) (string, error)
}
class AgentResolver {
<<interface>>
+GetAgentInfo(agentID string) *AgentInfo
+ListAgents() []AgentInfo
}
Tool <|-- ContextualTool
Tool <|-- AsyncTool
LLMProvider <|.. HTTPProvider
LLMProvider <|.. ClaudeCliProvider
LLMProvider <|.. CodexCliProvider
LLMProvider <|.. CodexProvider
LLMProvider <|.. ClaudeProvider
LLMProvider <|.. FallbackChain
Tool <|.. BlackboardTool
Tool <|.. HandoffTool
Tool <|.. ListAgentsTool
ContextualTool <|.. HandoffTool
AgentResolver <|.. registryResolver
```
## Tool Loop Execution
```mermaid
flowchart TD
MSG[Incoming Message] --> RR[RouteResolver.ResolveAgent]
RR --> AI[AgentInstance selected]
AI --> SL[Session.Load history]
SL --> SP[Build system prompt]
SP --> BS{Multi-agent?}
BS -->|Yes| INJ[Inject Blackboard snapshot into system prompt]
BS -->|No| LLM
INJ --> LLM[provider.Chat - send to LLM]
LLM --> RESP{Response type?}
RESP -->|Text only| OUT[Return text to channel]
RESP -->|Tool calls| TC[Execute tool calls]
TC --> WHICH{Which tool?}
WHICH -->|blackboard| BB[BlackboardTool.Execute]
BB --> WL[Read/Write/List/Delete shared context]
WL --> LLM
WHICH -->|handoff| HO[HandoffTool.Execute]
HO --> EH[ExecuteHandoff]
EH --> TA[Resolve target agent]
TA --> WC[Write context to blackboard]
WC --> RTL[RunToolLoop for target agent]
RTL --> HR[HandoffResult]
HR --> LLM
WHICH -->|list_agents| LA[ListAgentsTool.Execute]
LA --> LLM
WHICH -->|shell, file, web...| OT[Other tools execute]
OT --> LLM
RESP -->|stop| SS[Session.Save]
SS --> OUT
```
## Blackboard Lifecycle
```mermaid
stateDiagram-v2
[*] --> Empty: getOrCreateBlackboard(sessionKey)
Empty --> HasEntries: Agent writes via BlackboardTool
HasEntries --> HasEntries: Agent reads/writes/deletes
HasEntries --> Snapshot: System prompt build
Snapshot --> HasEntries: Snapshot injected, loop continues
HasEntries --> HandoffContext: Handoff writes "handoff_context_*"
HandoffContext --> TargetReads: Target agent reads context
TargetReads --> HasEntries: Target completes, result written
HasEntries --> Empty: All entries deleted
Empty --> [*]: Session ends
note right of Snapshot
Snapshot format:
## Shared Context
- key1: value1 (by agent-a)
- key2: value2 (by agent-b)
end note
```
## Fallback Chain Decision Tree
```mermaid
flowchart TD
REQ[Chat Request] --> P[Try Primary Model]
P --> PS{Success?}
PS -->|Yes| RST[Reset cooldown] --> RET[Return response]
PS -->|No| CLS[ClassifyError]
CLS --> RT{Retriable?}
RT -->|No: auth, format| FAIL[Return error immediately]
RT -->|Yes| NXT[Next candidate]
NXT --> CD{In cooldown?}
CD -->|Yes| SKIP[Skip, try next]
CD -->|No| TRY[Try candidate]
SKIP --> MORE{More candidates?}
TRY --> TS{Success?}
TS -->|Yes| RST2[Reset cooldown] --> RET
TS -->|No| REC[Record failure, update cooldown]
REC --> MORE
MORE -->|Yes| NXT
MORE -->|No| EXHAUST[FallbackExhaustedError]
```

View file

@ -0,0 +1,104 @@
# Multi-Agent Feature Roadmap
Phased implementation plan based on issues #294, #283, and discussion #122.
## Phase Overview
```mermaid
gantt
title PicoClaw Multi-Agent Roadmap
dateFormat YYYY-MM-DD
axisFormat %b %d
section Provider Refactor (#283)
Phase 1: Protocol packages (PR #213) :done, p1, 2026-02-01, 2026-02-18
Phase 2: model_list + explicit api_type :active, p2, 2026-02-19, 2026-03-05
Phase 3: Independent Gemini protocol :p3, after p2, 7d
Phase 4: Local LLM + cleanup :p4, after p3, 5d
section Multi-Agent (#294)
Fallback chain + routing (PR #131) :done, ma1, 2026-02-01, 2026-02-18
Blackboard + Handoff + Discovery (PR #423) :active, ma2, 2026-02-18, 2026-03-01
Swarm mode (async agent negotiation) :ma3, after ma2, 14d
Visual AIEOS dashboard :ma4, after ma3, 14d
section Integration
model_list + multi-agent config merge :int1, after p2, 7d
Community agent marketplace :int2, after ma3, 21d
```
## Detailed Status
### Done
| Phase | PR | Description |
|-------|----|-------------|
| Provider Protocol Refactor | [#213](https://github.com/sipeed/picoclaw/pull/213) | `protocoltypes/`, `openai_compat/`, `anthropic/` packages, thin delegates, factory refactor |
| Fallback Chain + Routing | [#131](https://github.com/sipeed/picoclaw/pull/131) | `FallbackChain`, `CooldownTracker`, `ErrorClassifier`, `AgentRegistry`, `RouteResolver`, `AgentInstance`, channel peer metadata |
### In Progress (PR #423)
| Component | Package | Files | Status |
|-----------|---------|-------|--------|
| Agent Config extensions | `pkg/config` | `config.go` | `Role`, `SystemPrompt` fields added |
| Blackboard shared context | `pkg/multiagent` | `blackboard.go`, `blackboard_tool.go` | Complete, 18 tests |
| Agent Handoff | `pkg/multiagent` | `handoff.go`, `handoff_tool.go` | Complete, 10 tests |
| Agent Discovery | `pkg/multiagent` | `list_agents_tool.go` | Complete |
| AgentLoop integration | `pkg/agent` | `loop.go` | Snapshot injection, tool registration, per-session blackboards |
| AgentResolver interface | `pkg/multiagent` | `handoff.go` | Decouples multiagent from agent pkg |
### Next: Provider Phase 2 - `model_list` (#283)
Based on @yinwm's design in [issue #283](https://github.com/sipeed/picoclaw/issues/283#issuecomment-3915867555):
```
model_list config -> model-centric resolution -> protocol prefix routing
```
| Task | Description | Impact |
|------|-------------|--------|
| `ModelConfig` struct | `model_name`, `model` (protocol/id), `api_base`, `api_key` | Eliminates per-vendor code changes |
| Protocol prefix routing | `openai/`, `anthropic/`, `antigravity/` prefixes | Clean protocol selection |
| Backward compatibility | Support both `providers` (deprecated) and `model_list` | Smooth migration |
| Agent model reference | Agents reference `model_name` instead of `provider` + `model` | Simplifies multi-agent config |
### Future: Out of Scope for #294
| Feature | Issue | Depends on |
|---------|-------|------------|
| Intelligent Model Routing (small/large model token saving) | TBD | model_list + multi-agent |
| Swarm Mode (autonomous agent-to-agent negotiation) | TBD | Handoff foundation |
| Visual AIEOS Dashboard | TBD | All above |
| Community Agent Marketplace | TBD | Stable agent interface |
## Dependency Graph
```mermaid
graph TD
PR213[PR #213: Protocol Refactor]:::done --> PR131[PR #131: Fallback + Routing]:::done
PR131 --> PR423[PR #423: Blackboard + Handoff]:::active
PR213 --> P2[Phase 2: model_list]:::planned
P2 --> P3[Phase 3: Gemini Protocol]:::planned
P3 --> P4[Phase 4: Local LLM]:::planned
PR423 --> SWARM[Swarm Mode]:::future
PR423 --> P2
P2 --> MCONFIG[model_list + multi-agent config merge]:::planned
SWARM --> DASH[AIEOS Dashboard]:::future
MCONFIG --> MARKET[Agent Marketplace]:::future
classDef done fill:#22c55e,color:#fff
classDef active fill:#eab308,color:#000
classDef planned fill:#3b82f6,color:#fff
classDef future fill:#6b7280,color:#fff
```
## Key Decisions
| Decision | Choice | Rationale |
|----------|--------|-----------|
| Shared context pattern | Blackboard (key-value) | Simple, auditable, no coupling between agents |
| Handoff mechanism | Synchronous via RunToolLoop | Predictable, debuggable; async deferred to Swarm Mode |
| Circular import avoidance | `AgentResolver` interface in pkg/multiagent | Clean dependency direction: agent -> multiagent, not reverse |
| Multi-agent tool activation | Conditional on `len(agents) > 1` | Zero overhead for single-agent setups |
| Provider abstraction | Protocol-first (openai_compat, anthropic) | Adding new OpenAI-compat providers = config only |
| Config evolution | model_list (LiteLLM-inspired) | Model-centric aligns with multi-agent where agents pick models |

View file

@ -0,0 +1,204 @@
# Sequence Diagrams
Runtime interaction flows for multi-agent collaboration.
## 1. Agent Handoff Flow
A main agent delegates a sub-task to a specialized agent.
```mermaid
sequenceDiagram
participant U as User (Discord/Telegram)
participant CH as Channel Manager
participant AL as AgentLoop
participant RR as RouteResolver
participant MA as Main Agent
participant LLM as LLM Provider
participant HT as HandoffTool
participant BB as Blackboard
participant AR as AgentResolver
participant SA as Specialized Agent
U->>CH: "Translate this code to Python"
CH->>AL: Message{channel, chat_id, content}
AL->>RR: ResolveAgent(channel, chat_id)
RR-->>AL: "main"
AL->>MA: Load AgentInstance + session
AL->>BB: getOrCreateBlackboard(sessionKey)
AL->>AL: Inject BB snapshot into system prompt
AL->>LLM: Chat(messages + tools)
LLM-->>AL: ToolCall{name: "handoff", args: {target: "coder", task: "translate to python"}}
AL->>HT: Execute(args)
HT->>AR: GetAgentInfo("coder")
AR-->>HT: AgentInfo{ID: "coder", Role: "Code Expert"}
HT->>BB: Set("handoff_context_coder", task + context)
HT->>AL: RunToolLoop(coderAgent, task)
AL->>SA: Load AgentInstance("coder")
AL->>LLM: Chat(coder_system_prompt + task)
LLM-->>AL: "Here's the Python translation..."
AL-->>HT: HandoffResult{Response: "...", Success: true}
HT-->>AL: Tool result string
AL->>LLM: Chat(messages + tool_result)
LLM-->>AL: "The coder agent translated your code: ..."
AL->>CH: Send response
CH->>U: "The coder agent translated your code: ..."
```
## 2. Blackboard Shared Context Flow
Multiple agents share data through the blackboard within a session.
```mermaid
sequenceDiagram
participant A1 as Agent: Researcher
participant BB as Blackboard
participant AL as AgentLoop
participant A2 as Agent: Writer
Note over A1, A2: Same session, shared blackboard
A1->>BB: BlackboardTool.write("findings", "3 key points...")
BB-->>A1: OK
A1->>BB: BlackboardTool.write("sources", "arxiv:2024...")
BB-->>A1: OK
Note over AL: Handoff from Researcher to Writer
AL->>BB: Snapshot()
BB-->>AL: "findings: 3 key points... (by researcher)\nsources: arxiv:2024... (by researcher)"
AL->>A2: System prompt + snapshot + task
A2->>BB: BlackboardTool.read("findings")
BB-->>A2: "3 key points..."
A2->>BB: BlackboardTool.read("sources")
BB-->>A2: "arxiv:2024..."
A2->>BB: BlackboardTool.write("draft", "Article based on findings...")
BB-->>A2: OK
Note over BB: Blackboard state:<br/>findings (by researcher)<br/>sources (by researcher)<br/>draft (by writer)
```
## 3. Model Fallback Chain Flow
Provider resilience with automatic failover.
```mermaid
sequenceDiagram
participant AL as AgentLoop
participant FB as FallbackChain
participant CD as CooldownTracker
participant EC as ErrorClassifier
participant P1 as Primary: GPT-4o
participant P2 as Fallback: Claude-3.5
participant P3 as Fallback: DeepSeek
AL->>FB: Chat(messages)
FB->>CD: IsAvailable("gpt-4o")?
CD-->>FB: Yes
FB->>P1: Chat(messages)
P1-->>FB: Error 429 (rate limit)
FB->>EC: ClassifyError(err)
EC-->>FB: FailoverReason: RATE_LIMITED (retriable)
FB->>CD: RecordFailure("gpt-4o", RATE_LIMITED)
Note over CD: gpt-4o cooldown: 30s
FB->>CD: IsAvailable("claude-3.5")?
CD-->>FB: Yes
FB->>P2: Chat(messages)
P2-->>FB: Error 503 (overloaded)
FB->>EC: ClassifyError(err)
EC-->>FB: FailoverReason: OVERLOADED (retriable)
FB->>CD: RecordFailure("claude-3.5", OVERLOADED)
FB->>CD: IsAvailable("deepseek")?
CD-->>FB: Yes
FB->>P3: Chat(messages)
P3-->>FB: LLMResponse{Content: "..."}
FB->>CD: RecordSuccess("deepseek")
FB-->>AL: LLMResponse
```
## 4. Route Resolution Flow
How incoming messages are routed to the correct agent.
```mermaid
sequenceDiagram
participant MSG as Incoming Message
participant RR as RouteResolver
participant REG as AgentRegistry
participant SK as SessionKeyBuilder
MSG->>RR: ResolveAgent(channel:"discord", chat:"123", peer_kind:"guild", peer_id:"456")
RR->>RR: Check bindings
Note over RR: Binding: {channel: "discord", chat: "123"} -> "support-agent"
alt Match found
RR-->>MSG: "support-agent"
else No match
RR->>REG: GetDefault()
REG-->>RR: "main"
RR-->>MSG: "main"
end
MSG->>SK: BuildKey(channel, chat, agentID)
SK-->>MSG: "discord:123:support-agent"
Note over MSG: Session key used for:<br/>- Session history<br/>- Blackboard lookup<br/>- State persistence
```
## 5. Multi-Agent Configuration Lifecycle
From config.json to running agents.
```mermaid
sequenceDiagram
participant CFG as config.json
participant REG as AgentRegistry
participant INST as AgentInstance
participant LOOP as AgentLoop
participant TOOLS as Tool Registry
CFG->>REG: Parse agents.list[]
loop For each AgentConfig
REG->>INST: NewAgentInstance(agentCfg, cfg)
INST->>INST: Set ID, Name, Role, SystemPrompt
INST->>INST: Create per-agent tools (shell, file, exec)
INST-->>REG: Register(instance)
end
alt No agents.list configured
REG->>INST: Create implicit "main" agent
INST-->>REG: Register as default
end
REG-->>LOOP: Registry ready
LOOP->>LOOP: Check registry.ListAgentIDs()
alt len(agents) > 1
LOOP->>TOOLS: Register BlackboardTool
LOOP->>TOOLS: Register HandoffTool
LOOP->>TOOLS: Register ListAgentsTool
Note over TOOLS: Multi-agent tools active
else Single agent
Note over TOOLS: No multi-agent tools (zero overhead)
end
```