agent-Specialization/workflow_research/code_mount_points/code_mount_points.md

25 KiB
Raw Blame History

代码库「工作流Workflow功能」挂载点调研报告

调研目标为即将新增的「工作流Workflow功能」定位代码库内的接入挂载点。 前提理解:工作流 = 用户把「一套既定流程:工作方式→验证方式→结束方式」存为一个工作流文件夹(类似现有 skill 文件夹机制,可附带验证过的脚本/代码文件);之后在对话中复用以现有智能体循环+执行引擎运行它;可能有独立 URL/workflow/new)或作为普通对话的一种运行方式;阶段/整体结束时由审核智能体审核(复用两套现有审核:工具审核 + 目标模式 goal_review

调研约束:仅只读操作,未修改任何项目文件。所有结论均基于实际读到的代码,标注文件路径与行号;不确定处明确写「未确认」。 所有代码路径均以项目根 /Users/jojo/Desktop/agents/正在修复中/agents 为准(相对路径书写)。


1. Skill 系统全链路(工作流文件夹需仿照它)

1.1 目录结构与 SKILL.md frontmatter

  • 源码树 skill 库agentskills/(每个 skill 一个子目录,内含 SKILL.md,可含 references/scripts/ 等附带文件)。示例:agentskills/terminal-guide/SKILL.mdagentskills/skill-creator/SKILL.md
  • SKILL.md frontmatter 格式YAML 简单解析):
    ---
    name: terminal-guide
    description: 持久化终端使用指南。……
    ---
    
    后端校验逻辑见 modules/skills_manager.py::validate_skill_directory(第 146 行起),只强制要求存在 name:description:re.search(r"(?m)^\s*name\s*:", content) 与 description 同理。frontmatter 全文解析见 _parse_frontmatterL174
  • 目录名校验_is_valid_skill_idL202SKILL_ID_PATTERN

工作流接入判断工作流文件夹可直接复用这套「SKILL.md + 附带脚本」结构。建议新增一个 WORKFLOW.md(或复用 frontmatter 扩展字段),并在目录中携带验证过的 scripts/ 目录。校验时除 SKILL.md 的 name/description 外,可扩展校验「工作方式→验证方式→结束方式」三段定义。

1.2 skill 创建/归档工具后端实现

  • 工具定义core/main_terminal_parts/tools_definition/file_tools.py L139 定义 create_skill(描述「验证并归档一个已创建好的 skill 文件夹」)。
  • handlercore/main_terminal_parts/tools_execution.py
    • _resolve_create_skill_source_dirL525解析 source_dir相对/绝对/宿主机任意路径)。
    • _get_create_skill_target_rootL539归档目标根目录 —— 优先 infer_private_skills_dir(self.data_dir),否则 data_dir 父级下 agentskills
    • _handle_create_skill_toolL545调用 archive_skill_directory(source, target_root) 归档;成功后同步工作区 skillssync_workspace_skills)。
  • 归档函数modules/skills_manager.py::archive_skill_directoryL182——先 validate_skill_directory 校验,再 shutil.move 移动到目标库;目标存在则拒绝(不覆盖)。
  • 私有 skill 目录推断modules/skills_manager.py::infer_private_skills_dirL97——host 模式统一 ~/.astrion/astrion/<mode>/agentskillsweb/docker 按用户路径推断。

工作流接入判断:可仿 create_skill 新增 create_workflow 工具或复用同一归档通道handler 在 tools_execution.pyhandle_tool_call 分发链L960elif tool_name 分支约 L1130注册归档逻辑复用 archive_skill_directory 的校验+移动+拒绝覆盖机制。

1.3 skill 如何注入提示词

  • 注入点:core/main_terminal_parts/context/messages.py L305-320build_messages 内按 system prompt 顺序追加 skills 列表:
    skills_catalog = get_skills_catalog(private_dir=infer_private_skills_dir(self.data_dir))
    enabled_skills = merge_enabled_skills(...)
    def _build_skills_system_prompt():
        template = self.load_prompt("skills_system")
        return build_skills_prompt(template, build_skills_list(...))
    skills_prompt = self._get_or_init_frozen_prompt("frozen_skills_prompt", _build_skills_system_prompt)
    if skills_prompt: messages.append({"role":"system","content":skills_prompt})
    
  • 模板prompts/skills_system.txt(占位 {skills_list},提示用 read_skill 读取)。
  • enabled/syncmerge_enabled_skillsskills_manager L373sync_workspace_skillsL409——把启用 skill 复制到工作区 .astrion/skills/
  • skill_hints 意图识别config/skill_hints.json关键词→hint用于在用户消息中检测相关 skill 并注入提示(读 _inject_intent 相关)。

工作流接入判断:工作流列表可仿 skills_prompt 在 messages.py build_messages 增加一段 system prompt 注入当前工作流上下文(当前已激活工作流的流程说明),复用 _get_or_init_frozen_prompt 冻结机制与 load_prompt 模板机制。

1.4 skill 列表/读取 API

  • 列表 APIserver/tasks/skills.py GET /api/skillsL126@tasks_bp.route)→ _list_workspace_skillsL83读取工作区 .astrion/skills/*/SKILL.md,解析 name/description/path。
  • 读取:工具 read_skillfile_tools.py L132→ handler _handle_read_skill_tooltools_execution.py 中)。

工作流接入判断:仿 server/tasks/skills.py 新增 GET /api/workflows(读工作流库目录),用于前端列表展示与「作为对话新类型创建」时选择工作流。


2. 两套审核智能体架构(工作流阶段审核复用)

2.1 工具审核 approval_agent

  • 实现modules/approval_agent.py(由配置 CONFIG_PATH = Path(resolve_deploy_config("auto_approval.json")) 指定L16 → config/auto_approval.json[.example])。
  • 调用方式modules/auto_approval_service.py::run_auto_approvalL84构造 ApprovalAgent(web_terminal=web_terminal)await agent.review(payload_text=..., progress_cb=..., cancel_check=...)build_auto_approval_payloadL15组装用户输入+最近工具操作+触发风险标记。
  • 输入payload 纯文本(审批场景上下文 + 当前工具调用函数名/参数)。
  • 输出{"decision": "approved"|"rejected", "reason": str, "source": "approval_agent"}。内部通过工具 approve_decisionL168返回异常/配置缺失时兜底 {"decision":"rejected", ...}
  • 执行模式readonly 或注入只读 run_command 取证(与 goal_review 同构)。

工作流接入判断:工作流的「工具/操作级」安全审核可直接复用 ApprovalAgent,通过 auto_approval_service 同构入口调用;无需新造。若需按工作流阶段应用不同审核,可在 run_auto_approval 之外包装一个「阶段审核」封装函数。

2.2 目标审核 goal_review

  • 实现modules/goal_review_agent.py(配置 CONFIG_PATH = resolve_deploy_config("goal_review.json")L20GoalReviewAgent(web_terminal=...)async review(payload_text, review_mode, progress_cb, cancel_check)
  • 输出{"status":"done"|"continue", "message": str, "source":"goal_review_agent"};兜底保守返回 continue。review_mode 由 modules/goal_state_manager.py 常量 REVIEW_MODE_READONLY="readonly" / REVIEW_MODE_ACTIVE="active"L34-35决定是否注入只读 run_command。
  • 目标模式如何触发审核server/goal_flow.py
    • maybe_start_goalL56用户显式开启目标模式时启动读 personalization 的 review_mode/end_conditions
    • inject_goal_promptL88注入目标模式提示词。
    • handle_goal_after_turnL147在主循环「主模型一轮无 tool_calls」时拦截——先空转保护/边界检查,再调 GoalReviewAgent.review
      • status=="continue"append_review 记录审核历史 + inject_runtime_user_message(CONTINUE_PREFIX + message) 回写续命 user 消息到 messages,调用方 continue 回主循环开下一轮;
      • status=="done"mark_done,任务结束。
  • 状态落盘modules/goal_state_manager.py,工作区 {data_dir}/goal_state.json(含 goal、review_mode、turns、review_history 等)。
  • 触发入口(后端):创建任务时传 goal_modeserver/tasks/models.py create_chat_task 存 session_data → run_chat_task_sync 时置 terminal._goal_mode_requested=Truemodels.py L961/L998-999chat_flow_task_main.py L1863 检测并 maybe_start_goal

工作流接入判断(关键复用点):工作流的「阶段结束/整体结束审核」几乎可 1:1 复用 goal_review 的回写机制——在 chat_flow_task_main.py 主循环的 no-tool-call 结束判定处L2226 附近 if not tool_calls:),当前已有 if goal_is_active(workspace): handle_goal_after_turn(...) 分支;工作流运行时可仿照新增「工作流阶段/整体审核」调用 GoalReviewAgent(或新 WorkflowReviewAgent),并把 continue/done 语义映射为「进入下一阶段/结束工作流」。建议抽出一个与 goal_flow.py 同构的 workflow_flow.py 编排模块,减少对主循环侵入。


3. 智能体循环与执行引擎(工作流运行时复用)

3.1 主循环入口链路(骨架级)

  • 唯一入口(门闸)server/chat_flow.py::process_message_taskL130——先 acquire_adopted_main_task_gate 拿对话级门闸§12 单写者不变量),然后 loop.create_task(handle_task_with_sender(...))任何新增的主任务入口必须走此门闸AGENTS.md §12.4)。
  • 实际任务执行server/chat_flow_task_main.py::handle_task_with_senderL1411
    • L1855 messages = web_terminal.build_messages(context, message)tools = web_terminal.define_tools()
    • L1863 目标模式启动/续注入。
    • L1962 while max_iterations is None or iteration < max_iterations: 主循环迭代:
      • 每轮 run_streaming_attempts(messages=messages, tools=tools, ...)L2082导入自 server/chat_flow_stream_loop.py)调模型,返回 full_response / tool_calls。
      • 有 tool_calls → L2325 execute_tool_calls(...) 执行工具(结果 append 到 messages/对话历史),continue 下一轮。
      • 无 tool_callsL2226 if not tool_calls:)→ 目标审核分支L2230→ 多智能体注入分支L2314→ 否则 break 结束。
  • 工具执行循环server/chat_flow_tool_loop.py::execute_tool_callsL409_execute_tool_calls_implL426守护包装 try/finally 复位 _tool_loop_active
    • 白名单校验allowed_tool_names→ 权限评估 web_terminal.evaluate_tool_permission → 逐个 tool_call 解析/执行,结果 web_terminal.context_manager.add_conversation("tool", ...) + messages.append({"role":"tool", ...})
    • 工具真实执行在 core/main_terminal_parts/tools_execution.py::handle_tool_callL960elif tool_name = handler 分发大表)。

工作流接入判断:工作流运行不需要新增主循环,直接复用 process_message_task 门闸 + handle_task_with_sender 迭代即可(把工作流定义作为额外的 system 上下文 + 结束阶段审核挂钩即可)。若想「阶段结束审核后进入下一阶段并继续迭代」,参照 goal_review 的 continue → inject_runtime_user_message + continue 模式,完全在现有消息/迭代机制内实现。

3.2 运行模式 work_mode 三档plan/ask/execute——新增一种运行方式的最相近参照

  • 核心实现core/main_terminal_parts/tools_policy.pyWORK_MODES = {"plan","ask","execute"}, WORK_MODE_DEFAULT="plan"L88set_work_mode / switch_work_mode(处理 plan⇄只读权限+沙箱联动)/ get_work_mode;权限模式 PERMISSION_MODES 与 plan 锁。
  • 怎么注入提示词规则core/main_terminal_parts/context/mode.py
    • _build_work_mode_rules(mode)L192三档规则文本唯一来源plan/ask/execute 各自的 detailed_rules
    • _build_work_mode_messageL220load_prompt("work_mode") 模板 + replace work_mode/work_mode_label/mode_description/detailed_rules
    • 属于 _RUNTIME_MODE_KINDSL133含 permission_mode/execution_mode/network_permission/work_mode切换走 drift 通知(_RUNTIME_MODE_SOURCE 第 花 种 "work_mode_change")。
    • 冻结注入messages.py::build_messages L203-208 _get_or_init_frozen_mode_prompt("frozen_work_mode_prompt", self._build_work_mode_message)
  • 怎么影响工具可用性work_mode 主要通过提示词约束(三档规则正文),而非硬性工具过滤(行为差异在规则里,如 ask 禁用 ask_user 工具由提示词说明plan 的只读是权限层联动)。工具的硬开关由 tool_category_states/disabled_tools(同一文件 tools_policy.py控制。

工作流接入判断:若把「工作流运行」作为与 work_mode 平行的「一种运行方式」,可仿此模式:新增一类提示词规则(如 workflow.txt 模板 + _build_workflow_rules+ 在 messages.py 追加一段冻结注入;运行会话期间注入工作流当前阶段上下文。但注意 work_mode 是「与用户交互节奏」正交档位,与工作流(一套流程)语义不同——更倾向工作流作为「消息级上下文+审核挂钩」,而非新增第四档 work_mode。建议工作流保持并在 _RUNTIME_MODE_KINDS 之外独立管理(不要混入 work_mode 切档,避免交互节奏冲突)。

3.3 提示词模板机制prompts/ 组织 + mode.py 构建)

  • 目录prompts/*.txt(如 main_system.txtwork_mode.txtskills_system.txtgoal_review_agent.txtexecution_mode/multi_agent/sub_agent/)。
  • 加载core/main_terminal_parts/context/prompt.py::load_prompt(name)L157——Path(PROMPTS_DIR)/f"{name}.txt",存在则读,否则返回兜底文案。
  • 构建规则context/mode.py 负责把「运行期状态」渲染进 promptpermission/execution/work_mode/networkcontext/messages.pybuild_messagesL109按固定 order 追加各 system prompt主 prompt → 权限 → 执行环境 → 运行模式 → 最近对话 → 个性化 → 工作区 → AGENTS.md → skills → 记忆 → 自定义 → 禁用提示。
  • 冻结机制_get_or_init_frozen_prompt / _get_or_init_frozen_mode_prompt 对可变但需稳定的 system 段做一次性构建缓存。

工作流接入判断:新增 prompts/workflow.txt 模板(或 prompts/workflow/ 子目录),在 messages.py::build_messages 适当的 order 位(建议主 prompt 后、skills 前/后)插入工作流上下文 system 段,并用 load_prompt("workflow") 加载。完全复用现有模板/冻结机制。


4. 前端入口与路由(/workflow/new 怎么挂)

4.1 路由定义位置与现有 /multiagent 兼容重定向

  • 前端未用 vue-router,而是手动处理 window.location.pathname(无 createRouter/createWebHistory全库无 vue-router
  • 路由解析/重定向核心static/src/app/methods/ui/route.ts::bootstrapRouteL26 起):
    let path = window.location.pathname.replace(/^\/+/, '');
    if (path === 'multiagent/new' || path === 'multiagent') {
      history.replaceState({}, '', '/new'); path = 'new';
    } else if (path.startsWith('multiagent/')) {
      const bareId = ...; history.replaceState({}, '', `/${bareId}`); path = bareId;
    }
    
    即旧 /multiagent/* → 重定向到裸 /conv_xxx/multiagent/new/new(对话类型是 metadata 属性,不再是路由概念)。
    • 若裸新建路由:清空当前对话、恢复 draft → 结束。
    • 否则按 conv_<id>this.enterConversation(convId, ...)app/methods/conversation/bootstrap.ts)加载并恢复。
  • isExplicitNewConversationRoute():判断是否显式新建路由。

工作流接入判断/workflow/new 可在 bootstrapRoute 增加一个分支:if (path === 'workflow/new' || path === 'workflow') → 进入「新建工作流对话」模式(清空 + 标记 newConversationType='workflow'history.replaceState 保持 URL 为 /workflow/new。后端需相应 with_terminal/路由能接受该路径(未确认:当前 route 无条件把 path 当 conv id需额外分支避开

4.2 对话类型机制newConversationType / currentConversationType

  • 状态定义static/src/app/state.ts
    • currentConversationTypeL57当前已打开对话类型 'normal'|'multi_agent'|null,由 enterConversation 从 metadata 恢复(bootstrap.ts L66
    • newConversationTypeL59空对话待创建类型 'agent'|'multi_agent'localStorage 持久化key 见 state.ts 上方 NEW_CONVERSATION_TYPE_STORAGE_KEY),由 input composer 的 agent-type-switcher 修改。
  • 创建对话按类型选 API
    • 首条消息创建:static/src/app/methods/message/send.ts L269const isMultiAgent = this.newConversationType === 'multi_agent'; const createUrl = isMultiAgent ? '/api/multiagent/conversations' : '/api/conversations';
    • 侧边栏新建:static/src/app/methods/conversation/action.ts L134/L276useConversationStore().sidebarConversationType 选同两个 URL。
  • 输入栏类型选择器components/input/InputComposer.vue L328 agent-type-switcher(渲染 newConversationType 选项:智能体/多智能体)。

工作流接入判断(关键):若工作流作为新对话类型:需在 newConversationType/currentConversationType 类型联合中增加 'workflow'send.ts L269action.ts L134/276 增加「工作流创建」的 URL 分支(如 /api/workflow/conversations 或复用 /api/conversations+workflow_id 参数);InputComposer.vue 的 agent-type-switcher 增加工作流选项。注意 types 是字符串字面量联合L780 newConversationType?: 'agent'|'multi_agent'),需同步扩展 TS 类型与所有 switch 点。

4.3 输入栏运行模式切换器 work-mode-switcher

  • 实现位置static/src/components/input/InputComposer.vue L354<div class="agent-type-switcher work-mode-switcher" ...>,渲染 workModeOptions@clickworkModeMenuOpen 菜单。
  • 切换逻辑static/src/app/methods/ui/workMode.tsfetchWorkModeGET /api/work-mode带 conversation_idchangeWorkModePOST /api/work-mode409 空闲才可切)、toggleWorkModeMenu/closeWorkModeMenu。plan 联动更新前端 permissionMode/executionMode 显示。
  • 后端 APIserver/chat/permission.py GET/POST /api/work-modeL402/L418

工作流接入判断:若工作流作为「普通对话的一种运行方式」(而非新 URL可在 work-mode-switcher 同区域加一个「工作流选择器」(选当前激活的工作流 / 另存为新工作流),方法放 static/src/app/methods/ui/workflow.ts(同构 workMode.ts后端提供 GET/POST /api/workflow 子资源。


5. 数据存储约定(工作流文件夹放哪)

  • 运行态数据根config/paths.pyRUNTIME_ROOT = ~/.astrion/astrionL83-84ASTRION_DATA_ROOT 覆盖);_MODE = _runtime_mode() 分流 host/webTERMINAL_SANDBOX_MODE 决定)。各目录见 §1.5DATA_DIR/LOGS_DIR/USER_SPACE_DIR/API_USER_SPACE_DIRL102-106
  • CUSTOM_SKILLS_DIRstr(Path(RUNTIME_ROOT)/_MODE/"agentskills")L109——私有 skill/工作流的运行态位置。host 模式 IS_HOST_MODEL112
  • 源码树 seedAGENT_SKILLS_DIR(默认 ./agentskillsL163PROMPTS_DIR./promptsL162AGENT_SKILLS_DIR 默认源码树。
  • resolve_deploy_config 回退链L135<data_root>/config/<filename>(部署者真实配置)→ 源码树 config/<filename>seed→ 源码树 config/<filename>.example(示例兜底)。deploy_config_pathL126用于可写配置不回退
  • 工作区级 .astrionWORKSPACE_SKILLS_DIRNAME=".astrion/skills"L170WORKSPACE_MEMORY_DIRNAME=".astrion/memory"L171WORKSPACE_REVIEW_DIRNAME=".astrion/review"L172注意:这是工作区项目内(源码树或其他工作目录)的 .astrion,与运行态 ~/.astrion/astrion/<mode> 不同。

工作流接入判断(关键决策点)

  • 源码树 vs 运行态skill 采用「源码树 seedagentskills/)” + “运行态私有(~/.astrion/astrion/<mode>/agentskills/CUSTOM_SKILLS_DIR双源」通过 get_skills_catalog(base_dir=AGENT_SKILLS_DIR, private_dir=CUSTOM_SKILLS_DIR) 合并skills_manager.py L282启用后同步到工作区 .astrion/skills/sync_workspace_skills)。
  • 现有机制同时支持两种:工作流库若仿 skill可在源码树 workflows/seed+ 运行态 ~/.astrion/astrion/<mode>/workflowsCUSTOM_SKILLS_DIR 同级)建库,再按启用/激活同步到工作区 .astrion/workflows/判断:用户创建的工作流属「运行态/用户私有」,应落运行态(含脚本的可执行文件),源码树只放内置种子示例;这与 AGENTS.md §1.5「运行态数据不落源码树」一致。
  • 部署级配置(如 auto_approvalgoal_review)走 resolve_deploy_config;工作流若需独立审核配置可仿 config/workflow_review.json[.example] 加入该回退链。

总结:新增工作流功能的最小改动路径建议(文件级)

基于上述调研,判断实现「工作流」的最小改动路径如下(按依赖顺序,每个文件给出改动性质):

  1. config/paths.py(改动):新增 CUSTOM_WORKFLOWS_DIR(运行态,仿 CUSTOM_SKILLS_DIR L109WORKFLOWS_DIR(源码树 seed仿 AGENT_SKILLS_DIR L163WORKSPACE_WORKFLOWS_DIRNAME(仿 L170 .astrion/workflows)三个路径常量。

  2. modules/workflows_manager.py(新增):仿 modules/skills_manager.py 提供 validate_workflow_directory / archive_workflow_directory / get_workflows_catalog / sync_workspace_workflows,校验「工作方式→验证方式→结束方式」三段 + 附带 scripts。

  3. core/main_terminal_parts/tools_definition/file_tools.py + tools_execution.py(改动):新增 create_workflow 工具定义(仿 create_skill L139与 handler _handle_create_workflow_tool(仿 L545/530handle_tool_call 分发链L960 的 elif 分支)注册;归档复用 modules/workflows_manager

  4. prompts/workflow.txt(新增)+ core/main_terminal_parts/context/messages.py(改动):新增工作流上下文模板;在 build_messagesL109skills 段 L305 附近)追加「当前激活工作流」的 system 上下文注入(复用 load_prompt + _get_or_init_frozen_prompt 冻结)。

  5. server/workflow_flow.py(新增)+ server/chat_flow_task_main.py(改动):仿 server/goal_flow.py 编排「阶段/整体审核」。接入点:主循环 if not tool_calls: 结束判定L2226仿 goal 分支L2230增加工作流审核调用——复用 modules/goal_review_agent.py(或其派生 WorkflowReviewAgent)返回 done/continuecontinue 注入续命 user 消息回写 messages复用 chat_flow_task_support.inject_runtime_user_message)。注意:任何新增主任务入口必须遵守 §12 门闸(process_message_task)。

  6. server/tasks/workflows.py(新增,可并入 skills.py仿 server/tasks/skills.pyGET /api/workflows(列表/选择)+ 创建工作流对话的后端端点(如 /api/workflow/conversations 或复用 /api/conversations+workflow_id)。

  7. static/src/app/methods/ui/route.ts(改动):bootstrapRouteL26增加 /workflow/new(及 /workflow)分支,进入「新建工作流对话」模式并 history.replaceState;避免被当作 conv id 解析。

  8. 前端对话类型链路(改动):static/src/app/state.tsL57/59 类型联合加 'workflow')、static/src/app/methods/message/send.tsL269 createUrl 分支)、static/src/app/methods/conversation/action.tsL134/276 分支)、static/src/components/input/InputComposer.vueL328 agent-type-switcher / L354 work-mode-switcher 区域加「工作流选择器」)。若新增「选择/另存工作流」UI仿 static/src/app/methods/ui/workMode.tsstatic/src/app/methods/ui/workflow.ts

附注 / 未确认项:

  • /workflow/new 后端的 with_terminal 路由是否接受该路径、前端是否需新 socket/status 兼容——未确认,需在实现时验证。
  • 工作流「阶段结束审核后进入下一阶段」与 goal mode「目标完成后结束」的边界语义略有差异需在 workflow_flow.py 内明确「阶段衔接」与「整体结束」的状态机,避免与 chat_flow_task_main.py 现有 break/continue 逻辑冲突。
  • work_mode 三档plan/ask/execute是「交互节奏」正交档位工作流不应作为第四档 work_mode而应作为独立的「消息级上下文 + 审核挂钩」,避免与现有 _RUNTIME_MODE_KINDS drift 通知机制冲突。