@fieldwangai/agentflow 0.1.33 → 0.1.35

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 (40) hide show
  1. package/bin/lib/agent-runners.mjs +17 -0
  2. package/bin/lib/composer-agent.mjs +2 -0
  3. package/bin/lib/composer-skill-router.mjs +23 -4
  4. package/bin/lib/git-worktree.mjs +15 -0
  5. package/bin/lib/locales/en.json +3 -7
  6. package/bin/lib/locales/zh.json +2 -6
  7. package/bin/lib/paths.mjs +0 -1
  8. package/bin/lib/scheduler.mjs +8 -3
  9. package/bin/lib/skill-registry.mjs +46 -2
  10. package/bin/lib/ui-server.mjs +896 -22
  11. package/bin/pipeline/build-node-prompt.mjs +27 -1
  12. package/bin/pipeline/pre-process-node.mjs +70 -34
  13. package/builtin/nodes/agent_subAgent.md +2 -0
  14. package/builtin/nodes/control_agent_toBool.md +4 -0
  15. package/builtin/nodes/control_cancelled.md +8 -4
  16. package/builtin/nodes/control_cd_workspace.md +2 -0
  17. package/builtin/nodes/control_delay.md +9 -0
  18. package/builtin/nodes/control_toBool.md +6 -2
  19. package/builtin/nodes/control_user_workspace.md +2 -0
  20. package/builtin/nodes/control_wait_until.md +9 -0
  21. package/builtin/nodes/provide_bool.md +2 -0
  22. package/builtin/nodes/provide_file.md +2 -0
  23. package/builtin/nodes/provide_str.md +2 -0
  24. package/builtin/nodes/tool_get_env.md +4 -0
  25. package/builtin/nodes/tool_git_checkout.md +6 -1
  26. package/builtin/nodes/tool_git_worktree_load.md +7 -2
  27. package/builtin/nodes/tool_git_worktree_unload.md +5 -5
  28. package/builtin/nodes/tool_load_key.md +4 -0
  29. package/builtin/nodes/tool_nodejs.md +4 -0
  30. package/builtin/nodes/tool_print.md +2 -0
  31. package/builtin/nodes/tool_save_key.md +4 -0
  32. package/builtin/nodes/tool_user_ask.md +3 -1
  33. package/builtin/nodes/tool_user_check.md +3 -1
  34. package/builtin/web-ui/dist/assets/index-BzmhleR9.css +1 -0
  35. package/builtin/web-ui/dist/assets/index-DEeZI5V6.js +214 -0
  36. package/builtin/web-ui/dist/index.html +2 -2
  37. package/package.json +1 -1
  38. package/builtin/nodes/control_deadline.md +0 -32
  39. package/builtin/web-ui/dist/assets/index-BWAb27N0.js +0 -198
  40. package/builtin/web-ui/dist/assets/index-DgfSfcjH.css +0 -1
@@ -112,6 +112,31 @@ function marketplaceRuntimeCommand(marketplaceNode, resolvedInputs, resolvedOutp
112
112
  });
113
113
  }
114
114
 
115
+ function normalizePromptImages(images) {
116
+ if (!Array.isArray(images)) return [];
117
+ return images
118
+ .filter((item) => item && typeof item === "object")
119
+ .map((item, index) => ({
120
+ label: String(item.label || `image ${index + 1}`),
121
+ name: String(item.name || `image-${index + 1}`),
122
+ mimeType: String(item.mimeType || item.type || "image/png"),
123
+ dataUrl: String(item.dataUrl || item.data || ""),
124
+ }))
125
+ .filter((item) => item.dataUrl.startsWith("data:image/"));
126
+ }
127
+
128
+ function renderImagesForPrompt(images) {
129
+ const list = normalizePromptImages(images);
130
+ if (list.length === 0) return "";
131
+ const blocks = list.map((item) => [
132
+ `### [${item.label}]`,
133
+ `name: ${item.name}`,
134
+ `mimeType: ${item.mimeType}`,
135
+ `dataUrl: ${item.dataUrl}`,
136
+ ].join("\n"));
137
+ return `## 图片附件\n\n${blocks.join("\n\n")}`;
138
+ }
139
+
115
140
  /**
116
141
  * 执行占位符替换,组装 prompt 并写入 intermediate 文件(文件名带 _execId)。
117
142
  * @param {number} [execId] - 本轮 execId,缺省则从 memory 读取
@@ -153,6 +178,7 @@ export function buildNodePrompt(workspaceRoot, flowName, uuid, instanceId, execI
153
178
  inst?.script != null
154
179
  ? String(inst.script || "").trim()
155
180
  : "";
181
+ const imagePrompt = renderImagesForPrompt(inst?.images);
156
182
 
157
183
  const { resolvedInputs = {}, resolvedOutputs = {}, systemPrompt = "" } = data;
158
184
  const workspaceContext = normalizeWorkspaceContext(opts.workspaceContext || resolvedInputs.workspaceContext, workspaceRoot, flowName, { flowDir });
@@ -197,7 +223,7 @@ ${contextBlocks.join("\n\n")}
197
223
 
198
224
  ## 执行任务
199
225
 
200
- ${taskBody || "(无)"}
226
+ ${[taskBody || "(无)", imagePrompt].filter((x) => x && String(x).trim()).join("\n\n")}
201
227
  `;
202
228
 
203
229
  try {
@@ -48,7 +48,7 @@ import {
48
48
  parseSkillKeyList,
49
49
  resolveWorkspaceTarget,
50
50
  } from "../lib/runtime-context.mjs";
51
- import { buildGitContext, loadGitWorktree, normalizeGitContext, unloadGitWorktree } from "../lib/git-worktree.mjs";
51
+ import { buildGitContext, inferGitRepoRootFromWorktree, loadGitWorktree, normalizeGitContext, unloadGitWorktree } from "../lib/git-worktree.mjs";
52
52
  import { createGitLabMergeRequest } from "../lib/gitlab-mr.mjs";
53
53
 
54
54
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -403,12 +403,16 @@ function emitGitWorktreeUnloadNode(workspaceRoot, flowName, uuid, instanceId, ex
403
403
  const { inputs, workspaceContext, flowJson } = resolveNodeRuntimeContexts(workspaceRoot, flowName, uuid, instanceId);
404
404
  requireWorkspaceContextInput(inputs, "tool_git_worktree_unload");
405
405
  const gitContext = normalizeGitContext(inputs.gitContext);
406
- const repoPath = resolveMaybeWorkspacePath(inputs.repoPath, workspaceContext) ||
407
- (gitContext?.repoPath ? path.resolve(gitContext.repoPath) : "");
408
406
  const worktreePath = resolveMaybeWorkspacePath(inputs.worktreePath, workspaceContext) ||
409
- (gitContext?.worktreePath ? path.resolve(gitContext.worktreePath) : "");
410
- if (!repoPath) throw new Error("tool_git_worktree_unload: repoPath or gitContext.repoPath is required");
411
- if (!worktreePath) throw new Error("tool_git_worktree_unload: worktreePath or gitContext.worktreePath is required");
407
+ (gitContext?.worktreePath ? path.resolve(gitContext.worktreePath) : "") ||
408
+ (workspaceContext.cwd ? path.resolve(workspaceContext.cwd) : "") ||
409
+ (workspaceContext.workspaceRoot ? path.resolve(workspaceContext.workspaceRoot) : "");
410
+ if (!worktreePath) throw new Error("tool_git_worktree_unload: workspaceContext.cwd or worktreePath is required");
411
+ const repoPath = resolveMaybeWorkspacePath(inputs.repoPath, workspaceContext) ||
412
+ (gitContext?.repoPath ? path.resolve(gitContext.repoPath) : "") ||
413
+ inferGitRepoRootFromWorktree(worktreePath) ||
414
+ (workspaceContext.previous?.cwd ? path.resolve(workspaceContext.previous.cwd) : "") ||
415
+ (workspaceContext.previous?.workspaceRoot ? path.resolve(workspaceContext.previous.workspaceRoot) : "");
412
416
  const force = isTruthyInput(inputs.force);
413
417
  const prune = String(inputs.prune ?? "true").trim().toLowerCase() !== "false";
414
418
  const result = unloadGitWorktree({ repoPath, worktreePath, force, prune });
@@ -636,8 +640,14 @@ function writeWaitState(runDir, state) {
636
640
  if (parsed && typeof parsed === "object" && Array.isArray(parsed.waits)) registry = parsed;
637
641
  } catch (_) {}
638
642
  }
639
- const waits = registry.waits.filter((w) => w && w.instanceId !== state.instanceId);
640
- const wait = { ...state, id: state.id || state.instanceId };
643
+ const waitId = String(state.waitId || state.id || `${state.instanceId}:${state.execId || 1}`).trim();
644
+ const waits = registry.waits.filter((w) => {
645
+ if (!w) return false;
646
+ const key = String(w.waitId || w.id || "").trim();
647
+ if (key && key === waitId) return false;
648
+ return !(w.instanceId === state.instanceId && String(w.execId || 1) === String(state.execId || 1));
649
+ });
650
+ const wait = { ...state, waitId, id: state.id || waitId };
641
651
  waits.push(wait);
642
652
  registry = {
643
653
  ...registry,
@@ -651,6 +661,44 @@ function writeWaitState(runDir, state) {
651
661
  fs.writeFileSync(legacyPath, JSON.stringify(wait, null, 2) + "\n", "utf-8");
652
662
  }
653
663
 
664
+ function buildWaitId(uuid, instanceId, execId, explicit = "") {
665
+ const text = String(explicit || "").trim();
666
+ if (text) return text;
667
+ return `${uuid}:${instanceId}:${execId || 1}`;
668
+ }
669
+
670
+ function readWaitStateById(runDir, waitId) {
671
+ const text = String(waitId || "").trim();
672
+ if (!text) return null;
673
+ const registryPath = path.join(runDir, "wait-states.json");
674
+ if (fs.existsSync(registryPath)) {
675
+ try {
676
+ const registry = JSON.parse(fs.readFileSync(registryPath, "utf-8"));
677
+ const waits = Array.isArray(registry?.waits) ? registry.waits : [];
678
+ const found = waits.find((w) => {
679
+ const key = String(w?.waitId || w?.id || "").trim();
680
+ return key === text;
681
+ });
682
+ if (found) return found;
683
+ } catch (_) {}
684
+ }
685
+ const legacyPath = path.join(runDir, "wait-state.json");
686
+ if (fs.existsSync(legacyPath)) {
687
+ try {
688
+ const state = JSON.parse(fs.readFileSync(legacyPath, "utf-8"));
689
+ const key = String(state?.waitId || state?.id || "").trim();
690
+ if (key === text) return state;
691
+ } catch (_) {}
692
+ }
693
+ return null;
694
+ }
695
+
696
+ function readCancelFlagForWait(runDir, waitId) {
697
+ const state = readWaitStateById(runDir, waitId);
698
+ if (state && (state.cancelled === true || state.status === "cancelled" || state.branch === "cancelled")) return true;
699
+ return readCancelFlag(runDir);
700
+ }
701
+
654
702
  function readCancelFlag(runDir) {
655
703
  for (const name of ["cancelled", "cancelled.json", "wait-cancelled.json"]) {
656
704
  const p = path.join(runDir, name);
@@ -966,8 +1014,11 @@ async function main() {
966
1014
  process.exit(1);
967
1015
  }
968
1016
 
1017
+ const waitId = buildWaitId(uuid, instanceId, execId, inputs.waitId || inputs.watchId);
1018
+ writeOutputSlot(runDir, instanceId, execId, "waitId", waitId);
969
1019
  writeOutputSlot(runDir, instanceId, execId, "wakeAt", wakeAt);
970
1020
  writeWaitState(runDir, {
1021
+ waitId,
971
1022
  status: "waiting",
972
1023
  reason: definitionId,
973
1024
  flowName,
@@ -993,7 +1044,7 @@ async function main() {
993
1044
  `此节点为 ${definitionId},已写入 wait-state.json,等待 scheduler 在 ${wakeAt} 唤醒。\n`,
994
1045
  );
995
1046
  writeCacheJsonForNode(workspaceRoot, flowName, uuid, instanceId, execId);
996
- logToRunTag(workspaceRoot, flowName, uuid, "pre-process", { event: "waiting", instanceId, wakeAt, definitionId });
1047
+ logToRunTag(workspaceRoot, flowName, uuid, "pre-process", { event: "waiting", instanceId, waitId, wakeAt, definitionId });
997
1048
  console.log(JSON.stringify({
998
1049
  ok: true,
999
1050
  promptPath,
@@ -1084,37 +1135,22 @@ async function main() {
1084
1135
  return;
1085
1136
  }
1086
1137
 
1087
- if (definitionId === "control_deadline" || definitionId === "control_cancelled") {
1138
+ if (definitionId === "control_cancelled") {
1088
1139
  const data = getResolvedValues(workspaceRoot, flowName, uuid, instanceId);
1089
1140
  if (!data.ok) {
1090
- console.error(JSON.stringify({ ok: false, error: `${definitionId}: getResolvedValues failed` }));
1141
+ console.error(JSON.stringify({ ok: false, error: "control_cancelled: getResolvedValues failed" }));
1091
1142
  process.exit(1);
1092
1143
  }
1093
- const inputs = data.resolvedInputs || {};
1094
- let boolValue = false;
1095
- let message = "";
1144
+ let boolValue;
1145
+ let message;
1096
1146
  try {
1097
- if (definitionId === "control_deadline") {
1098
- const timezone = inputs.timezone || "Asia/Shanghai";
1099
- let deadline;
1100
- if (inputs.deadlineAt) {
1101
- deadline = parseDateTime(inputs.deadlineAt, timezone);
1102
- } else {
1103
- const start = inputs.startAt ? parseDateTime(inputs.startAt, timezone) : new Date();
1104
- deadline = new Date(start.getTime() + parseDurationMs(inputs.duration || ""));
1105
- }
1106
- const deadlineAt = deadline.toISOString();
1107
- boolValue = Date.now() >= deadline.getTime();
1108
- writeOutputSlot(runDir, instanceId, execId, "deadlineAt", deadlineAt);
1109
- writeOutputSlot(runDir, instanceId, execId, "expired", boolValue ? "true" : "false");
1110
- message = boolValue ? `已超过截止时间 ${deadlineAt}` : `未超过截止时间 ${deadlineAt}`;
1111
- } else {
1112
- boolValue = readCancelFlag(runDir);
1113
- writeOutputSlot(runDir, instanceId, execId, "cancelled", boolValue ? "true" : "false");
1114
- message = boolValue ? "已取消" : "未取消";
1115
- }
1147
+ const inputs = data.resolvedInputs || {};
1148
+ const waitId = String(inputs.waitId || inputs.watchId || "").trim();
1149
+ boolValue = waitId ? readCancelFlagForWait(runDir, waitId) : readCancelFlag(runDir);
1150
+ writeOutputSlot(runDir, instanceId, execId, "cancelled", boolValue ? "true" : "false");
1151
+ message = boolValue ? "已取消" : "未取消";
1116
1152
  } catch (e) {
1117
- console.error(JSON.stringify({ ok: false, error: `${definitionId}: ${e.message}` }));
1153
+ console.error(JSON.stringify({ ok: false, error: `control_cancelled: ${e.message}` }));
1118
1154
  process.exit(1);
1119
1155
  }
1120
1156
  writeResult(workspaceRoot, flowName, uuid, instanceId, { status: "success", message }, { execId, preserveBody: false });
@@ -19,5 +19,7 @@ output:
19
19
  - type: text
20
20
  name: result
21
21
  default: ""
22
+ required: true
23
+ showOnNode: true
22
24
  ---
23
25
  ${USER_PROMPT}
@@ -9,6 +9,8 @@ input:
9
9
  - type: text
10
10
  name: value
11
11
  default: ""
12
+ required: true
13
+ showOnNode: true
12
14
  output:
13
15
  - type: node
14
16
  name: next
@@ -16,5 +18,7 @@ output:
16
18
  - type: bool
17
19
  name: prediction
18
20
  default: ""
21
+ required: true
22
+ showOnNode: true
19
23
  ---
20
24
  ${USER_PROMPT}
@@ -1,14 +1,16 @@
1
1
  ---
2
- # 内置节点:取消状态判断
3
- description: Check whether the current run/watch has been cancelled. Use cancelled output with control_if.
4
- displayName: Cancelled
2
+ # 内置节点:取消判断
3
+ description: Check whether the current wait/run has been cancelled. Use cancelled output with control_if.
4
+ displayName: Cancel Check
5
5
  input:
6
6
  - type: node
7
7
  name: prev
8
8
  default: ""
9
9
  - type: text
10
- name: watchId
10
+ name: waitId
11
11
  default: ""
12
+ required: true
13
+ showOnNode: true
12
14
  output:
13
15
  - type: node
14
16
  name: next
@@ -16,5 +18,7 @@ output:
16
18
  - type: bool
17
19
  name: cancelled
18
20
  default: ""
21
+ required: true
22
+ showOnNode: true
19
23
  ---
20
24
  ${USER_PROMPT}
@@ -35,6 +35,8 @@ output:
35
35
  - type: text
36
36
  name: workspaceContext
37
37
  default: ""
38
+ required: true
39
+ showOnNode: true
38
40
  - type: file
39
41
  name: cwd
40
42
  default: ""
@@ -9,12 +9,21 @@ input:
9
9
  - type: text
10
10
  name: duration
11
11
  default: "10m"
12
+ required: true
13
+ showOnNode: true
12
14
  output:
13
15
  - type: node
14
16
  name: next
15
17
  default: ""
18
+ - type: text
19
+ name: waitId
20
+ default: ""
21
+ required: true
22
+ showOnNode: true
16
23
  - type: text
17
24
  name: wakeAt
18
25
  default: ""
26
+ required: true
27
+ showOnNode: true
19
28
  ---
20
29
  ${USER_PROMPT}
@@ -1,7 +1,7 @@
1
1
  ---
2
- # 内置节点:转布尔(本地脚本执行,★ 可扩展输入)
2
+ # 内置节点:代码转布尔(本地脚本执行,★ 可扩展输入)
3
3
  description: "Script-based boolean conversion: executes script to produce true/false prediction. Like tool_nodejs but enforces bool output. Must have script field."
4
- displayName: ToBool
4
+ displayName: Code ToBool
5
5
  input:
6
6
  - type: node
7
7
  name: prev
@@ -9,6 +9,8 @@ input:
9
9
  - type: text
10
10
  name: value
11
11
  default: ""
12
+ required: true
13
+ showOnNode: true
12
14
  output:
13
15
  - type: node
14
16
  name: next
@@ -16,6 +18,8 @@ output:
16
18
  - type: bool
17
19
  name: prediction
18
20
  default: ""
21
+ required: true
22
+ showOnNode: true
19
23
  extensible: true
20
24
  ---
21
25
  ${USER_PROMPT}
@@ -13,6 +13,8 @@ output:
13
13
  - type: text
14
14
  name: workspaceContext
15
15
  default: ""
16
+ required: true
17
+ showOnNode: true
16
18
  - type: file
17
19
  name: cwd
18
20
  default: ""
@@ -9,6 +9,8 @@ input:
9
9
  - type: text
10
10
  name: until
11
11
  default: ""
12
+ required: true
13
+ showOnNode: true
12
14
  - type: text
13
15
  name: timezone
14
16
  default: "Asia/Shanghai"
@@ -16,8 +18,15 @@ output:
16
18
  - type: node
17
19
  name: next
18
20
  default: ""
21
+ - type: text
22
+ name: waitId
23
+ default: ""
24
+ required: true
25
+ showOnNode: true
19
26
  - type: text
20
27
  name: wakeAt
21
28
  default: ""
29
+ required: true
30
+ showOnNode: true
22
31
  ---
23
32
  ${USER_PROMPT}
@@ -7,5 +7,7 @@ output:
7
7
  - type: bool
8
8
  name: value
9
9
  default: "false"
10
+ required: true
11
+ showOnNode: true
10
12
  ---
11
13
  ${USER_PROMPT}
@@ -7,5 +7,7 @@ output:
7
7
  - type: file
8
8
  name: value
9
9
  default: ""
10
+ required: true
11
+ showOnNode: true
10
12
  ---
11
13
  ${USER_PROMPT}
@@ -7,5 +7,7 @@ output:
7
7
  - type: text
8
8
  name: value
9
9
  default: ""
10
+ required: true
11
+ showOnNode: true
10
12
  ---
11
13
  ${USER_PROMPT}
@@ -6,9 +6,13 @@ input:
6
6
  - type: text
7
7
  name: key
8
8
  default: ""
9
+ required: true
10
+ showOnNode: true
9
11
  output:
10
12
  - type: text
11
13
  name: value
12
14
  default: ""
15
+ required: true
16
+ showOnNode: true
13
17
  ---
14
18
  ${USER_PROMPT}
@@ -22,7 +22,6 @@ input:
22
22
  - type: text
23
23
  name: branch
24
24
  default: ""
25
- showOnNode: true
26
25
  - type: text
27
26
  name: targetDir
28
27
  default: ""
@@ -38,6 +37,8 @@ input:
38
37
  - type: text
39
38
  name: workspaceContext
40
39
  default: ""
40
+ required: true
41
+ showOnNode: true
41
42
  output:
42
43
  - type: node
43
44
  name: next
@@ -57,8 +58,12 @@ output:
57
58
  - type: text
58
59
  name: workspaceContext
59
60
  default: ""
61
+ required: true
62
+ showOnNode: true
60
63
  - type: text
61
64
  name: gitContext
62
65
  default: ""
66
+ required: true
67
+ showOnNode: true
63
68
  ---
64
69
  Clone or update `${repoUrl}` and output workspace/git contexts for the checked-out repository.
@@ -16,21 +16,22 @@ input:
16
16
  - type: file
17
17
  name: repoPath
18
18
  default: ""
19
- showOnNode: true
20
19
  - type: text
21
20
  name: branch
22
21
  default: ""
23
- showOnNode: true
24
22
  - type: file
25
23
  name: worktreePath
26
24
  default: ""
27
25
  - type: text
28
26
  name: gitContext
29
27
  default: ""
28
+ required: true
29
+ showOnNode: true
30
30
  - type: text
31
31
  name: workspaceContext
32
32
  default: ""
33
33
  required: true
34
+ showOnNode: true
34
35
  output:
35
36
  - type: node
36
37
  name: next
@@ -47,8 +48,12 @@ output:
47
48
  - type: text
48
49
  name: workspaceContext
49
50
  default: ""
51
+ required: true
52
+ showOnNode: true
50
53
  - type: text
51
54
  name: gitContext
52
55
  default: ""
56
+ required: true
57
+ showOnNode: true
53
58
  ---
54
59
  Load a Git worktree from `${repoPath}` and switch downstream workspace context to it.
@@ -3,9 +3,8 @@
3
3
  description: |
4
4
  Remove a Git worktree.
5
5
 
6
- - `repoPath` is required unless `gitContext.repoPath` is connected.
7
- - `worktreePath` is required unless `gitContext.worktreePath` is connected.
8
- - `workspaceContext` is required so the node can restore the previous execution context.
6
+ - `workspaceContext` is required. Its `cwd` is used as the worktree to remove.
7
+ - `repoPath`, `worktreePath` and `gitContext` are optional compatibility overrides.
9
8
  - By default `force` is false; dirty worktrees fail instead of being removed.
10
9
  - By default `prune` is true.
11
10
  displayName: Unload Worktree
@@ -16,11 +15,9 @@ input:
16
15
  - type: file
17
16
  name: repoPath
18
17
  default: ""
19
- showOnNode: true
20
18
  - type: file
21
19
  name: worktreePath
22
20
  default: ""
23
- showOnNode: true
24
21
  - type: text
25
22
  name: gitContext
26
23
  default: ""
@@ -28,6 +25,7 @@ input:
28
25
  name: workspaceContext
29
26
  default: ""
30
27
  required: true
28
+ showOnNode: true
31
29
  - type: bool
32
30
  name: force
33
31
  default: "false"
@@ -44,6 +42,8 @@ output:
44
42
  - type: text
45
43
  name: workspaceContext
46
44
  default: ""
45
+ required: true
46
+ showOnNode: true
47
47
  - type: text
48
48
  name: message
49
49
  default: ""
@@ -9,6 +9,8 @@ input:
9
9
  - type: text
10
10
  name: key
11
11
  default: ""
12
+ required: true
13
+ showOnNode: true
12
14
  output:
13
15
  - type: node
14
16
  name: next
@@ -16,5 +18,7 @@ output:
16
18
  - type: text
17
19
  name: result
18
20
  default: ""
21
+ required: true
22
+ showOnNode: true
19
23
  ---
20
24
  ${USER_PROMPT}
@@ -33,6 +33,8 @@ input:
33
33
  - type: text
34
34
  name: workspaceContext
35
35
  default: ""
36
+ required: true
37
+ showOnNode: true
36
38
  - type: text
37
39
  name: skillsContext
38
40
  default: ""
@@ -43,5 +45,7 @@ output:
43
45
  - type: text
44
46
  name: result
45
47
  default: ""
48
+ required: true
49
+ showOnNode: true
46
50
  ---
47
51
  ${USER_PROMPT}
@@ -9,6 +9,8 @@ input:
9
9
  - type: text
10
10
  name: content
11
11
  default: ""
12
+ required: true
13
+ showOnNode: true
12
14
  output:
13
15
  - type: node
14
16
  name: next
@@ -9,9 +9,13 @@ input:
9
9
  - type: text
10
10
  name: key
11
11
  default: ""
12
+ required: true
13
+ showOnNode: true
12
14
  - type: text
13
15
  name: value
14
16
  default: ""
17
+ required: true
18
+ showOnNode: true
15
19
  output:
16
20
  - type: node
17
21
  name: next
@@ -8,8 +8,10 @@ input:
8
8
  default: ""
9
9
  - type: file
10
10
  name: question
11
- description: 要展示给用户的问题(Markdown 格式,可选)
11
+ description: 要展示给用户的问题(Markdown 格式)
12
12
  default: ""
13
+ required: true
14
+ showOnNode: true
13
15
  output:
14
16
  - type: node
15
17
  name: option_0
@@ -10,6 +10,8 @@ input:
10
10
  name: content
11
11
  description: 要展示给用户确认的内容(Markdown 格式)
12
12
  default: ""
13
+ required: true
14
+ showOnNode: true
13
15
  output:
14
16
  - type: node
15
17
  name: next
@@ -19,4 +21,4 @@ output:
19
21
  description: 用户确认后的内容(可能已编辑/AI修改)
20
22
  default: ""
21
23
  ---
22
- ${USER_PROMPT}
24
+ ${USER_PROMPT}