@ai-setting/roy-agent-core 1.5.87 → 1.5.89

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 (39) hide show
  1. package/dist/env/agent/index.js +6 -6
  2. package/dist/env/event-source/index.js +6 -2
  3. package/dist/env/index.js +17 -12
  4. package/dist/env/prompt/index.js +2 -1
  5. package/dist/env/session/index.js +1 -2
  6. package/dist/env/task/delegate/index.js +3 -2
  7. package/dist/env/task/index.js +5 -4
  8. package/dist/env/task/plugins/index.js +7 -4
  9. package/dist/env/task/tools/index.js +1 -1
  10. package/dist/env/tool/built-in/index.js +2 -1
  11. package/dist/env/tool/index.js +11 -8
  12. package/dist/env/workflow/engine/index.js +4 -2
  13. package/dist/env/workflow/index.js +5 -3
  14. package/dist/env/workflow/tools/index.js +7 -1
  15. package/dist/env/workflow/utils/index.js +5 -0
  16. package/dist/index.js +32 -25
  17. package/dist/shared/@ai-setting/{roy-agent-core-6mk0m4t3.js → roy-agent-core-2q7cshpm.js} +1 -1
  18. package/dist/shared/@ai-setting/{roy-agent-core-0y64qaac.js → roy-agent-core-32m0nb9j.js} +119 -30
  19. package/dist/shared/@ai-setting/{roy-agent-core-9y09xfav.js → roy-agent-core-3f6k060j.js} +5 -417
  20. package/dist/shared/@ai-setting/roy-agent-core-4yq23m5g.js +421 -0
  21. package/dist/shared/@ai-setting/{roy-agent-core-mmkyydw7.js → roy-agent-core-83d035pp.js} +91 -579
  22. package/dist/shared/@ai-setting/roy-agent-core-8wd3qwx5.js +35 -0
  23. package/dist/shared/@ai-setting/{roy-agent-core-29fh9mxg.js → roy-agent-core-bwjpte58.js} +1 -2
  24. package/dist/shared/@ai-setting/{roy-agent-core-r1adqgaa.js → roy-agent-core-ewr1nw7t.js} +7 -8
  25. package/dist/shared/@ai-setting/{roy-agent-core-yx0vw1aw.js → roy-agent-core-fgpnv7dt.js} +31 -4
  26. package/dist/shared/@ai-setting/{roy-agent-core-jymz9fzp.js → roy-agent-core-fvfc7f6v.js} +64 -33
  27. package/dist/shared/@ai-setting/{roy-agent-core-9vwyj29a.js → roy-agent-core-h5867smx.js} +16 -22
  28. package/dist/shared/@ai-setting/roy-agent-core-hvdfgvfz.js +114 -0
  29. package/dist/shared/@ai-setting/{roy-agent-core-3arrpf7n.js → roy-agent-core-hxsbegfc.js} +229 -9
  30. package/dist/shared/@ai-setting/{roy-agent-core-7fdzfsm6.js → roy-agent-core-m3dkyprg.js} +35 -211
  31. package/dist/shared/@ai-setting/{roy-agent-core-bgw4dq11.js → roy-agent-core-mw4ty0ba.js} +44 -5
  32. package/dist/shared/@ai-setting/{roy-agent-core-7z4xtrmw.js → roy-agent-core-nqzt9ne4.js} +53 -0
  33. package/dist/shared/@ai-setting/roy-agent-core-pt7as39r.js +0 -0
  34. package/dist/shared/@ai-setting/{roy-agent-core-6n7xwv4v.js → roy-agent-core-qbq3jgrn.js} +5 -3
  35. package/dist/shared/@ai-setting/roy-agent-core-w6bmrgap.js +581 -0
  36. package/dist/shared/@ai-setting/{roy-agent-core-qhjb153z.js → roy-agent-core-xnxyzaw4.js} +27 -4
  37. package/dist/shared/@ai-setting/roy-agent-core-yanpq5gb.js +116 -0
  38. package/package.json +1 -1
  39. package/dist/shared/@ai-setting/roy-agent-core-x3gtyqax.js +0 -378
@@ -1,3 +1,7 @@
1
+ import {
2
+ AUTO_TASK_METADATA_BEGIN,
3
+ AUTO_TASK_METADATA_END
4
+ } from "./roy-agent-core-yanpq5gb.js";
1
5
  import {
2
6
  AskUserError,
3
7
  init_workflow_hil
@@ -25,8 +29,6 @@ import {
25
29
  import {
26
30
  __require
27
31
  } from "./roy-agent-core-fs0mn2jk.js";
28
- // src/env/tool/tool-component.ts
29
- import { z } from "zod";
30
32
 
31
33
  // src/env/tool/registry.ts
32
34
  class ToolRegistry {
@@ -144,6 +146,7 @@ class ToolValidator {
144
146
  }
145
147
 
146
148
  // src/env/tool/tool-component.ts
149
+ import { z } from "zod";
147
150
  init_logger();
148
151
  init_global_hook_manager();
149
152
 
@@ -178,7 +181,138 @@ var TOOL_CONFIG_REGISTRATION = {
178
181
  // src/env/tool/tool-component.ts
179
182
  init_workflow_hil();
180
183
  init_env_context();
181
- var logger = createLogger("tool");
184
+
185
+ // src/utils/temp-file-manager.ts
186
+ init_logger();
187
+ import * as fs from "node:fs";
188
+ import * as path from "node:path";
189
+ import * as os from "node:os";
190
+ import * as crypto from "node:crypto";
191
+ var logger = createLogger("temp-file-manager");
192
+
193
+ class TempFileManager {
194
+ static _instance = null;
195
+ _files = new Set;
196
+ _hooksRegistered = false;
197
+ static FILE_PREFIX = "roy-agent-truncation";
198
+ static FILE_EXT = ".txt";
199
+ static LARGE_FILE_THRESHOLD = 10 * 1024 * 1024;
200
+ static STALE_FILE_AGE_MS = 24 * 60 * 60 * 1000;
201
+ constructor() {
202
+ this.sweepStaleFiles().catch((err) => {
203
+ logger.warn(`[TempFileManager] Stale file sweep failed: ${err}`);
204
+ });
205
+ }
206
+ static getInstance() {
207
+ if (!TempFileManager._instance) {
208
+ TempFileManager._instance = new TempFileManager;
209
+ }
210
+ return TempFileManager._instance;
211
+ }
212
+ static _resetForTesting() {
213
+ if (TempFileManager._instance) {
214
+ TempFileManager._instance.cleanupAll().catch(() => {});
215
+ }
216
+ TempFileManager._instance = null;
217
+ }
218
+ async writeTempFile(content, prefix = "default") {
219
+ this.ensureHooksRegistered();
220
+ if (content.length > TempFileManager.LARGE_FILE_THRESHOLD) {
221
+ logger.warn(`[TempFileManager] Writing large temp file: ${content.length} bytes (> ${TempFileManager.LARGE_FILE_THRESHOLD} bytes). Consider increasing maxOutputSize or filtering output.`);
222
+ }
223
+ const sanitizedPrefix = this.sanitizePrefix(prefix);
224
+ const uuid = crypto.randomUUID();
225
+ const filename = `${TempFileManager.FILE_PREFIX}-${process.pid}-${uuid}-${sanitizedPrefix}${TempFileManager.FILE_EXT}`;
226
+ const filePath = path.join(os.tmpdir(), filename);
227
+ await fs.promises.writeFile(filePath, content, "utf-8");
228
+ this._files.add(filePath);
229
+ logger.debug(`[TempFileManager] Created temp file: ${filePath} (${content.length} bytes)`);
230
+ return filePath;
231
+ }
232
+ async cleanupAll() {
233
+ const files = Array.from(this._files);
234
+ this._files.clear();
235
+ const results = await Promise.allSettled(files.map(async (filePath) => {
236
+ try {
237
+ await fs.promises.unlink(filePath);
238
+ } catch (err) {
239
+ if (err.code !== "ENOENT") {
240
+ logger.warn(`[TempFileManager] Failed to delete ${filePath}: ${err.message}`);
241
+ }
242
+ }
243
+ }));
244
+ const succeeded = results.filter((r) => r.status === "fulfilled").length;
245
+ logger.debug(`[TempFileManager] Cleanup complete: ${succeeded}/${files.length} files deleted`);
246
+ }
247
+ getActiveFileCount() {
248
+ return this._files.size;
249
+ }
250
+ async sweepStaleFiles(maxAgeMs = TempFileManager.STALE_FILE_AGE_MS) {
251
+ const tmpDir = os.tmpdir();
252
+ const now = Date.now();
253
+ let deletedCount = 0;
254
+ let entries;
255
+ try {
256
+ entries = await fs.promises.readdir(tmpDir);
257
+ } catch (err) {
258
+ logger.warn(`[TempFileManager] Failed to read tmpdir ${tmpDir}: ${err.message}`);
259
+ return 0;
260
+ }
261
+ for (const entry of entries) {
262
+ if (!entry.startsWith(`${TempFileManager.FILE_PREFIX}-`))
263
+ continue;
264
+ const filePath = path.join(tmpDir, entry);
265
+ try {
266
+ const stat = await fs.promises.stat(filePath);
267
+ const age = now - stat.mtimeMs;
268
+ if (age > maxAgeMs) {
269
+ await fs.promises.unlink(filePath);
270
+ deletedCount++;
271
+ }
272
+ } catch (err) {
273
+ if (err.code !== "ENOENT") {
274
+ logger.warn(`[TempFileManager] Failed to sweep ${filePath}: ${err.message}`);
275
+ }
276
+ }
277
+ }
278
+ if (deletedCount > 0) {
279
+ logger.info(`[TempFileManager] Swept ${deletedCount} stale files from ${tmpDir}`);
280
+ }
281
+ return deletedCount;
282
+ }
283
+ ensureHooksRegistered() {
284
+ if (this._hooksRegistered)
285
+ return;
286
+ if (typeof process === "undefined" || !process.on) {
287
+ return;
288
+ }
289
+ const cleanup = () => {
290
+ for (const filePath of this._files) {
291
+ try {
292
+ fs.unlinkSync(filePath);
293
+ } catch (err) {}
294
+ }
295
+ this._files.clear();
296
+ };
297
+ process.on("exit", cleanup);
298
+ process.on("SIGINT", () => {
299
+ cleanup();
300
+ process.exit(130);
301
+ });
302
+ process.on("SIGTERM", () => {
303
+ cleanup();
304
+ process.exit(143);
305
+ });
306
+ this._hooksRegistered = true;
307
+ logger.debug("[TempFileManager] Process exit hooks registered");
308
+ }
309
+ sanitizePrefix(prefix) {
310
+ return prefix.replace(/[\/\\<>:"|?*\x00-\x1f]/g, "-").replace(/\s+/g, "-").substring(0, 32) || "default";
311
+ }
312
+ }
313
+
314
+ // src/env/tool/tool-component.ts
315
+ var logger2 = createLogger("tool");
182
316
  var configComponentInstance = null;
183
317
  function setToolConfigComponent(component) {
184
318
  configComponentInstance = component;
@@ -199,6 +333,29 @@ function truncateOutput(output, maxSize) {
199
333
  metadata: {}
200
334
  };
201
335
  }
336
+ const beginIdx = output.indexOf(AUTO_TASK_METADATA_BEGIN);
337
+ const endIdx = output.indexOf(AUTO_TASK_METADATA_END, beginIdx >= 0 ? beginIdx + AUTO_TASK_METADATA_BEGIN.length : 0);
338
+ if (beginIdx >= 0 && endIdx > beginIdx) {
339
+ const metaEnd = endIdx + AUTO_TASK_METADATA_END.length;
340
+ const metadataBlock = output.substring(beginIdx, metaEnd);
341
+ const remainder = output.substring(0, beginIdx) + output.substring(metaEnd);
342
+ const budget = Math.max(0, maxSize - metadataBlock.length);
343
+ const truncatedRemainder = remainder.substring(0, budget);
344
+ const isRemainderTruncated = remainder.length > budget;
345
+ const truncationNotice2 = isRemainderTruncated ? `
346
+
347
+ [OUTPUT TRUNCATED: ${remainder.length} → ${budget} characters. Use offset/limit parameters or pipe to file for full content.]` : "";
348
+ return {
349
+ output: metadataBlock + `
350
+
351
+ ` + truncatedRemainder + truncationNotice2,
352
+ metadata: {
353
+ output_truncated: isRemainderTruncated,
354
+ original_output_size: output.length,
355
+ truncated_output_size: maxSize
356
+ }
357
+ };
358
+ }
202
359
  const truncatedOutput = output.substring(0, maxSize);
203
360
  const truncationNotice = `
204
361
 
@@ -212,6 +369,49 @@ function truncateOutput(output, maxSize) {
212
369
  }
213
370
  };
214
371
  }
372
+ var TOOL_MAX_OUTPUT_SIZE_OVERRIDES = {
373
+ grep: 51200,
374
+ read_file: 204800,
375
+ glob: 10240
376
+ };
377
+ function getMaxOutputSizeForTool(toolName, overrideMaxSize) {
378
+ if (typeof overrideMaxSize === "number" && overrideMaxSize >= 0) {
379
+ return overrideMaxSize;
380
+ }
381
+ if (toolName && TOOL_MAX_OUTPUT_SIZE_OVERRIDES[toolName] !== undefined) {
382
+ return TOOL_MAX_OUTPUT_SIZE_OVERRIDES[toolName];
383
+ }
384
+ return getMaxOutputSize();
385
+ }
386
+ function truncateOutputInline(result, maxSize, overrideMaxSize, toolName) {
387
+ const cloned = {
388
+ success: result.success,
389
+ output: result.output,
390
+ error: result.error,
391
+ metadata: result.metadata ? { ...result.metadata } : { execution_time_ms: 0 }
392
+ };
393
+ const effectiveMax = typeof maxSize === "number" ? maxSize : getMaxOutputSizeForTool(toolName, overrideMaxSize);
394
+ if (effectiveMax <= 0) {
395
+ return cloned;
396
+ }
397
+ if (typeof cloned.output === "string") {
398
+ const truncated = truncateOutput(cloned.output, effectiveMax);
399
+ cloned.output = truncated.output;
400
+ cloned.metadata = {
401
+ ...cloned.metadata,
402
+ ...truncated.metadata
403
+ };
404
+ }
405
+ if (typeof cloned.error === "string" && cloned.error.length > effectiveMax) {
406
+ const truncated = truncateOutput(cloned.error, effectiveMax);
407
+ cloned.error = truncated.output;
408
+ cloned.metadata = {
409
+ ...cloned.metadata,
410
+ ...truncated.metadata
411
+ };
412
+ }
413
+ return cloned;
414
+ }
215
415
 
216
416
  class ToolComponent extends BaseComponent {
217
417
  name = "tool";
@@ -238,7 +438,7 @@ class ToolComponent extends BaseComponent {
238
438
  if (this.config?.builtInTools?.enabled !== false) {
239
439
  await this.loadBuiltInTools();
240
440
  }
241
- logger.info(`ToolComponent initialized with ${this.getToolCount()} tools`);
441
+ logger2.info(`ToolComponent initialized with ${this.getToolCount()} tools`);
242
442
  }
243
443
  async registerConfig(options) {
244
444
  const configComponent = options.configComponent;
@@ -336,7 +536,7 @@ class ToolComponent extends BaseComponent {
336
536
  });
337
537
  }
338
538
  onConfigChange(event) {
339
- logger.info(`Tool config changed: ${event.key}`, {
539
+ logger2.info(`Tool config changed: ${event.key}`, {
340
540
  oldValue: event.oldValue,
341
541
  newValue: event.newValue
342
542
  });
@@ -354,7 +554,7 @@ class ToolComponent extends BaseComponent {
354
554
  source,
355
555
  enabled: true
356
556
  });
357
- logger.debug(`Registered tool: ${tool.name}`);
557
+ logger2.debug(`Registered tool: ${tool.name}`);
358
558
  globalHookManager.execute(ToolHookPoints.AFTER_REGISTER, { tool });
359
559
  }
360
560
  registerMany(tools, source = "dynamic") {
@@ -422,13 +622,32 @@ class ToolComponent extends BaseComponent {
422
622
  }
423
623
  if (typeof result.output === "string") {
424
624
  const maxOutputSize = getMaxOutputSize();
625
+ let fullOutput = null;
425
626
  if (maxOutputSize > 0) {
627
+ fullOutput = result.output;
426
628
  const { output: truncatedOutput, metadata: truncationMeta } = truncateOutput(result.output, maxOutputSize);
427
629
  result.output = truncatedOutput;
428
630
  result.metadata = {
429
631
  ...result.metadata,
430
632
  ...truncationMeta
431
633
  };
634
+ if (truncationMeta.output_truncated === true && tool.name !== "read_file" && fullOutput !== null) {
635
+ try {
636
+ const tempFilePath = await TempFileManager.getInstance().writeTempFile(fullOutput, tool.name);
637
+ result.metadata = {
638
+ ...result.metadata,
639
+ truncation_temp_file: tempFilePath
640
+ };
641
+ result.output += `
642
+
643
+ ⚠️ 输出被截断(原 ${truncationMeta.original_output_size} 字符,截断到 ${truncationMeta.truncated_output_size} 字符)
644
+ \uD83D\uDCC1 完整内容保存到: ${tempFilePath}
645
+ \uD83D\uDD0D 使用 read_file 工具按需读取`;
646
+ logger2.debug(`[tool-component] Truncated output saved to temp file: ${tempFilePath} (${truncationMeta.original_output_size} bytes)`);
647
+ } catch (err) {
648
+ logger2.warn(`[tool-component] Failed to write temp file for truncated output: ${err}`);
649
+ }
650
+ }
432
651
  }
433
652
  const currentTaskId = getCurrentTaskId();
434
653
  if (currentTaskId !== undefined) {
@@ -471,9 +690,9 @@ class ToolComponent extends BaseComponent {
471
690
  const { getAllBuiltInTools } = await import("../../env/tool/built-in/index.js");
472
691
  const tools = getAllBuiltInTools();
473
692
  this.registerMany(tools, "built-in");
474
- logger.info(`Loaded ${tools.length} built-in tools`);
693
+ logger2.info(`Loaded ${tools.length} built-in tools`);
475
694
  } catch (err) {
476
- logger.warn(`Failed to load built-in tools: ${err.message}`);
695
+ logger2.warn(`Failed to load built-in tools: ${err.message}`);
477
696
  }
478
697
  }
479
698
  getHookPoints() {
@@ -503,4 +722,5 @@ var ToolComponentConfigSchema = z.object({
503
722
  maxConcurrency: z.number().int().positive().default(4)
504
723
  }).default({})
505
724
  });
506
- export { ToolRegistry, ToolValidator, setToolConfigComponent, getMaxOutputSize, ToolComponent };
725
+
726
+ export { ToolRegistry, ToolValidator, setToolConfigComponent, getMaxOutputSize, truncateOutputInline, ToolComponent };
@@ -1,6 +1,12 @@
1
+ import {
2
+ WORKFLOW_EXTRACT_PROMPT
3
+ } from "./roy-agent-core-83d035pp.js";
1
4
  import {
2
5
  BasePlugin
3
6
  } from "./roy-agent-core-az13yzmc.js";
7
+ import {
8
+ validateWorkflowDefinition
9
+ } from "./roy-agent-core-8wd3qwx5.js";
4
10
  import {
5
11
  TaskHookPoints
6
12
  } from "./roy-agent-core-92z6t4he.js";
@@ -12,8 +18,7 @@ import {
12
18
  } from "./roy-agent-core-y5d04fm3.js";
13
19
  import {
14
20
  TracedAs,
15
- init_decorator,
16
- wrapFunction
21
+ init_decorator
17
22
  } from "./roy-agent-core-k05v31rc.js";
18
23
  import {
19
24
  createLogger,
@@ -28,107 +33,7 @@ import {
28
33
  init_logger();
29
34
 
30
35
  // src/env/task/plugins/workflow-extractor-agent.ts
31
- var WORKFLOW_EXTRACTOR_PROMPT = `你是 Workflow 提取专家,负责将自然语言描述转换为符合规范的 Workflow YAML。
32
-
33
- ## 提取原则
34
-
35
- 1. **优先具象节点**:优先使用特定工具节点(如 read_file, write_file, grep, bash 等)
36
- 2. **Fallback 到通用节点**:没有对应工具时,使用 agent/llm/bash 节点
37
- 3. **避免条件分支**:不提取循环和条件判断,保持线性流程
38
- 4. **泛化但可执行**:步骤描述可泛化,但节点类型和工具要具体
39
-
40
- ## 构建流程
41
-
42
- **重要**:构建的 Workflow 必须通过 \`roy workflow validate\` 验证才能输出。
43
-
44
- \`\`\`
45
- 1. 理解用户需求
46
- 2. 参考 roy workflow nodes 查看可用节点类型
47
- 3. 参考 roy workflow get <name> 查看已有 workflow 示例
48
- 4. 生成 Workflow YAML
49
- 5. 使用 roy workflow validate --yaml "<生成的YAML>" 验证
50
- 6. 验证通过后输出最终结果
51
- \`\`\`
52
-
53
- ## 验证检查清单
54
-
55
- 完成 Workflow 构建后,必须使用以下命令验证:
56
-
57
- \`\`\`bash
58
- roy workflow validate --yaml "<your-yaml>"
59
- \`\`\`
60
-
61
- 验证通过后(无错误输出)才输出最终结果。验证失败时根据错误信息修正后重新验证。
62
-
63
- ## 可用的 Workflow 节点类型
64
-
65
- 使用以下命令查看所有节点类型的详细配置:
66
-
67
- \`\`\`bash
68
- roy workflow nodes # 列出所有节点类型
69
- roy workflow nodes <type> # 查看特定节点详情(如 tool, agent, skill)
70
- \`\`\`
71
-
72
- **支持的节点类型:**
73
- - **tool**:执行工具(bash, read-file, write-file, grep 等)
74
- - **skill**:调用技能
75
- - **agent**:AI Agent
76
- - **workflow**:子工作流
77
- - **condition**:条件判断
78
- - **merge**:合并结果
79
- - **decorator**:装饰器方法
80
-
81
- ## 查看已有 Workflow 示例
82
-
83
- 使用以下命令查看已有 workflow 的 YAML 结构:
84
-
85
- \`\`\`bash
86
- roy workflow list # 列出所有 workflow
87
- roy workflow get <name> # 获取指定 workflow 详情(YAML 格式)
88
- \`\`\`
89
-
90
- ## 输出要求
91
-
92
- 验证通过后,输出符合以下格式的 YAML Workflow:
93
-
94
- \`\`\`yaml
95
- name: {泛化的任务名称}
96
- version: "1.0"
97
- description: {一句话描述}
98
- nodes:
99
- - id: node-1
100
- type: tool|skill|agent|workflow|condition|merge|decorator
101
- name: {节点名称}
102
- config:
103
- # 根据类型配置必填字段:
104
- # tool: tool, input/args
105
- # skill: skill, input
106
- # agent: agent_type, prompt, options
107
- # workflow: workflow_name, input
108
- # condition: condition
109
- # merge: strategy, depends_on
110
- # decorator: _methodName, _instance
111
- depends_on: []
112
- outputs: []
113
- \`\`\`
114
-
115
- ## 限制
116
-
117
- - 至少 2 个节点才有意义
118
- - 不要生成条件节点(if/else/switch)
119
- - 不要生成循环节点(while/for)
120
- - 每个节点要有清晰的名称和描述
121
- - 必须为 tool 节点指定 tool 名称
122
- - 必须为 agent 节点指定 agent_type 和 prompt`;
123
- function createWorkflowExtractorAgent() {
124
- return {
125
- type: "sub",
126
- name: "workflow-extractor",
127
- systemPrompt: WORKFLOW_EXTRACTOR_PROMPT,
128
- maxIterations: 10,
129
- filterHistory: false
130
- };
131
- }
36
+ var WORKFLOW_EXTRACTOR_PROMPT = WORKFLOW_EXTRACT_PROMPT;
132
37
  function formatExtractorInput(params) {
133
38
  const lines = [];
134
39
  lines.push("# 任务信息");
@@ -225,7 +130,6 @@ class TaskTagPlugin extends BasePlugin {
225
130
  priority: 10,
226
131
  handler: this.onOperationAfterCreate.bind(this)
227
132
  });
228
- env.registerAgent(createWorkflowExtractorAgent());
229
133
  logger.info("[TaskTagPlugin] Initialized");
230
134
  }
231
135
  dispose() {
@@ -327,10 +231,22 @@ ${prompt}`;
327
231
  if (!this.agentComponent)
328
232
  return;
329
233
  const input = formatExtractorInput({ task, operations, messages: allMessages });
330
- const result = await this.agentComponent.run("workflow-extractor", input);
234
+ const result = await this.agentComponent.run("workflow-extract", input);
331
235
  const workflowDef = await parseExtractorOutput(result.finalText || "");
332
236
  if (!workflowDef)
333
237
  return;
238
+ const validation = this.validateWorkflowDefinition(workflowDef);
239
+ if (!validation.valid) {
240
+ logger.warn(`[TaskTagPlugin] Skipping workflow creation due to validation failure: ` + `${validation.errors.join("; ")}`);
241
+ await this.taskComponent?.createOperation({
242
+ taskId,
243
+ sessionId,
244
+ actionType: "workflow_extraction_failed",
245
+ actionTitle: `Workflow extraction failed validation: ${workflowDef.name}`,
246
+ actionDescription: validation.errors.join("; ")
247
+ });
248
+ return;
249
+ }
334
250
  const workflowRepo = await this.getWorkflowRepository();
335
251
  if (!workflowRepo)
336
252
  return;
@@ -346,7 +262,7 @@ ${prompt}`;
346
262
  description: workflowDef.description,
347
263
  definition: workflowDef,
348
264
  config: workflowDef.config || {},
349
- metadata: { author: "workflow-extractor", created_at: new Date().toISOString() },
265
+ metadata: { author: "workflow-extract", created_at: new Date().toISOString() },
350
266
  tags: [`task:${taskId}`]
351
267
  });
352
268
  await this.taskComponent?.createOperation({
@@ -361,6 +277,9 @@ ${prompt}`;
361
277
  logger.warn(`[TaskTagPlugin] Workflow extraction failed: ${error}`);
362
278
  }
363
279
  }
280
+ validateWorkflowDefinition(workflowDef) {
281
+ return validateWorkflowDefinition(workflowDef);
282
+ }
364
283
  _workflowRepo = null;
365
284
  async getWorkflowRepository() {
366
285
  const workflowComponent = this.env.getComponent("workflow");
@@ -388,107 +307,12 @@ ${prompt}`;
388
307
  __require("fs").mkdirSync(dataDir, { recursive: true });
389
308
  }
390
309
  }
391
- // src/env/task/plugins/auto-task-plugin.ts
392
- init_logger();
393
- init_decorator();
394
- var logger2 = createLogger("AutoTaskPlugin");
395
- function createAutoTaskPlugin(config) {
396
- const threshold = config?.threshold ?? 20;
397
- const agentName = config?.agentName ?? "default";
398
- const agentComponent = config?.agentComponent ?? null;
399
- const subagentType = config?.subagentType ?? "task-agent";
400
- let lastProcessedTraceId = "";
401
- async function executeImpl(ctx) {
402
- try {
403
- logger2.debug(`[AutoTaskPlugin] agentName=${ctx.agent.name} (expected=${agentName})`);
404
- if (ctx.agent.name !== agentName)
405
- return { continue: true };
406
- logger2.debug(`[AutoTaskPlugin] iteration=${ctx.iteration} (threshold=${threshold})`);
407
- if (ctx.iteration !== threshold)
408
- return { continue: true };
409
- const traceId = ctx.context?.traceId ?? ctx.context?.sessionId ?? "unknown";
410
- const sid = ctx.context?.sessionId ?? "unknown";
411
- if (traceId === lastProcessedTraceId) {
412
- logger2.debug(`[AutoTaskPlugin] skip - traceId=${traceId.slice(0, 20)}... already processed`);
413
- return { continue: true };
414
- }
415
- lastProcessedTraceId = traceId;
416
- logger2.debug(`[AutoTaskPlugin] new query detected (traceId=${traceId.slice(0, 20)}...)`);
417
- if (!agentComponent || typeof agentComponent.run !== "function") {
418
- logger2.warn(`[AutoTaskPlugin] agentComponent not provided or invalid (session=${sid.slice(0, 12)}...)`);
419
- return { continue: true };
420
- }
421
- let userQuery = "";
422
- for (let i = ctx.messages.length - 1;i >= 0; i--) {
423
- const m = ctx.messages[i];
424
- if (m.role === "user") {
425
- userQuery = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
426
- break;
427
- }
428
- }
429
- if (!userQuery) {
430
- userQuery = "分析项目结构并执行相关任务";
431
- }
432
- logger2.info(`[AutoTaskPlugin] Calling agentComponent.run("${subagentType}") at iteration ${ctx.iteration} (session=${sid.slice(0, 12)}..., persistSession=false)`);
433
- const shortDesc = typeof userQuery === "string" ? userQuery.slice(0, 50) : "分析需求";
434
- const beforeMsg = `
435
-
436
- ---
437
- ⏳ **${subagentType} 正在执行**: ${shortDesc}(等待结果...)`;
438
- if (ctx.toolResult?.result?.output !== undefined) {
439
- ctx.toolResult.result.output += beforeMsg;
440
- }
441
- let taskAgentFinalText = "";
442
- try {
443
- const taskAgentResult = await agentComponent.run(subagentType, userQuery, {
444
- sessionId: sid,
445
- traceId,
446
- persistSession: false
447
- });
448
- taskAgentFinalText = taskAgentResult?.finalText || "";
449
- logger2.info(`[AutoTaskPlugin] task-agent completed (session=${sid.slice(0, 12)}..., finalTextLength=${taskAgentFinalText.length})`);
450
- } catch (err) {
451
- logger2.error(`[AutoTaskPlugin] task-agent failed: ${err instanceof Error ? err.message : String(err)}`);
452
- taskAgentFinalText = `❌ **${subagentType} 执行失败**: ${err instanceof Error ? err.message : String(err)}`;
453
- }
454
- if (taskAgentFinalText && ctx.toolResult?.result?.output !== undefined) {
455
- const injection = `
456
-
457
- ---
458
- ${taskAgentFinalText}
459
- ---`;
460
- ctx.toolResult.result.output += injection;
461
- logger2.info(`[AutoTaskPlugin] task-agent finalText injected (session=${sid.slice(0, 12)}...)`);
462
- } else if (!ctx.toolResult?.result?.output) {
463
- logger2.warn(`[AutoTaskPlugin] toolResult unavailable for injection`);
464
- }
465
- return { continue: true };
466
- } catch (err) {
467
- logger2.error(`[AutoTaskPlugin] hook failed: ${err instanceof Error ? err.message : String(err)}`);
468
- return { continue: true };
469
- }
470
- }
471
- const execute = wrapFunction(executeImpl, "plugin.auto-task.launch-agent", {
472
- recordParams: false,
473
- recordResult: true,
474
- log: true
475
- });
476
- return {
477
- name: "AutoTaskPlugin",
478
- version: "4.5.0",
479
- description: "ReAct iteration 达到阈值时 await task-agent 执行并提取 delegate_task 结果注入 tool result",
480
- hooks: [
481
- { point: "agent:after.tool", priority: 50 }
482
- ],
483
- execute
484
- };
485
- }
486
310
  // src/env/task/plugins/lark-cli-task-notify-plugin.ts
487
311
  init_decorator();
488
312
  init_logger();
489
313
  init_context();
490
314
  import { spawn } from "child_process";
491
- var logger3 = createLogger("lark-cli:task-notify");
315
+ var logger2 = createLogger("lark-cli:task-notify");
492
316
  function isTaskNotifyDebugEnabled() {
493
317
  return process.env.ROY_TASK_NOTIFY_DEBUG === "1" || process.env.ROY_TRACE_DEBUG === "1";
494
318
  }
@@ -535,7 +359,7 @@ class LarkCliTaskNotifyHook {
535
359
  if (this.pluginName && this.sourceId) {
536
360
  const key = `${this.sourceId}:${this.pluginName}`;
537
361
  if (env.pluginEnabled && env.pluginEnabled[key] !== true) {
538
- logger3.debug(`Plugin not enabled for source: ${key}`);
362
+ logger2.debug(`Plugin not enabled for source: ${key}`);
539
363
  return;
540
364
  }
541
365
  }
@@ -597,7 +421,7 @@ class LarkCliTaskNotifyHook {
597
421
  async onAfterOperationCreate(ctx) {
598
422
  const { operation } = ctx.data;
599
423
  if (!operation) {
600
- logger3.debug("onAfterOperationCreate: operation is missing, skip");
424
+ logger2.debug("onAfterOperationCreate: operation is missing, skip");
601
425
  return;
602
426
  }
603
427
  if (!this.shouldNotify("operation_created" /* OPERATION_CREATED */)) {
@@ -627,7 +451,7 @@ class LarkCliTaskNotifyHook {
627
451
  const chatId = replyChannel?.chatId;
628
452
  const messageId = replyChannel?.messageId;
629
453
  if (!chatId && !messageId) {
630
- logger3.debug(`No replyChannel available for ${type}`);
454
+ logger2.debug(`No replyChannel available for ${type}`);
631
455
  return;
632
456
  }
633
457
  const message = `${title}
@@ -635,16 +459,16 @@ class LarkCliTaskNotifyHook {
635
459
  ${content}`;
636
460
  try {
637
461
  if (isTaskNotifyDebugEnabled()) {
638
- logger3.debug(`Sending message - messageId: ${messageId}`);
462
+ logger2.debug(`Sending message - messageId: ${messageId}`);
639
463
  }
640
464
  await this.sendLarkMessage({
641
465
  chatId,
642
466
  messageId,
643
467
  content: message
644
468
  });
645
- logger3.info(`Notification sent: ${type}`);
469
+ logger2.info(`Notification sent: ${type}`);
646
470
  } catch (error) {
647
- logger3.error(`Failed to send notification: ${error}`);
471
+ logger2.error(`Failed to send notification: ${error}`);
648
472
  }
649
473
  }
650
474
  sendLarkMessage(options) {
@@ -686,7 +510,7 @@ ${content}`;
686
510
  });
687
511
  proc.on("close", (code) => {
688
512
  if (code === 0) {
689
- logger3.debug(`lark-cli output: ${stdout}`);
513
+ logger2.debug(`lark-cli output: ${stdout}`);
690
514
  resolve();
691
515
  } else {
692
516
  reject(new Error(`lark-cli exited with code ${code}: ${stderr}`));
@@ -770,7 +594,7 @@ ${content}`;
770
594
  const now = Date.now();
771
595
  const lastTime = this.lastNotifyTimestamps.get(key);
772
596
  if (lastTime && now - lastTime < throttleMs) {
773
- logger3.debug(`[throttle] Skipping OPERATION_CREATED notify for task #${operation.taskId}, last notified ${now - lastTime}ms ago`);
597
+ logger2.debug(`[throttle] Skipping OPERATION_CREATED notify for task #${operation.taskId}, last notified ${now - lastTime}ms ago`);
774
598
  return true;
775
599
  }
776
600
  this.lastNotifyTimestamps.set(key, now);
@@ -811,4 +635,4 @@ __legacyDecorateClassTS([
811
635
  function createLarkCliTaskNotifyHook(config = {}) {
812
636
  return new LarkCliTaskNotifyHook(config);
813
637
  }
814
- export { createAutoTaskPlugin, WORKFLOW_EXTRACTOR_PROMPT, createWorkflowExtractorAgent, formatExtractorInput, formatExtractorInputFromDescription, parseExtractorOutput, TaskTagPlugin, NotifyType, LarkCliTaskNotifyHook, createLarkCliTaskNotifyHook };
638
+ export { WORKFLOW_EXTRACTOR_PROMPT, formatExtractorInput, formatExtractorInputFromDescription, parseExtractorOutput, TaskTagPlugin, NotifyType, LarkCliTaskNotifyHook, createLarkCliTaskNotifyHook };