Documentation
¶
Index ¶
Constants ¶
const ( DefaultAgentID = "main" DefaultMainKey = "main" DefaultAccountID = "default" MaxAgentIDLength = 64 )
Variables ¶
This section is empty.
Functions ¶
func NormalizeAccountID ¶
NormalizeAccountID sanitizes an account ID. Empty returns DefaultAccountID.
func NormalizeAgentID ¶
NormalizeAgentID sanitizes an agent ID to [a-z0-9][a-z0-9_-]{0,63}. Invalid characters are collapsed to "-". Leading/trailing dashes stripped. Empty input returns DefaultAgentID ("main").
Types ¶
type Classifier ¶ added in v0.2.1
Classifier evaluates a feature set and returns a complexity score in [0, 1]. A higher score indicates a more complex task that benefits from a heavy model. The score is compared against the configured threshold: score >= threshold selects the primary (heavy) model; score < threshold selects the light model.
Classifier is an interface so that future implementations (ML-based, embedding-based, or any other approach) can be swapped in without changing routing infrastructure.
type Features ¶ added in v0.2.1
type Features struct {
// TokenEstimate is a proxy for token count.
// CJK runes count as 1 token each; non-CJK runes as 0.25 tokens each.
// This avoids API calls while giving accurate estimates for all scripts.
TokenEstimate int
// CodeBlockCount is the number of fenced code blocks (“` pairs) in the message.
// Coding tasks almost always require the heavy model.
CodeBlockCount int
// RecentToolCalls is the count of tool_call messages in the last lookbackWindow
// history entries. A high density indicates an active agentic workflow.
RecentToolCalls int
// ConversationDepth is the total number of messages in the session history.
// Deep sessions tend to carry implicit complexity built up over many turns.
ConversationDepth int
// HasAttachments is true when the message appears to contain media (images,
// audio, video). Multi-modal inputs require vision-capable heavy models.
HasAttachments bool
}
Features holds the structural signals extracted from a message and its session context. Every dimension is language-agnostic by construction — no keyword or pattern matching against natural-language content. This ensures consistent routing for all locales.
type ResolvedRoute ¶
type ResolvedRoute struct {
AgentID string
Channel string
AccountID string
SessionPolicy SessionPolicy
MatchedBy string
}
ResolvedRoute is the result of agent routing.
type RouteResolver ¶
type RouteResolver struct {
// contains filtered or unexported fields
}
RouteResolver determines which agent handles a message.
func NewRouteResolver ¶
func NewRouteResolver(cfg *config.Config) *RouteResolver
NewRouteResolver creates a new route resolver.
func (*RouteResolver) ResolveRoute ¶
func (r *RouteResolver) ResolveRoute(inbound bus.InboundContext) ResolvedRoute
ResolveRoute determines which agent handles the message from a normalized inbound context and returns the session policy that should be used to allocate session state.
type Router ¶ added in v0.2.1
type Router struct {
// contains filtered or unexported fields
}
Router selects the appropriate model tier for each incoming message. It is safe for concurrent use from multiple goroutines.
func New ¶ added in v0.2.1
func New(cfg RouterConfig) *Router
New creates a Router with the given config and the default RuleClassifier. If cfg.Threshold is zero or negative, defaultThreshold (0.35) is used.
func (*Router) LightModel ¶ added in v0.2.1
LightModel returns the configured light model name.
func (*Router) SelectModel ¶ added in v0.2.1
func (r *Router) SelectModel( msg string, history []providers.Message, primaryModel string, ) (model string, usedLight bool, score float64)
SelectModel returns the model to use for this conversation turn along with the computed complexity score (for logging and debugging).
- If score < cfg.Threshold: returns (cfg.LightModel, true, score)
- Otherwise: returns (primaryModel, false, score)
The caller is responsible for resolving the returned model name into provider candidates (see AgentInstance.LightCandidates).
type RouterConfig ¶ added in v0.2.1
type RouterConfig struct {
// LightModel is the model_name (from model_list) used for simple tasks.
LightModel string
// Threshold is the complexity score cutoff in [0, 1].
// score >= Threshold → primary (heavy) model.
// score < Threshold → light model.
Threshold float64
}
RouterConfig holds the validated model routing settings. It mirrors config.RoutingConfig but lives in pkg/routing to keep the dependency graph simple: pkg/agent resolves config → routing, not the reverse.
type RuleClassifier ¶ added in v0.2.1
type RuleClassifier struct{}
RuleClassifier is the v1 implementation. It uses a weighted sum of structural signals with no external dependencies, no API calls, and sub-microsecond latency. The raw sum is capped at 1.0 so that the returned score always falls within the [0, 1] contract.
Individual weights (multiple signals can fire simultaneously):
token > 200 (≈600 chars): 0.35 — very long prompts are almost always complex token 50-200: 0.15 — medium length; may or may not be complex code block present: 0.40 — coding tasks need the heavy model tool calls > 3 (recent): 0.25 — dense tool usage signals an agentic workflow tool calls 1-3 (recent): 0.10 — some tool activity conversation depth > 10: 0.10 — long sessions carry implicit complexity attachments present: 1.00 — hard gate; multi-modal always needs heavy model
Default threshold is 0.35, so:
- Pure greetings / trivial Q&A: 0.00 → light ✓
- Medium prose message (50–200 tokens): 0.15 → light ✓
- Message with code block: 0.40 → heavy ✓
- Long message (>200 tokens): 0.35 → heavy ✓
- Active tool session + medium message: 0.25 → light (acceptable)
- Any message with an image/audio attachment: 1.00 → heavy ✓
func (*RuleClassifier) Score ¶ added in v0.2.1
func (c *RuleClassifier) Score(f Features) float64
Score computes the complexity score for the given feature set. The returned value is in [0, 1]. Attachments short-circuit to 1.0.
type SessionPolicy ¶ added in v0.2.7
SessionPolicy describes how a routed message should be mapped to a session.