feat(agent): 实现 Agent Runtime 核心胶水层 (Phase 4a)

- 添加 Agent trait、AgentSession、RuntimeBundle、AgentBuilder
- 添加 Plan/Step/StepStatus 任务规划数据结构
- 添加 AgentError 统一错误类型(聚合 LlmError/ToolError/MemoryError)
- 实现 submit_turn 单轮对话流程(含 hook 触发与 cost 累计)
- 扩展 LlmCycle 支持 Arc<dyn LlmProvider>
- 扩展 HookEvent 添加 OnTurnStart/OnTurnEnd
- 更新 roadmap 状态
This commit is contained in:
徐涛
2026-06-11 21:45:28 +08:00
parent 59ec0f5597
commit 2b189880a9
11 changed files with 1025 additions and 19 deletions
+110
View File
@@ -0,0 +1,110 @@
//! Runtime Bundle —— 显式依赖注入容器(OpenHarness 风格)。
//!
//! 集中持有 Agent 运行所需的全部运行时依赖:`LlmProvider` / `ToolRegistry` / `HookExecutor` /
//! `MemoryStore`(弱引用)/ `MemoryRetriever`(弱引用) / `AgentConfig`。
//!
//! **设计意图**(参见 `docs/7-agent-runtime.md` §3.2.2):
//!
//! - 所有运行时依赖显式打包,便于跨 `AgentSession` 共享、便于测试注入 mock
//! - `memory_store` / `retriever` 为 `Option`:上层应用不传也能跑(无记忆模式)
//! - 构造时若 `retriever` 为 `Some`,自动注册 `"retrieve"` toolv0.1 占位——
//! Phase 4a 不在 `submit_turn` 中真正调用;Phase 4a 任务范围仅"装配可注册",
//! 真正的 `RetrieveTool` 实现留待 v0.2 接入)
//! - 不持有 `Box<dyn LlmProvider>` 而是 `Arc<dyn LlmProvider>`:支持多 session 共享
use std::sync::Arc;
use std::time::Duration;
use crate::llm::compact::CompactConfig;
use crate::llm::provider::LlmProvider;
use crate::llm::hooks::HookExecutor;
use crate::memory::retriever::MemoryRetriever;
use crate::memory::store::MemoryStore;
use crate::tools::ToolRegistry;
/// Agent 运行配置。
#[derive(Debug, Clone)]
pub struct AgentConfig {
/// 单次会话最大 turn 数(含工具循环内部 turn),默认 50。
pub max_turns: u32,
/// 单次会话最大工具循环轮次(与 LlmCycle 的 `max_tool_turns` 对齐),默认 10。
pub max_tool_turns: u32,
/// 会话 TTLNone 表示无过期),默认 None。
pub session_ttl: Option<Duration>,
/// 上下文压缩配置(None 表示不启用自动压缩),默认 None。
pub compact_config: Option<CompactConfig>,
}
impl Default for AgentConfig {
fn default() -> Self {
Self {
max_turns: 50,
max_tool_turns: 10,
session_ttl: None,
compact_config: None,
}
}
}
/// Agent Runtime 依赖注入容器。
///
/// 通过 `AgentBuilder::build()` 构造;构造完成后内部为只读视图。
/// `Arc` 共享,多个 `AgentSession` 可共用同一个 bundle。
#[derive(Clone)]
pub struct RuntimeBundle {
/// LLM 后端(强引用,多 session 共享)。
pub provider: Arc<dyn LlmProvider>,
/// 工具注册表(强引用,多 session 共享)。
pub tool_registry: Arc<ToolRegistry>,
/// 钩子执行器(强引用,多 session 共享)。
pub hook_executor: Arc<HookExecutor>,
/// 持久化记忆后端(弱引用 —— 不传也能跑)。
pub memory_store: Option<Arc<dyn MemoryStore>>,
/// 记忆检索器(弱引用 —— 不传也能跑)。
/// 传入时可在 `submit_turn` 内部将检索能力作为工具暴露给 LLM。
pub retriever: Option<Arc<MemoryRetriever>>,
/// 运行时配置。
pub config: AgentConfig,
}
impl std::fmt::Debug for RuntimeBundle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RuntimeBundle")
.field("provider_type", &"<dyn LlmProvider>")
.field("tool_names", &self.tool_registry.list_tools())
.field("has_memory_store", &self.memory_store.is_some())
.field("has_retriever", &self.retriever.is_some())
.field("config", &self.config)
.finish()
}
}
impl RuntimeBundle {
/// 构造一个 `RuntimeBundle`。
///
/// **Phase 4a 行为**`retriever` 存在时仅占位记录,不真正注入工具
/// v0.1 不在 `submit_turn` 中启用检索;Phase 4c 之后再决定是否注册成 tool)。
/// 真正的工具注入留待 v0.2 接入 `RetrieveTool` 实现。
pub fn new(
provider: Arc<dyn LlmProvider>,
tool_registry: Arc<ToolRegistry>,
hook_executor: Arc<HookExecutor>,
memory_store: Option<Arc<dyn MemoryStore>>,
retriever: Option<Arc<MemoryRetriever>>,
config: AgentConfig,
) -> Self {
Self {
provider,
tool_registry,
hook_executor,
memory_store,
retriever,
config,
}
}
}