feat: model fallback chain + multi-agent routing#131
Open
Leeaandrob wants to merge 6 commits intosipeed:mainfrom
Open
feat: model fallback chain + multi-agent routing#131Leeaandrob wants to merge 6 commits intosipeed:mainfrom
Leeaandrob wants to merge 6 commits intosipeed:mainfrom
Conversation
Add 2-layer fallback system (text + image) with automatic candidate resolution. Includes error classifier (~40 patterns), per-provider cooldown (exponential backoff), and model reference parsing. - FailoverError/FailoverReason types for structured error handling - ErrorClassifier with rate_limit, billing, auth, timeout patterns - FallbackChain with cooldown management and candidate rotation - ModelRef parser for provider/model string format - 128 tests, 95%+ coverage
Implement per-agent workspace/model/session isolation with 7-level priority routing cascade (peer > parent_peer > guild > team > account > channel > default). Backward compatible - empty agents.list creates implicit "main" agent from defaults. Core components: - routing/agent_id.go: ID normalization with pre-compiled regex - routing/session_key.go: 4 DM scope modes with identity links - routing/route.go: RouteResolver with priority-based binding matcher - agent/instance.go: Per-agent state (workspace, sessions, tools, model) - agent/registry.go: Agent lifecycle, route resolution, subagent ACL Integration: - config.go: AgentModelConfig (flexible JSON), bindings, session config - loop.go: Complete rewrite for multi-agent dispatch - Channel adapters: peer_kind/peer_id metadata (telegram, discord, slack) - spawn.go: Subagent allowlist enforcement per agent Validated end-to-end with Discord channel-based bindings, default fallback routing, and per-agent session persistence.
Resolve conflicts in loop.go, config.go, config_test.go, spawn.go, and subagent.go. Integrate upstream ToolResult/AsyncTool pattern with multi-agent routing features. Rename mockProvider to mockRegistryProvider in registry_test.go to avoid redeclaration with upstream's loop_test.go.
Remove extra spaces in comment alignment to pass fmt-check CI.
8 tasks
Update registerSharedTools to use new WebSearchToolOptions API and add hardware tools (I2C, SPI) from upstream. Accept upstream's new web tools config test.
Resolve conflicts: - pkg/agent/loop.go: integrate context compression, command handling, utf8 token estimation, and summarization notification into multi-agent routing architecture - pkg/config/config_test.go: merge imports from both branches - pkg/agent/loop_test.go: update test to use registry-based sessions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This PR delivers two major features for PicoClaw, closing the gap with OpenClaw's production capabilities:
Both features are backward compatible — existing single-agent configs continue to work unchanged.
Feature 1: Model Fallback Chain
When a primary model fails (rate limit, billing, auth error, etc.), the system automatically rotates to the next available candidate.
What's included
pkg/providers/error_classifier.go) — ~40 regex patterns across 6 categories:rate_limit,billing,auth,context_length,content_filter,server_errorpkg/providers/cooldown.go) — Exponential backoff per model, separate billing cooldown (5h base), automatic recoverypkg/providers/fallback.go) — Candidate rotation, availability checks, transparent retrypkg/providers/model_ref.go) — Handlesprovider/modelformat and plain model namesConfig
{ "agents": { "defaults": { "model": "google/gemini-2.5-pro", "model_fallbacks": ["openai/gpt-4o", "anthropic/claude-sonnet"] } } }Tests
Feature 2: Multi-Agent Routing
Multiple agents with independent models, workspaces, sessions, and tools — routed by declarative bindings.
What's included
pkg/routing/route.go) — 7-level priority cascade:peer > parent_peer > guild > team > account > channel_wildcard > defaultpkg/agent/registry.go) — Lifecycle management, per-agent state isolation, subagent ACLpkg/agent/instance.go) — Per-agent container with workspace, model, session manager, toolspkg/routing/session_key.go) — 4 DM scopes:per-peer,per-channel,per-account,globalKind,ID,ParentID,GuildID)subagents.allow_agentsArchitecture
Config
{ "agents": { "defaults": { "model": "gpt-4", "model_fallbacks": ["gpt-4o-mini"] }, "list": [ { "id": "main", "default": true }, { "id": "cto", "model": { "primary": "claude-opus", "fallbacks": ["haiku"] }, "subagents": { "allow_agents": ["main"] } } ] }, "bindings": [ { "agent_id": "cto", "match": { "channel": "discord", "peer": { "kind": "channel", "id": "123456" } } } ], "session": { "dm_scope": "per-peer", "identity_links": { "john": ["telegram:123", "discord:456"] } } }Tests
Files changed (27 files)
New packages
pkg/routing/route.go,session_key.go,agent_id.go+ testspkg/providers/fallback.go,cooldown.go,error_classifier.go,model_ref.go+ testsModified
pkg/agent/loop.gopkg/config/config.goAgentsConfig.List,AgentBinding,SessionConfig,AgentModelConfigpkg/channels/telegram.gopkg/channels/discord.gopkg/channels/slack.gopkg/channels/base.goPeerInfostruct withKind,ID,ParentID,GuildIDpkg/tools/spawn.gopkg/tools/subagent.goNew
pkg/agent/instance.gopkg/agent/registry.gopkg/agent/registry_test.goValidation
go build ./...— cleango vet ./...— cleango test ./...— 44 tests passing (all packages)gofmt— formattedagents.listcreates implicit "main" agentCloses