taskmeld 0.1.1 → 0.1.41

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 (155) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +176 -172
  3. package/README.zh-CN.md +176 -172
  4. package/dist/src/app/app-context-env.js +1 -1
  5. package/dist/src/app/create-app-context.js +3 -3
  6. package/dist/src/app/data-dir.js +13 -3
  7. package/dist/src/app/pipeline-config.js +4 -4
  8. package/dist/src/app/pipeline-registry.js +11 -11
  9. package/dist/src/app/pipeline-runtime.js +6 -9
  10. package/dist/src/app/runtime-store.js +3 -3
  11. package/dist/src/artifacts/artifact-cleanup.js +17 -17
  12. package/dist/src/artifacts/artifact-index.js +14 -14
  13. package/dist/src/artifacts/artifact-rebuilder.js +3 -3
  14. package/dist/src/artifacts/storage-service.js +18 -18
  15. package/dist/src/cli/bootstrap.js +7 -7
  16. package/dist/src/cli/commands/agent.js +12 -11
  17. package/dist/src/cli/commands/artifact.js +31 -30
  18. package/dist/src/cli/commands/init.js +49 -47
  19. package/dist/src/cli/commands/pipeline/result.js +9 -8
  20. package/dist/src/cli/commands/pipeline/selector.js +1 -1
  21. package/dist/src/cli/commands/pipeline/watch.js +2 -2
  22. package/dist/src/cli/commands/pipeline.js +54 -53
  23. package/dist/src/cli/commands/scheduler.js +9 -8
  24. package/dist/src/cli/commands/server.js +12 -11
  25. package/dist/src/cli/commands/system.js +4 -3
  26. package/dist/src/cli/errors.js +2 -2
  27. package/dist/src/cli/help.js +18 -17
  28. package/dist/src/cli/i18n.js +46 -0
  29. package/dist/src/cli/locales/en.json +244 -0
  30. package/dist/src/cli/locales/zh.json +244 -0
  31. package/dist/src/cli/output.js +3 -3
  32. package/dist/src/cli/renderers/engine/markdown.js +1 -1
  33. package/dist/src/cli/renderers/specs/index.js +1 -1
  34. package/dist/src/cli/router.js +1 -1
  35. package/dist/src/cli/server-runtime-client.js +54 -95
  36. package/dist/src/cli/ui-prompts.js +96 -0
  37. package/dist/src/cli/ws-runtime-client.js +51 -0
  38. package/dist/src/gateway/gateway-client.js +4 -4
  39. package/dist/src/index.js +28 -2
  40. package/dist/src/logs/run-log-reader.js +1 -1
  41. package/dist/src/pipeline/agent-activity.js +2 -2
  42. package/dist/src/pipeline/artifact-storage.js +11 -11
  43. package/dist/src/pipeline/diagnostics/dependency-diagnostic.js +11 -11
  44. package/dist/src/pipeline/dispatch/pipeline-inbound-queue.js +2 -2
  45. package/dist/src/pipeline/execution/group-item-executor.js +1 -1
  46. package/dist/src/pipeline/execution/node-item-executor.js +3 -3
  47. package/dist/src/pipeline/execution/node-runner.js +7 -7
  48. package/dist/src/pipeline/execution/readiness-state.js +1 -1
  49. package/dist/src/pipeline/execution/reject-handler.js +5 -5
  50. package/dist/src/pipeline/execution/rejected-artifact-archiver.js +1 -1
  51. package/dist/src/pipeline/execution/route-item-manager.js +4 -4
  52. package/dist/src/pipeline/execution/run-abort-controller.js +5 -5
  53. package/dist/src/pipeline/execution/run-state-helpers.js +2 -2
  54. package/dist/src/pipeline/execution/service.js +4 -4
  55. package/dist/src/pipeline/execution/structured-node-runner.js +24 -24
  56. package/dist/src/pipeline/execution-timeout.js +3 -3
  57. package/dist/src/pipeline/identity/index.js +3 -3
  58. package/dist/src/pipeline/item-batch-controller.js +6 -6
  59. package/dist/src/pipeline/scheduler/dependency-state.js +5 -5
  60. package/dist/src/pipeline/scheduler-service.js +24 -24
  61. package/dist/src/pipeline/state-machine.js +2 -2
  62. package/dist/src/pipeline/structured-output/contract.js +4 -4
  63. package/dist/src/pipeline/structured-output/index.js +2 -2
  64. package/dist/src/pipeline/structured-output/parser.js +5 -5
  65. package/dist/src/pipeline/structured-output/prompt.js +38 -38
  66. package/dist/src/pipeline/structured-output/waiter.js +6 -6
  67. package/dist/src/pipeline/template.js +5 -5
  68. package/dist/src/pipeline/timeline-log-store.js +5 -5
  69. package/dist/src/pipeline/tool-activity.js +3 -3
  70. package/dist/src/pipeline/types/pipeline-output.js +1 -1
  71. package/dist/src/pipeline/workflow/branch-rules.js +19 -19
  72. package/dist/src/pipeline/workflow/io.js +1 -1
  73. package/dist/src/pipeline/workflow/normalize.js +18 -18
  74. package/dist/src/pipeline/workflow/template-mapper.js +3 -3
  75. package/dist/src/pipeline/workflow/validate.js +39 -39
  76. package/dist/src/pipeline/workflow-graph.js +10 -10
  77. package/dist/src/server/http-handler.js +74 -0
  78. package/dist/src/services/agent-service.js +2 -2
  79. package/dist/src/services/gateway-read-helpers.js +1 -1
  80. package/dist/src/services/pipeline-service.js +19 -19
  81. package/dist/src/services/pipeline-status.js +4 -4
  82. package/dist/src/services/read-services.js +1 -1
  83. package/dist/src/services/session-service.js +6 -6
  84. package/dist/src/services/system-service.js +1 -1
  85. package/dist/src/transport/ws-broker.js +12 -1
  86. package/dist/src/transport/ws-handler.js +60 -0
  87. package/dist/src/transport/ws-methods/agents.js +144 -0
  88. package/dist/src/transport/ws-methods/artifacts.js +171 -0
  89. package/dist/src/transport/ws-methods/gateway.js +16 -0
  90. package/dist/src/transport/ws-methods/logs.js +43 -0
  91. package/dist/src/transport/ws-methods/pipeline-batch.js +68 -0
  92. package/dist/src/transport/ws-methods/pipeline-links.js +100 -0
  93. package/dist/src/transport/ws-methods/pipeline-queue.js +51 -0
  94. package/dist/src/transport/ws-methods/pipeline-runtime.js +151 -0
  95. package/dist/src/transport/ws-methods/pipeline-scheduler.js +48 -0
  96. package/dist/src/transport/ws-methods/pipeline-workflow.js +127 -0
  97. package/dist/src/transport/ws-methods/pipelines.js +56 -0
  98. package/dist/src/transport/ws-methods/register-all.js +32 -0
  99. package/dist/src/transport/ws-methods/sessions.js +154 -0
  100. package/dist/src/transport/ws-methods/timeline.js +10 -0
  101. package/dist/src/{server/routes/pipeline-identity.js → transport/ws-methods/utils.js} +14 -9
  102. package/dist/src/version.js +1 -1
  103. package/package.json +16 -7
  104. package/web/dist/assets/agent-DP6TMcLj.js +1 -0
  105. package/web/dist/assets/agent-DmJHzLyj.js +1 -0
  106. package/web/dist/assets/artifact-BqnoZy2M.js +1 -0
  107. package/web/dist/assets/artifact-DfDkgkno.js +1 -0
  108. package/web/dist/assets/common-DRMTVwE9.js +1 -0
  109. package/web/dist/assets/common-DeXccbr2.js +1 -0
  110. package/web/dist/assets/dispatch-CBskGCQI.js +1 -0
  111. package/web/dist/assets/dispatch-sk4Wp30e.js +1 -0
  112. package/web/dist/assets/index-C8wTjZvH.css +1 -0
  113. package/web/dist/assets/index-DYDQZRLk.js +58 -0
  114. package/web/dist/assets/log-DN8cjb0w.js +1 -0
  115. package/web/dist/assets/log-HSeA_dYy.js +1 -0
  116. package/web/dist/assets/modal-BdNai9jf.js +1 -0
  117. package/web/dist/assets/modal-D9_KDpFD.js +1 -0
  118. package/web/dist/assets/nav-BmF7oAKg.js +1 -0
  119. package/web/dist/assets/nav-IjC2xqXQ.js +1 -0
  120. package/web/dist/assets/node-detail-CENRXcrh.js +1 -0
  121. package/web/dist/assets/node-detail-bndPr0IM.js +1 -0
  122. package/web/dist/assets/overview-B87zWAxq.js +1 -0
  123. package/web/dist/assets/overview-gQvk-NOK.js +1 -0
  124. package/web/dist/assets/pipeline-D4dSJRDz.js +1 -0
  125. package/web/dist/assets/pipeline-DZzyOqQa.js +1 -0
  126. package/web/dist/assets/session-CUWvU14v.js +5 -0
  127. package/web/dist/assets/session-DQ6UuCaJ.js +5 -0
  128. package/web/dist/assets/timeline-8y_2_0Em.js +1 -0
  129. package/web/dist/assets/timeline-CAPsXUTC.js +1 -0
  130. package/web/dist/index.html +3 -3
  131. package/dist/src/app/pipeline-plugin-config.js +0 -2
  132. package/dist/src/server/api-handler.js +0 -163
  133. package/dist/src/server/http-utils.js +0 -34
  134. package/dist/src/server/middleware.js +0 -61
  135. package/dist/src/server/router.js +0 -105
  136. package/dist/src/server/routes/agents.js +0 -189
  137. package/dist/src/server/routes/artifacts.js +0 -163
  138. package/dist/src/server/routes/gateway.js +0 -18
  139. package/dist/src/server/routes/health.js +0 -16
  140. package/dist/src/server/routes/logs.js +0 -73
  141. package/dist/src/server/routes/pipeline-batch.js +0 -163
  142. package/dist/src/server/routes/pipeline-diagnostics.js +0 -33
  143. package/dist/src/server/routes/pipeline-links.js +0 -117
  144. package/dist/src/server/routes/pipeline-outputs.js +0 -27
  145. package/dist/src/server/routes/pipeline-queue.js +0 -62
  146. package/dist/src/server/routes/pipeline-runtime.js +0 -162
  147. package/dist/src/server/routes/pipeline-scheduler.js +0 -69
  148. package/dist/src/server/routes/pipeline-workflow.js +0 -180
  149. package/dist/src/server/routes/pipelines.js +0 -96
  150. package/dist/src/server/routes/sessions.js +0 -244
  151. package/dist/src/server/routes/timeline.js +0 -14
  152. package/dist/src/server/serve-static.js +0 -42
  153. package/web/dist/assets/index-CWnfhkn-.js +0 -65
  154. package/web/dist/assets/index-gZ0xOfSO.css +0 -1
  155. /package/dist/src/{server → transport/ws-methods}/types.js +0 -0
@@ -8,9 +8,9 @@ const run_state_helpers_1 = require("./execution/run-state-helpers");
8
8
  const state_1 = require("./state");
9
9
  const identity_1 = require("./identity");
10
10
  /**
11
- * 流水线调度器。
12
- * 负责:决定何时执行节点、管理并发、控制调度模式。
13
- * 不负责:节点的具体执行逻辑。
11
+ * Pipeline scheduler.
12
+ * Responsible for: deciding when to execute nodes, managing concurrency, controlling scheduling mode.
13
+ * Not responsible for: the specific execution logic of nodes.
14
14
  */
15
15
  const createSchedulerService = (deps) => {
16
16
  const isSchedulerPluginEnabled = () => deps.graph.getWorkflow().plugins.scheduler.enabled;
@@ -96,8 +96,8 @@ const createSchedulerService = (deps) => {
96
96
  currentGroupItem.attempt = 0;
97
97
  currentGroupItem.artifacts = [];
98
98
  }
99
- // 手动重试模式下,目标节点可能已经满足依赖但被 reset blocked
100
- // 这里先重新评估依赖,再决定是否立刻执行首个节点,避免稳定复现 node_retry_blocked
99
+ // In manual retry mode, the target node may already have its dependencies met but was reset to blocked.
100
+ // Re-evaluate dependencies first, then decide whether to execute the first node immediately, to avoid reliably reproducing node_retry_blocked.
101
101
  markReadyItemsFromDependencies();
102
102
  markReadyGroupsFromDependencies();
103
103
  deps.runtimeStore.emitPipeline();
@@ -121,10 +121,10 @@ const createSchedulerService = (deps) => {
121
121
  return { ok: true, node, drained };
122
122
  };
123
123
  /**
124
- * 核心调度循环。遍历就绪节点并执行。这是调度器的核心职责。
124
+ * Core scheduling loop. Iterates over ready nodes and executes them. This is the scheduler's core responsibility.
125
125
  *
126
- * 传入的 AbortSignal 仅用于提前退出本地排水循环;
127
- * 远端 agent 的停止由 executionService.abortRunControllers 通过 "/stop" 命令处理。
126
+ * The passed AbortSignal is only used to exit the local drain loop early;
127
+ * remote agent stopping is handled by executionService.abortRunControllers via the "/stop" command.
128
128
  */
129
129
  const drainPipeline = async (reason, signal) => {
130
130
  const manualTick = reason.startsWith("manual_tick");
@@ -141,7 +141,7 @@ const createSchedulerService = (deps) => {
141
141
  return { executed: 0, hardFailed: false };
142
142
  }
143
143
  if (drainInFlight) {
144
- deps.runtimeStore.pushTimeline(`[调度排水锁] 调用方=${reason} 触发排水,但已有 ${drainInFlightReason} 排水正在执行,本次调用合并至现有排水`, "info");
144
+ deps.runtimeStore.pushTimeline(`[Scheduling drain lock] caller=${reason} triggered drain, but ${drainInFlightReason} drain is already in progress, merged into existing drain`, "info");
145
145
  return drainInFlight;
146
146
  }
147
147
  drainInFlight = (async () => {
@@ -161,13 +161,13 @@ const createSchedulerService = (deps) => {
161
161
  active.add(task);
162
162
  };
163
163
  while (true) {
164
- // 客户端侧中止:外部调用 abortRunControllers 后,signal 变为 aborted
165
- // 排水循环提前退出,不再等待活跃节点自然完成。
164
+ // Client-side abort: after external call to abortRunControllers, the signal becomes aborted,
165
+ // the drain loop exits early and no longer waits for active nodes to finish naturally.
166
166
  if (signal?.aborted) {
167
167
  stopScheduling = true;
168
168
  }
169
169
  if (executed >= maxIterations) {
170
- deps.runtimeStore.pushTimeline(`调度达到全局迭代上限: ${maxIterations}`, "warn");
170
+ deps.runtimeStore.pushTimeline(`Scheduling reached global iteration limit: ${maxIterations}`, "warn");
171
171
  break;
172
172
  }
173
173
  while (!stopScheduling && !signal?.aborted && active.size < maxConcurrency && executed < maxIterations) {
@@ -179,7 +179,7 @@ const createSchedulerService = (deps) => {
179
179
  const batchLabel = batch
180
180
  .map((item) => ("nodeId" in item ? `${item.nodeId}#${item.itemKey}` : `group:${item.groupId}#${item.itemKey}`))
181
181
  .join(", ");
182
- deps.runtimeStore.pushTimeline(`流水线自动调度: ${batchLabel} (${reason})`);
182
+ deps.runtimeStore.pushTimeline(`Pipeline auto-scheduled: ${batchLabel} (${reason})`);
183
183
  for (const item of batch) {
184
184
  launchItem(item);
185
185
  }
@@ -219,8 +219,8 @@ const createSchedulerService = (deps) => {
219
219
  return drainInFlight;
220
220
  };
221
221
  /**
222
- * 批量运行控制器。管理关键词池的分批执行生命周期(启动、停止、取消、状态查询)。
223
- * 属于调度器职责——控制何时及如何分批执行。
222
+ * Batch run controller. Manages the lifecycle of keyword-pool batch execution (start, stop, cancel, status query).
223
+ * Belongs to the scheduler's responsibility — controls when and how to execute batches.
224
224
  */
225
225
  const itemBatchController = (0, item_batch_controller_1.createItemBatchController)({
226
226
  pipelineId: deps.pipelineId,
@@ -231,7 +231,7 @@ const createSchedulerService = (deps) => {
231
231
  deps.executionService.setActiveBatchKeywordItems([...batchItems]);
232
232
  deps.graph.syncRunGroupsFromWorkflow(nextRun);
233
233
  deps.runtimeStore.emitPipeline();
234
- deps.runtimeStore.pushTimeline(`批量运行开始: ${batchIndex}/${totalBatches} 批, 关键词 ${batchItems.length}/${totalItems}`);
234
+ deps.runtimeStore.pushTimeline(`Batch run started: batch ${batchIndex}/${totalBatches}, keywords ${batchItems.length}/${totalItems}`);
235
235
  let drained;
236
236
  try {
237
237
  const drainSignal = deps.executionService.getOrCreateDrainSignal(getRun().id);
@@ -243,7 +243,7 @@ const createSchedulerService = (deps) => {
243
243
  deps.executionService.setActiveBatchKeywordItems(null);
244
244
  }
245
245
  if (getRun().status === "running") {
246
- deps.runtimeStore.pushTimeline(`批量运行结束: ${batchIndex} 批无后续可执行节点,直接进入下一批`, "warn", {
246
+ deps.runtimeStore.pushTimeline(`Batch run ended: batch ${batchIndex} has no further executable nodes, proceeding to next batch`, "warn", {
247
247
  batchIndex,
248
248
  totalBatches,
249
249
  drained,
@@ -251,9 +251,9 @@ const createSchedulerService = (deps) => {
251
251
  });
252
252
  return { ok: true };
253
253
  }
254
- // 仅在硬失败场景停止后续批次;业务型 failed(status=failed) 允许继续下一批。
254
+ // Only stop subsequent batches on hard-failure scenarios; business-type failed (status=failed) allows continuing to the next batch.
255
255
  if (drained.hardFailed) {
256
- deps.runtimeStore.pushTimeline(`批量运行失败: ${batchIndex} 批, 已停止后续批次`, "error", {
256
+ deps.runtimeStore.pushTimeline(`Batch run failed: batch ${batchIndex}, subsequent batches stopped`, "error", {
257
257
  batchIndex,
258
258
  totalBatches,
259
259
  drained,
@@ -261,14 +261,14 @@ const createSchedulerService = (deps) => {
261
261
  });
262
262
  return { ok: false, error: `batch_${batchIndex}_failed`, hardStop: true };
263
263
  }
264
- deps.runtimeStore.pushTimeline(`批量运行完成: ${batchIndex}/${totalBatches} 批, run=${getRun().id}`);
264
+ deps.runtimeStore.pushTimeline(`Batch run completed: batch ${batchIndex}/${totalBatches}, run=${getRun().id}`);
265
265
  return { ok: true };
266
266
  },
267
267
  });
268
268
  return {
269
269
  getSchedulerState: () => ({
270
270
  ...schedulerState,
271
- // 调度器插件关闭时,对外统一表现为 disabled,避免界面和运行时状态不一致。
271
+ // When the scheduler plugin is disabled, externally present as disabled to avoid UI/runtime state inconsistency.
272
272
  enabled: isSchedulerPluginEnabled() && schedulerState.enabled,
273
273
  }),
274
274
  setSchedulerEnabled: (enabled) => {
@@ -285,21 +285,21 @@ const createSchedulerService = (deps) => {
285
285
  startBatchRun: (items, batchSize, options) => {
286
286
  const started = itemBatchController.start(items, batchSize, options);
287
287
  if (started.ok) {
288
- deps.runtimeStore.pushTimeline(`已启动关键词池批量运行: ${started.snapshot.totalItems} 个, 每批 ${started.snapshot.batchSize} 个`);
288
+ deps.runtimeStore.pushTimeline(`Batch run started: ${started.snapshot.totalItems} total items, ${started.snapshot.batchSize} per batch`);
289
289
  }
290
290
  return started;
291
291
  },
292
292
  stopBatchRun: () => {
293
293
  const stopped = itemBatchController.stop();
294
294
  if (stopped.ok) {
295
- deps.runtimeStore.pushTimeline("已请求停止关键词池批量运行(当前批次结束后生效)", "warn");
295
+ deps.runtimeStore.pushTimeline("Batch run stop requested (takes effect after current batch completes)", "warn");
296
296
  }
297
297
  return stopped;
298
298
  },
299
299
  cancelBatchRun: () => {
300
300
  const canceled = itemBatchController.cancel();
301
301
  if (canceled.ok) {
302
- deps.runtimeStore.pushTimeline("已立即停止关键词池批量运行(插件已关闭)", "warn");
302
+ deps.runtimeStore.pushTimeline("Batch run cancelled immediately (plugin disabled)", "warn");
303
303
  }
304
304
  return canceled;
305
305
  },
@@ -83,8 +83,8 @@ const transitionStatus = (current, next, command) => {
83
83
  if (current === next)
84
84
  return current;
85
85
  const allowedByCommand = exports.VALID_TRANSITIONS[current];
86
- // 未指定 command 时仅允许 execute + dependency 权限(安全默认值),
87
- // 特殊权限(route_backfill/retry_reset/reject_reset/sleep/group_aggregate)必须显式传 command
86
+ // When no command is specified, only execute + dependency permissions are allowed (safe default),
87
+ // special permissions (route_backfill/retry_reset/reject_reset/sleep/group_aggregate) require an explicit command.
88
88
  const allowed = command
89
89
  ? (allowedByCommand[command] ?? [])
90
90
  : [
@@ -12,7 +12,7 @@ const normalizeSchemaVersion = (value) => {
12
12
  if (typeof value !== "string")
13
13
  return null;
14
14
  const trimmed = value.trim();
15
- // 兼容模型把 schemaVersion 输出成字符串数字(例如 "1")的场景。
15
+ // Accommodate models that output schemaVersion as a numeric string (e.g. "1").
16
16
  if (!/^\d+$/.test(trimmed))
17
17
  return null;
18
18
  const parsed = Number(trimmed);
@@ -33,7 +33,7 @@ const normalizeAllowedRoute = (rawRoute, allowedRoutes) => {
33
33
  if (direct)
34
34
  return direct;
35
35
  const lower = trimmed.toLowerCase();
36
- // 允许大小写不一致,统一纠正为工作流里声明的 route,避免无意义失败。
36
+ // Allow case-insensitive matches, normalizing to the declared workflow route to avoid pointless failures.
37
37
  const insensitive = allowedRoutes.find((route) => route.toLowerCase() === lower);
38
38
  return insensitive ?? null;
39
39
  };
@@ -96,7 +96,7 @@ const validateEnvelope = (envelope, ctx) => {
96
96
  return { ok: false, code: "artifact_spec_mismatch" };
97
97
  }
98
98
  }
99
- // 兼容历史/冗余字段:顶层 routedecisions 不再作为硬失败条件,忽略即可。
99
+ // Backward-compat with legacy/redundant fields: top-level route and decisions are no longer hard-failure conditions — simply ignore.
100
100
  if (envelope.control !== undefined) {
101
101
  if (!(0, guards_1.isRecord)(envelope.control))
102
102
  return { ok: false, code: "hold_control_invalid" };
@@ -113,7 +113,7 @@ const validateEnvelope = (envelope, ctx) => {
113
113
  return { ok: false, code: "route_content_invalid" };
114
114
  }
115
115
  if (!Array.isArray(primaryArtifact.content) && (0, guards_1.isRecord)(primaryArtifact.content)) {
116
- // 兼容单对象输出,统一纠正为数组,后续分流逻辑保持一致。
116
+ // Accommodate single-object output by normalizing to an array so downstream routing logic stays consistent.
117
117
  primaryArtifact.content = [primaryArtifact.content];
118
118
  }
119
119
  if (!Array.isArray(primaryArtifact.content) || primaryArtifact.content.length === 0) {
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- // 目录出口:调用方继续从 structured-output 子模块导入,内部文件按职责拆分。
18
- // 统一从这里 re-export,避免后续再次拆分时把外部 import 路径扩散到实现细节。
17
+ // Directory barrel export: callers continue importing from structured-output sub-modules; internal files are split by responsibility.
18
+ // Re-export uniformly from here to avoid spreading external import paths to implementation details upon future re-splits.
19
19
  __exportStar(require("./contract"), exports);
20
20
  __exportStar(require("./parser"), exports);
21
21
  __exportStar(require("./prompt"), exports);
@@ -31,8 +31,8 @@ exports.detectFenceLanguage = detectFenceLanguage;
31
31
  const extractBalancedJsonObjectCandidates = (text) => {
32
32
  const candidates = [];
33
33
  const seen = new Set();
34
- // 流式输出常出现“说明文字 + JSON”拼接在同一段文本中的情况。
35
- // 这里通过括号平衡扫描抽取内嵌 JSON 对象,避免整段 JSON.parse 直接失败。
34
+ // Streaming output often has "explanatory text + JSON" concatenated in the same text segment.
35
+ // Use bracket-balanced scanning to extract embedded JSON objects, avoiding direct JSON.parse failure on the whole segment.
36
36
  for (let start = text.indexOf("{"); start >= 0; start = text.indexOf("{", start + 1)) {
37
37
  let depth = 0;
38
38
  let inString = false;
@@ -130,7 +130,7 @@ const tryParseEnvelopeObject = (value) => {
130
130
  continue;
131
131
  const normalized = (0, contract_1.normalizeSchemaVersion)(rawArtifact.schemaVersion);
132
132
  if (normalized !== null) {
133
- // 解析阶段先做宽松纠正,后续统一走 number 语义校验与持久化。
133
+ // Loosely correct at parse stage; subsequent processing uniformly uses number semantic validation and persistence.
134
134
  rawArtifact.schemaVersion = normalized;
135
135
  }
136
136
  }
@@ -147,7 +147,7 @@ const tryParseEnvelopeText = (text) => {
147
147
  if (text.length > ENVELOPE_TEXT_SCAN_TAIL_CHARS) {
148
148
  const headLen = text.length - ENVELOPE_TEXT_SCAN_TAIL_CHARS;
149
149
  const headPart = text.slice(0, headLen);
150
- // 向前回溯到最近的 {,防止 JSON 起始被窗口切断
150
+ // Backtrack to the nearest { to prevent the JSON start from being cut off by the window
151
151
  const lastBrace = headPart.lastIndexOf("{");
152
152
  scanText = lastBrace >= 0 ? text.slice(lastBrace) : text.slice(-ENVELOPE_TEXT_SCAN_TAIL_CHARS);
153
153
  }
@@ -167,7 +167,7 @@ const tryParseEnvelopeText = (text) => {
167
167
  return envelope;
168
168
  }
169
169
  catch {
170
- // 继续尝试后续候选
170
+ // Continue trying subsequent candidates
171
171
  }
172
172
  }
173
173
  return null;
@@ -106,16 +106,16 @@ const createNodeExecutionPrompt = (ctx) => {
106
106
  return Array.from(grouped.values());
107
107
  })();
108
108
  const lines = [
109
- "# 流水线节点执行指令",
109
+ "# Pipeline Node Execution Instructions",
110
110
  "",
111
- "## 输出要求",
112
- "- 只能返回一个合法 JSON 对象(ResultEnvelope)。",
113
- "- 不要输出任何额外解释、前后缀、Markdown 之外的文本。",
114
- "- `status=success` 时,`artifacts` 必须至少 1 条。",
115
- "- `artifacts[].content` 支持任意 JSON 值(例如:`\"text\"`、`{\"k\":\"v\"}`、`[{\"k\":\"v1\"},{\"k\":\"v2\"}]`)。",
116
- ...(isRouteNode ? ["- 分流节点的 `artifacts[0].content` 必须是数组,数组内每个对象都要包含 `route` 字段。"] : []),
111
+ "## Output Requirements",
112
+ "- Return only a valid JSON object (ResultEnvelope).",
113
+ "- Do not output any extra explanations, prefixes, suffixes, or text outside of Markdown.",
114
+ "- When `status=success`, `artifacts` must contain at least 1 item.",
115
+ "- `artifacts[].content` accepts any JSON value (e.g., `\"text\"`, `{\"k\":\"v\"}`, `[{\"k\":\"v1\"},{\"k\":\"v2\"}]`).",
116
+ ...(isRouteNode ? ["- For routing nodes, `artifacts[0].content` must be an array, and each object in the array must include a `route` field."] : []),
117
117
  "",
118
- "## ResultEnvelope 固定字段",
118
+ "## ResultEnvelope Fixed Fields",
119
119
  `- version: \`2.0\``,
120
120
  `- runId: \`${ctx.runId}\``,
121
121
  `- nodeId: \`${ctx.nodeId}\``,
@@ -124,27 +124,27 @@ const createNodeExecutionPrompt = (ctx) => {
124
124
  "- status: `success | failed`",
125
125
  "- artifacts: `array`",
126
126
  "",
127
- "## 节点上下文",
128
- `- 当前节点: \`${ctx.nodeId}\`(${ctx.nodeTitle})`,
129
- `- 依赖节点: ${ctx.dependencies.length > 0 ? ctx.dependencies.map((id) => `\`${id}\``).join(", ") : "`none`"}`,
127
+ "## Node Context",
128
+ `- Current node: \`${ctx.nodeId}\` (${ctx.nodeTitle})`,
129
+ `- Dependencies: ${ctx.dependencies.length > 0 ? ctx.dependencies.map((id) => `\`${id}\``).join(", ") : "`none`"}`,
130
130
  ];
131
- lines.push("", "## 产物规格", `- type: \`${spec.type}\``, `- schemaVersion: \`${spec.schemaVersion}\``);
132
- // 仅在节点明确开启分流时,才注入分流相关说明,避免无配置时污染提示词。
131
+ lines.push("", "## Artifact Specification", `- type: \`${spec.type}\``, `- schemaVersion: \`${spec.schemaVersion}\``);
132
+ // Only inject routing instructions when the node explicitly enables routing, to avoid polluting the prompt when no routing is configured.
133
133
  if (ctx.allowedRoutes.length > 0) {
134
- lines.push("", "## 分流规则", `- 允许的 route 仅能是: ${ctx.allowedRoutes.map((route) => `\`${route}\``).join(", ")}`, `- \`${MAINLINE_ROUTE_VALUE}\` 表示继续主线,不需要配置分流目标。`, "- `artifacts[0].content` 必须输出为数组。", "- 数组中的每个对象都必须包含 `route` 字段。", "- 每个对象的 `route` 必须命中上述取值。", "- 系统会按 `content[*].route` 自动分组、汇总并推送到对应分支。");
134
+ lines.push("", "## Routing Rules", `- Allowed routes are: ${ctx.allowedRoutes.map((route) => `\`${route}\``).join(", ")}`, `- \`${MAINLINE_ROUTE_VALUE}\` indicates continuing on the mainline; no routing target configuration needed.`, "- `artifacts[0].content` must be an array.", "- Each object in the array must include a `route` field.", "- Each object's `route` must match one of the allowed values above.", "- The system will automatically group and dispatch items by `content[*].route` to the corresponding branches.");
135
135
  if (ctx.routeTargets.length > 0) {
136
- lines.push("- 当前配置的 route 目标如下:");
136
+ lines.push("- The configured route targets are:");
137
137
  for (const target of ctx.routeTargets) {
138
138
  lines.push(` - \`${target.route}\` -> \`${target.targetNodeId}\` (${target.targetNodeTitle}, agent:${target.targetAgentId}, lane:${target.lane})`);
139
139
  }
140
140
  }
141
141
  }
142
- // 仅在节点明确开启打回且存在上游依赖时,才注入打回相关说明,避免无配置时污染提示词。
142
+ // Only inject rejection instructions when the node explicitly enables rejection and has upstream dependencies, to avoid polluting the prompt when no rejection is configured.
143
143
  if (ctx.allowReject && ctx.dependencies.length > 0) {
144
- lines.push("", "## 打回配置", `- allowReject: \`${ctx.allowReject ? "true" : "false"}\``, `- maxRejectCount: \`${ctx.maxRejectCount}\``, "", "### 打回规则", "- 仅当上游内容不符合你的校验规范时,才允许打回。", "- 打回时必须返回 `status=failed`,且 `error.code=upstream_reject`。", "- 如需指定目标上游,可提供 `error.targets=[\"nodeId\"]`。", "- 不提供 `targets` 时,系统默认打回上一个直接上游节点。", "", "```json", "{\"code\":\"upstream_reject\",\"message\":\"打回原因\"}", "```");
144
+ lines.push("", "## Rejection Configuration", `- allowReject: \`${ctx.allowReject ? "true" : "false"}\``, `- maxRejectCount: \`${ctx.maxRejectCount}\``, "", "### Rejection Rules", "- Rejection is only allowed when upstream content does not meet your validation criteria.", "- When rejecting, you must return `status=failed` with `error.code=upstream_reject`.", "- To specify target upstream nodes, provide `error.targets=[\"nodeId\"]`.", "- When `targets` is not provided, the system defaults to rejecting the most recent direct upstream node.", "", "```json", "{\"code\":\"upstream_reject\",\"message\":\"rejection reason\"}", "```");
145
145
  }
146
146
  if (isRouteNode) {
147
- lines.push("", "## 分流节点 JSON 示例", "```json", JSON.stringify({
147
+ lines.push("", "## Routing Node JSON Example", "```json", JSON.stringify({
148
148
  version: "2.0",
149
149
  runId: "__RUN_ID__",
150
150
  nodeId: "__NODE_ID__",
@@ -173,7 +173,7 @@ const createNodeExecutionPrompt = (ctx) => {
173
173
  }, null, 2), "```");
174
174
  }
175
175
  else {
176
- lines.push("", "## JSON 输出示例", "```json", JSON.stringify({
176
+ lines.push("", "## JSON Output Example", "```json", JSON.stringify({
177
177
  version: "2.0",
178
178
  runId: "__RUN_ID__",
179
179
  nodeId: "__NODE_ID__",
@@ -202,22 +202,22 @@ const createNodeExecutionPrompt = (ctx) => {
202
202
  if (ctx.externalPipelineArtifact) {
203
203
  const artifact = ctx.externalPipelineArtifact;
204
204
  const fence = (0, parser_1.detectFenceLanguage)(artifact.content);
205
- lines.push("## 外部流水线上游产物", "", `来源: 流水线 ${artifact.sourcePipelineId} 的最终输出`, "", "内容:", `\`\`\`${fence}`, artifact.content, "```");
205
+ lines.push("## External Pipeline Upstream Artifacts", "", `Source: final output of pipeline ${artifact.sourcePipelineId}`, "", "Content:", `\`\`\`${fence}`, artifact.content, "```");
206
206
  }
207
207
  if (groupedDependencies.length > 0) {
208
- lines.push("## 上游输输出结构:");
208
+ lines.push("## Upstream Output Structure:");
209
209
  for (const dep of groupedDependencies) {
210
210
  const merged = dep.contents.join("\n");
211
211
  const fence = (0, parser_1.detectFenceLanguage)(merged);
212
- lines.push(`### 节点 \`${dep.sourceNodeId}\`(${dep.sourceNodeTitle})- agent \`${dep.sourceAgentId}\``, `\`\`\`${fence}`, merged, "```");
212
+ lines.push(`### Node \`${dep.sourceNodeId}\` (${dep.sourceNodeTitle}) - agent \`${dep.sourceAgentId}\``, `\`\`\`${fence}`, merged, "```");
213
213
  }
214
214
  lines.push("");
215
215
  }
216
- // 节点目标是执行 prompt 的核心约束,不能因为存在打回反馈或分流说明而被覆盖掉。
217
- // 这里固定保留“节点目标”段,再额外追加反馈,避免分流节点提示词缺少主任务目标。
218
- lines.push("## 节点目标", ctx.instruction || "请按节点职责完成任务");
216
+ // The node objective is the core constraint of the execution prompt and must not be overwritten by rejection feedback or routing instructions.
217
+ // Always keep the "Node Objective" section here, then append feedback separately, to avoid routing-node prompts missing the main task objective.
218
+ lines.push("## Node Objective", ctx.instruction || "Complete the task according to the node's responsibilities");
219
219
  if (ctx.rejectFeedbacks.length > 0) {
220
- lines.push("", "## 下游打回反馈(请优先修正)");
220
+ lines.push("", "## Downstream Rejection Feedback (please prioritize fixes)");
221
221
  for (const item of ctx.rejectFeedbacks) {
222
222
  lines.push(`- ${item}`);
223
223
  }
@@ -226,28 +226,28 @@ const createNodeExecutionPrompt = (ctx) => {
226
226
  };
227
227
  exports.createNodeExecutionPrompt = createNodeExecutionPrompt;
228
228
  const createNodeCorrectionPrompt = (ctx, lastViolation) => [
229
- `结构校验未通过,错误码: ${lastViolation}`,
230
- "请严格基于本次请求的固定字段重发完整 ResultEnvelope,不要沿用旧请求的顶层字段。",
231
- `固定字段必须为: version="2.0", runId="${ctx.runId}", nodeId="${ctx.nodeId}", requestId="${ctx.requestId}", sessionId="${ctx.sessionId}"`,
232
- `产物规格必须为: type="${ctx.outputSpec.type}", schemaVersion=${ctx.outputSpec.schemaVersion}`,
229
+ `Structural validation failed, error code: ${lastViolation}`,
230
+ "Resend a complete ResultEnvelope strictly based on the fixed fields of this request. Do not reuse top-level fields from previous requests.",
231
+ `Fixed fields must be: version="2.0", runId="${ctx.runId}", nodeId="${ctx.nodeId}", requestId="${ctx.requestId}", sessionId="${ctx.sessionId}"`,
232
+ `Artifact specification must be: type="${ctx.outputSpec.type}", schemaVersion=${ctx.outputSpec.schemaVersion}`,
233
233
  ctx.allowedRoutes && ctx.allowedRoutes.length > 0
234
- ? `这是分流节点。允许的 route 只有: ${ctx.allowedRoutes.map((route) => `"${route}"`).join(", ")}。请把 route 写进 artifacts[0].content 的每个对象里。`
234
+ ? `This is a routing node. The only allowed routes are: ${ctx.allowedRoutes.map((route) => `"${route}"`).join(", ")}. Include the route field in each object within artifacts[0].content.`
235
235
  : ctx.externalPipelineArtifact
236
- ? `本次请求包含来自流水线 ${ctx.externalPipelineArtifact.sourcePipelineId} 的外部上游产物。请继续基于该上游产物修正。`
237
- : "请按当前结构输出结果。",
238
- "请先把完整 ResultEnvelope 保存为当前工作目录下的 result.json,然后自行运行下面的校验命令,确认 JSON valid 后再继续:",
236
+ ? `This request contains an external upstream artifact from pipeline ${ctx.externalPipelineArtifact.sourcePipelineId}. Continue corrections based on this upstream artifact.`
237
+ : "Output the result in the current structure.",
238
+ "First save the complete ResultEnvelope as result.json in the current working directory, then run the following validation command and confirm JSON valid before continuing:",
239
239
  "```bash",
240
240
  "cat result.json | python3 -m json.tool > /dev/null && echo \"JSON valid\" || echo \"JSON invalid\"",
241
241
  "```",
242
- "如果校验结果不是 JSON valid,请继续修正 result.json,直到通过为止。",
243
- "必须输出完整 JSON 对象,不要只输出 artifacts 片段。",
244
- "只输出修正后的合法 JSON ResultEnvelope,不要输出任何解释。",
242
+ "If the validation result is not JSON valid, continue fixing result.json until it passes.",
243
+ "You must output the complete JSON object, not just the artifacts fragment.",
244
+ "Output only the corrected valid JSON ResultEnvelope. Do not output any explanations.",
245
245
  ].join("\n");
246
246
  exports.createNodeCorrectionPrompt = createNodeCorrectionPrompt;
247
247
  const buildExternalPipelineArtifactInput = async (output) => {
248
248
  try {
249
249
  const { absolutePath } = output.artifactRef;
250
- // Verify path is within artifact directory (basic path traversal check)
250
+ // Normalize path to resolve relative segments (e.g. '..', '.')
251
251
  const normalizedPath = (0, node_path_1.resolve)(absolutePath);
252
252
  if (!normalizedPath)
253
253
  return null;
@@ -54,8 +54,8 @@ const evaluateObservedEnvelopeWindow = (observed, ctx, options) => {
54
54
  const forRequestId = observed.filter((entry) => entry.envelope.requestId === ctx.requestId);
55
55
  if (forRequestId.length > 0) {
56
56
  if (!confirmFinal) {
57
- // agent 会话未结束前,只记录“已见到候选”,不能提前认定成功/失败。
58
- // 否则中途调试 JSON、半成品 envelope 都可能被过早消费。
57
+ // Before the agent session ends, only record "candidate seen" — cannot prematurely declare success/failure.
58
+ // Otherwise intermediate debug JSON or half-finished envelopes could be consumed too early.
59
59
  return { seenCandidate: true };
60
60
  }
61
61
  let latestFailure = null;
@@ -80,12 +80,12 @@ const evaluateObservedEnvelopeWindow = (observed, ctx, options) => {
80
80
  };
81
81
  exports.evaluateObservedEnvelopeWindow = evaluateObservedEnvelopeWindow;
82
82
  /**
83
- * 等待结构化回执。
83
+ * Wait for a structured receipt.
84
84
  *
85
- * 当传入 AbortSignal 且被触发时,提前退出本地轮询循环。
86
- * 远端 agent 的停止由上游 executionService 通过 "/stop" 命令处理。
85
+ * When an AbortSignal is passed and triggered, exit the local polling loop early.
86
+ * Remote agent stopping is handled by the upstream executionService via the "/stop" command.
87
87
  *
88
- * @param signal 可选的中止信号,用于流水线 stop/retry 时提前退出轮询。
88
+ * @param signal Optional abort signal, used to exit polling early during pipeline stop/retry.
89
89
  */
90
90
  const waitForStructuredEnvelope = async (emitter, ctx, initialViolation, hasSessionCompleted, signal) => {
91
91
  const deadline = Date.now() + STRUCTURED_RESULT_TIMEOUT_MS;
@@ -69,30 +69,30 @@ exports.readTemplateNodesFromRaw = readTemplateNodesFromRaw;
69
69
  // ====== Migration ======
70
70
  const migrateWorkflowDefinitionV2RawToV3 = (value) => {
71
71
  if (!(0, guards_1.isRecord)(value) || value.version !== "2.0") {
72
- return { ok: false, error: "invalid_workflow_definition", detail: "仅支持从 workflow v2.0 迁移" };
72
+ return { ok: false, error: "invalid_workflow_definition", detail: "Migration is only supported from workflow v2.0" };
73
73
  }
74
74
  if (!Array.isArray(value.nodes) || !Array.isArray(value.edges) || !Array.isArray(value.groups)) {
75
- return { ok: false, error: "invalid_workflow_definition", detail: "workflow.nodes/edges/groups 必须为数组" };
75
+ return { ok: false, error: "invalid_workflow_definition", detail: "workflow.nodes/edges/groups must be arrays" };
76
76
  }
77
77
  const nodes = [];
78
78
  for (const item of value.nodes) {
79
79
  const normalized = (0, normalize_1.normalizeWorkflowNode)(item);
80
80
  if (!normalized)
81
- return { ok: false, error: "invalid_workflow_definition", detail: "workflow.nodes 存在非法节点结构" };
81
+ return { ok: false, error: "invalid_workflow_definition", detail: "workflow.nodes contains an invalid node structure" };
82
82
  nodes.push(normalized);
83
83
  }
84
84
  const edges = [];
85
85
  for (const item of value.edges) {
86
86
  const normalized = (0, normalize_1.normalizeWorkflowEdge)(item);
87
87
  if (!normalized)
88
- return { ok: false, error: "invalid_workflow_definition", detail: "workflow.edges 存在非法边结构" };
88
+ return { ok: false, error: "invalid_workflow_definition", detail: "workflow.edges contains an invalid edge structure" };
89
89
  edges.push(normalized);
90
90
  }
91
91
  const groups = [];
92
92
  for (const item of value.groups) {
93
93
  const normalized = (0, normalize_1.normalizeWorkflowGroup)(item);
94
94
  if (!normalized)
95
- return { ok: false, error: "invalid_workflow_definition", detail: "workflow.groups 存在非法并行组结构" };
95
+ return { ok: false, error: "invalid_workflow_definition", detail: "workflow.groups contains an invalid parallel group structure" };
96
96
  groups.push(normalized);
97
97
  }
98
98
  const workflow = {
@@ -7,8 +7,8 @@ const LOG_FILE_NAME = "timeline.log";
7
7
  const stringifyTimelineEntry = (entry) => {
8
8
  const seen = new WeakSet();
9
9
  return JSON.stringify(entry, (_key, value) => {
10
- // 允许完整保留 detail 内容,但循环引用对象本身无法直接 JSON 化,
11
- // 这里仅做兜底,避免日志持久化因为异常对象而中断主流程。
10
+ // Allow keeping the full detail content, but cyclic-referencing objects themselves can't be directly JSON-serialized;
11
+ // this is purely a safety net to prevent log persistence from being interrupted by an anomalous object in the main flow.
12
12
  if (typeof value !== "object" || value === null)
13
13
  return value;
14
14
  if (seen.has(value))
@@ -30,7 +30,7 @@ const createTimelineLogStore = (options) => {
30
30
  text: item.text,
31
31
  ...(item.detail === undefined ? {} : { detail: item.detail }),
32
32
  })}\n`;
33
- // 单行大小兜底,防止超大 detail 撑爆日志文件
33
+ // Per-line size safety net to prevent oversized details from blowing up the log file
34
34
  const MAX_LOG_LINE_BYTES = 512 * 1024;
35
35
  if (Buffer.byteLength(line, "utf8") > MAX_LOG_LINE_BYTES) {
36
36
  const truncated = line.slice(0, MAX_LOG_LINE_BYTES);
@@ -40,14 +40,14 @@ const createTimelineLogStore = (options) => {
40
40
  }
41
41
  writeChain = writeChain
42
42
  .catch(() => {
43
- // 前一次写盘失败后继续后续写入,避免整个队列永久卡死。
43
+ // Continue subsequent writes after a previous flush failure to avoid permanently deadlocking the entire queue.
44
44
  })
45
45
  .then(async () => {
46
46
  await (0, promises_1.mkdir)((0, node_path_1.dirname)(logFile), { recursive: true });
47
47
  await (0, promises_1.appendFile)(logFile, line, "utf8");
48
48
  });
49
49
  return writeChain.catch(() => {
50
- // 日志持久化失败不能影响流水线运行,这里吞掉异常交给调用方按需记录。
50
+ // Log persistence failure must not affect pipeline execution; swallow the exception here and let the caller record it as needed.
51
51
  });
52
52
  };
53
53
  return {
@@ -77,15 +77,15 @@ const createToolActivityLogger = (deps) => {
77
77
  if (!markSeen(dedupeKey))
78
78
  return;
79
79
  if (phase === "start") {
80
- deps.pushTimeline(`Agent ${agentId} 工具开始: ${toolName} (run:${runId})`);
80
+ deps.pushTimeline(`Agent ${agentId} tool started: ${toolName} (run:${runId})`);
81
81
  return;
82
82
  }
83
83
  if (phase === "result" || phase === "end") {
84
84
  const isError = data.isError === true;
85
- deps.pushTimeline(`Agent ${agentId} 工具结束: ${toolName} (run:${runId}${isError ? ", error" : ""})`, isError ? "warn" : "info");
85
+ deps.pushTimeline(`Agent ${agentId} tool finished: ${toolName} (run:${runId}${isError ? ", error" : ""})`, isError ? "warn" : "info");
86
86
  return;
87
87
  }
88
- deps.pushTimeline(`Agent ${agentId} 工具事件: ${toolName}/${phase || "unknown"} (run:${runId})`);
88
+ deps.pushTimeline(`Agent ${agentId} tool event: ${toolName}/${phase || "unknown"} (run:${runId})`);
89
89
  };
90
90
  return {
91
91
  handleFrame,
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildOutputId = void 0;
4
4
  const node_crypto_1 = require("node:crypto");
5
- /** 用去重键计算短哈希,稳定去重且长度可控。 */
5
+ /** Compute a short hash from a deduplication key; stable dedup with manageable length. */
6
6
  const buildOutputId = (pipelineId, runId, batchRunId, itemKey, outputNodeId, artifactId, hash) => {
7
7
  const key = `${pipelineId}|${runId}|${batchRunId ?? ""}|${itemKey ?? ""}|${outputNodeId}|${artifactId}|${hash}`;
8
8
  const digest = (0, node_crypto_1.createHash)("sha256").update(key).digest("hex").slice(0, 16);