feat(agent): add rule-based query classification for automatic model routing

Classify incoming user messages by keyword/pattern and route to the
appropriate model hint automatically, feeding into the existing
RouterProvider. Disabled by default; opt-in via [query_classification]
config section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Edvard 2026-02-17 19:53:37 -05:00 committed by Chummy
parent 1336c2f03e
commit 6e53341bb1
6 changed files with 260 additions and 8 deletions

View file

@ -3,13 +3,13 @@ pub mod schema;
#[allow(unused_imports)]
pub use schema::{
AgentConfig, AuditConfig, AutonomyConfig, BrowserComputerUseConfig, BrowserConfig,
ChannelsConfig, ComposioConfig, Config, CostConfig, CronConfig, DelegateAgentConfig,
DiscordConfig, DockerRuntimeConfig, GatewayConfig, HardwareConfig, HardwareTransport,
HeartbeatConfig, HttpRequestConfig, IMessageConfig, IdentityConfig, LarkConfig, MatrixConfig,
MemoryConfig, ModelRouteConfig, ObservabilityConfig, PeripheralBoardConfig, PeripheralsConfig,
ReliabilityConfig, ResourceLimitsConfig, RuntimeConfig, SandboxBackend, SandboxConfig,
SchedulerConfig, SecretsConfig, SecurityConfig, SlackConfig, TelegramConfig, TunnelConfig,
WebhookConfig,
ChannelsConfig, ClassificationRule, ComposioConfig, Config, CostConfig, CronConfig,
DelegateAgentConfig, DiscordConfig, DockerRuntimeConfig, GatewayConfig, HardwareConfig,
HardwareTransport, HeartbeatConfig, HttpRequestConfig, IMessageConfig, IdentityConfig,
LarkConfig, MatrixConfig, MemoryConfig, ModelRouteConfig, ObservabilityConfig,
PeripheralBoardConfig, PeripheralsConfig, QueryClassificationConfig, ReliabilityConfig,
ResourceLimitsConfig, RuntimeConfig, SandboxBackend, SandboxConfig, SchedulerConfig,
SecretsConfig, SecurityConfig, SlackConfig, TelegramConfig, TunnelConfig, WebhookConfig,
};
#[cfg(test)]

View file

@ -47,6 +47,10 @@ pub struct Config {
#[serde(default)]
pub model_routes: Vec<ModelRouteConfig>,
/// Automatic query classification — maps user messages to model hints.
#[serde(default)]
pub query_classification: QueryClassificationConfig,
#[serde(default)]
pub heartbeat: HeartbeatConfig,
@ -1205,6 +1209,40 @@ pub struct ModelRouteConfig {
pub api_key: Option<String>,
}
// ── Query Classification ─────────────────────────────────────────
/// Automatic query classification — classifies user messages by keyword/pattern
/// and routes to the appropriate model hint. Disabled by default.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct QueryClassificationConfig {
#[serde(default)]
pub enabled: bool,
#[serde(default)]
pub rules: Vec<ClassificationRule>,
}
/// A single classification rule mapping message patterns to a model hint.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ClassificationRule {
/// Must match a `[[model_routes]]` hint value.
pub hint: String,
/// Case-insensitive substring matches.
#[serde(default)]
pub keywords: Vec<String>,
/// Case-sensitive literal matches (for "```", "fn ", etc.).
#[serde(default)]
pub patterns: Vec<String>,
/// Only match if message length >= N chars.
#[serde(default)]
pub min_length: Option<usize>,
/// Only match if message length <= N chars.
#[serde(default)]
pub max_length: Option<usize>,
/// Higher priority rules are checked first.
#[serde(default)]
pub priority: i32,
}
// ── Heartbeat ────────────────────────────────────────────────────
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -1740,6 +1778,7 @@ impl Default for Config {
peripherals: PeripheralsConfig::default(),
agents: HashMap::new(),
hardware: HardwareConfig::default(),
query_classification: QueryClassificationConfig::default(),
}
}
}