@fieldwangai/agentflow 0.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +201 -0
  3. package/README.zh-CN.md +201 -0
  4. package/agents/agentflow-node-executor-code.md +32 -0
  5. package/agents/agentflow-node-executor-planning.md +32 -0
  6. package/agents/agentflow-node-executor-requirement.md +32 -0
  7. package/agents/agentflow-node-executor-test.md +32 -0
  8. package/agents/agentflow-node-executor-ui.md +32 -0
  9. package/agents/agentflow-node-executor.md +32 -0
  10. package/agents/agents.json +8 -0
  11. package/agents/en/agentflow-node-executor.md +32 -0
  12. package/agents/zh/agentflow-node-executor.md +32 -0
  13. package/bin/agentflow.mjs +52 -0
  14. package/bin/ensure-workspace-reference.mjs +35 -0
  15. package/bin/lib/agent-runners.mjs +1199 -0
  16. package/bin/lib/agents-path.mjs +61 -0
  17. package/bin/lib/api-runner.mjs +361 -0
  18. package/bin/lib/apply.mjs +852 -0
  19. package/bin/lib/catalog-agents.mjs +300 -0
  20. package/bin/lib/catalog-flows.mjs +532 -0
  21. package/bin/lib/composer-agent.mjs +884 -0
  22. package/bin/lib/composer-flow-instances.mjs +68 -0
  23. package/bin/lib/composer-flow-skeleton.mjs +334 -0
  24. package/bin/lib/composer-flow-validate.mjs +47 -0
  25. package/bin/lib/composer-log.mjs +197 -0
  26. package/bin/lib/composer-model-router.mjs +160 -0
  27. package/bin/lib/composer-node-schema.mjs +299 -0
  28. package/bin/lib/composer-planner.mjs +749 -0
  29. package/bin/lib/composer-script-ops.mjs +233 -0
  30. package/bin/lib/composer-skill-router.mjs +384 -0
  31. package/bin/lib/flow-import.mjs +305 -0
  32. package/bin/lib/flow-normalize.mjs +71 -0
  33. package/bin/lib/flow-write.mjs +395 -0
  34. package/bin/lib/help.mjs +139 -0
  35. package/bin/lib/hub-login.mjs +54 -0
  36. package/bin/lib/hub-publish.mjs +159 -0
  37. package/bin/lib/hub-remote.mjs +189 -0
  38. package/bin/lib/hub.mjs +299 -0
  39. package/bin/lib/i18n.mjs +233 -0
  40. package/bin/lib/locales/en.json +344 -0
  41. package/bin/lib/locales/zh.json +344 -0
  42. package/bin/lib/log.mjs +37 -0
  43. package/bin/lib/main.mjs +611 -0
  44. package/bin/lib/model-config.mjs +118 -0
  45. package/bin/lib/model-lists.mjs +188 -0
  46. package/bin/lib/node-exec-context.mjs +336 -0
  47. package/bin/lib/node-execute.mjs +513 -0
  48. package/bin/lib/normalize-node-tool-command.mjs +97 -0
  49. package/bin/lib/paths.mjs +216 -0
  50. package/bin/lib/pipeline-scripts.mjs +41 -0
  51. package/bin/lib/recent-runs.mjs +173 -0
  52. package/bin/lib/run-apply-active-lock.mjs +82 -0
  53. package/bin/lib/run-events.mjs +85 -0
  54. package/bin/lib/run-node-statuses-from-disk.mjs +85 -0
  55. package/bin/lib/schedule-config.mjs +227 -0
  56. package/bin/lib/scheduler.mjs +312 -0
  57. package/bin/lib/table.mjs +4 -0
  58. package/bin/lib/terminal.mjs +42 -0
  59. package/bin/lib/ui-print.mjs +94 -0
  60. package/bin/lib/ui-server.mjs +2113 -0
  61. package/bin/lib/workspace-tree.mjs +266 -0
  62. package/bin/lib/workspace.mjs +180 -0
  63. package/bin/pipeline/build-node-prompt.mjs +179 -0
  64. package/bin/pipeline/check-cache.mjs +191 -0
  65. package/bin/pipeline/check-flow.mjs +543 -0
  66. package/bin/pipeline/collect-nodes.mjs +212 -0
  67. package/bin/pipeline/compute-cache-md5.mjs +177 -0
  68. package/bin/pipeline/ensure-run-dir.mjs +71 -0
  69. package/bin/pipeline/extract-thinking.mjs +308 -0
  70. package/bin/pipeline/gc.mjs +129 -0
  71. package/bin/pipeline/get-env.mjs +83 -0
  72. package/bin/pipeline/get-exec-id.mjs +145 -0
  73. package/bin/pipeline/get-ready-nodes.mjs +435 -0
  74. package/bin/pipeline/get-resolved-values.mjs +337 -0
  75. package/bin/pipeline/load-key.mjs +62 -0
  76. package/bin/pipeline/parse-bool.mjs +33 -0
  77. package/bin/pipeline/parse-flow.mjs +698 -0
  78. package/bin/pipeline/post-process-control-if.mjs +23 -0
  79. package/bin/pipeline/post-process-node.mjs +490 -0
  80. package/bin/pipeline/pre-process-node.mjs +449 -0
  81. package/bin/pipeline/resolve-inputs.mjs +201 -0
  82. package/bin/pipeline/run-log.mjs +34 -0
  83. package/bin/pipeline/run-tool-nodejs.mjs +160 -0
  84. package/bin/pipeline/save-key.mjs +93 -0
  85. package/bin/pipeline/snapshot-prior-round.mjs +70 -0
  86. package/bin/pipeline/validate-flow.mjs +825 -0
  87. package/bin/pipeline/validate-for-ui.mjs +226 -0
  88. package/bin/pipeline/validate-script-output.mjs +130 -0
  89. package/bin/pipeline/write-result.mjs +182 -0
  90. package/builtin/nodes/agent_subAgent.md +14 -0
  91. package/builtin/nodes/control_agent_toBool.md +20 -0
  92. package/builtin/nodes/control_anyOne.md +17 -0
  93. package/builtin/nodes/control_end.md +11 -0
  94. package/builtin/nodes/control_if.md +20 -0
  95. package/builtin/nodes/control_start.md +11 -0
  96. package/builtin/nodes/control_toBool.md +21 -0
  97. package/builtin/nodes/provide_file.md +11 -0
  98. package/builtin/nodes/provide_str.md +11 -0
  99. package/builtin/nodes/tool_get_env.md +14 -0
  100. package/builtin/nodes/tool_load_key.md +20 -0
  101. package/builtin/nodes/tool_nodejs.md +40 -0
  102. package/builtin/nodes/tool_print.md +14 -0
  103. package/builtin/nodes/tool_save_key.md +20 -0
  104. package/builtin/nodes/tool_user_ask.md +23 -0
  105. package/builtin/nodes/tool_user_check.md +22 -0
  106. package/builtin/pipelines/module-migrate/flow.yaml +819 -0
  107. package/builtin/pipelines/module-migrate/scripts/check_imports.mjs +700 -0
  108. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Makefile +362 -0
  109. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/.deps/Release/obj.target/node_modules/node-addon-api/node_addon_api_except.stamp.d +1 -0
  110. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/.deps/Release/obj.target/tree_sitter_kotlin_binding/bindings/node/binding.o.d +17 -0
  111. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/.deps/Release/obj.target/tree_sitter_kotlin_binding/src/parser.o.d +5 -0
  112. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/.deps/Release/obj.target/tree_sitter_kotlin_binding/src/scanner.o.d +8 -0
  113. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/.deps/Release/tree_sitter_kotlin_binding.node.d +1 -0
  114. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/obj.target/node_modules/node-addon-api/node_addon_api_except.stamp +0 -0
  115. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/obj.target/tree_sitter_kotlin_binding/bindings/node/binding.o +0 -0
  116. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/obj.target/tree_sitter_kotlin_binding/src/parser.o +0 -0
  117. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/obj.target/tree_sitter_kotlin_binding/src/scanner.o +0 -0
  118. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/tree_sitter_kotlin_binding.node +0 -0
  119. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/binding.Makefile +6 -0
  120. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/gyp-mac-tool +768 -0
  121. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/node_modules/node-addon-api/node_addon_api.Makefile +6 -0
  122. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/node_modules/node-addon-api/node_addon_api.target.mk +122 -0
  123. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/node_modules/node-addon-api/node_addon_api_except.target.mk +126 -0
  124. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/node_modules/node-addon-api/node_addon_api_maybe.target.mk +122 -0
  125. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/tree_sitter_kotlin_binding.target.mk +203 -0
  126. package/builtin/pipelines/new/flow.yaml +545 -0
  127. package/builtin/pipelines/new/scripts/check-flow.mjs +9 -0
  128. package/builtin/pipelines/new/scripts/collect-nodes.mjs +211 -0
  129. package/builtin/pipelines/scripts/adjust-node-positions.mjs +113 -0
  130. package/builtin/web-ui/dist/agentflow-icon.svg +23 -0
  131. package/builtin/web-ui/dist/assets/index-CZkUPcXE.css +1 -0
  132. package/builtin/web-ui/dist/assets/index-DkkhNESc.js +190 -0
  133. package/builtin/web-ui/dist/index.html +24 -0
  134. package/package.json +67 -0
  135. package/reference/flow-control-capabilities.md +274 -0
  136. package/reference/flow-layout.md +84 -0
  137. package/reference/flow-prompt-handler-check.md +12 -0
  138. package/reference/flow-result-semantics.md +14 -0
@@ -0,0 +1,24 @@
1
+ <!DOCTYPE html>
2
+ <html class="af-dark" lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>AgentFlow UI</title>
7
+ <link rel="icon" href="/agentflow-icon.svg" type="image/svg+xml" />
8
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
+ <link
11
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Space+Grotesk:wght@400;500;600;700&display=swap"
12
+ rel="stylesheet"
13
+ />
14
+ <link
15
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0"
16
+ rel="stylesheet"
17
+ />
18
+ <script type="module" crossorigin src="/assets/index-DkkhNESc.js"></script>
19
+ <link rel="stylesheet" crossorigin href="/assets/index-CZkUPcXE.css">
20
+ </head>
21
+ <body>
22
+ <div id="root"></div>
23
+ </body>
24
+ </html>
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@fieldwangai/agentflow",
3
+ "version": "0.1.25",
4
+ "description": "Orchestration system for long-running complex agent tasks using Cursor, OpenCode, or Claude Code as execution backends",
5
+ "type": "module",
6
+ "main": "bin/agentflow.mjs",
7
+ "bin": {
8
+ "agentflow": "bin/agentflow.mjs"
9
+ },
10
+ "engines": {
11
+ "node": ">=20"
12
+ },
13
+ "keywords": [
14
+ "agentflow",
15
+ "cursor",
16
+ "opencode",
17
+ "claude-code",
18
+ "agent-orchestration",
19
+ "workflow",
20
+ "cli",
21
+ "automation",
22
+ "checkpoint-resume",
23
+ "long-running"
24
+ ],
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/pproject-github/agentflow.git"
29
+ },
30
+ "homepage": "https://github.com/pproject-github/agentflow#readme",
31
+ "bugs": {
32
+ "url": "https://github.com/pproject-github/agentflow/issues"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public",
36
+ "registry": "https://registry.npmjs.org"
37
+ },
38
+ "files": [
39
+ "bin",
40
+ "agents",
41
+ "builtin/nodes",
42
+ "builtin/pipelines",
43
+ "builtin/web-ui/dist",
44
+ "reference"
45
+ ],
46
+ "scripts": {
47
+ "postinstall": "node bin/ensure-workspace-reference.mjs",
48
+ "build:web-ui": "cd builtin/web-ui && npm install && npm run build",
49
+ "build:website": "cd website && npm install && npm run build",
50
+ "dev": "AGENTFLOW_DEV=1 node bin/agentflow.mjs ui",
51
+ "dev:web": "cd builtin/web-ui && npm run dev",
52
+ "dev:website": "cd website && npm run dev",
53
+ "preview:website": "cd website && npm run preview",
54
+ "prepack": "npm run build:web-ui"
55
+ },
56
+ "dependencies": {
57
+ "busboy": "^1.6.0",
58
+ "chalk": "^5.6.2",
59
+ "cli-table3": "^0.6.5",
60
+ "fflate": "^0.8.2",
61
+ "js-yaml": "^4.1.0",
62
+ "markdansi": "^0.2.1",
63
+ "ora": "^9.3.0",
64
+ "sharp": "^0.34.5",
65
+ "update-notifier": "^7.0.0"
66
+ }
67
+ }
@@ -0,0 +1,274 @@
1
+ # AgentFlow 常见流程控制能力
2
+
3
+ 本文档供 AI 参考:流程中常用的控制节点及其用法、连线方式与典型模式。
4
+
5
+ **说明**:下文中的 handle(如 input-0、output-1)是**可变的**,由节点类或 instance 的 input/output 列表顺序决定;若槽位顺序有变动,须以实际 definition/instance 的 frontmatter 为准。
6
+
7
+ **约定**:内置节点(nodes 目录下的节点类)的 **description** 字段语义为 **agentSystemPrompt**(供执行时作为 agent 的系统 prompt),**不应被修改**;instance 中可覆盖或扩展用户区内容,但不改变该语义。
8
+
9
+ ---
10
+
11
+ ## 1. 入口与出口
12
+
13
+ | 节点 | definitionId | 作用 |
14
+ |------|----------------|------|
15
+ | **Start** | control_start | 流程唯一入口,无 input,只有 output `next`(output-0)。所有边从 start 连出到第一个执行节点。 |
16
+ | **End** | control_end | 流程唯一出口,只有 input `prev`(input-0),无 output。所有最终节点连到 end。 |
17
+
18
+ **约定**:每个 flow 必须包含且仅包含一个 control_start、一个 control_end。
19
+
20
+ ---
21
+
22
+ ## 2. 条件分支(If)
23
+
24
+ - **control_if**:单节点双分支。根据 **prediction**(bool):为 true 时沿 **next1**(output-0)继续,为 false 时沿 **next2**(output-1)继续。适用于「二选一」分支。
25
+
26
+ **典型用法**:上游接一个能输出布尔值的节点(如 **control_toBool**(确定性)或 **control_agent_toBool**(AI 判断)),把布尔槽位连到 If 的 **input-1**(prediction),再根据需要连到不同分支。
27
+
28
+ **control_if Handle**:
29
+ - input: prev → input-0, prediction → input-1
30
+ - output: next1 → output-0(条件为真时), next2 → output-1(条件为假时)
31
+
32
+ ---
33
+
34
+ ## 3. 转布尔(ToBool)
35
+
36
+ ### 3a. control_toBool(本地确定性执行)
37
+
38
+ - **definitionId**: control_toBool
39
+ - **作用**:**本地代码**将上游 **value** 文本用 parseBool 解析为布尔(true/1/yes/on → true,其余 → false),写入 **prediction**。**不调用 AI agent**。
40
+ - **适用场景**:上游输出已是明确的 "true"/"false"、"1"/"0"、"yes"/"no" 等确定性文本。
41
+
42
+ **Handle**:
43
+ - input: prev → input-0, value → input-1
44
+ - output: next → output-0, prediction → output-1
45
+
46
+ ### 3b. control_agent_toBool(AI agent 执行)
47
+
48
+ - **definitionId**: control_agent_toBool
49
+ - **作用**:由 **AI agent** 理解上游 **value** 内容的语义,判断布尔含义后写入 **prediction**。
50
+ - **适用场景**:上游输出是自然语言描述、代码分析结果、复杂报告等需要语义理解才能判定真假的内容。
51
+
52
+ **Handle**:
53
+ - input: prev → input-0, value → input-1
54
+ - output: next → output-0, prediction → output-1
55
+
56
+ **共同约定**:写入 **prediction**(output-1)的**文件内容必须仅为 true 或 false**,供下游 control_if 等解析;不得写入长文本或 markdown 报告。
57
+
58
+ ---
59
+
60
+ ## 4. 多路汇合(AnyOne)
61
+
62
+ - **definitionId**: control_anyOne
63
+ - **作用**:多个上游分支中**任意一个**就绪(success)时,即从 **next** 继续,常用于「多路并行、任一路完成即进入下一步」的场景。
64
+
65
+ **Handle**:
66
+ - input: prev1 → input-0, prev2 → input-1(可扩展更多输入槽位时按 input-2, input-3… 约定)
67
+ - output: next → output-0
68
+
69
+ ---
70
+
71
+ ## 5. 全局存储与环境(LoadKey / SaveKey / GetEnv)
72
+
73
+ 用于**当前 flow 在一次 run 内的全局信息保存与读取**:按 key 在 run 目录下的 memory 存储中写入或读取文本,供多节点共享状态、跨分支传递结果。**GetEnv** 从系统环境变量与用户目录 `~/.cursor/config.json` 按 key 读取,用于注入 API Key、工作区配置等。
74
+
75
+ | 节点 | definitionId | 作用 |
76
+ |------|----------------|------|
77
+ | **LoadKey** | tool_load_key | 按 **key** 从当前 run 的存储中读取一个值,结果输出到 **result** 槽位,可连到下游节点的 input。 |
78
+ | **SaveKey** | tool_save_key | 按 **key** 将 **value** 写入当前 run 的存储;value 可为字面文本,或 run 内相对路径(如 `output/node_xxx_result.md`),脚本会读文件内容后写入。 |
79
+ | **GetEnv** | tool_get_env | 按 **key** 从系统环境变量与 `~/.cursor/config.json` 读取一个值(优先环境变量);key 支持点号路径如 `openai.apiKey` 读取 config 嵌套字段;结果输出到 **value** 槽位。 |
80
+
81
+ **Handle**:
82
+
83
+ - **LoadKey**
84
+ - input: prev → input-0, key → input-1
85
+ - output: next → output-0, result → output-1
86
+ - **SaveKey**
87
+ - input: prev → input-0, key → input-1, value → input-2
88
+ - output: next → output-0
89
+ - **GetEnv**
90
+ - input: key → input-0
91
+ - output: value → output-0
92
+
93
+ **典型用法**:
94
+
95
+ 1. **保存后再读**:某节点产出结果 → SaveKey(key 固定如 `flowName`,value 接上游 output)→ 下游分支中 LoadKey(同一 key)→ result 连到后续 agent/tool。
96
+ 2. **跨分支共享**:并行分支中一路用 SaveKey 写入(如「选中的方案名」),汇合后或另一分支用 LoadKey 读取,保证全 flow 看到同一份全局信息。
97
+ 3. **占位符**:instance 中 key/value 可写占位符(如 `${output/node_plan_result.md}`),由 apply 在 resolvedInputs 中解析后传入脚本。
98
+ 4. **环境/配置注入**:GetEnv(key 如 `OPENAI_API_KEY` 或 `openai.apiKey`)→ value 连到下游 agent 的 input,用于从环境或 `~/.cursor/config.json` 读取密钥或配置,避免写死在 flow 中。
99
+
100
+ 存储由 apply 通过 `agentflow apply -ai run-tool-nodejs` 调用 load-key/save-key 实现;GetEnv 由 `agentflow apply -ai get-env <workspaceRoot> <flowName> <uuid> <instanceId> <execId> <key>` 直接执行,run 上下文通过命令行参数传入,不再经 run-tool-nodejs。LoadKey/SaveKey 数据仅在**当前 run**(同一 uuid 的 `~/agentflow/runBuild/<FlowName>/<uuid>/`)内有效;GetEnv 读取的是系统环境与用户级 `~/.cursor/config.json`,不随 run 隔离。
101
+
102
+ ---
103
+
104
+ ## 6. 工具节点与 Agent 节点选型
105
+
106
+ **核心原则:能用工具节点确定性执行的,不要用 agent_subAgent。**
107
+
108
+ | 场景 | 推荐节点 | 原因 |
109
+ |------|----------|------|
110
+ | 执行已知命令/脚本(打印、文件操作、数据处理等) | **tool_nodejs** + `script` 字段 | 直接执行,零 LLM 调用,毫秒级完成 |
111
+ | 向用户输出醒目信息 | **tool_print** | 专用输出节点 |
112
+ | 需要 AI 理解上下文、做判断、生成内容 | **agent_subAgent** | 需要 LLM 推理能力 |
113
+
114
+ ### 6.1 tool_nodejs 直接执行模式(推荐)
115
+
116
+ 在 instance 中设置 `script` 字段,流水线**跳过 AI 直接执行命令**:
117
+
118
+ ```yaml
119
+ print_hello:
120
+ definitionId: tool_nodejs
121
+ label: 打印Hello
122
+ script: node -e "console.log(${value})"
123
+ input:
124
+ - type: 节点
125
+ name: prev
126
+ value: ''
127
+ - type: 文本
128
+ name: value
129
+ value: ''
130
+ output:
131
+ - type: 节点
132
+ name: next
133
+ value: ''
134
+ - type: 文本
135
+ name: result
136
+ value: ''
137
+ ```
138
+
139
+ - `script` 支持 `${}` 占位符(workspaceRoot、flowName、runDir 及所有 input 槽位),值自动 shell-quote。
140
+ - 适用于:打印文本、运行已有脚本、文件复制/移动、数据格式转换等**确定性操作**。
141
+ - input 可按需添加额外的文本/文件槽位(如上例的 `value`),供 `script` 中 `${value}` 引用。
142
+ - **成败判定**:以脚本进程 **exit code** 为准(0 = success,非 0 = failed)。
143
+ - **stdout → result**:脚本 stdout 直接作为 result 槽位内容,纯文本即可(如 `console.log("hello")`)。
144
+ - **JSON 兼容(可选)**:stdout 为 `{"err_code":0,"message":{"result":"..."}}` 时,err_code 覆盖 exit code 语义——仅在需要与 exit code 不同的成败语义时使用。
145
+
146
+ ### 6.2 判断标准
147
+
148
+ 问自己:**"这个步骤的行为是否完全由输入决定,不需要 AI 推理?"**
149
+
150
+ - **是** → 用 `tool_nodejs` + `script`,或 `tool_print`
151
+ - 例:打印一段文字、执行 `agentflow apply -ai validate-flow`、跑一个已有的 `.mjs` 脚本
152
+ - **否** → 用 `agent_subAgent`
153
+ - 例:根据需求撰写文档、分析代码并提出修改方案、理解上下文后做决策
154
+
155
+ ### 6.3 `script` 与 `body` 的职责(必须遵守)
156
+
157
+ | 字段 | 职责 | 有 `script` 时 | 无 `script` 时 |
158
+ |------|------|---------------|---------------|
159
+ | `script` | 实际执行的 shell/node 命令 | 流水线直接 spawn 执行 | — |
160
+ | `body` | 纯文档说明(供人类阅读) | **完全忽略**,不参与执行 | 作为 AI 指令兜底(AI 执行模式) |
161
+
162
+ **约束规则**:
163
+ 1. `tool_nodejs` **必须写 `script` 字段**,内容为完整可执行的命令
164
+ 2. `script` 中的 `${}` 占位符自动 shell-quote,引用 input/output 槽位或系统变量
165
+ 3. **`script` 必须引用所有非 node 类型的 input 和 output 引脚**(validate-flow 硬性校验):
166
+ - input 引脚 `${slotName}` → 解析为上游数据值或文件路径
167
+ - output 引脚 `${slotName}` → 解析为 output 文件的绝对路径,脚本应 `fs.writeFileSync(path, value)` 直接写入
168
+ - **禁止使用 JSON stdout 封装**(`{"err_code":0,"message":{...}}`),用 exit code 0/非 0 决定成败
169
+ 4. `body` 可选,仅用于文档说明,**禁止写期望被执行的逻辑**
170
+ 5. 如果无法写出完整可执行的 `script`(需要 AI 理解/判断),**必须改用 `agent_subAgent`**
171
+ 6. `script` 支持多行(YAML `|` 语法)和管道组合
172
+
173
+ **复杂脚本示例(API 调用 + JSON 处理)**:
174
+
175
+ ```yaml
176
+ fetch_user_list:
177
+ definitionId: tool_nodejs
178
+ label: 获取用户列表
179
+ script: |
180
+ curl -s -H "Authorization: Bearer ${token}" "${apiUrl}/users" | node -e "
181
+ let d=''; process.stdin.on('data',c=>d+=c); process.stdin.on('end',()=>{
182
+ const res=JSON.parse(d);
183
+ console.log(JSON.stringify(res.data.map(u=>({id:u.id,name:u.name}))));
184
+ });"
185
+ body: |
186
+ 调用 API 获取用户列表并提取 id 和 name
187
+ input:
188
+ - { type: 节点, name: prev, value: '' }
189
+ - { type: 文本, name: apiUrl, value: '' }
190
+ - { type: 文本, name: token, value: '' }
191
+ output:
192
+ - { type: 节点, name: next, value: '' }
193
+ - { type: 文本, name: result, value: '' }
194
+ ```
195
+
196
+ **错误示范**(校验将报 warning):
197
+ ```yaml
198
+ # ❌ tool_nodejs 无 script,body 写自然语言 → 节点无法正确执行
199
+ bad_example:
200
+ definitionId: tool_nodejs
201
+ label: 获取数据
202
+ body: |
203
+ 调用 API 获取数据,解析 JSON,提取关键字段保存到文件
204
+ ```
205
+
206
+ ### 6.4 常见误用
207
+
208
+ | 用户需求 | 错误做法 | 正确做法 |
209
+ |----------|----------|----------|
210
+ | 打印一段文字 | agent_subAgent + body 描述打印任务 | tool_nodejs + `script: node -e "console.log(${value})"` |
211
+ | 执行已有脚本 | agent_subAgent + body 要求运行脚本 | tool_nodejs + `script: node scripts/xxx.mjs` |
212
+ | 读取环境变量 | agent_subAgent + body 要求读环境变量 | tool_get_env(专用节点) |
213
+ | 复杂 AI 推理/生成 | tool_nodejs + body 写自然语言 | agent_subAgent(需 LLM 能力时必须用 agent) |
214
+
215
+ ### 6.5 节点单一职责(必须遵守)
216
+
217
+ **每个节点只做一件事,工作内容保持专注和专一。**
218
+
219
+ - **不要把多个无关操作塞进同一个节点的 `body`**。如果一个任务包含多个可独立完成的步骤,应拆分为多个节点,通过边串联或并行。
220
+ - **每个 agent_subAgent 的 body 应聚焦于单一目标**:写一个文件、分析一段代码、做一次决策等。不要在一个 body 里要求"先做 A,再做 B,最后做 C"。
221
+ - **拆分的好处**:
222
+ - 可调试:单个节点失败时容易定位问题
223
+ - 可复用:拆出的节点可被其他流程引用
224
+ - 可并行:无依赖的步骤拆开后可自动并行执行
225
+ - AI 质量更高:小而明确的任务比大而模糊的任务生成质量更好
226
+
227
+ **示例**:用户要求"分析代码并生成测试"
228
+
229
+ | 做法 | 结构 |
230
+ |------|------|
231
+ | **错误**:一个 agent 节点,body 写"先分析代码找出关键函数,然后为每个函数写单元测试" | 单节点承担分析 + 生成两个职责 |
232
+ | **正确**:节点 A(分析代码,输出关键函数列表)→ 节点 B(根据函数列表生成测试) | 每个节点职责清晰、输入输出明确 |
233
+
234
+ ---
235
+
236
+ ## 7. 常见流程模式简述
237
+
238
+ 1. **线性链**:Start → A → B → … → End
239
+ 2. **条件分支**:
240
+ - **单节点 If**:… → ToBool → **control_if** → next1 连分支A、next2 连分支B(true 走 output-0,false 走 output-1)。
241
+ 3. **多路任一**:分支1、分支2 均连到 AnyOne(prev1/prev2),AnyOne 的 next 再连到后续或 End。
242
+ 4. **用户确认**:在需要暂停处插入 **tool_user_check**,用户确认后再继续。
243
+ 5. **全局存储**:用 **SaveKey** 写入、**LoadKey** 读取当前 flow 的全局信息(见上节)。
244
+ 6. **检查 → 修改 → 检查 → 修改**:见下节。
245
+
246
+ ---
247
+
248
+ ### 8 入环 → 检查 → 修复 → 检查 → 修复 → 检查 → 出环
249
+
250
+ 该流程可概括为:**入环 → 检查 → 修复 → 检查 → 修复 → … → 检查通过 → 出环**。参考 **builtin/pipelines/module-migrate** 的连线方式。
251
+
252
+ - **入环**:用 **control_anyOne** 汇合两条路——「首次进入」与「上一轮修复完成后再检查」。prev1 / prev2 任一路就绪即从 next 继续,进入**检查**。
253
+ - **检查**:执行检查节点(可并行、可汇总),结果经 **control_toBool**(确定性)或 **control_agent_toBool**(AI 判断)转为布尔,再接到 **control_if**。
254
+ - **分支**:**control_if** 的 next1(true,通过)→ 出环到后续或 End;next2(false,未通过)→ 进入**修复**。
255
+ - **修复**:修复节点消费检查结果,修改后通过边回到「检查」上游或回到 **AnyOne** 的 prev2,形成环;可再套一层 ToBool + If 判断「是否修完」,未修完再修复、修完再回检查。
256
+ - **出环**:当 **control_if** 为 true 时,从 next1 连到环外节点,不再回到 AnyOne。
257
+
258
+ 要点:**AnyOne** 做入环/复入环汇合;**ToBool + If** 做通过/未通过二选一;未通过 → 修复 → 回到检查或 AnyOne(成环);通过 → 连到环外即出环。
259
+
260
+ ---
261
+
262
+ ## 9. Edge 与 Handle 注意点
263
+
264
+ - **Fan-out 允许,Fan-in 禁止**:一个 output handle 可连多个 input(扇出),但**一个 input handle 只允许一条入边**(禁止扇入)。同一 `target + targetHandle` 不得出现在多条 edge 中——运行时 `resolve-inputs` 仅取 `find()` 首条匹配,其余静默丢失。若需替换连线,先删旧边再加新边。
265
+ - 条件/分支节点有多输入时,必须在 edge 上写清 **targetHandle**(如 prediction 用 input-1)。
266
+ - 从 ToBool 的 prediction 连到 If(control_if)时:sourceHandle 用 **output-1**,targetHandle 用 **input-1**。
267
+ - 多输出节点连到不同下游时,用不同 **sourceHandle**(output-0, output-1, …)区分槽位。
268
+ - **control_if** 必须写清:从 output-0 连到「条件为真」的后继、从 output-1 连到「条件为假」的后继,否则 get-ready-nodes 无法正确解锁分支。
269
+
270
+ ---
271
+
272
+ ## 10. 图与 USER_PROMPT 的读写一致性
273
+
274
+ ${USER_PROMPT} 中描述的「读取」「写入」应与图中的 **handler 节点**(input/output 通过 edge 连接的节点)对应:描述的每项「读」应有节点的 input 入边,每项「写」应有节点的 output 出边。详见 [flow-prompt-handler-check.md](./flow-prompt-handler-check.md)。
@@ -0,0 +1,84 @@
1
+ # flow.yaml 节点布局建议
2
+
3
+ 本文档说明如何在 flow.yaml 中通过 `ui.nodePositions` 排布节点,使流程图**易读、不挤成一条线**。供编辑或生成 flow 时参考。
4
+
5
+ ---
6
+
7
+ ## 1. 布局定义位置
8
+
9
+ 在 flow.yaml 末尾通过 `ui.nodePositions` 为每个节点指定坐标:
10
+
11
+ ```yaml
12
+ ui:
13
+ nodePositions:
14
+ start:
15
+ x: -300
16
+ 'y': 190
17
+ agent_plan:
18
+ x: 0
19
+ 'y': 200
20
+ # ... 每个 instanceId 对应一个 { x, y }
21
+ description: 可选,整图简短说明
22
+ ```
23
+
24
+ - 坐标单位为像素(或画布单位),从左到右 x 增大,从上到下 y 增大。
25
+ - 未出现在 `nodePositions` 中的节点由渲染端自行排布,可能挤在一起或成一条线。
26
+
27
+ ---
28
+
29
+ ## 2. 避免「一条线」
30
+
31
+ **不推荐**:所有节点共线(同一 y 或同一 x),例如:
32
+
33
+ - 全部同一 y、只改 x → 一条横线,分支和汇合难以区分。
34
+ - 全部同一 x、只改 y → 一条竖线,顺序感弱、边易重叠。
35
+
36
+ **推荐**:利用**二维平面**,让主流程、分支、环在 x 与 y 上都有区分。
37
+
38
+ ---
39
+
40
+ ## 3. 布局原则
41
+
42
+ ### 3.1 主流程沿 x 递进
43
+
44
+ - **主链路**(如 Start → A → B → … → End)的节点 **x 递增**,便于从左到右阅读。
45
+ - 同一条主链上的节点 **y 接近**(可设为基础 y,如 200),不要上下跳动过大。
46
+
47
+ ### 3.2 分支用 y 错开
48
+
49
+ - **并行分支**:不同分支用不同 y(例如上支 y 小、下支 y 大),避免多条边叠在同一水平线。
50
+ - **If 的 next1 / next2**:true/false 两支可一上一下(如 next1 略上、next2 略下),再在后方汇合。
51
+
52
+ ### 3.3 环与回流
53
+
54
+ - **入环/复入环**(如 AnyOne):可放在主链左侧或与主链同 x,其 next 指向的「检查」节点 x 更大。
55
+ - **回流边**(修复 → 再检查):从右回到左时,**回流节点 y 与主链明显不同**(例如主链 y≈200,修复链 y≈450),这样环在图上呈「下层回流」而不是与主链重叠成一条线。
56
+
57
+ ### 3.4 辅助节点集中一侧
58
+
59
+ - **provide_***、**SaveKey/LoadKey** 等不参与主链的节点,可放在**左侧或下方**固定区域(例如 x 较小、y 按 300/400 排布),与主链在视觉上分离。
60
+
61
+ ### 3.5 间距
62
+
63
+ - 同层节点之间 **x 差** 建议不少于约 150~250,避免节点重叠、边难以辨认。
64
+ - 上下层之间 **y 差** 建议不少于约 80~120,分支与主链区分清晰。
65
+
66
+ ---
67
+
68
+ ## 4. 简要对照
69
+
70
+ | 目标 | 做法 | 避免 |
71
+ |----------------|------------------------------|--------------------------|
72
+ | 主流程清晰 | 主链节点 x 递增、y 接近 | 主链节点 y 乱跳 |
73
+ | 分支可辨 | 不同分支用不同 y | 所有分支同一 y(一条线) |
74
+ | 环可见 | 回流节点 y 与主链错开 | 环与主链叠在同一行 |
75
+ | 辅助节点不抢戏 | 放左侧或下方、x 小或 y 大 | 与主链混在同一列 |
76
+
77
+ ---
78
+
79
+ ## 5. 参考示例
80
+
81
+ - **builtin/pipelines/new/flow.yaml**:主链从左到右(start 负 x → control_end 大 x),provide/collect 等偏左,检查/修复分支在 y 上有区分。
82
+ - **builtin/pipelines/module-migrate/flow.yaml**:主链沿 x 递增;provide/SaveKey 在左侧(x≈50~240);静态环与编译环在 y 上分层(如 agent_fix_todo、control_if_fixed 等 y≈460~470,与主链 y≈100~280 分开),回流不压在主链一条线上。
83
+
84
+ 生成或手改 `ui.nodePositions` 时,可先按「主链 x 递增 + 分支/环 y 错开」排一版,再微调间距与对齐。
@@ -0,0 +1,12 @@
1
+ # AgentFlow 图与 USER_PROMPT 的读写一致性检查
2
+
3
+ 本文档供 AI 参考:对流程图的**语义检查**——${USER_PROMPT} 中描述的「读取」「写入」应与图中的 **handler 节点**(即带 input/output 槽位且通过 edge 连线的节点)一一对应。
4
+
5
+ ---
6
+
7
+ ## 约定
8
+
9
+ - **USER_PROMPT**:用户或上游在流程中注入的「需求描述」或「本节点说明」,常出现在 provide_str / provide_file、control_start 等节点的正文中,或作为流程级需求。
10
+ - **Handler 节点**:在 flow 中通过 **input/output 槽位** 与其它节点用 **edge** 连接、参与数据流的节点。不含 provide_*、control_start、control_end 等「仅作为源/汇」的节点时,通常指会「读入」或「写出」数据的 agent/tool/control 节点。
11
+ - **读取**:某节点**消费**某数据 → 对应其 **input** 槽位上有 **入边**(target 为该节点,targetHandle 为该 input)。
12
+ - **写入**:某节点**产出**某数据 → 对应其 **output** 槽位上有 **出边**(source 为该节点,sourceHandle 为该 output)。
@@ -0,0 +1,14 @@
1
+ # AgentFlow Result 语义
2
+
3
+ 供 AI 与流程编写参考:**intermediate 中的 result 文档表示节点自身执行状态**。
4
+
5
+ ## 约定
6
+
7
+ - **result.status**:表示**本节点是否执行成功**,不是「业务结果是否通过」。
8
+ - **success**:节点已正常执行完毕(脚本跑完且输出合法、或逻辑完成)。
9
+ - **failed**:节点执行失败,例如依赖的输入不存在(配置错误)、脚本异常或输出格式非法。
10
+
11
+ ## 示例
12
+
13
+ - **agent_ai_check_tool**:若依赖的输入文件(如 `output/node_AI_CHECK_FILE_value.md`)不存在,属配置错误 → 应写 **failed**,message 如「找不到依赖的输入文件」。
14
+ - **tool_check(tool_nodejs)**:脚本 stdout 为合法 JSON、output 已写入后,后处理根据脚本返回的 **err_code** 写 result.status:**err_code 0 → success**,**err_code 1 → failed**。节点执行结果即由 err_code 表示。