// src/agent/hooks/traits.rs // // Agent 生命周期 Hook traits。 use async_trait::async_trait; use std::time::Duration; use super::matcher::ToolMatchFilter; use super::types::{ HookEvent, PermissionDeniedContext, PermissionRequestAction, PermissionRequestContext, PostCompactContext, PostToolUseAction, PostToolUseContext, PostToolUseFailureContext, PreCompactContext, PreToolUseAction, PreToolUseContext, SessionStartContext, SessionStopContext, StepCompleteContext, SubagentStartContext, SubagentStopContext, UserPromptSubmitContext, }; // ── Hook Trait ── /// Agent 生命周期 Hook trait。 /// 所有方法都有默认空实现,只需覆写关心的 hook 点。 #[async_trait] pub trait AgentHook: Send + Sync { /// Hook 名称(用于日志和调试) fn name(&self) -> &str; /// 声明该 hook 订阅的生命周期事件。 /// 返回空切片表示订阅所有事件(向后兼容的默认行为)。 /// HookRegistry 用此信息预计算事件→hook 索引,避免无关调用。 fn subscribed_events(&self) -> &[HookEvent] { &[] // 空 = 订阅全部 } /// Per-hook 超时时间。返回 `None` 使用全局默认值 (30s)。 fn timeout(&self) -> Option { None } /// 声明此 hook 关心哪些工具调用。 /// /// 返回的 `ToolMatchFilter` 用于在 dispatch 时过滤无关的工具调用, /// 减少不必要的 hook 执行。默认返回空过滤器(匹配所有工具)。 /// /// 仅对 `PreToolUse`、`PostToolUse`、`PostToolUseFailure` 事件生效。 /// 其他事件忽略此过滤器。 fn match_filter(&self) -> ToolMatchFilter { ToolMatchFilter::default() } // ── 原有 5 个生命周期事件 ── /// 会话创建/恢复时调用。 async fn on_session_start(&self, _ctx: &SessionStartContext) {} /// 用户提交新提示词时调用(fire-and-forget)。 /// 在 context building 之前触发,hook 可以记录日志、触发边车操作或注入审计上下文。 async fn on_user_prompt_submit(&self, _ctx: &UserPromptSubmitContext) {} /// 工具执行前调用。可返回 Continue/Block/MutateInput/PermissionRequired。 async fn pre_tool_use(&self, _ctx: &PreToolUseContext) -> PreToolUseAction { PreToolUseAction::Continue } /// 工具执行后调用。可返回 Continue 或 MutateOutput。 async fn post_tool_use(&self, _ctx: &PostToolUseContext) -> PostToolUseAction { PostToolUseAction::Continue } /// 每个 ReAct step 完成后调用。 async fn on_step_complete(&self, _ctx: &StepCompleteContext) {} /// 会话终止时调用。 async fn on_session_stop(&self, _ctx: &SessionStopContext<'_>) {} // ── 新增 4 个生命周期事件(默认 no-op) ── /// 子代理启动时调用。 async fn on_subagent_start(&self, _ctx: &SubagentStartContext) {} /// 子代理停止时调用。 async fn on_subagent_stop(&self, _ctx: &SubagentStopContext) {} /// 上下文压缩前调用。 async fn on_pre_compact(&self, _ctx: &PreCompactContext) {} /// 上下文压缩后调用。 async fn on_post_compact(&self, _ctx: &PostCompactContext) {} /// 工具执行失败时调用(独立于 PostToolUse,专注错误处理)。 async fn on_post_tool_use_failure( &self, _ctx: &PostToolUseFailureContext, ) -> PostToolUseAction { PostToolUseAction::Continue } /// 权限请求前调用(参考 Claude Code PermissionRequest hook)。 /// /// Hook 可以覆盖权限决策或注入附加上下文。此方法在 PermissionChecker /// 做出初步决策后、最终返回前触发。 /// /// 返回 `PermissionRequestAction::Continue` 保持当前决策不变。 async fn on_permission_request( &self, _ctx: &PermissionRequestContext, ) -> PermissionRequestAction { PermissionRequestAction::Continue } /// 权限被拒绝后调用(参考 Claude Code PermissionDenied hook)。 /// /// 仅用于审计/日志/监控——返回值不影响执行流程。 /// 在权限被最终拒绝后触发(规则拒绝、Classifier 拒绝或用户拒绝)。 async fn on_permission_denied(&self, _ctx: &PermissionDeniedContext) {} } // ── Async Hook Trait ── /// Fire-and-forget hook trait(Phase 4.1+)。 /// /// 与 `AgentHook` 分离设计: /// - `AgentHook` 的返回值(`PreToolUseAction` / `PostToolUseAction`)会立即影响执行流程 /// - `AsyncAgentHook` 不返回决策——它适合用于后台操作(上传、远程日志上报等) /// /// HookRegistry 并行调度两类 hook:sync hook 的结果用于决策,async hook 仅 fire-and-forget。 /// Async hook dispatch 默认超时 5 秒(仅限方法返回,后台工作继续独立执行)。 #[async_trait] pub trait AsyncAgentHook: Send + Sync { /// Hook 名称(用于日志和调试) fn name(&self) -> &str; /// 声明订阅的事件(默认全部)。与 AgentHook 相同的索引机制。 fn subscribed_events(&self) -> &[HookEvent] { &[] } /// 工具执行后异步回调(fire-and-forget) async fn on_post_tool_use_async(&self, _ctx: PostToolUseContext) {} /// 工具执行失败时异步回调 async fn on_post_tool_use_failure_async(&self, _ctx: PostToolUseFailureContext) {} /// 会话结束时异步回调 async fn on_session_stop_async(&self, _ctx: SessionStopContext<'_>) {} }