clawseed-agent — Agent 核心运行时¶
概述¶
clawseed-agent 是 Agent 的核心 crate,负责工具调度、Hook 执行、安全策略、定时任务等。它是连接 Provider、Tool、Memory、Hook 的枢纽。
注意: 除了编排,此 crate 还承担运行时装配职责。
Agent::from_config_with_registry()直接实例化 provider(通过ProviderFactoryRegistry)、memory(通过clawseed_memory::create_memory())和 tools(通过clawseed_tools::registry::all_tools()),然后根据provider.supports_native_tools()选择调度器。tools 依赖 memory 先构造完成;调度器依赖 provider 能力。
核心结构¶
Agent — Agent 注册中心¶
pub struct Agent {
provider: Box<dyn Provider>,
tool_registry: Arc<dyn ToolRegistry>,
memory: Arc<dyn Memory>,
observer: Arc<dyn Observer>,
tool_dispatcher: Box<dyn ToolDispatcher>,
capabilities: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
workspace_dir: PathBuf,
// ...
}
Agent 是一个注册中心,通过 ToolRegistry trait 统一管理所有来源的工具(内置、MCP、远程),通过 HookRunner 管理 Hook 管线。核心代码不感知具体工具实现,扩展只需向注册表中添加条目。
MCP 注意事项:
crates/clawseed-agent/src/tools.rs中的所有 MCP 类型(McpRegistry、DeferredMcpToolSet、McpToolWrapper、ToolSearchTool)都是 stub——返回空集合或错误。ToolSource::Mcp枚举变体和McpConfigschema 已存在,但没有实际的 MCP 协议客户端。请勿将 MCP 视为可用能力。
AgentBuilder — 构建器¶
let agent = Agent::builder()
.provider(provider)
.tools(tools) // 方式一:传入工具列表,自动构建 DefaultToolRegistry
.tool_registry(registry) // 方式二:传入预构建的 ToolRegistry(优先级更高)
.memory(memory)
.observer(observer)
.tool_dispatcher(dispatcher)
.workspace_dir(path)
.allowed_tools(Some(vec!["file_*".into()])) // glob 模式工具白名单
.denied_tools(Some(vec!["shell".into()])) // glob 模式工具黑名单
.mcp_tool_filters(Some(filters)) // 按 MCP 服务器过滤
.hook_runner(Some(Arc::new(hook_runner))) // Hook 管线
.build()?;
// 从配置文件构建(可选传入自定义 ProviderFactoryRegistry)
let agent = Agent::from_config(&config).await?;
let agent = Agent::from_config_with_registry(&config, Some(provider_factory_registry)).await?;
模块架构¶
agent_loop.rs — Agent 循环入口¶
提供 Gateway 兼容的 turn() 调用接口:
- 接收用户消息
- 构建系统提示(调用
prompt.rs) - 发送至 LLM
- 解析响应
- 若包含工具调用 → 进入工具循环
- 返回最终文本响应
tool_loop.rs — 工具循环¶
管理工具循环的执行流程:
- 解析 LLM 响应中的工具调用
- 对每个工具调用执行 before_hook
- 执行工具
- 执行 after_hook
- 格式化结果,发送回 LLM
- 重复直到 LLM 返回纯文本
tool_execution.rs — 单次工具执行¶
- 工具通过
tool_registry.get_tool(name)查找(返回Arc<dyn Tool>,O(1) 哈希查找) - 包装工具执行,附带 Observer 事件记录、耗时测量、错误处理、取消支持
dispatcher.rs — 工具调度器¶
两种实现:
| 调度器 | 适用场景 | 工作方式 |
|---|---|---|
NativeToolDispatcher |
支持原生工具调用的 Provider | 直接从响应中提取 tool_calls |
XmlToolDispatcher |
不支持原生工具调用的 Provider | 先尝试 ◁▷ 格式,失败后 fallback 到多格式解析器 |
parser.rs — 工具调用解析器¶
多格式工具调用解析,支持 12+ 种 LLM 输出格式:
- OpenAI 原生 JSON
tool_calls数组 - XML 标签:
<tool_call>、<toolcall>、<tool-call>、<invoke> - MiniMax
<invoke>格式 - Markdown 代码块(
```tool_call) - Anthropic
<FunctionCall>标签 - GLM 缩短格式
- Perl/哈希引用风格
- xAI grok
```tool <name>格式
XmlToolDispatcher::parse_response() 先尝试 ◁▷ 格式(prompt 引导的确定性解析),失败后调用 parser::parse_tool_calls() 作为 fallback,用原始响应文本尝试多格式解析。
安全设计:不提取无显式包裹的原始 JSON,防止提示注入攻击。
context.rs — 工具上下文¶
pub struct AgentToolContext {
workspace_dir: PathBuf,
capabilities: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
}
impl ToolContext for AgentToolContext {
fn workspace_dir(&self) -> &Path { &self.workspace_dir }
fn get<T: 'static>(&self) -> Option<&T> {
self.capabilities.get(&TypeId::of::<T>())
.and_then(|arc| arc.downcast_ref::<T>())
}
}
hooks.rs — Hook 运行器¶
执行流程:
1. run_before_tool_call() — 按顺序遍历 Hook
- 第一个返回 Cancel 的 Hook 停止管线
- Modify 修改后的调用传递给下一个 Hook
2. fire_after_tool_call() — 通知所有 Hook,仅观察,不修改
声明式 Hook 链:通过配置文件中的 [hooks] 段声明 Hook 链,HookFactoryRegistry 根据 hook_type 创建 Hook 实例。from_config() 中 SecurityPolicy 始终作为管线的第一个 Hook 自动注册。
pub trait HookFactory: Send + Sync {
fn hook_type(&self) -> &str;
fn create(&self, config: &serde_json::Value) -> Option<Box<dyn Hook>>;
}
tool_registry.rs — 工具注册表实现¶
DefaultToolRegistry 是 ToolRegistry trait 的默认实现:
- 使用
DashMap实现无锁并发访问,在 async 上下文中安全使用 ToolSpec缓存 + 写时失效,避免重复计算- 支持 glob 模式的三层过滤:denied 优先 → allowed 白名单 → MCP 服务器级过滤
register_all()批量注册、register_all_arc()使用共享Arc<dyn Tool>实例批量注册(避免网关场景下重复构造)、unregister_by_source()按来源批量移除
双重注册表注意: 运行时存在两个独立的
ToolRegistry实例。网关级AppState.tool_registry用于/api/tools端点可见性;每个 Agent 的tool_registry用于实际工具调度。远程工具必须在两者中都注册。详见架构概览中的"双重工具注册表"一节。
security/ — 安全策略¶
mod.rs—SecurityPolicy结构体- 自主等级(ReadOnly / Supervised / Full)
- 命令白名单
- 中等风险命令列表(touch, rm, cp, mv, mkdir, chmod, chown, kill)
- 路径限制(
/etc/passwd,/etc/shadow,/etc/ssh,/root/.ssh) - 操作速率限制(
max_actions_per_hour) - 实现
Hooktrait:before_tool_call()检查自主等级、速率限制、命令白名单和路径守卫;after_tool_call()记录操作计数。SecurityPolicy 始终作为 Hook 管线的第一个 Hook 注册,不再作为 Capability 注入 pairing.rs—PairingGuard,设备配对验证,使用常量时间比较secrets.rs—SecretStore凭证管理,WebAuthnManager支持
cron/ — 定时任务¶
scheduler.rs— 任务执行引擎,跟踪任务和运行历史store.rs— 持久化存储add_agent_job()/add_shell_job()— 创建定时任务update_job()/remove_job()— 修改/删除list_jobs()/due_jobs()— 查询record_run()/list_runs()— 运行历史sync_declarative_jobs()— 从配置文件同步types.rs—CronJob、Schedule、SessionTarget、DeliveryConfigmod.rs— 安全集成validate_shell_command()— 安全策略检查add_shell_job_with_approval()— 审批后持久化
prompt.rs — 模块化系统提示构建器¶
系统提示通过可插拔的 PromptSection 实现由 SystemPromptBuilder 组装:
SystemPromptBuilder::with_defaults()
├── IdentitySection — AIEOS 身份 + 人格 Markdown 文件
├── PlatformSection — 平台和环境信息
├── WorkspaceSection — 工作目录路径
├── StableMemorySection — 注入系统提示的 Core 记忆
├── ToolsSection — 可用工具描述
├── MemorySection — 记忆系统指令
├── SafetySection — 安全规则(感知自主等级)
├── ToolHonestySection — 工具诚实性约束
├── SkillsIndexSection — 可用技能定义
└── ActiveSkillsSection — 当前激活的技能
注意:DateTimeSection 已从系统提示中移除。当前时间现在通过每条用户消息的 [YYYY-MM-DD HH:MM:SS TZ] 前缀提供,使系统提示在所有轮次中 100% 稳定,从而优化前缀缓存(详见 Prompt 缓存优化)。
personality.rs — 人格文件加载器¶
从工作区目录加载预定义的 Markdown 文件:
| 文件 | 用途 |
|---|---|
SOUL.md |
核心人格和行为准则 |
IDENTITY.md |
名称、角色、背景 |
USER.md |
用户偏好和上下文 |
AGENTS.md |
多 Agent 协调规则 |
TOOLS.md |
工具使用指南 |
HEARTBEAT.md |
定期自检指令 |
BOOTSTRAP.md |
首次运行初始化指令 |
MEMORY.md |
记忆管理指南 |
每个文件在 20K 字符处截断。首次运行时自动生成默认的 SOUL.md。
identity.rs — AIEOS 身份系统¶
支持 AIEOS v1.1(AI Entity Object Specification)— 一种用于可移植 AI 身份的结构化 JSON 格式。涵盖身份、心理学、语言学、动机、能力、外貌、历史和兴趣。
load_aieos_identity()— 从文件或内联 JSON 加载aieos_to_system_prompt()— 将 AIEOS 身份渲染为 Markdown- 通过归一化处理官方生成器输出和简化 JSON 格式
详细文档参见人格与身份教程。
其他模块¶
| 模块 | 职责 |
|---|---|
cost.rs |
令牌计费追踪 |
observer.rs |
事件发射(默认 NoopObserver,定义在 clawseed-agent 本地) |
observability.rs |
重新导出 Observer 类型供外部消费者使用 |
approval.rs |
危险操作的审批工作流 |
history.rs |
对话历史管理 |
parser.rs |
多格式工具调用解析(12+ 种 LLM 输出格式) |
health.rs |
健康检查存根 |