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:
parent
c9a5769576
commit
38ff3b8aa5
7 changed files with 865 additions and 0 deletions
28
docs/architecture/README.md
Normal file
28
docs/architecture/README.md
Normal 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) |
|
||||||
59
docs/architecture/c1-system-context.md
Normal file
59
docs/architecture/c1-system-context.md
Normal 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 |
|
||||||
58
docs/architecture/c2-container.md
Normal file
58
docs/architecture/c2-container.md
Normal 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` |
|
||||||
264
docs/architecture/c3-component-multi-agent.md
Normal file
264
docs/architecture/c3-component-multi-agent.md
Normal 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
|
||||||
|
```
|
||||||
148
docs/architecture/c4-code-detail.md
Normal file
148
docs/architecture/c4-code-detail.md
Normal 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]
|
||||||
|
```
|
||||||
104
docs/architecture/roadmap.md
Normal file
104
docs/architecture/roadmap.md
Normal 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 |
|
||||||
204
docs/architecture/sequences.md
Normal file
204
docs/architecture/sequences.md
Normal 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
|
||||||
|
```
|
||||||
Loading…
Add table
Reference in a new issue