Files
beaver_project/app-instance/backend/flow.md
steven_li 30ab74ffb2 feat(engine): 添加MCP连接管理和工具集成功能
- 集成MCP连接管理器,支持MCP服务器连接
- 添加多种内置工具:ClarifyTool、CronTool、DelegateTool、ExecuteCodeTool、
  PatchFileTool、ProcessTool、SendMessageTool、SpawnTool、TerminalTool、
  TodoTool、WebFetchTool、WebSearchTool、WriteFileTool等
- 实现工具注册和装配功能
- 添加技能选择上下文参数
- 支持思考模式控制参数thinking_enabled

feat(coordinator): 重构任务执行计划器参数命名

- 将learning_candidate_enabled重命名为allow_candidate_generation
- 更新TeamGraphScheduler中的参数传递
- 修改LocalAgentRunner中的相关参数处理
- 更新README文档中的相应描述

refactor(context): 标准化工具调用参数格式

- 添加_json导入用于参数序列化
- 实现_provider_tool_calls方法标准化OpenAI兼容的工具调用载荷
- 修复工具调用中参数非字符串类型的序列化问题

refactor(session): 优化消息历史记录过滤逻辑

- 修改get_messages_as_conversation为基于运行状态过滤消息
- 排除未完成、失败或错误结束的运行记录
- 改进对话历史的可见性控制机制

fix(store): 修复FTS索引重建逻辑

- 添加异常处理防止FTS索引创建失败
- 实现_rebuild_fts_index方法重新构建全文搜索索引
- 优化索引触发器和表的维护流程
2026-05-14 09:43:48 +08:00

37 KiB
Raw Blame History

Beaver Backend Flow

这份文档只保留树形运行结构

  • 原理、参考项目边界、长期蓝图:看 change.md
  • 施工顺序、阶段目标、完成标准:看 施工指南.md

1. 总入口

用户输入(用户在不同入口发来一句话或一个任务)
│
├─ CLI命令行入口
├─ Web网页前端入口
├─ Gateway消息通道入口比如以后接 Slack / Telegram
└─ future channels未来扩展入口
   │
   └─ AgentService统一服务层所有入口都先汇总到这里
├─ MainAgentRouterLLM 语义判断 simple / continue task / new task / close / abandon
      ├─ create_loop()(创建 AgentLoop 运行核心)
      ├─ start()(启动后台运行模式)
      ├─ submit_direct()(把任务提交到运行队列)
      ├─ process_direct()(直接处理一次任务,不走队列)
      ├─ submit_feedback()(记录聊天反馈并驱动内部 Task 状态)
      ├─ stop()(停止接收新任务,并等待队列收尾)
      ├─ shutdown()(停止运行并释放资源)
      └─ close()(关闭已经创建的 runtime

2. Boot / Loader

AgentService.create_loop()(服务层创建运行核心)
│
└─ AgentLoop(profile, loader)Agent 主循环:真正跑任务的核心对象)
   │
   └─ AgentLoop.boot()(启动前装配依赖)
      │
      └─ EngineLoader.load()(加载所有运行时模块)
         ├─ SessionManager会话管理保存聊天记录和隐藏事件
         ├─ MemoryStore长期记忆存储真正落盘的 curated memory
         ├─ MemoryService记忆服务运行时访问 memory 的唯一入口)
         ├─ RunMemoryStore运行记录存储保存每次 run 的结果)
         ├─ SkillLearningStore技能学习存储保存表现统计和学习候选
         ├─ ToolRegistry工具注册表登记系统有哪些工具
         ├─ ToolAssembler工具选择器决定本轮暴露哪些工具
         ├─ ToolExecutor工具执行器真正调用工具
         ├─ SkillsLoader技能目录加载器只加载可用技能
         ├─ SkillAssembler技能选择器决定本轮激活哪些 skill
         ├─ SkillSpecStore技能生命周期存储保存版本、草稿、审核
         ├─ DraftService草稿服务创建 skill draft
         ├─ ReviewService审核服务approve / reject draft
         ├─ SkillPublisher发布服务publish / disable / rollback
         ├─ EvidenceSelector证据选择器为学习闭环挑选历史证据
         ├─ SkillDraftSynthesizer草稿合成器让 LLM 生成 skill draft
         ├─ SkillLearningService技能学习服务生成学习候选和草稿
         ├─ TaskService内部 Task 服务:自动 Task 化、状态、事件、反馈)
         ├─ TaskExecutionPlannerTask 执行规划器:决定 single / team
         ├─ ValidationService结果验证服务Task run 完成后的自动验证)
         └─ ContextBuilder上下文构建器拼 system prompt 和 messages

3. Main Agent Routing / Internal Task

AgentService.process_direct / submit_direct聊天入口统一进入服务层
│
├─ resolve session_id复用请求 session或生成新 session
├─ task_service.get_latest_open_task(session_id)(查找同会话未关闭 Task
├─ MainAgentRouter.classify(message, active_task, recent_messages)LLM 语义分类)
│  ├─ simple简单问题
│  │  └─ runner(message, include_skill_assembly=False, include_tools=False)(不创建 Task不跑 skills/tools
│  │
│  ├─ continue_task继续当前 Task
│  │  └─ reuse active Task只要话题没有完全无关就继续当前 open Task
│  │
│  ├─ new_task明确开启新任务
│  │  └─ TaskService.create_task(...)(内部创建 Task并保存 short_title
│  │
│  ├─ close_task / abandon_task用户明确结束或放弃
│  │  └─ TaskService.close_task / abandon_task关闭当前 Task
│  │
│  └─ task execution
│     └─ AgentService._run_task_mode(...)(进入 Task 模式执行)
TaskService内部 Task 状态机)
│
├─ TaskRecord
│  ├─ task_id
│  ├─ session_id
│  ├─ goal / description / constraints
│  ├─ metadata.short_title5-15 字左右的短标题,用于前端当前任务标识)
│  ├─ status
│  │  ├─ open
│  │  ├─ running
│  │  ├─ validating
│  │  ├─ awaiting_feedback
│  │  ├─ needs_revision
│  │  ├─ closed
│  │  └─ abandoned
│  ├─ run_ids
│  ├─ skill_names
│  ├─ validation_result
│  └─ feedback
│
└─ TaskEvent
   ├─ created
   ├─ run_started
   ├─ run_completed
   ├─ validated
   ├─ feedback_satisfied
   ├─ feedback_revise
   └─ feedback_abandon
Task Mode Execution复杂任务执行
│
├─ attempt 1
│  ├─ task_service.start_run(...)
│  ├─ TaskExecutionPlanner.plan(...)LLM 规划 single / team
│  ├─ session hidden event: task_execution_planned
│  ├─ if plan.mode == team
│  │  ├─ TeamService.run_team(parent_task_id=task_id, parent_session_id=session_id)
│  │  ├─ sub-agent runs -> parent Task run_ids
│  │  ├─ session hidden event: task_team_run_completed / task_team_run_failed
│  │  └─ team summary + node results -> 主 Agent synthesis execution_context
│  ├─ AgentLoop.process_direct / submit_direct(..., task_id, task_mode=True, attempt_index=1)
│  ├─ ValidationService.validate_task_result(..., team_summaries=...)
│  ├─ TaskService.record_validation(...)
│  ├─ RunMemoryStore.update_run_record(validation_result=...)
│  └─ session hidden event: task_validation_snapshotted
│
├─ if validation accepted
│  └─ return result with task_id / task_status / validation_result
│
└─ if validation failed
   ├─ session_manager.set_run_context_visible(run_id, false)(隐藏失败草稿尝试)
   ├─ attempt 2 重新规划 single / team
   ├─ revision request + team result -> 主 Agent synthesis execution_context
   └─ 第二次结果无论验证是否通过,都返回并等待用户反馈

4. Direct Run

AgentLoop.process_direct(task)(直接执行一轮用户任务)
│
├─ 生成 session_id确定这句话属于哪个会话
├─ 生成 run_id给本次运行生成唯一编号
├─ memory_service.capture_snapshot_for_run()(每个 run 捕获独立记忆快照)
│  └─ fresh MemoryStore(root).load_from_disk()(不写共享 `_snapshot`,避免并发串记忆)
│
├─ session_manager.ensure_session(session_id)(确保会话存在)
├─ session_manager.append_message(event_type="run_started", hidden)(记录隐藏事件:本轮开始)
│
├─ make_provider_bundle()(装配模型 provider 组合)
│  ├─ main_runtime主模型配置
│  ├─ main_provider主模型调用器
│  ├─ fallback_runtime备用模型配置
│  ├─ fallback_provider备用模型调用器
│  ├─ auxiliary_runtime辅助模型配置
│  ├─ auxiliary_provider辅助模型调用器用于选 skill 等)
│  └─ embedding_runtime向量模型配置用于语义召回
│
├─ if include_skill_assembly=Falsesimple_chat 默认关闭)
│  └─ skip SkillAssembler不激活 skill不注入 skill 正文)
│
├─ if include_skill_assembly=TrueTask mode 默认开启,在 Task 创建/复用和规划之后执行)
│  └─ skill_assembler.assemble(...)(选择本轮应该激活哪些 published skill
│     ├─ input task_description = skill_selection_context or current user input
│     │  ├─ Task goal / description
│     │  ├─ current user request
│     │  ├─ attempt / revision / team synthesis phase
│     │  ├─ validation feedback重试时
│     │  ├─ team summary / planteam synthesis 时)
│     │  └─ previously activated skills只作为 reuse bias不是 pinned
│     ├─ SkillsLoader.build_selection_candidates()(列出候选技能摘要)
│     ├─ embedding retrieve skill candidates用向量召回相关技能
│     ├─ LLM shortlist candidate names先用摘要粗选少量候选
│     │  └─ if retrieved candidates <= max_detailed_candidates -> skip shortlist
│     ├─ SkillsLoader.load_published_skill(...)(系统侧内部读取粗选候选正文,不暴露 skill_view 给主 Agent
│     ├─ LLM final select activated skills结合候选正文做最终选择
│     ├─ if no matching skill -> return [] and continue run without skills
│     └─ 返回 activated skills返回本轮被激活的技能
│        ├─ name技能名称
│        ├─ content技能正文
│        ├─ version技能版本
│        ├─ content_hash技能内容哈希用于追踪
│        ├─ activation_reason为什么激活
│        └─ tool_hints技能建议使用哪些工具
│
├─ ContextBuilder.build_skill_activation_messages(...)(把激活技能变成模型可读消息)
├─ 构造 SkillActivationReceipt[](构造技能激活收据)
├─ session_manager.append_message(...)(记录隐藏事件:本轮用了哪些技能)
│  ├─ event_type="skill_activation_snapshotted"(技能激活快照)
│  ├─ hidden不进入普通聊天上下文
│  └─ payload隐藏数据
│     ├─ receipts技能激活收据
│     └─ activation_messages实际注入给模型的技能消息
│
├─ tool_assembler.assemble(...)选择本轮应该暴露哪些工具simple_chat 默认跳过)
│  ├─ always tools默认总是可用的工具
│  ├─ activated skill tool hints被激活技能推荐的工具
│  ├─ embedding retrieve tools用向量召回相关工具
│  └─ 返回 selected ToolSpec[](返回本轮工具列表)
│
├─ session_manager.append_message(event_type="tool_selection_snapshotted", hidden)(记录隐藏事件:工具选择快照)
│
├─ ContextBuilder.build_messages(...)(构造发给模型的完整 messages
│  ├─ build_system_prompt()(构造 system prompt
│  │  ├─ base system prompt基础系统提示词
│  │  ├─ session metadata当前会话元信息
│  │  ├─ execution context本轮额外执行上下文
│  │  └─ frozen memory snapshot冻结记忆快照
│  ├─ insert activated skill messages插入已激活技能正文
│  ├─ append visible history追加可见历史聊天
│  └─ append current user input追加当前用户输入
│
├─ session_manager.update_system_prompt(...)(把本轮 system prompt 快照写回会话)
├─ session_manager.append_message(event_type="skill_selection_context_snapshotted", hidden)(完整记录 skill query
├─ session_manager.append_message(event_type="system_prompt_snapshotted", hidden)记录隐藏事件system prompt 快照)
├─ session_manager.append_message(event_type="user_message_added")(记录可见事件:用户消息)
│
├─ 进入 tool loop进入模型回答和工具调用循环
│
├─ 成功时(模型正常结束)
│  ├─ session_manager.append_message(event_type="run_completed", hidden)(记录隐藏事件:运行完成)
│  └─ _record_run_receipts(...)(记录运行证据,不生成学习候选)
│
├─ 失败时(运行中出现异常)
│  ├─ append assistant error message写入 assistant 错误消息)
│  ├─ session_manager.append_message(event_type="run_failed", hidden)(记录隐藏事件:运行失败)
│  └─ _record_run_receipts(...)(即使失败也记录运行证据)
│
└─ return AgentRunResult返回本轮结果
   ├─ session_id会话编号
   ├─ run_id运行编号
   ├─ output_text最终回复文本
   ├─ finish_reason结束原因
   ├─ tool_iterations工具循环次数
   ├─ provider_name模型供应商
   ├─ model模型名称
   ├─ usagetoken 用量)
   ├─ task_idTask 模式下返回)
   ├─ task_statusTask 模式下返回)
   └─ validation_resultTask 模式下返回)

5. Tool Loop

tool loop工具调用循环
│
├─ session_manager.append_message(event_type="llm_request_snapshotted", hidden)(完整记录本次 provider messages / tools
├─ provider.chat(messages, tools=schemas)(把消息和工具 schema 发给模型)
├─ session_manager.update_usage(...)(累计 token 用量)
├─ session_manager.append_message(event_type="assistant_message_added")(记录 assistant 回复)
├─ ContextBuilder.add_assistant_message(...)(把 assistant 回复追加到本轮 messages
│
├─ if no tool calls如果模型没有要求调用工具
│  └─ finish结束本轮回答
│
└─ if tool calls如果模型要求调用工具
   ├─ ToolExecutor.execute_tool_call(...)(执行一个工具调用)
   ├─ session_manager.append_message(event_type="tool_result_recorded")(记录工具结果)
   ├─ ContextBuilder.add_tool_result(...)(把工具结果追加到 messages
   └─ 回到 provider.chat(...)(带着工具结果继续问模型)

6. Run Evidence / Skill Effect Recording

AgentLoop._record_run_receipts(...)(记录本轮运行证据;不直接学习)
│
├─ 构造 RunRecord构造本轮运行记录
│  ├─ run_id运行编号
│  ├─ session_id会话编号
│  ├─ task_text用户原始任务
│  ├─ task_id内部 Task 编号,简单问题可为空)
│  ├─ attempt_indexTask 模式下的尝试序号)
│  ├─ started_at开始时间
│  ├─ ended_at结束时间
│  ├─ success是否成功
│  ├─ finish_reason结束原因
│  ├─ validation_resultTask 模式下的验证结果)
│  ├─ feedback用户反馈
│  └─ activated_skills本轮激活过的技能收据
│
├─ 构造 SkillEffectRecord[](构造技能效果记录)
│  └─ 每个 activated skill 一条(每个被用到的技能都单独记一条)
│
├─ skill_learning_service.collect_run_receipts(...)(收集运行收据)
│  ├─ RunMemoryStore.append_run_record(...)(把 RunRecord 写入 memory/runs/runs.jsonl
│  ├─ RunMemoryStore.append_skill_effect(...)(把 SkillEffectRecord 写入 memory/runs/skill-effects.jsonl
│  ├─ SkillLearningService.rescore_skill_versions()(重新统计每个技能版本表现)
│  │  └─ SkillLearningStore.update_performance_snapshot(...)(更新表现快照)
│  └─ never build learning candidates in runtime hot path运行完成时永不生成候选
│
└─ session_manager.append_message(...)(记录隐藏事件:技能效果快照)
   ├─ event_type="skill_effects_snapshotted"(技能效果已快照)
   ├─ hidden不进入普通聊天上下文
   └─ payload隐藏数据
      ├─ run_record本轮运行记录
      ├─ skill_effects技能效果记录
      ├─ candidate_generation_allowed本轮是否允许生成候选runtime 固定 false
      └─ learning_candidates学习候选默认空
runtime invariant运行期不直接学习
│
├─ run completed / run failed
│  └─ 只写 RunRecord + SkillEffectRecord + performance snapshot
│
├─ simple chat
│  └─ 不创建 Task不触发 learning candidate
│
└─ Task attempt / sub-agent run
   └─ 只留下证据,等待 feedback gate 决定是否学习

7. Chat Feedback / Learning Gate

POST /api/chat/feedback聊天反馈接口不是 Task 管理 API
│
├─ input
│  ├─ session_id
│  ├─ run_id
│  ├─ feedback_type
│  │  ├─ satisfied
│  │  ├─ revise
│  │  └─ abandon
│  └─ comment?
│
├─ AgentService.submit_feedback(...)
│  ├─ TaskService.get_task_by_run_id(run_id)
│  ├─ reject if task/session mismatch
│  ├─ reject conflicting feedback for same run
│  ├─ same feedback is idempotent
│  └─ TaskService.add_feedback(...)
│
├─ satisfied
│  ├─ if validation accepted
│  │  ├─ Task status -> closed
│  │  └─ SkillLearningService.build_learning_candidates_for_task(task_id, trigger_run_id)
│  └─ if validation not accepted
│     └─ 记录人工接受但保留验证风险;不自动生成 learning candidate
│
├─ revise
│  ├─ Task status -> needs_revision
│  ├─ 更新 run / skill effect 为需修订证据
│  └─ 下一条用户消息默认复用该 Task不生成 learning candidate
│
└─ abandon
   ├─ Task status -> abandoned
   ├─ 更新 run / skill effect 为失败证据
   ├─ 追加 task_failure_evidence_recorded 隐藏事件
   └─ 默认不写主 memory不生成成功 Skill draft

8. Agent Team v1 / Local Coordinator

TeamService.run_team(...)(内部 team 执行入口,不暴露产品级 Task API
│
├─ validate parent task如果传 parent_task_id先校验 Task 存在且 session 匹配)
│
├─ TeamGraphScheduler.run(...)
│  ├─ graph.validate()
│  │  ├─ v1 implemented strategies: sequence / parallel / dag
│  │  └─ reserved strategies: moa / hierarchy / heavy / group_chat / forest / maker / router
│  ├─ provider_bundle_factory(node)(推荐:每个节点拿 fresh provider bundle
│  ├─ inherited_pinned_skills主 agent 明确委派给 sub-agent 的 pinned skills
│  ├─ inherited_pinned_skill_contextsmissing skill 生成的一次性 ephemeral guidance
│  └─ allow_candidate_generation=False默认只写 receipts不绕过 Task feedback gate
│
├─ LocalAgentRunner.run(envelope)
│  ├─ 生成 child_session_id
│  ├─ parent_session_id -> 主 session建立 session lineage
│  ├─ AgentLoop.process_direct / submit_direct(...)(复用主 AgentLoop / ContextBuilder / ToolAssembler / SkillAssembler / MemoryService
│  ├─ pinned_skill_names -> AgentLooppublished pinned skill 必须注入)
│  ├─ pinned_skill_contexts -> AgentLoopephemeral guidance 只在本次 run 注入)
│  └─ provider_bundle + node model/provider override 禁止混用
│
├─ strategy execution
│  ├─ sequence前一节点成功输出进入后一节点 dependency_outputs
│  ├─ parallel同层节点 asyncio.gather 真并发执行
│  └─ dag按依赖拓扑分批并发失败节点会阻断依赖它的后续节点
│
├─ node-level failure normalization
│  ├─ provider factory / runner 普通异常 -> NodeRunResult(success=False, finish_reason="error")
│  ├─ asyncio.CancelledError 继续抛出
│  └─ blocked dependency -> NodeRunResult(success=False, finish_reason="blocked")
│
├─ TeamRunResult
│  ├─ success
│  ├─ summary只聚合成功节点输出失败节点列入 Failed nodes
│  ├─ node_results
│  ├─ run_ids
│  ├─ session_ids
│  └─ task_id父 Task
│
└─ attach runs to parent Task
   └─ TaskService.append_run(parent_task_id, sub_run_id, skill_names=...)
Team v1 scope当前边界
│
├─ 已实现
│  ├─ Beaver 自有 coordinator models
│  ├─ sequence / parallel / dag 三个执行原语
│  ├─ pinned skill 继承 + open skill assembly
│  ├─ per-run memory snapshot支持真并发 prompt 构建
│  ├─ per-node provider factory 语义
│  ├─ parent Task 一致性校验
│  └─ 节点失败归一和 summary 失败区块
│
├─ 已接入 Task mode 内部执行链
│  ├─ TaskExecutionPlanner 先决定 single / team
│  ├─ team run 只作为内部 sub-agent 执行策略
│  ├─ TeamRunResult 不直接返回给用户
│  └─ 主 Agent synthesis run 生成用户可见最终回答
│
└─ 仍不暴露产品级 team / Task API
   └─ 外部仍只使用聊天入口和反馈入口

9. Session Module

SessionManager会话管理门面
│
├─ ensure_session(...)(确保会话存在)
├─ append_message(...)(追加一条事件或聊天消息)
├─ get_event_records(session_id)(获取完整事件流)
├─ get_run_event_records(session_id, run_id)(获取某次 run 的事件)
├─ update_latest_assistant_event_payload(...)(把 task/validation/feedback 状态投影到最新 assistant 消息)
├─ set_run_context_visible(session_id, run_id, visible)(隐藏失败重试草稿等 run
├─ list_run_ids(session_id)(列出某个会话下所有 run_id
├─ get_messages_as_conversation(session_id)(获取可作为聊天展示的消息)
├─ get_visible_history(session_id)(获取可进入 prompt 的历史)
├─ update_system_prompt(...)(更新当前会话 system prompt 快照)
├─ update_usage(...)(更新 token 用量)
├─ end_session(...)(结束会话)
├─ reopen_session(...)(重新打开会话)
├─ list_sessions_rich(...)(列出带摘要的会话)
├─ search_messages(...)(搜索历史消息)
└─ resolve_session_id(...)(根据前缀解析 session_id
SessionStore (SQLite)SQLite 会话数据库)
│
├─ sessions table会话表
├─ messages table消息和事件表
├─ messages_fts全文搜索索引
├─ WALSQLite 写入日志模式)
├─ parent_session_id父会话字段给未来分支会话用
└─ hidden / visible event split隐藏事件和可见消息分离
hidden events隐藏事件类型
│
├─ run_started运行开始
├─ skill_activation_snapshotted技能激活快照
├─ tool_selection_snapshotted工具选择快照
├─ system_prompt_snapshotted系统提示词快照
├─ run_completed运行完成
├─ run_failed运行失败
├─ skill_effects_snapshotted技能效果快照
├─ task_validation_snapshottedTask 验证快照)
└─ task_feedback_recordedTask 用户反馈快照)

10. Memory Module

MemoryService记忆服务
│
├─ initialize()(初始化记忆存储)
├─ reload_for_new_run()(每轮开始前刷新记忆快照)
├─ get_snapshot()(获取本轮冻结记忆快照)
└─ get_store()(获取底层 MemoryStore
MemoryStore长期记忆存储
│
├─ target: memory项目/任务级长期记忆)
├─ target: user用户偏好记忆
├─ add(...)(新增记忆)
├─ replace(...)(替换记忆)
├─ remove(...)(删除记忆)
├─ load_from_disk()(从磁盘读取)
├─ save_to_disk()(保存到磁盘)
└─ format_for_system_prompt(...)(格式化成 system prompt 段落)
memory runtime semantics记忆运行语义
│
├─ run start本轮开始
│  └─ refresh live state -> capture frozen snapshot刷新 live memory并冻结本轮快照
│
├─ run middle本轮进行中
│  ├─ memory tool may write durable statememory 工具可以写入长期记忆)
│  └─ current run prompt snapshot stays frozen但本轮 prompt 里的记忆不变)
│
└─ next run下一轮
   └─ newly written memory becomes visible上一轮写入的新记忆开始可见

11. Skills Module

SkillsLoader技能加载器
│
├─ workspace published catalog工作区正式发布的技能目录
├─ workspace legacy skills/*/SKILL.md旧格式技能文件
├─ builtin skills内置技能
├─ list_skills()(列出运行时可见技能)
├─ list_published_skills()(只列正式发布技能)
├─ get_current_version()(获取当前正式版本)
├─ load_published_skill()(加载正式版本正文)
├─ get_skill_record()(获取技能元数据记录)
├─ get_skill_metadata()(获取 frontmatter 元数据)
├─ get_skill_tool_hints()(获取技能推荐工具)
├─ load_skills_for_context()(把多个技能加载成上下文块)
├─ build_skills_summary()(构造技能摘要索引)
├─ build_selection_candidates()(构造给 SkillAssembler 的候选摘要)
├─ list_skill_supporting_files()(列出技能支持文件)
└─ get_always_skills()(获取 always 类型技能)
SkillAssembler技能选择器
│
├─ input输入
│  ├─ task_descriptionTask-aware queryTask 描述 / 当前用户消息 / previous skills / attempt context / validation revision context / team context
│  ├─ candidate skill summaries候选技能摘要
│  ├─ embedding runtime向量模型配置
│  └─ selector provider/model用于选择技能的模型
│
├─ embedding retrieve candidates先用向量召回相关技能
├─ LLM shortlist names用摘要粗选需要查看正文的候选
│  └─ skip when candidate count <= max_detailed_candidates候选很少时直接读取正文
├─ internal load shortlisted SKILL.mdSkillAssembler 内部读取候选正文)
├─ LLM final select names结合候选正文选择最终技能名
├─ no match returns [](没有对应 published skill 时返回空,不阻塞任务)
└─ return SkillContext[](返回技能上下文)
   ├─ name技能名
   ├─ content技能正文
   ├─ version技能版本
   ├─ content_hash内容哈希
   ├─ activation_reason激活原因
   └─ tool_hints推荐工具
skills lifecycle baseline技能生命周期基线
│
├─ SkillSpecStore技能生命周期文件存储
│  ├─ skill.json技能总信息
│  ├─ current.json当前版本指针
│  ├─ versions/(正式版本目录)
│  ├─ drafts/(草稿目录)
│  ├─ reviews/(审核记录目录)
│  └─ archive/(归档目录)
│
├─ DraftService草稿服务
│  ├─ create_new_skill_draft(...)(创建新技能草稿)
│  ├─ create_revision_draft(...)(创建修订草稿)
│  ├─ create_merge_draft(...)(创建合并草稿)
│  ├─ create_retire_proposal(...)(创建退役提案)
│  ├─ list_drafts(...)(列出草稿)
│  └─ get_draft(...)(读取单个草稿)
│
├─ ReviewService审核服务
│  ├─ submit_for_review(...)(提交审核)
│  ├─ approve(...)(批准草稿)
│  └─ reject(...)(拒绝草稿)
│
└─ SkillPublisher发布服务
   ├─ publish(...)(发布 approved 草稿为正式版本)
   ├─ apply_retire_proposal(...)(应用退役提案,不创建新版本)
   ├─ disable(...)(禁用技能)
   └─ rollback(...)(回滚到旧版本)

12. Tools Module

ToolRegistry工具注册表
│
├─ echo回显工具
├─ memory写入/管理长期记忆)
├─ session_search搜索会话历史
├─ list_directory列目录
├─ read_file读文件
└─ search_files搜索文件
ToolAssembler工具选择器
│
├─ selected = always tools先加入默认工具
├─ selected += activated skill tool hints再加入技能推荐工具
├─ selected += embedding top-k tools再用向量召回任务相关工具
└─ return ToolSpec[](返回本轮可用工具列表;不通过工具动态加载 skill
ToolExecutor工具执行器
│
├─ normalize tool call规范化模型发来的工具调用
├─ resolve tool找到对应工具
├─ invoke tool执行工具
└─ return ToolResult返回工具结果
filesystem tool boundary文件系统工具边界
│
├─ workspace scoped只能访问 workspace 范围)
├─ realpath enforcement用真实路径校验
├─ reject path escape拒绝路径逃逸
├─ reject symlink escape拒绝软链接逃逸
└─ reject binary file reads拒绝读取二进制文件

13. Provider Module

make_provider_bundle(...)(创建模型调用组合)
│
├─ main_runtime主模型配置
├─ main_provider主模型调用器
├─ fallback_runtime备用模型配置
├─ fallback_provider备用模型调用器
├─ auxiliary_runtime辅助模型配置
├─ auxiliary_provider辅助模型调用器
└─ embedding_runtime向量模型配置
provider roles模型角色分工
│
├─ main主模型
│  └─ assistant/tool loop负责正常回答和工具循环
├─ fallback备用模型
│  └─ main failure recovery主模型失败时兜底
├─ auxiliary辅助模型
│  └─ skill selection / future helper tasks负责选择技能等辅助任务
└─ embedding向量模型
   └─ skill/tool semantic retrieval负责 skill / tool 的语义召回)

14. Service Lifecycle

AgentService服务生命周期
│
├─ MainAgentRouter请求进入 AgentLoop 前先分类 simple / task
├─ submit_feedback(...)(聊天反馈入口,内部更新 Task 状态)
│
├─ direct mode直接模式适合 CLI / 单次调用)
│  └─ process_direct(...)(直接处理一次任务)
│
└─ running mode后台运行模式适合 Web / Gateway
   ├─ start()(启动 AgentLoop.run
   ├─ submit_direct(...)(向队列提交任务)
   ├─ stop(timeout_seconds, force)(停止并等待任务收尾)
   ├─ shutdown(timeout_seconds, force)(停止并释放 runtime
   └─ close()(关闭已停止的 loop
running mode semantics后台运行语义
│
├─ start()(启动)
│  └─ AgentLoop.run()(进入队列消费循环)
│
├─ submit_direct()(提交任务)
│  └─ enqueue _DirectRunRequest把任务放入队列
│
├─ stop()(停止)
│  ├─ stop accepting new tasks不再接收新任务
│  └─ drain queued tasks等待已排队任务处理完
│
└─ close()(关闭)
   └─ requires loop already stopped必须先 stop才能 close

15. Task Team Registry / Process / Learning 闭环

TaskExecutionPlannerTask 内部执行规划)
│
├─ LLM planner
│  ├─ 输出 single / team
│  └─ team 只允许 sequence / parallel / dag
│
├─ TaskSkillResolver
│  ├─ 从 published skill catalog 检索候选
│  ├─ 按 skill_query / required_capabilities / node task 选择 skill
│  ├─ 命中 published skill 后写入 graph.nodes[].inherited_pinned_skills
│  └─ 无命中时创建 ephemeral guidance并写入 graph.nodes[].inherited_pinned_skill_contexts
│
└─ TaskExecutionPlan
   ├─ graph.nodes[].agent 只是 generic runtime trace identity
   └─ to_event_payload() 写入 skill_queries / selected_skill_names / ephemeral_guidance_ids / skill_resolution_report
Task mode attempt每次 Task attempt
│
├─ task_execution_planned隐藏事件
│  └─ plan_mode / strategy / node_ids / skill_resolution_report
│
├─ team run仅 team plan
│  ├─ sub-agent run_ids 回填父 Task
│  ├─ team summary 只进入主 Agent synthesis context
│  └─ task_team_run_completed / task_team_run_failed隐藏事件
│
├─ main Agent synthesis
│  ├─ 输出最终用户可见回答
│  └─ task_synthesis_completed隐藏事件
│
└─ validation
   ├─ task_validation_snapshotted隐藏事件
   ├─ 第一次失败隐藏草稿并重试一次
   └─ 第二次或验证通过后等待反馈
Frontend process projection
│
├─ GET /api/sessions/{session_id}/process
│  ├─ 读取隐藏 Task/team/validation 事件
│  ├─ 合并 run memory records
│  └─ 输出 processRuns / processEvents / processArtifacts / agents
│
└─ ChatWorkbench
   ├─ 桌面端显示 ProcessLane
   ├─ 移动端显示 Process tab
   └─ 不直接暴露隐藏事件原始 JSON
Learning pipeline
│
├─ evidence recording
│  ├─ every run -> RunRecord
│  ├─ activated skills -> SkillEffectRecord
│  └─ no candidates generated here
│
├─ feedback gate
│  ├─ validation accepted + satisfied -> scoped learning candidate
│  ├─ validation rejected + satisfied -> 记录人工接受风险,不生成候选
│  ├─ revise -> 保持 Task 打开,不生成候选
│  └─ abandon -> 失败证据,不写主 memory不生成成功候选
│
├─ scoped candidate generation
│  ├─ source = current task run_ids
│  ├─ no published skill -> new_skill
│  └─ published skill used -> revise_skill
│
├─ SkillLearningPipelineService
│  ├─ candidate -> queued / synthesizing
│  ├─ worker/run-once -> draft
│  ├─ draft -> safety report
│  ├─ draft -> lightweight eval report
│  ├─ safety_failed / eval_failed 阻断发布
│  ├─ draft -> submit review
│  ├─ approve / reject
│  ├─ approved + safety passed + eval not failed -> publish
│  ├─ retire proposal -> apply retire
│  └─ rollback / disable
│
├─ SkillLearningWorker
│  ├─ 默认按配置定时扫描 open candidates
│  ├─ 自动生成 draft_ready / safety_failed / eval_failed
│  └─ 永不自动 approve / publish
│
├─ Web review workbench
│  ├─ Candidates
│  ├─ Draft detail
│  ├─ Safety report
│  └─ Eval report
│
└─ Runtime catalog
   └─ 只有 published skill 进入运行时选择draft 不生效

16. Web / Gateway

Web网页入口
│
├─ FastAPI lifespanFastAPI 生命周期)
│  ├─ create or receive AgentService创建或接收 AgentService
│  ├─ start() when app owns lifecycle如果 Web app 拥有生命周期,就启动 service
│  ├─ start SkillLearningWorker when enabled按配置启动技能学习 worker
│  └─ shutdown() when app owns lifecycle如果 Web app 拥有生命周期,就关闭 service / worker
│
├─ GET /api/ping健康检查接口
│  └─ return status / running / mode返回状态、是否运行、运行模式
│
├─ POST /api/chat聊天接口
│  ├─ validate WebChatRequest校验请求体
│  ├─ agent_service.submit_direct(...)(把用户消息提交给 AgentService
│  └─ return WebChatResponse返回模型回复 + run/task/validation 元数据)
│
├─ WS /ws/{session_id}(网页 WebSocket 适配层)
│  ├─ ping -> pong
│  ├─ message -> agent_service.submit_direct(...)
│  ├─ return status / assistant message携带 run/task/validation 元数据)
│  └─ return session_updated通知前端刷新 session/process
│
└─ POST /api/chat/feedback聊天反馈接口
   ├─ validate WebChatFeedbackRequest
   ├─ agent_service.submit_feedback(...)
   └─ return WebChatFeedbackResponse

Skills learning admin API
│
├─ GET /api/skills/candidates
├─ POST /api/skills/candidates/{candidate_id}/draft
├─ POST /api/skills/candidates/{candidate_id}/regenerate
├─ POST /api/skills/learning/run-once
├─ GET /api/skills/{skill_name}/drafts/{draft_id}/safety
├─ GET /api/skills/{skill_name}/drafts/{draft_id}/eval
└─ POST /api/skills/{skill_name}/drafts/{draft_id}/publish
   └─ requires approved review + safety passed + eval not failed
Gateway消息通道入口
│
├─ MessageBus内部消息总线
├─ ChannelAdapterTelegram / Slack / Email / WhatsApp 等只作为 adapter
├─ inbound -> AgentService.handle_inbound_message(...)(外部消息进入 AgentService
├─ outbound <- OutboundMessageAgentService 返回结构化输出消息)
└─ ChannelManager按 message.channel 分发 outbound

17. Bus Mode Skeleton

AgentLoop.run()(后台队列运行模式)
│
├─ create queue创建任务队列
├─ mark running标记为运行中
├─ consume _DirectRunRequest消费一个任务请求
├─ call _process_direct_impl(...)(调用真正的单轮执行逻辑)
├─ set future result / exception把结果或异常写回等待方
├─ stop() -> enqueue sentinel停止时放入结束标记
└─ drain pending queue on exit退出时清理未处理任务