diff --git a/_primitives/_rust/kei-auth/src/tokens.rs b/_primitives/_rust/kei-auth/src/tokens.rs index 7164fda..42011d0 100644 --- a/_primitives/_rust/kei-auth/src/tokens.rs +++ b/_primitives/_rust/kei-auth/src/tokens.rs @@ -43,27 +43,41 @@ pub fn issue( ) -> Result { let now = Utc::now().timestamp(); let expires_at = now + ttl_secs; + let payload = new_payload(user_id, project, scope, expires_at); + let token = encode_token(&payload, key)?; + persist_token(conn, &token, user_id, project, scope, expires_at, now)?; + Ok(token) +} + +fn new_payload(user_id: &str, project: &str, scope: Scope, expires_at: i64) -> Payload { let mut raw = [0u8; 16]; rand::thread_rng().fill_bytes(&mut raw); let tid = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(raw); - let payload = Payload { - tid: tid.clone(), + Payload { + tid, user_id: user_id.into(), project: project.into(), scope: scope.to_string(), expires_at, - }; - let body = serde_json::to_vec(&payload)?; + } +} + +fn encode_token(payload: &Payload, key: &[u8]) -> Result { + let body = serde_json::to_vec(payload)?; let body_b64 = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(&body); let sig = sign(key, body_b64.as_bytes()); - let token = format!("{}.{}", body_b64, sig); + Ok(format!("{}.{}", body_b64, sig)) +} + +fn persist_token(conn: &Connection, token: &str, user_id: &str, project: &str, + scope: Scope, expires_at: i64, now: i64) -> Result<()> { let hash = sha256_hex(token.as_bytes()); conn.execute( "INSERT INTO auth_tokens (token_hash, user_id, project, scope, expires_at, created_at) VALUES (?1,?2,?3,?4,?5,?6)", params![hash, user_id, project, scope.as_str(), expires_at, now], )?; - Ok(token) + Ok(()) } /// Verify a token: signature valid, not revoked, not expired, returns identity + scope. diff --git a/_primitives/_rust/kei-router/src/keywords.rs b/_primitives/_rust/kei-router/src/keywords.rs index f39e7c8..86773b5 100644 --- a/_primitives/_rust/kei-router/src/keywords.rs +++ b/_primitives/_rust/kei-router/src/keywords.rs @@ -1,9 +1,13 @@ -//! Default keyword tables. Each function returns a static slice of rules. +//! Default keyword tables — aggregated from per-domain cubes. //! //! Ordering matters — more-specific multi-word keywords must come before //! single-word matches on the same tool family. -use crate::rules::*; +use crate::kw_tables::{ + CHAT_RULES, CODE_RULES, CONTENT_RULES, CROSS_RULES, CURATOR_RULES, + SAGE_RULES, SEARCH_RULES, SOCIAL_RULES, TASK_RULES, +}; +use crate::rules::KeywordRule; pub fn default_rules() -> Vec { let mut rules = Vec::with_capacity(128); @@ -18,200 +22,3 @@ pub fn default_rules() -> Vec { rules.extend_from_slice(&SEARCH_RULES); rules } - -// --- sage ----------------------------------------------------------------- -const SAGE_RULES: [KeywordRule; 13] = [ - KeywordRule { tool: "find_related_knowledge", - keywords: &["related_knowledge", "related knowledge", "vault related"], require: always }, - KeywordRule { tool: "search_knowledge", - keywords: &["search_knowledge", "search knowledge", "vault search", "find in vault", "knowledge search"], require: always }, - KeywordRule { tool: "get_unit", - keywords: &["get_unit", "get unit", "show unit", "read unit"], require: always }, - KeywordRule { tool: "get_unit", keywords: &["unit"], require: has_id }, - KeywordRule { tool: "list_units", - keywords: &["list_units", "list units", "show units", "all units"], require: always }, - KeywordRule { tool: "get_unit_graph", - keywords: &["unit_graph", "unit graph", "knowledge graph", "vault graph"], require: always }, - KeywordRule { tool: "knowledge_stats", - keywords: &["knowledge_stats", "knowledge stats", "vault stats"], require: always }, - KeywordRule { tool: "add_note", - keywords: &["add_note", "add note", "create note", "new note"], require: always }, - KeywordRule { tool: "update_note", - keywords: &["update_note", "update note", "edit note"], require: has_id }, - KeywordRule { tool: "grade_evidence", - keywords: &["grade_evidence", "grade evidence", "set grade", "evidence grade"], require: has_id }, - KeywordRule { tool: "link_units", - keywords: &["link_units", "link units", "connect units", "create edge"], require: always }, - KeywordRule { tool: "import_vault", - keywords: &["import_vault", "import vault", "import obsidian"], require: has_path }, - KeywordRule { tool: "sync_vault", - keywords: &["sync_vault", "sync vault", "sync obsidian"], require: always }, -]; - -// --- code ----------------------------------------------------------------- -const CODE_RULES: [KeywordRule; 17] = [ - KeywordRule { tool: "get_architecture", - keywords: &["architecture", "arch", "overview", "project overview", "get_architecture"], require: has_path }, - KeywordRule { tool: "find_importers", - keywords: &["importer", "importers", "who imports", "depends on", "reverse dep", "find_importers"], require: has_path }, - KeywordRule { tool: "find_tests", - keywords: &["test file", "find_tests", "find tests", "test for"], require: has_path }, - KeywordRule { tool: "get_change_impact", - keywords: &["impact", "change_impact", "change impact", "refactor impact", "get_change_impact"], require: has_path }, - KeywordRule { tool: "get_file_info", - keywords: &["file_info", "file info", "get_file_info"], require: has_path }, - KeywordRule { tool: "find_similar", - keywords: &["similar", "find_similar", "like this file"], require: has_path }, - KeywordRule { tool: "get_related_files", - keywords: &["related", "get_related", "get_related_files"], require: has_path }, - KeywordRule { tool: "get_edges", - keywords: &["edges", "get_edges", "dependencies of"], require: has_path }, - KeywordRule { tool: "batch_edges", - keywords: &["batch", "batch_edges"], require: has_paths }, - KeywordRule { tool: "check_patterns", - keywords: &["lint", "check_pattern", "check_patterns", "constructor pattern", "loc check"], require: has_path }, - KeywordRule { tool: "suggest_files", - keywords: &["suggest", "suggest_files", "next file", "what to open"], require: has_path }, - KeywordRule { tool: "hot_files", - keywords: &["hot file", "hottest", "hot_files", "most connected"], require: always }, - KeywordRule { tool: "ranked_files", - keywords: &["ranked", "pagerank", "ranked_files", "important files", "central files"], require: always }, - KeywordRule { tool: "graph_stats", - keywords: &["graph_stats", "graph stats", "edge count", "code stats"], require: always }, - KeywordRule { tool: "add_root", - keywords: &["add_root", "add root", "add scan root"], require: has_path }, - KeywordRule { tool: "list_roots", - keywords: &["list_roots", "list roots", "scan roots", "show roots"], require: always }, - KeywordRule { tool: "search_code", - keywords: &["search_code", "search code", "find code", "grep", "fts"], require: always }, -]; - -// --- task ----------------------------------------------------------------- -const TASK_RULES: [KeywordRule; 9] = [ - KeywordRule { tool: "search_tasks", - keywords: &["search_tasks", "search task", "find task", "task search"], require: always }, - KeywordRule { tool: "get_task", - keywords: &["get_task", "get task", "task detail"], require: has_id }, - KeywordRule { tool: "task_graph", - keywords: &["task_graph", "task graph", "task deps"], require: always }, - KeywordRule { tool: "task_stats", - keywords: &["task_stats", "task stats", "task statistics"], require: always }, - KeywordRule { tool: "dependency_chain", - keywords: &["dependency_chain", "dep chain", "critical path"], require: always }, - KeywordRule { tool: "create_task", - keywords: &["create_task", "create task", "new task", "add task"], require: always }, - KeywordRule { tool: "update_task", - keywords: &["update_task", "update task"], require: has_id }, - KeywordRule { tool: "add_dependency", - keywords: &["add_dependency", "add dep", "task depends"], require: always }, - KeywordRule { tool: "create_milestone", - keywords: &["create_milestone", "create milestone", "new milestone"], require: always }, -]; - -// --- chat ----------------------------------------------------------------- -const CHAT_RULES: [KeywordRule; 9] = [ - KeywordRule { tool: "search_chat", - keywords: &["search_chat", "search chat", "find in chat", "chat search"], require: always }, - KeywordRule { tool: "get_session", - keywords: &["get_session", "chat session", "get session"], require: has_any_id_or_query }, - KeywordRule { tool: "list_sessions", - keywords: &["list_sessions", "list sessions", "list chats", "chat history", "my chats"], require: always }, - KeywordRule { tool: "chat_stats", - keywords: &["chat_stats", "chat stats", "chat analytics"], require: always }, - KeywordRule { tool: "chat_model_usage", - keywords: &["chat_model_usage", "model usage", "token usage"], require: always }, - KeywordRule { tool: "start_chat", - keywords: &["start_chat", "new chat", "start chat", "create session"], require: always }, - KeywordRule { tool: "save_message", - keywords: &["save_message", "save message", "log message"], require: always }, - KeywordRule { tool: "archive_chat", - keywords: &["archive_chat", "archive chat", "close chat"], require: has_any_id_or_query }, - KeywordRule { tool: "link_chat", - keywords: &["link_chat", "link chat", "connect chat"], require: always }, -]; - -// --- content, social, cross, curator, search ------------------------------- -const CONTENT_RULES: [KeywordRule; 8] = [ - KeywordRule { tool: "search_content", - keywords: &["search_content", "search content", "find content", "content search"], require: always }, - KeywordRule { tool: "get_asset", - keywords: &["get_asset", "get asset", "asset detail"], require: has_id }, - KeywordRule { tool: "content_lineage", - keywords: &["content_lineage", "content lineage", "asset lineage"], require: always }, - KeywordRule { tool: "content_stats", - keywords: &["content_stats", "content stats", "content statistics"], require: always }, - KeywordRule { tool: "prompt_history", - keywords: &["prompt_history", "prompt history", "prompt log"], require: always }, - KeywordRule { tool: "register_asset", - keywords: &["register_asset", "register asset", "new asset", "add asset"], require: always }, - KeywordRule { tool: "register_prompt", - keywords: &["register_prompt", "register prompt", "new prompt", "add prompt"], require: always }, - KeywordRule { tool: "create_campaign", - keywords: &["create_campaign", "create campaign", "new campaign", "add campaign"], require: always }, -]; - -const SOCIAL_RULES: [KeywordRule; 8] = [ - KeywordRule { tool: "search_people", - keywords: &["search_people", "search people", "find people", "people search"], require: always }, - KeywordRule { tool: "get_person", - keywords: &["get_person", "get person", "person detail"], require: has_id }, - KeywordRule { tool: "relationship_graph", - keywords: &["relationship_graph", "relationship graph", "social graph"], require: always }, - KeywordRule { tool: "social_stats", - keywords: &["social_stats", "social stats", "social statistics"], require: always }, - KeywordRule { tool: "add_person", - keywords: &["add_person", "add person", "new person"], require: always }, - KeywordRule { tool: "add_org", - keywords: &["add_org", "add org", "new org", "add organization"], require: always }, - KeywordRule { tool: "log_interaction", - keywords: &["log_interaction", "log interaction", "record interaction"], require: always }, - KeywordRule { tool: "link_people", - keywords: &["link_people", "link people", "connect people"], require: always }, -]; - -const CROSS_RULES: [KeywordRule; 8] = [ - KeywordRule { tool: "cross_search", - keywords: &["cross_search", "cross search", "search cross", "cross-domain search"], require: always }, - KeywordRule { tool: "cross_graph", - keywords: &["cross_graph", "cross graph", "cross-domain graph", "connected across"], require: always }, - KeywordRule { tool: "cross_edges", - keywords: &["cross_edges", "cross edges", "inter-domain edges"], require: always }, - KeywordRule { tool: "cross_stats", - keywords: &["cross_stats", "cross stats", "cross-domain stats"], require: always }, - KeywordRule { tool: "domain_cooccurrence", - keywords: &["domain_cooccurrence", "cooccurrence", "domain cooccurrence"], require: always }, - KeywordRule { tool: "cross_link", - keywords: &["cross_link", "link domain", "cross link"], require: always }, - KeywordRule { tool: "cross_unlink", - keywords: &["cross_unlink", "unlink domain", "cross unlink"], require: always }, - KeywordRule { tool: "cross_auto_link", - keywords: &["cross_auto_link", "auto link", "discover links"], require: always }, -]; - -const CURATOR_RULES: [KeywordRule; 3] = [ - KeywordRule { tool: "curator_status", - keywords: &["curator_status", "curator status", "curation status", "curation"], require: always }, - KeywordRule { tool: "curator_check", - keywords: &["curator_check", "curator check", "curator dry-run", "curator preview"], require: always }, - KeywordRule { tool: "curator_run", - keywords: &["curator_run", "curator run", "run curator"], require: always }, -]; - -const SEARCH_RULES: [KeywordRule; 8] = [ - KeywordRule { tool: "search_research", - keywords: &["search_research", "search research", "find research", "past research"], require: always }, - KeywordRule { tool: "get_research", - keywords: &["get_research", "get research", "research detail", "show research"], require: has_id }, - KeywordRule { tool: "research_sources", - keywords: &["research_sources", "research sources", "sources for research"], require: has_id }, - KeywordRule { tool: "research_claims", - keywords: &["research_claims", "research claims", "validated claims", "claims for"], require: has_id }, - KeywordRule { tool: "search_stats", - keywords: &["search_stats", "search stats", "research statistics", "research stats"], require: always }, - KeywordRule { tool: "run_research", - keywords: &["run_research", "deep research", "research:", "investigate:", "research this"], require: always }, - KeywordRule { tool: "stop_research", - keywords: &["stop_research", "stop research", "cancel research"], require: has_id }, - KeywordRule { tool: "research_export", - keywords: &["research_export", "export research", "research markdown", "download research"], require: has_id }, -]; diff --git a/_primitives/_rust/kei-router/src/kw_tables.rs b/_primitives/_rust/kei-router/src/kw_tables.rs new file mode 100644 index 0000000..4f067a2 --- /dev/null +++ b/_primitives/_rust/kei-router/src/kw_tables.rs @@ -0,0 +1,197 @@ +//! Per-domain keyword rule tables. Split from `keywords.rs` for Constructor +//! Pattern <200 LOC compliance. Each table is a `const` slice so the whole +//! router is built at compile time — zero allocation hot-path. + +use crate::rules::{always, has_any_id_or_query, has_id, has_path, has_paths, KeywordRule}; + +pub const SAGE_RULES: [KeywordRule; 13] = [ + KeywordRule { tool: "find_related_knowledge", + keywords: &["related_knowledge", "related knowledge", "vault related"], require: always }, + KeywordRule { tool: "search_knowledge", + keywords: &["search_knowledge", "search knowledge", "vault search", "find in vault", "knowledge search"], require: always }, + KeywordRule { tool: "get_unit", + keywords: &["get_unit", "get unit", "show unit", "read unit"], require: always }, + KeywordRule { tool: "get_unit", keywords: &["unit"], require: has_id }, + KeywordRule { tool: "list_units", + keywords: &["list_units", "list units", "show units", "all units"], require: always }, + KeywordRule { tool: "get_unit_graph", + keywords: &["unit_graph", "unit graph", "knowledge graph", "vault graph"], require: always }, + KeywordRule { tool: "knowledge_stats", + keywords: &["knowledge_stats", "knowledge stats", "vault stats"], require: always }, + KeywordRule { tool: "add_note", + keywords: &["add_note", "add note", "create note", "new note"], require: always }, + KeywordRule { tool: "update_note", + keywords: &["update_note", "update note", "edit note"], require: has_id }, + KeywordRule { tool: "grade_evidence", + keywords: &["grade_evidence", "grade evidence", "set grade", "evidence grade"], require: has_id }, + KeywordRule { tool: "link_units", + keywords: &["link_units", "link units", "connect units", "create edge"], require: always }, + KeywordRule { tool: "import_vault", + keywords: &["import_vault", "import vault", "import obsidian"], require: has_path }, + KeywordRule { tool: "sync_vault", + keywords: &["sync_vault", "sync vault", "sync obsidian"], require: always }, +]; + +pub const CODE_RULES: [KeywordRule; 17] = [ + KeywordRule { tool: "get_architecture", + keywords: &["architecture", "arch", "overview", "project overview", "get_architecture"], require: has_path }, + KeywordRule { tool: "find_importers", + keywords: &["importer", "importers", "who imports", "depends on", "reverse dep", "find_importers"], require: has_path }, + KeywordRule { tool: "find_tests", + keywords: &["test file", "find_tests", "find tests", "test for"], require: has_path }, + KeywordRule { tool: "get_change_impact", + keywords: &["impact", "change_impact", "change impact", "refactor impact", "get_change_impact"], require: has_path }, + KeywordRule { tool: "get_file_info", + keywords: &["file_info", "file info", "get_file_info"], require: has_path }, + KeywordRule { tool: "find_similar", + keywords: &["similar", "find_similar", "like this file"], require: has_path }, + KeywordRule { tool: "get_related_files", + keywords: &["related", "get_related", "get_related_files"], require: has_path }, + KeywordRule { tool: "get_edges", + keywords: &["edges", "get_edges", "dependencies of"], require: has_path }, + KeywordRule { tool: "batch_edges", + keywords: &["batch", "batch_edges"], require: has_paths }, + KeywordRule { tool: "check_patterns", + keywords: &["lint", "check_pattern", "check_patterns", "constructor pattern", "loc check"], require: has_path }, + KeywordRule { tool: "suggest_files", + keywords: &["suggest", "suggest_files", "next file", "what to open"], require: has_path }, + KeywordRule { tool: "hot_files", + keywords: &["hot file", "hottest", "hot_files", "most connected"], require: always }, + KeywordRule { tool: "ranked_files", + keywords: &["ranked", "pagerank", "ranked_files", "important files", "central files"], require: always }, + KeywordRule { tool: "graph_stats", + keywords: &["graph_stats", "graph stats", "edge count", "code stats"], require: always }, + KeywordRule { tool: "add_root", + keywords: &["add_root", "add root", "add scan root"], require: has_path }, + KeywordRule { tool: "list_roots", + keywords: &["list_roots", "list roots", "scan roots", "show roots"], require: always }, + KeywordRule { tool: "search_code", + keywords: &["search_code", "search code", "find code", "grep", "fts"], require: always }, +]; + +pub const TASK_RULES: [KeywordRule; 9] = [ + KeywordRule { tool: "search_tasks", + keywords: &["search_tasks", "search task", "find task", "task search"], require: always }, + KeywordRule { tool: "get_task", + keywords: &["get_task", "get task", "task detail"], require: has_id }, + KeywordRule { tool: "task_graph", + keywords: &["task_graph", "task graph", "task deps"], require: always }, + KeywordRule { tool: "task_stats", + keywords: &["task_stats", "task stats", "task statistics"], require: always }, + KeywordRule { tool: "dependency_chain", + keywords: &["dependency_chain", "dep chain", "critical path"], require: always }, + KeywordRule { tool: "create_task", + keywords: &["create_task", "create task", "new task", "add task"], require: always }, + KeywordRule { tool: "update_task", + keywords: &["update_task", "update task"], require: has_id }, + KeywordRule { tool: "add_dependency", + keywords: &["add_dependency", "add dep", "task depends"], require: always }, + KeywordRule { tool: "create_milestone", + keywords: &["create_milestone", "create milestone", "new milestone"], require: always }, +]; + +pub const CHAT_RULES: [KeywordRule; 9] = [ + KeywordRule { tool: "search_chat", + keywords: &["search_chat", "search chat", "find in chat", "chat search"], require: always }, + KeywordRule { tool: "get_session", + keywords: &["get_session", "chat session", "get session"], require: has_any_id_or_query }, + KeywordRule { tool: "list_sessions", + keywords: &["list_sessions", "list sessions", "list chats", "chat history", "my chats"], require: always }, + KeywordRule { tool: "chat_stats", + keywords: &["chat_stats", "chat stats", "chat analytics"], require: always }, + KeywordRule { tool: "chat_model_usage", + keywords: &["chat_model_usage", "model usage", "token usage"], require: always }, + KeywordRule { tool: "start_chat", + keywords: &["start_chat", "new chat", "start chat", "create session"], require: always }, + KeywordRule { tool: "save_message", + keywords: &["save_message", "save message", "log message"], require: always }, + KeywordRule { tool: "archive_chat", + keywords: &["archive_chat", "archive chat", "close chat"], require: has_any_id_or_query }, + KeywordRule { tool: "link_chat", + keywords: &["link_chat", "link chat", "connect chat"], require: always }, +]; + +pub const CONTENT_RULES: [KeywordRule; 8] = [ + KeywordRule { tool: "search_content", + keywords: &["search_content", "search content", "find content", "content search"], require: always }, + KeywordRule { tool: "get_asset", + keywords: &["get_asset", "get asset", "asset detail"], require: has_id }, + KeywordRule { tool: "content_lineage", + keywords: &["content_lineage", "content lineage", "asset lineage"], require: always }, + KeywordRule { tool: "content_stats", + keywords: &["content_stats", "content stats", "content statistics"], require: always }, + KeywordRule { tool: "prompt_history", + keywords: &["prompt_history", "prompt history", "prompt log"], require: always }, + KeywordRule { tool: "register_asset", + keywords: &["register_asset", "register asset", "new asset", "add asset"], require: always }, + KeywordRule { tool: "register_prompt", + keywords: &["register_prompt", "register prompt", "new prompt", "add prompt"], require: always }, + KeywordRule { tool: "create_campaign", + keywords: &["create_campaign", "create campaign", "new campaign", "add campaign"], require: always }, +]; + +pub const SOCIAL_RULES: [KeywordRule; 8] = [ + KeywordRule { tool: "search_people", + keywords: &["search_people", "search people", "find people", "people search"], require: always }, + KeywordRule { tool: "get_person", + keywords: &["get_person", "get person", "person detail"], require: has_id }, + KeywordRule { tool: "relationship_graph", + keywords: &["relationship_graph", "relationship graph", "social graph"], require: always }, + KeywordRule { tool: "social_stats", + keywords: &["social_stats", "social stats", "social statistics"], require: always }, + KeywordRule { tool: "add_person", + keywords: &["add_person", "add person", "new person"], require: always }, + KeywordRule { tool: "add_org", + keywords: &["add_org", "add org", "new org", "add organization"], require: always }, + KeywordRule { tool: "log_interaction", + keywords: &["log_interaction", "log interaction", "record interaction"], require: always }, + KeywordRule { tool: "link_people", + keywords: &["link_people", "link people", "connect people"], require: always }, +]; + +pub const CROSS_RULES: [KeywordRule; 8] = [ + KeywordRule { tool: "cross_search", + keywords: &["cross_search", "cross search", "search cross", "cross-domain search"], require: always }, + KeywordRule { tool: "cross_graph", + keywords: &["cross_graph", "cross graph", "cross-domain graph", "connected across"], require: always }, + KeywordRule { tool: "cross_edges", + keywords: &["cross_edges", "cross edges", "inter-domain edges"], require: always }, + KeywordRule { tool: "cross_stats", + keywords: &["cross_stats", "cross stats", "cross-domain stats"], require: always }, + KeywordRule { tool: "domain_cooccurrence", + keywords: &["domain_cooccurrence", "cooccurrence", "domain cooccurrence"], require: always }, + KeywordRule { tool: "cross_link", + keywords: &["cross_link", "link domain", "cross link"], require: always }, + KeywordRule { tool: "cross_unlink", + keywords: &["cross_unlink", "unlink domain", "cross unlink"], require: always }, + KeywordRule { tool: "cross_auto_link", + keywords: &["cross_auto_link", "auto link", "discover links"], require: always }, +]; + +pub const CURATOR_RULES: [KeywordRule; 3] = [ + KeywordRule { tool: "curator_status", + keywords: &["curator_status", "curator status", "curation status", "curation"], require: always }, + KeywordRule { tool: "curator_check", + keywords: &["curator_check", "curator check", "curator dry-run", "curator preview"], require: always }, + KeywordRule { tool: "curator_run", + keywords: &["curator_run", "curator run", "run curator"], require: always }, +]; + +pub const SEARCH_RULES: [KeywordRule; 8] = [ + KeywordRule { tool: "search_research", + keywords: &["search_research", "search research", "find research", "past research"], require: always }, + KeywordRule { tool: "get_research", + keywords: &["get_research", "get research", "research detail", "show research"], require: has_id }, + KeywordRule { tool: "research_sources", + keywords: &["research_sources", "research sources", "sources for research"], require: has_id }, + KeywordRule { tool: "research_claims", + keywords: &["research_claims", "research claims", "validated claims", "claims for"], require: has_id }, + KeywordRule { tool: "search_stats", + keywords: &["search_stats", "search stats", "research statistics", "research stats"], require: always }, + KeywordRule { tool: "run_research", + keywords: &["run_research", "deep research", "research:", "investigate:", "research this"], require: always }, + KeywordRule { tool: "stop_research", + keywords: &["stop_research", "stop research", "cancel research"], require: has_id }, + KeywordRule { tool: "research_export", + keywords: &["research_export", "export research", "research markdown", "download research"], require: has_id }, +]; diff --git a/_primitives/_rust/kei-router/src/lib.rs b/_primitives/_rust/kei-router/src/lib.rs index 62d7450..d19cd6a 100644 --- a/_primitives/_rust/kei-router/src/lib.rs +++ b/_primitives/_rust/kei-router/src/lib.rs @@ -12,6 +12,7 @@ pub mod extract; pub mod keywords; +pub mod kw_tables; pub mod router; pub mod rules;