routing

package
v0.2.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 21, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DefaultAgentID   = "main"
	DefaultMainKey   = "main"
	DefaultAccountID = "default"
	MaxAgentIDLength = 64
)

Variables

This section is empty.

Functions

func NormalizeAccountID

func NormalizeAccountID(id string) string

NormalizeAccountID sanitizes an account ID. Empty returns DefaultAccountID.

func NormalizeAgentID

func NormalizeAgentID(id string) string

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

type Classifier interface {
	Score(f Features) float64
}

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.

func ExtractFeatures added in v0.2.1

func ExtractFeatures(msg string, history []providers.Message) Features

ExtractFeatures computes the structural feature vector for a message. It is a pure function with no side effects and zero allocations beyond the returned struct.

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

func (r *Router) LightModel() string

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).

func (*Router) Threshold added in v0.2.1

func (r *Router) Threshold() float64

Threshold returns the complexity threshold in use.

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

type SessionPolicy struct {
	Dimensions    []string
	IdentityLinks map[string][]string
}

SessionPolicy describes how a routed message should be mapped to a session.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL