diff --git a/.task/feature-agent-harness-p4.md b/.task/feature-agent-harness-p4.md new file mode 100644 index 00000000..174efb3a --- /dev/null +++ b/.task/feature-agent-harness-p4.md @@ -0,0 +1,29 @@ +# feature/agent-harness-p4 任务卡 + +任务主记录:;状态:进行中;owner:weichen + +## 基线与授权 + +- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= 959179f88fafa06daeab121929112069d34e8419 +- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-agent-harness-p4(worktree);分支:feature/agent-harness-p4 +- 授权与交付终点:实现 P4 意图到工作流。允许改 Core、Backend、Frontend、UI、Documents,并在各自 `feature/agent-harness-p4` 上提 PR;Dev 仓推进 `modules/core`、`modules/backend`、`modules/frontend`、`modules/ui`、`modules/documents` 与 `plugins/example` 并提 PR。终点是六个 PR 已开、不合入。未授权:合入 main、改 agent-native、改 agent-squad 契约、动 `dev` 服务。 +- 启动自检(2026-10-01T15:52Z):`make precheck` verdict READY。head=959179f88f,origin/main 同步,树干净。必读 core/baseline.md、workflows/delivery.md §1 已读。 +- 裁定:路由先命令总线,再绑定工作流,最后才是普通回合。工作流启动时拷贝一份定义,插件卸载不影响已经在跑的工作流。声明式工作流最多 20 步;模型生成的最多 8 步,不能含 `script`,执行前必须用户确认。critic 每步最多重试 3 次、缺省 1 次,整个工作流最多重试 6 次。脚本最多回调 50 次,单行不超过 1MB,超时缺省 600s、最长 1800s(墙钟,含等待 HITL 和子代理)。脚本与 `run_python` 相同,以当前用户身份运行,工作目录为会话沙箱,没有网络或文件系统隔离。回调一律经过 `runCtx.ExecuteTool`,不能调用 `run_python`、`run_shell`、`run_workflow` 和派发类工具。模型写的脚本运行前必须确认;插件自带的脚本不需要。开关 `runtime.workflowScripts` 缺省关闭。critic 无法解析按不通过处理。小队入口不提供 `run_workflow`。 + +## 目标与非目标 + +- 目标:`WorkflowDef` 有执行器。意图命中后接到绑定的工作流。critic 按步骤打回,每步和整条工作流都有上限。同时支持模型生成步骤和沙箱脚本两种动态工作流。 +- 非目标:不新增工作流界面和事件。Frontend 与 UI 只同步契约。不改内核与小队仓契约。不合入 main。 + +## 同步记录 + +| 节点 | sync_base_sha | tested_head_sha | checked_at | +|---|---|---|---| +| 启动 | 959179f88fafa06daeab121929112069d34e8419 | 959179f88fafa06daeab121929112069d34e8419 | 2026-10-01T15:53:54Z | +| 同步前验收 | 959179f88fafa06daeab121929112069d34e8419 | 5f872f3b7f165c2a6cbef09bbcaa711f5bdf723c | 2026-10-01T16:38:23Z | + +## 结果与验证(完成后填写) + +- 结果:Core `f93f473` 给步骤加上 Agent、Script、Critic,kind 增加 script。Backend `4b4be2b` 注册工作流、按意图启动、执行六类步骤、确认后跑模型规划、以及 fd 3/fd 4 脚本宿主。Frontend `7d796ee` 与 UI `22666a0` 只同步了契约。Documents `974db6a` 写入 P4 裁定。Dev `5f872f3` 推进这五个模块,并给示例插件加上 `demo.brief` 与 `demo.script`。 +- 验证:启动时 `make precheck` 为 READY,head `959179f88f`(2026-10-01T15:52Z)。`make task-sync` 记录 sync_base `959179f88f`、tested_head `5f872f3`、checked_at 2026-10-01T16:38:23Z。随后在该 head 上 `make test` 通过:边界检查、core、backend、frontend vitest 53、UI tsc 与 vitest 71、agent-command。三处 agent-native 仍是 `a34689c`。p4 服务(127.0.0.1:8929,数据从 dev 备份,未改 dev)核对了三项:会话 `cnv_e3f0cf85f48d` 中「写一份简报」先问「主题是什么?」,critic 打回一次并留下丢弃理由,重跑后完成,工件 `art_76f9b51b4e27`,收件箱有「简报好了」。会话 `cnv_ccba204decb3` 中 `run_workflow` 的 goal 先请用户确认计划,确认后执行完成。打开 `runtime.workflowScripts` 后,会话 `cnv_adadae794ae2` 跑插件脚本 `demo.script`,脚本问「要记下来吗?」,确认后产出 `demo-script.md`(`art_13fe6947ef6e`)。 +- 影响与剩余项:六个 PR 不合入。核对用的 p4 服务在收尾时删除。脚本没有沙箱隔离,靠开关、确认和回调白名单。墙钟超时包含等待人工的时间。 diff --git a/modules/backend b/modules/backend index 46ce1b2c..4b4be2be 160000 --- a/modules/backend +++ b/modules/backend @@ -1 +1 @@ -Subproject commit 46ce1b2c8e11bbaf17dc6937d2f7365296390444 +Subproject commit 4b4be2be259639b0e192aedc72921289de2d0ed3 diff --git a/modules/core b/modules/core index 9b8cf79c..f93f473a 160000 --- a/modules/core +++ b/modules/core @@ -1 +1 @@ -Subproject commit 9b8cf79c96668628926d32046cd650f0cfbd285b +Subproject commit f93f473a0ea898785921e3c4fb16114549fd2783 diff --git a/modules/documents b/modules/documents index a3f0b807..974db6a0 160000 --- a/modules/documents +++ b/modules/documents @@ -1 +1 @@ -Subproject commit a3f0b80759fa01094cb9ee26b2a17dba831317e2 +Subproject commit 974db6a011f04ed7eb229f2807c5dc79813ffd58 diff --git a/modules/frontend b/modules/frontend index f718095d..7d796ee5 160000 --- a/modules/frontend +++ b/modules/frontend @@ -1 +1 @@ -Subproject commit f718095d783d7e13c445a490c52551b29a3f93a8 +Subproject commit 7d796ee5070c0729d2a96ba03183799c9bb04b60 diff --git a/modules/ui b/modules/ui index bd3baff9..22666a08 160000 --- a/modules/ui +++ b/modules/ui @@ -1 +1 @@ -Subproject commit bd3baff9ea43c05597dcc92ce4c17b5a9fd255ac +Subproject commit 22666a0835e1992bc8ade80d9e3b074d9e9e5d4c diff --git a/plugins/example/intents/demo.json b/plugins/example/intents/demo.json index 370d3852..eccf1cc7 100644 --- a/plugins/example/intents/demo.json +++ b/plugins/example/intents/demo.json @@ -6,5 +6,20 @@ "description": "示例意图:命中『示例/演示』关键词(slots 声明即 HITL 该问什么;本示例无必填槽位)", "matcher": { "includes_any": ["示例", "演示"] }, "slots": [] + }, + { + "id": "demo.brief", + "domain": "demo", + "version": 1, + "description": "写一份简报。必填槽位 topic,没写就问「主题是什么?」。", + "matcher": { "includes_any": ["简报"] }, + "slots": [ + { + "key": "topic", + "required": true, + "pattern": "主题[::]\\s*(\\S+)", + "question": "主题是什么?" + } + ] } ] diff --git a/plugins/example/plugin.json b/plugins/example/plugin.json index 6b040d15..df19a2f1 100644 --- a/plugins/example/plugin.json +++ b/plugins/example/plugin.json @@ -32,6 +32,10 @@ ], "commands": [ "demo" + ], + "workflows": [ + "demo-brief", + "demo-script" ] } } diff --git a/plugins/example/workflows/demo-brief.json b/plugins/example/workflows/demo-brief.json new file mode 100644 index 00000000..f7c62945 --- /dev/null +++ b/plugins/example/workflows/demo-brief.json @@ -0,0 +1,57 @@ +{ + "id": "demo.brief", + "title": "示例简报", + "description": "命中 demo.brief 后:选篇幅、起草、落成工件、发一张结果卡,再请用户确认。", + "intentId": "demo.brief", + "steps": [ + { + "id": "length", + "title": "篇幅", + "kind": "hitl", + "hitl": { + "question": "要多长?", + "kind": "choice", + "allowFreeInput": false, + "choices": [ + {"id": "short", "label": "短", "description": "一段", "impact": "只写一段"}, + {"id": "long", "label": "长", "description": "几段", "impact": "会写得更长"} + ] + } + }, + { + "id": "draft", + "title": "起草", + "kind": "prompt", + "agent": "research", + "prompt": "写一份关于「{{slots.topic}}」的简报,篇幅:{{steps.length.output}}。", + "critic": {"criteria": "必须包含单独一行「核对标记:P4」。没有这一行就不通过,nextAction 请要求补上这一行。", "maxRetries": 1} + }, + { + "id": "save", + "title": "成稿", + "kind": "artifact", + "artifact": "demo-brief.md", + "prompt": "{{steps.draft.output}}" + }, + { + "id": "note", + "title": "收件", + "kind": "card", + "card": {"kind": "result", "title": "简报好了", "tone": "ok"} + }, + { + "id": "confirm", + "title": "确认", + "kind": "hitl", + "hitl": { + "question": "这份简报可以用吗?", + "kind": "confirm", + "allowFreeInput": false, + "choices": [ + {"id": "yes", "label": "可以用", "description": "结束", "impact": "不会再改"}, + {"id": "no", "label": "先不用", "description": "结束", "impact": "不会再改"} + ] + } + } + ] +} diff --git a/plugins/example/workflows/demo-script.json b/plugins/example/workflows/demo-script.json new file mode 100644 index 00000000..1dba4a73 --- /dev/null +++ b/plugins/example/workflows/demo-script.json @@ -0,0 +1,13 @@ +{ + "id": "demo.script", + "title": "示例脚本", + "description": "插件自带脚本。需要打开 runtime.workflowScripts。不绑定意图,用 run_workflow 启动。", + "steps": [ + { + "id": "run", + "title": "跑脚本", + "kind": "script", + "script": "workflows/scripts/demo.py" + } + ] +} diff --git a/plugins/example/workflows/scripts/demo.py b/plugins/example/workflows/scripts/demo.py new file mode 100644 index 00000000..ce23392f --- /dev/null +++ b/plugins/example/workflows/scripts/demo.py @@ -0,0 +1,6 @@ +import agentwf as wf + +now = wf.tool("time_now", {}) +answer = wf.ask("要记下来吗?", [{"id": "yes", "label": "记下", "impact": "会写入一份备忘"}]) +wf.artifact("demo-script.md", "时间 " + now + "\n选择 " + answer) +wf.step("run", "跑脚本", "done")