Add intent-to-workflow execution #144

Merged
weichen merged 10 commits from feature/agent-harness-p4 into main 2026-10-02 01:04:03 +00:00
11 changed files with 129 additions and 5 deletions
+29
View File
@@ -0,0 +1,29 @@
# feature/agent-harness-p4 任务卡
任务主记录:<PR 链接,task-finish 时填写>;状态:进行中;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 服务在收尾时删除。脚本没有沙箱隔离,靠开关、确认和回调白名单。墙钟超时包含等待人工的时间。
+15
View File
@@ -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": "主题是什么?"
}
]
}
]
+4
View File
@@ -32,6 +32,10 @@
],
"commands": [
"demo"
],
"workflows": [
"demo-brief",
"demo-script"
]
}
}
+57
View File
@@ -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": "不会再改"}
]
}
}
]
}
@@ -0,0 +1,13 @@
{
"id": "demo.script",
"title": "示例脚本",
"description": "插件自带脚本。需要打开 runtime.workflowScripts。不绑定意图,用 run_workflow 启动。",
"steps": [
{
"id": "run",
"title": "跑脚本",
"kind": "script",
"script": "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")