feat(butler): upgrade ButlerRouter to semantic skill routing
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

Replace keyword-only ButlerRouter with SemanticSkillRouter (TF-IDF).
75 skills now participate in intent classification instead of 4 hardcoded domains.

- Expose ButlerRouterBackend trait + RoutingHint as pub
- Add with_router() constructor for injecting custom backends
- Add SemanticRouterAdapter in kernel layer (bridges skills ↔ runtime)
- Enhance context injection with skill-level match info
This commit is contained in:
iven
2026-04-10 21:24:30 +08:00
parent 88cac9557b
commit 1e675947d5
2 changed files with 69 additions and 8 deletions

View File

@@ -193,7 +193,40 @@ impl Kernel {
// Butler router — semantic skill routing context injection
{
use std::sync::Arc;
let mw = zclaw_runtime::middleware::butler_router::ButlerRouterMiddleware::new();
use zclaw_runtime::middleware::butler_router::{ButlerRouterBackend, RoutingHint};
use async_trait::async_trait;
use zclaw_skills::semantic_router::SemanticSkillRouter;
/// Adapter bridging `SemanticSkillRouter` (zclaw-skills) to `ButlerRouterBackend`.
/// Lives here in kernel because kernel depends on both zclaw-runtime and zclaw-skills.
struct SemanticRouterAdapter {
router: Arc<SemanticSkillRouter>,
}
impl SemanticRouterAdapter {
fn new(router: Arc<SemanticSkillRouter>) -> Self {
Self { router }
}
}
#[async_trait]
impl ButlerRouterBackend for SemanticRouterAdapter {
async fn classify(&self, query: &str) -> Option<RoutingHint> {
let result: Option<_> = self.router.route(query).await;
result.map(|r| RoutingHint {
category: "semantic_skill".to_string(),
confidence: r.confidence,
skill_id: Some(r.skill_id),
})
}
}
// Build semantic router from the skill registry (75 SKILL.md loaded at boot)
let semantic_router = SemanticSkillRouter::new_tf_idf_only(self.skills.clone());
let adapter = SemanticRouterAdapter::new(Arc::new(semantic_router));
let mw = zclaw_runtime::middleware::butler_router::ButlerRouterMiddleware::with_router(
Box::new(adapter)
);
chain.register(Arc::new(mw));
}