P1-1: 硬编码 wechat URL 抽常量统一两处
- config/mod.rs: 定义 pub const WECHAT_DEFAULT_BASE_URL
- cli/init.rs: import 并引用常量,消除字面量重复
- 消除两处不一致风险(default_wechat_base_url 与 init 向导)
P1-2: ConfigPage any 类型定义具体类型(8 处)
- types.ts: 新增 FeishuChannelConfig/WechatChannelConfig/ChannelConfig/
SchedulerJobConfig 类型;jobs?: any[] → SchedulerJobConfig[];
channels: Record<string, any> → Record<string, ChannelConfig>
- api/config.ts: 新增 RestartResponse 类型,data: any → RestartResponse
- ConfigPage.tsx: catch (e: any) ×2 → catch (e: unknown) + 类型守卫;
as any → as SchedulerConfig['misfire_policy'];
Record<string, any> → Partial<ChannelConfig>;(ch: any) → (ch: ChannelConfig)
P1-3: dead_code 18 处逐一审查清理
- 删除 10 处未使用函数/struct(YAGNI 原则):
context_compressor.rs (into_messages, is_tool_round)
agent_loop.rs (EmptySkillProvider struct + impl)
memory_maintenance.rs (run_for_scope)
session.rs (try_start/finish_background_compaction)
session_history.rs (try_start/finish_background_compaction)
tool_registry_factory.rs (shell_session_manager)
task/runtime.rs (effective_allowed_tools)
- 保留 8 处 serde 反序列化字段(删除会破坏 JSON 反序列化):
feishu.rs/openai.rs/anthropic.rs/skills/mod.rs/task/runtime.rs
244 lines
8.1 KiB
Rust
244 lines
8.1 KiB
Rust
use std::collections::{HashMap, HashSet};
|
||
use std::sync::Arc;
|
||
|
||
use tokio::sync::RwLock;
|
||
|
||
use crate::config::TaskConfig;
|
||
use crate::mcp::McpClientManager;
|
||
use crate::skills::SkillRuntime;
|
||
use crate::storage::{MemoryRepository, SchedulerJobRepository, SkillEventRepository, TodoRepository};
|
||
use crate::tools::todo_write::TodoItem;
|
||
use crate::tools::{
|
||
BashTool, CalculatorTool, FileEditTool, FileReadTool, FileWriteTool,
|
||
HttpRequestTool, MemoryManageTool, MemorySearchTool,
|
||
SchedulerManageTool, SessionMessageSender, SessionSendTool, ShellSessionManager,
|
||
SkillActivateTool, SkillManageTool, SubAgentRuntime, TaskTool, TimeTool,
|
||
TodoReadTool, TodoWriteTool, ToolRegistry, WebFetchTool,
|
||
};
|
||
|
||
pub(crate) struct ToolRegistryFactory {
|
||
skills: Arc<SkillRuntime>,
|
||
memories: Arc<dyn MemoryRepository>,
|
||
scheduler_jobs: Arc<dyn SchedulerJobRepository>,
|
||
skill_events: Arc<dyn SkillEventRepository>,
|
||
todo_repository: Arc<dyn TodoRepository>,
|
||
session_message_sender: Arc<dyn SessionMessageSender>,
|
||
known_agents: HashSet<String>,
|
||
default_timezone: String,
|
||
disabled_tools: HashSet<String>,
|
||
task_config: TaskConfig,
|
||
subagent_runtime: Option<Arc<dyn SubAgentRuntime>>,
|
||
mcp_manager: Option<Arc<McpClientManager>>,
|
||
todo_state: Option<Arc<RwLock<HashMap<String, Vec<TodoItem>>>>>,
|
||
shell_session_manager: Arc<ShellSessionManager>,
|
||
}
|
||
|
||
impl ToolRegistryFactory {
|
||
pub(crate) fn new(
|
||
skills: Arc<SkillRuntime>,
|
||
memories: Arc<dyn MemoryRepository>,
|
||
scheduler_jobs: Arc<dyn SchedulerJobRepository>,
|
||
skill_events: Arc<dyn SkillEventRepository>,
|
||
todo_repository: Arc<dyn TodoRepository>,
|
||
session_message_sender: Arc<dyn SessionMessageSender>,
|
||
known_agents: HashSet<String>,
|
||
default_timezone: String,
|
||
disabled_tools: HashSet<String>,
|
||
task_config: TaskConfig,
|
||
) -> Self {
|
||
Self {
|
||
skills,
|
||
memories,
|
||
scheduler_jobs,
|
||
skill_events,
|
||
todo_repository,
|
||
session_message_sender,
|
||
known_agents,
|
||
default_timezone,
|
||
disabled_tools,
|
||
task_config,
|
||
subagent_runtime: None,
|
||
mcp_manager: None,
|
||
todo_state: None,
|
||
shell_session_manager: Arc::new(ShellSessionManager::new()),
|
||
}
|
||
}
|
||
|
||
pub(crate) fn with_todo_state(
|
||
mut self,
|
||
state: Arc<RwLock<HashMap<String, Vec<TodoItem>>>>,
|
||
) -> Self {
|
||
self.todo_state = Some(state);
|
||
self
|
||
}
|
||
|
||
pub(crate) fn with_subagent_runtime(
|
||
mut self,
|
||
runtime: Arc<dyn SubAgentRuntime>,
|
||
) -> Self {
|
||
self.subagent_runtime = Some(runtime);
|
||
self
|
||
}
|
||
|
||
pub(crate) fn with_mcp_manager(
|
||
mut self,
|
||
manager: Arc<McpClientManager>,
|
||
) -> Self {
|
||
self.mcp_manager = Some(manager);
|
||
self
|
||
}
|
||
|
||
pub(crate) fn is_enabled(&self, tool_name: &str) -> bool {
|
||
!self.disabled_tools.contains(tool_name)
|
||
}
|
||
|
||
pub(crate) fn build(&self) -> ToolRegistry {
|
||
let registry = ToolRegistry::new();
|
||
|
||
if self.is_enabled("calculator") {
|
||
registry.register(CalculatorTool::new());
|
||
}
|
||
if self.is_enabled("get_time") {
|
||
registry.register(TimeTool::new(self.default_timezone.clone()));
|
||
}
|
||
if self.is_enabled("read") {
|
||
registry.register(FileReadTool::new());
|
||
}
|
||
if self.is_enabled("write") {
|
||
registry.register(FileWriteTool::new());
|
||
}
|
||
if self.is_enabled("edit") {
|
||
registry.register(FileEditTool::new());
|
||
}
|
||
if self.is_enabled("memory_search") {
|
||
registry.register(MemorySearchTool::new(self.memories.clone()));
|
||
}
|
||
if self.is_enabled("memory_manage") {
|
||
registry.register(MemoryManageTool::new(self.memories.clone()));
|
||
}
|
||
if self.is_enabled("todo_write") {
|
||
if let Some(ref state) = self.todo_state {
|
||
registry.register(TodoWriteTool::new(state.clone(), self.todo_repository.clone()));
|
||
registry.register(TodoReadTool::new(state.clone(), self.todo_repository.clone()));
|
||
}
|
||
}
|
||
if self.is_enabled("session_send") {
|
||
registry.register(SessionSendTool::new(self.session_message_sender.clone()));
|
||
}
|
||
if self.is_enabled("scheduler_manage") {
|
||
registry.register(SchedulerManageTool::new(
|
||
self.scheduler_jobs.clone(),
|
||
self.known_agents.clone(),
|
||
));
|
||
}
|
||
if self.is_enabled("skill_activate") {
|
||
registry.register(SkillActivateTool::new(
|
||
self.skills.clone(),
|
||
self.skill_events.clone(),
|
||
));
|
||
}
|
||
if self.is_enabled("skill_manage") {
|
||
registry.register(SkillManageTool::new(self.skills.clone()));
|
||
}
|
||
if self.is_enabled("bash") {
|
||
registry.register(BashTool::new(self.shell_session_manager.clone()));
|
||
}
|
||
if self.is_enabled("http_request") {
|
||
registry.register(HttpRequestTool::new(
|
||
vec!["*".to_string()],
|
||
1_000_000,
|
||
30,
|
||
false,
|
||
));
|
||
}
|
||
if self.is_enabled("web_fetch") {
|
||
registry.register(WebFetchTool::new(50_000, 30));
|
||
}
|
||
|
||
// 注册 Task 工具(如果启用且有 subagent_runtime)
|
||
if self.is_enabled("task") && self.task_config.enabled {
|
||
if let Some(runtime) = &self.subagent_runtime {
|
||
registry.register(TaskTool::new(runtime.clone(), None));
|
||
}
|
||
}
|
||
|
||
registry
|
||
}
|
||
|
||
/// 构建子代理专用工具集
|
||
/// 可选地包含 MCP 工具(通过 mcp_tools 参数传递)
|
||
/// 注意:task 工具由调用方在 runtime 就绪后通过 registry.register() 单独注册
|
||
pub(crate) fn build_subagent_tools(
|
||
&self,
|
||
mcp_tools: Option<Vec<crate::mcp::tool_adapter::McpToolWrapper>>,
|
||
) -> ToolRegistry {
|
||
let registry = ToolRegistry::new();
|
||
|
||
// 基础工具
|
||
if self.is_enabled("calculator") {
|
||
registry.register(CalculatorTool::new());
|
||
}
|
||
if self.is_enabled("get_time") {
|
||
registry.register(TimeTool::new(self.default_timezone.clone()));
|
||
}
|
||
if self.is_enabled("read") {
|
||
registry.register(FileReadTool::new());
|
||
}
|
||
if self.is_enabled("write") {
|
||
registry.register(FileWriteTool::new());
|
||
}
|
||
if self.is_enabled("edit") {
|
||
registry.register(FileEditTool::new());
|
||
}
|
||
if self.is_enabled("bash") {
|
||
registry.register(BashTool::new(self.shell_session_manager.clone()));
|
||
}
|
||
if self.is_enabled("http_request") {
|
||
registry.register(HttpRequestTool::new(
|
||
vec!["*".to_string()],
|
||
1_000_000,
|
||
30,
|
||
false,
|
||
));
|
||
}
|
||
if self.is_enabled("web_fetch") {
|
||
registry.register(WebFetchTool::new(50_000, 30));
|
||
}
|
||
|
||
// 记忆工具(只读)
|
||
if self.is_enabled("memory_search") {
|
||
registry.register(MemorySearchTool::new(self.memories.clone()));
|
||
}
|
||
|
||
// Skill 工具
|
||
if self.is_enabled("skill_activate") {
|
||
registry.register(SkillActivateTool::new(
|
||
self.skills.clone(),
|
||
self.skill_events.clone(),
|
||
));
|
||
}
|
||
|
||
// 进度通知工具
|
||
if self.is_enabled("session_send") {
|
||
registry.register(SessionSendTool::new(self.session_message_sender.clone()));
|
||
}
|
||
|
||
// Todo 追踪工具
|
||
if self.is_enabled("todo_write") {
|
||
if let Some(ref state) = self.todo_state {
|
||
registry.register(TodoWriteTool::new(state.clone(), self.todo_repository.clone()));
|
||
registry.register(TodoReadTool::new(state.clone(), self.todo_repository.clone()));
|
||
}
|
||
}
|
||
|
||
// 注册 MCP 工具(如果提供)
|
||
if let Some(mcp_tools) = mcp_tools {
|
||
for tool in mcp_tools {
|
||
registry.register(tool);
|
||
}
|
||
}
|
||
|
||
registry
|
||
}
|
||
}
|