@ai-setting/roy-agent-core 1.4.13 → 1.4.15

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 (102) hide show
  1. package/dist/config/index.js +32 -0
  2. package/dist/env/agent/index.js +24 -0
  3. package/dist/env/commands/index.js +14 -0
  4. package/dist/env/debug/formatters/index.js +11 -0
  5. package/dist/env/debug/index.js +26 -0
  6. package/dist/env/hook/index.js +29 -0
  7. package/dist/env/index.js +81 -0
  8. package/dist/env/llm/index.js +40 -0
  9. package/dist/env/log-trace/index.js +83 -0
  10. package/dist/env/mcp/index.js +39 -0
  11. package/dist/env/mcp/tool/index.js +14 -0
  12. package/dist/env/memory/built-in/index.js +11 -0
  13. package/dist/env/memory/index.js +56 -0
  14. package/dist/env/memory/plugin/index.js +36 -0
  15. package/dist/env/prompt/index.js +20 -0
  16. package/dist/env/session/index.js +25 -0
  17. package/dist/env/session/storage/index.js +18 -0
  18. package/dist/env/skill/index.js +34 -0
  19. package/dist/env/skill/tool/index.js +9 -0
  20. package/dist/env/task/delegate/index.js +18 -0
  21. package/dist/env/task/hooks/index.js +7 -0
  22. package/dist/env/task/index.js +30 -0
  23. package/dist/env/task/plugins/index.js +23 -0
  24. package/dist/env/task/storage/index.js +14 -0
  25. package/dist/env/task/tools/index.js +17 -0
  26. package/dist/env/task/tools/operation/index.js +15 -0
  27. package/dist/{shared/chunk-1d4rwms4.js → env/tool/built-in/index.js} +4 -4
  28. package/dist/env/tool/index.js +39 -0
  29. package/dist/env/workflow/decorators/index.js +27 -0
  30. package/dist/env/workflow/engine/index.js +28 -0
  31. package/dist/env/workflow/index.js +132 -0
  32. package/dist/env/workflow/nodes/index.js +19 -0
  33. package/dist/env/workflow/service/index.js +13 -0
  34. package/dist/env/workflow/storage/index.js +27 -0
  35. package/dist/env/workflow/tools/index.js +159 -0
  36. package/dist/env/workflow/types/index.js +94 -0
  37. package/dist/env/workflow/utils/index.js +637 -0
  38. package/dist/index.js +233 -16386
  39. package/dist/shared/{chunk-2b5kbhx3.js → @ai-setting/roy-agent-core-0rtxwr28.js} +6 -114
  40. package/dist/shared/@ai-setting/roy-agent-core-0vbdz0x7.js +36 -0
  41. package/dist/shared/@ai-setting/roy-agent-core-12zkpda2.js +393 -0
  42. package/dist/shared/@ai-setting/roy-agent-core-1ce3fqrk.js +117 -0
  43. package/dist/shared/@ai-setting/roy-agent-core-2dhd60aw.js +11 -0
  44. package/dist/shared/@ai-setting/roy-agent-core-2kg2wma8.js +620 -0
  45. package/dist/shared/@ai-setting/roy-agent-core-2x0m2p66.js +851 -0
  46. package/dist/shared/@ai-setting/roy-agent-core-35x0wrtt.js +172 -0
  47. package/dist/shared/{chunk-1pf5mfgd.js → @ai-setting/roy-agent-core-37e4tep3.js} +2 -2
  48. package/dist/shared/@ai-setting/roy-agent-core-3agad0d9.js +603 -0
  49. package/dist/shared/@ai-setting/roy-agent-core-4arba14a.js +419 -0
  50. package/dist/shared/@ai-setting/roy-agent-core-4rqmfr7t.js +266 -0
  51. package/dist/shared/@ai-setting/roy-agent-core-4t40mkpv.js +206 -0
  52. package/dist/shared/@ai-setting/roy-agent-core-561b1c4p.js +377 -0
  53. package/dist/shared/@ai-setting/roy-agent-core-5xf65pz6.js +1305 -0
  54. package/dist/shared/@ai-setting/roy-agent-core-6a72jfdy.js +303 -0
  55. package/dist/shared/{chunk-1aakcfp1.js → @ai-setting/roy-agent-core-7f303ffd.js} +3 -3
  56. package/dist/shared/@ai-setting/roy-agent-core-7fgf85wc.js +284 -0
  57. package/dist/shared/{chunk-t1rh6jtm.js → @ai-setting/roy-agent-core-7n436rb4.js} +7 -12
  58. package/dist/shared/@ai-setting/roy-agent-core-7r85t0qn.js +492 -0
  59. package/dist/shared/@ai-setting/roy-agent-core-7rewcey6.js +862 -0
  60. package/dist/shared/@ai-setting/roy-agent-core-92z6t4he.js +14 -0
  61. package/dist/shared/@ai-setting/roy-agent-core-9qwp5qkz.js +1387 -0
  62. package/dist/shared/{chunk-mf5xqbdh.js → @ai-setting/roy-agent-core-9yxb3ty9.js} +3 -2
  63. package/dist/shared/@ai-setting/roy-agent-core-anwsxdds.js +1205 -0
  64. package/dist/shared/{chunk-1qwabsm0.js → @ai-setting/roy-agent-core-bncgx3gb.js} +1 -1
  65. package/dist/shared/@ai-setting/roy-agent-core-cd00w5mb.js +762 -0
  66. package/dist/shared/@ai-setting/roy-agent-core-cgs0j60t.js +442 -0
  67. package/dist/shared/@ai-setting/roy-agent-core-ctdhjv68.js +93 -0
  68. package/dist/shared/@ai-setting/roy-agent-core-dbsk841j.js +286 -0
  69. package/dist/shared/@ai-setting/roy-agent-core-e25xkv53.js +64 -0
  70. package/dist/shared/{chunk-yqmx37vm.js → @ai-setting/roy-agent-core-e5jcp24a.js} +2 -2
  71. package/dist/shared/@ai-setting/roy-agent-core-e62e2a5a.js +204 -0
  72. package/dist/shared/{chunk-g6j5n3gv.js → @ai-setting/roy-agent-core-ewrj1c4k.js} +2 -2
  73. package/dist/shared/{chunk-rncy3rtd.js → @ai-setting/roy-agent-core-fdb6m4e4.js} +119 -1113
  74. package/dist/shared/{chunk-q9j99fsm.js → @ai-setting/roy-agent-core-fv32jaa8.js} +3 -3
  75. package/dist/shared/@ai-setting/roy-agent-core-g1s2h0e5.js +171 -0
  76. package/dist/shared/@ai-setting/roy-agent-core-gmnkza34.js +202 -0
  77. package/dist/shared/@ai-setting/roy-agent-core-hz7rr4yx.js +513 -0
  78. package/dist/shared/@ai-setting/roy-agent-core-j3bbr2n0.js +378 -0
  79. package/dist/shared/{chunk-a9qmy3sc.js → @ai-setting/roy-agent-core-j3wc4465.js} +6 -3
  80. package/dist/shared/@ai-setting/roy-agent-core-jj79gszx.js +1130 -0
  81. package/dist/shared/@ai-setting/roy-agent-core-mwwk6req.js +913 -0
  82. package/dist/shared/{chunk-0q6s9wm6.js → @ai-setting/roy-agent-core-pc9g3962.js} +6 -50
  83. package/dist/shared/@ai-setting/roy-agent-core-psvxt4c9.js +60 -0
  84. package/dist/shared/@ai-setting/roy-agent-core-pzsg9pvf.js +393 -0
  85. package/dist/shared/{chunk-91bas8w5.js → @ai-setting/roy-agent-core-q779wnwm.js} +5 -5
  86. package/dist/shared/{chunk-25x2pdtp.js → @ai-setting/roy-agent-core-qw0ebh1d.js} +1 -1
  87. package/dist/shared/@ai-setting/roy-agent-core-qxhq8ven.js +57 -0
  88. package/dist/shared/@ai-setting/roy-agent-core-qxnbvgwe.js +66 -0
  89. package/dist/shared/@ai-setting/roy-agent-core-qya7seh6.js +408 -0
  90. package/dist/shared/@ai-setting/roy-agent-core-rbetrphj.js +97 -0
  91. package/dist/shared/@ai-setting/roy-agent-core-re1wjfw7.js +587 -0
  92. package/dist/shared/@ai-setting/roy-agent-core-rft3fmp0.js +14 -0
  93. package/dist/shared/@ai-setting/roy-agent-core-rvv6ydff.js +584 -0
  94. package/dist/shared/{chunk-ze20rksg.js → @ai-setting/roy-agent-core-rvxg1wps.js} +1 -1
  95. package/dist/shared/@ai-setting/roy-agent-core-rzp9kxne.js +341 -0
  96. package/dist/shared/@ai-setting/roy-agent-core-t94ktchq.js +213 -0
  97. package/dist/shared/@ai-setting/roy-agent-core-w78syn7w.js +788 -0
  98. package/dist/shared/{chunk-9qzt1v1p.js → @ai-setting/roy-agent-core-z2t8hse8.js} +3 -2
  99. package/package.json +8 -7
  100. package/dist/index.d.ts +0 -7825
  101. package/dist/shared/chunk-hs7tbmje.js +0 -24
  102. /package/dist/shared/{chunk-wbkh7wat.js → @ai-setting/roy-agent-core-fs0mn2jk.js} +0 -0
@@ -1,119 +1,11 @@
1
+ import {
2
+ DecoratorNode,
3
+ init_decorator_node
4
+ } from "./roy-agent-core-1ce3fqrk.js";
1
5
  import {
2
6
  __esm,
3
7
  __export
4
- } from "./chunk-wbkh7wat.js";
5
-
6
- // src/env/workflow/decorators/decorator-node.ts
7
- class DecoratorNode {
8
- type = "decorator";
9
- id;
10
- methodName;
11
- instance;
12
- dependsOn;
13
- timeout;
14
- retryConfig;
15
- constructor(definition) {
16
- const config = definition.config;
17
- this.id = definition.id;
18
- this.methodName = config._methodName;
19
- this.instance = config._instance;
20
- this.dependsOn = definition.depends_on || [];
21
- this.timeout = definition.timeout;
22
- this.retryConfig = definition.retry;
23
- }
24
- async execute(context) {
25
- const startTime = Date.now();
26
- const method = this.instance[this.methodName];
27
- if (typeof method !== "function") {
28
- return {
29
- success: false,
30
- error: `Method '${this.methodName}' is not a function`,
31
- duration: Date.now() - startTime
32
- };
33
- }
34
- const input = this.prepareInput(context);
35
- const result = await this.executeWithRetry(input, context.abort);
36
- return {
37
- success: !result.error,
38
- output: result.output,
39
- error: result.error,
40
- duration: Date.now() - startTime,
41
- metadata: {
42
- methodName: this.methodName
43
- }
44
- };
45
- }
46
- prepareInput(context) {
47
- const nodeOutputs = context.nodeOutputs;
48
- if (this.dependsOn.length === 0) {
49
- return context.input || {};
50
- }
51
- const input = {};
52
- for (const depId of this.dependsOn) {
53
- const depOutput = nodeOutputs instanceof Map ? nodeOutputs.get(depId) : nodeOutputs?.[depId];
54
- if (depOutput && typeof depOutput === "object") {
55
- if ("output" in depOutput) {
56
- input[depId] = depOutput.output;
57
- } else {
58
- input[depId] = depOutput;
59
- }
60
- }
61
- }
62
- return input;
63
- }
64
- async executeWithRetry(input, abort) {
65
- const maxAttempts = this.retryConfig?.max_attempts ?? 1;
66
- const backoff = this.retryConfig?.backoff ?? "exponential";
67
- const initialDelay = this.retryConfig?.initial_delay ?? 1000;
68
- let lastError;
69
- for (let attempt = 1;attempt <= maxAttempts; attempt++) {
70
- if (abort?.aborted) {
71
- return { error: "Execution aborted" };
72
- }
73
- try {
74
- const output = await this.executeWithTimeout(input, abort);
75
- return { output };
76
- } catch (error) {
77
- lastError = error instanceof Error ? error : new Error(String(error));
78
- if (attempt < maxAttempts) {
79
- const delay = this.calculateBackoff(backoff, initialDelay, attempt - 1);
80
- await this.sleep(delay, abort);
81
- }
82
- }
83
- }
84
- return { error: lastError?.message || "Unknown error" };
85
- }
86
- async executeWithTimeout(input, abort) {
87
- if (!this.timeout) {
88
- return this.instance[this.methodName](input);
89
- }
90
- const timeoutPromise = new Promise((_, reject) => {
91
- setTimeout(() => {
92
- reject(new Error(`Execution timeout after ${this.timeout}ms`));
93
- }, this.timeout);
94
- });
95
- return Promise.race([
96
- this.instance[this.methodName](input),
97
- timeoutPromise
98
- ]);
99
- }
100
- calculateBackoff(backoff, initialDelay, attempt) {
101
- if (backoff === "exponential") {
102
- return initialDelay * Math.pow(2, attempt);
103
- }
104
- return initialDelay;
105
- }
106
- sleep(ms, abort) {
107
- return new Promise((resolve) => {
108
- const timeout = setTimeout(resolve, ms);
109
- abort?.addEventListener("abort", () => {
110
- clearTimeout(timeout);
111
- resolve();
112
- });
113
- });
114
- }
115
- }
116
- var init_decorator_node = () => {};
8
+ } from "./roy-agent-core-fs0mn2jk.js";
117
9
 
118
10
  // src/env/workflow/nodes/condition-node.ts
119
11
  class ConditionNode {
@@ -363,4 +255,4 @@ var init_node_registry_helper = __esm(() => {
363
255
  init_merge_node();
364
256
  });
365
257
 
366
- export { init_decorator_node, registerDecoratorNodeType, hasDecoratorNodes, getDecoratorNodes, exports_node_registry_helper, init_node_registry_helper };
258
+ export { registerDecoratorNodeType, hasDecoratorNodes, getDecoratorNodes, exports_node_registry_helper, init_node_registry_helper };
@@ -0,0 +1,36 @@
1
+ import {
2
+ AskUserError,
3
+ init_workflow_hil
4
+ } from "./roy-agent-core-e25xkv53.js";
5
+
6
+ // src/env/workflow/tools/ask-user-tool.ts
7
+ init_workflow_hil();
8
+ import { z } from "zod";
9
+ var AskUserInputSchema = z.object({
10
+ query: z.string().describe("The question or request to ask the user"),
11
+ options: z.array(z.string()).optional().describe("Optional choices for the user"),
12
+ required_confirm: z.boolean().optional().describe("If true, user must explicitly confirm")
13
+ });
14
+ var askUserTool = {
15
+ name: "ask_user",
16
+ description: "Ask user for input or confirmation. Use this tool when you need user input or validation to continue the workflow.",
17
+ parameters: AskUserInputSchema,
18
+ async execute(args, context) {
19
+ const runId = context.metadata?.runId || "unknown";
20
+ const sessionId = context.metadata?.sessionId || `workflow_${runId}`;
21
+ const nodeId = context.metadata?.nodeId || "unknown";
22
+ let fullQuery = args.query;
23
+ if (args.options && args.options.length > 0) {
24
+ fullQuery = `${args.query} (选项: ${args.options.join(", ")})`;
25
+ }
26
+ throw new AskUserError(runId, sessionId, nodeId, "agent", fullQuery);
27
+ },
28
+ metadata: {
29
+ category: "workflow",
30
+ tags: ["human-in-loop", "user-input"],
31
+ version: "1.0.0"
32
+ }
33
+ };
34
+ var askUserToolInstance = askUserTool;
35
+
36
+ export { AskUserInputSchema, askUserTool, askUserToolInstance };
@@ -0,0 +1,393 @@
1
+ import {
2
+ TaskHookPoints
3
+ } from "./roy-agent-core-92z6t4he.js";
4
+ import {
5
+ createLogger,
6
+ init_logger
7
+ } from "./roy-agent-core-j3wc4465.js";
8
+ import {
9
+ __require
10
+ } from "./roy-agent-core-fs0mn2jk.js";
11
+
12
+ // src/env/task/plugins/task-plugin.ts
13
+ class TaskPlugin {
14
+ config;
15
+ constructor(config = {}) {
16
+ this.config = { enabled: true, priority: 0, ...config };
17
+ }
18
+ getHookPoints() {
19
+ return this.hooks.map((h) => h.point);
20
+ }
21
+ getPriorityForHook(hookPoint) {
22
+ const hook = this.hooks.find((h) => h.point === hookPoint);
23
+ return hook?.priority ?? this.config.priority ?? 0;
24
+ }
25
+ isEnabled() {
26
+ return this.config.enabled ?? true;
27
+ }
28
+ setEnabled(enabled) {
29
+ this.config.enabled = enabled;
30
+ }
31
+ }
32
+ // src/env/task/plugins/task-tag-plugin.ts
33
+ init_logger();
34
+
35
+ // src/env/task/plugins/workflow-extractor-agent.ts
36
+ var WORKFLOW_EXTRACTOR_PROMPT = `你是 Workflow 提取专家,负责将自然语言描述转换为符合规范的 Workflow YAML。
37
+
38
+ ## 提取原则
39
+
40
+ 1. **优先具象节点**:优先使用特定工具节点(如 read_file, write_file, grep, bash 等)
41
+ 2. **Fallback 到通用节点**:没有对应工具时,使用 agent/llm/bash 节点
42
+ 3. **避免条件分支**:不提取循环和条件判断,保持线性流程
43
+ 4. **泛化但可执行**:步骤描述可泛化,但节点类型和工具要具体
44
+
45
+ ## 构建流程
46
+
47
+ **重要**:构建的 Workflow 必须通过 \`roy workflow validate\` 验证才能输出。
48
+
49
+ \`\`\`
50
+ 1. 理解用户需求
51
+ 2. 参考 roy workflow nodes 查看可用节点类型
52
+ 3. 参考 roy workflow get <name> 查看已有 workflow 示例
53
+ 4. 生成 Workflow YAML
54
+ 5. 使用 roy workflow validate --yaml "<生成的YAML>" 验证
55
+ 6. 验证通过后输出最终结果
56
+ \`\`\`
57
+
58
+ ## 验证检查清单
59
+
60
+ 完成 Workflow 构建后,必须使用以下命令验证:
61
+
62
+ \`\`\`bash
63
+ roy workflow validate --yaml "<your-yaml>"
64
+ \`\`\`
65
+
66
+ 验证通过后(无错误输出)才输出最终结果。验证失败时根据错误信息修正后重新验证。
67
+
68
+ ## 可用的 Workflow 节点类型
69
+
70
+ 使用以下命令查看所有节点类型的详细配置:
71
+
72
+ \`\`\`bash
73
+ roy workflow nodes # 列出所有节点类型
74
+ roy workflow nodes <type> # 查看特定节点详情(如 tool, agent, skill)
75
+ \`\`\`
76
+
77
+ **支持的节点类型:**
78
+ - **tool**:执行工具(bash, read-file, write-file, grep 等)
79
+ - **skill**:调用技能
80
+ - **agent**:AI Agent
81
+ - **workflow**:子工作流
82
+ - **condition**:条件判断
83
+ - **merge**:合并结果
84
+ - **decorator**:装饰器方法
85
+
86
+ ## 查看已有 Workflow 示例
87
+
88
+ 使用以下命令查看已有 workflow 的 YAML 结构:
89
+
90
+ \`\`\`bash
91
+ roy workflow list # 列出所有 workflow
92
+ roy workflow get <name> # 获取指定 workflow 详情(YAML 格式)
93
+ \`\`\`
94
+
95
+ ## 输出要求
96
+
97
+ 验证通过后,输出符合以下格式的 YAML Workflow:
98
+
99
+ \`\`\`yaml
100
+ name: {泛化的任务名称}
101
+ version: "1.0"
102
+ description: {一句话描述}
103
+ nodes:
104
+ - id: node-1
105
+ type: tool|skill|agent|workflow|condition|merge|decorator
106
+ name: {节点名称}
107
+ config:
108
+ # 根据类型配置必填字段:
109
+ # tool: tool, input/args
110
+ # skill: skill, input
111
+ # agent: agent_type, prompt, options
112
+ # workflow: workflow_name, input
113
+ # condition: condition
114
+ # merge: strategy, depends_on
115
+ # decorator: _methodName, _instance
116
+ depends_on: []
117
+ outputs: []
118
+ \`\`\`
119
+
120
+ ## 限制
121
+
122
+ - 至少 2 个节点才有意义
123
+ - 不要生成条件节点(if/else/switch)
124
+ - 不要生成循环节点(while/for)
125
+ - 每个节点要有清晰的名称和描述
126
+ - 必须为 tool 节点指定 tool 名称
127
+ - 必须为 agent 节点指定 agent_type 和 prompt`;
128
+ function createWorkflowExtractorAgent() {
129
+ return {
130
+ type: "sub",
131
+ name: "workflow-extractor",
132
+ systemPrompt: WORKFLOW_EXTRACTOR_PROMPT,
133
+ maxIterations: 10,
134
+ filterHistory: false
135
+ };
136
+ }
137
+ function formatExtractorInput(params) {
138
+ const lines = [];
139
+ lines.push("# 任务信息");
140
+ lines.push(`- 标题: ${params.task.title}`);
141
+ if (params.task.description) {
142
+ lines.push(`- 描述: ${params.task.description}`);
143
+ }
144
+ if (params.task.goals_and_expected_deliverables) {
145
+ lines.push(`- 目标: ${params.task.goals_and_expected_deliverables}`);
146
+ }
147
+ lines.push("");
148
+ if (params.operations.length > 0) {
149
+ lines.push("# 操作记录");
150
+ for (const op of params.operations) {
151
+ lines.push(`- [${op.actionType}] ${op.actionTitle}`);
152
+ if (op.actionDescription) {
153
+ lines.push(` ${op.actionDescription.slice(0, 200)}`);
154
+ }
155
+ }
156
+ lines.push("");
157
+ }
158
+ lines.push("# Session 消息历史");
159
+ lines.push("(以下是相关的对话历史,请从中提取 Workflow)");
160
+ for (const msg of params.messages.slice(-50)) {
161
+ const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
162
+ const truncated = content.slice(0, 500);
163
+ lines.push(`**${msg.role}**: ${truncated}${content.length > 500 ? "..." : ""}`);
164
+ }
165
+ lines.push("");
166
+ lines.push("## 任务");
167
+ lines.push("请分析以上信息,构建一个可复用的 Workflow。");
168
+ lines.push("使用迭代式流程:生成 YAML → validate 验证 → 修正错误 → 重复直到通过验证。");
169
+ return lines.join(`
170
+ `);
171
+ }
172
+ function formatExtractorInputFromDescription(params) {
173
+ const lines = [];
174
+ lines.push("# Workflow 描述");
175
+ lines.push(params.description);
176
+ lines.push("");
177
+ lines.push("## 任务");
178
+ lines.push("请根据以上描述,构建一个可复用的 Workflow。");
179
+ lines.push("使用迭代式流程:生成 YAML → validate 验证 → 修正错误 → 重复直到通过验证。");
180
+ return lines.join(`
181
+ `);
182
+ }
183
+ async function parseExtractorOutput(output) {
184
+ const yamlMatch = output.match(/```yaml\n?([\s\S]*?)\n?```/) || output.match(/```\n?([\s\S]*?)\n?```/) || output.match(/(\|[\s\S]*?)(?:\n\n|$)/);
185
+ const yamlContent = yamlMatch?.[1] || output;
186
+ try {
187
+ const YAML = await import("yaml");
188
+ const parsed = YAML.parse(yamlContent);
189
+ if (!parsed.name || !parsed.nodes || !Array.isArray(parsed.nodes)) {
190
+ return null;
191
+ }
192
+ if (parsed.nodes.length < 2) {
193
+ return null;
194
+ }
195
+ parsed.version = parsed.version || "1.0";
196
+ return parsed;
197
+ } catch {
198
+ return null;
199
+ }
200
+ }
201
+
202
+ // src/env/task/plugins/task-tag-plugin.ts
203
+ var logger = createLogger("task:plugin:tag");
204
+
205
+ class TaskTagPlugin extends TaskPlugin {
206
+ name = "TaskTagPlugin";
207
+ hooks = [
208
+ { point: TaskHookPoints.DELEGATE_BEFORE, priority: 20 },
209
+ { point: TaskHookPoints.OPERATION_AFTER_CREATE, priority: 10 }
210
+ ];
211
+ taskComponent = null;
212
+ agentComponent = null;
213
+ constructor(config = {}) {
214
+ super({ enabled: true, priority: 0, ...config });
215
+ }
216
+ static getRequiredAgents() {
217
+ return [createWorkflowExtractorAgent()];
218
+ }
219
+ setComponents(_llmComponent, taskComponent) {
220
+ this.taskComponent = taskComponent;
221
+ if (taskComponent?.env) {
222
+ this.agentComponent = taskComponent.env.getComponent("agent");
223
+ }
224
+ }
225
+ async execute(ctx) {
226
+ if (!this.config.enabled)
227
+ return;
228
+ switch (ctx.hookPoint) {
229
+ case TaskHookPoints.DELEGATE_BEFORE:
230
+ await this.onDelegateBefore(ctx);
231
+ break;
232
+ case TaskHookPoints.OPERATION_AFTER_CREATE:
233
+ await this.onOperationAfterCreate(ctx);
234
+ break;
235
+ }
236
+ }
237
+ async onDelegateBefore(ctx) {
238
+ const { taskId, tagService, prompt } = ctx.data;
239
+ if (!taskId || !this.taskComponent) {
240
+ return;
241
+ }
242
+ try {
243
+ const currentTask = await this.taskComponent.getTask(taskId);
244
+ if (!currentTask)
245
+ return;
246
+ const keywords = this.extractKeywords(currentTask);
247
+ if (keywords.length === 0)
248
+ return;
249
+ const tagServiceForSearch = tagService;
250
+ const similarTasks = await tagServiceForSearch?.findSimilarTasksByKeywords?.(keywords, {
251
+ limit: 5,
252
+ excludeTaskId: taskId
253
+ }) ?? [];
254
+ if (similarTasks.length === 0)
255
+ return;
256
+ const hint = this.formatSimilarTasks(similarTasks);
257
+ ctx.data.prompt = `${hint}
258
+
259
+ ---
260
+
261
+ ## 用户指令
262
+
263
+ ${prompt}`;
264
+ logger.info(`[TaskTagPlugin] Injected ${similarTasks.length} similar tasks`);
265
+ } catch (error) {
266
+ logger.warn(`[TaskTagPlugin] Similar tasks injection failed: ${error}`);
267
+ }
268
+ }
269
+ extractKeywords(task) {
270
+ const keywords = [];
271
+ if (task.tags?.length) {
272
+ keywords.push(...task.tags);
273
+ }
274
+ if (task.title) {
275
+ const words = task.title.split(/[\s\-_,,。、#]+/).filter((w) => w.length > 2 && !/^\d+$/.test(w)).slice(0, 5);
276
+ keywords.push(...words);
277
+ }
278
+ return keywords;
279
+ }
280
+ formatSimilarTasks(tasks) {
281
+ const lines = [
282
+ "## \uD83D\uDD0D 类似任务参考",
283
+ "",
284
+ "_提示:可通过 `task_get <id>` 获取详情,`task_operation_list <id>` 获取操作记录_",
285
+ ""
286
+ ];
287
+ for (const task of tasks) {
288
+ lines.push(`### Task #${task.id}`);
289
+ lines.push(`**Title**: ${task.title}`);
290
+ if (task.description) {
291
+ const desc = task.description.slice(0, 100);
292
+ lines.push(`**Description**: ${desc}${task.description.length > 100 ? "..." : ""}`);
293
+ }
294
+ if (task.goals_and_expected_deliverables) {
295
+ const goal = task.goals_and_expected_deliverables.slice(0, 100);
296
+ lines.push(`**Goal**: ${goal}${task.goals_and_expected_deliverables.length > 100 ? "..." : ""}`);
297
+ }
298
+ lines.push("");
299
+ }
300
+ return lines.join(`
301
+ `);
302
+ }
303
+ async onOperationAfterCreate(ctx) {
304
+ const data = ctx.data;
305
+ const operation = data?.operation ?? data?.data?.operation;
306
+ if (!operation || operation?.actionType !== "completed")
307
+ return;
308
+ await this.extractWorkflow(operation.taskId, operation.sessionId);
309
+ }
310
+ async extractWorkflow(taskId, sessionId) {
311
+ try {
312
+ const task = await this.taskComponent?.getTask(taskId);
313
+ if (!task)
314
+ return;
315
+ const operations = await this.taskComponent?.listOperations({ taskId }) ?? [];
316
+ const allSessionIds = [...new Set([sessionId, ...operations.map((op) => op.sessionId).filter(Boolean)])];
317
+ const sessionComponent = this.taskComponent?.env?.getComponent("session");
318
+ const allMessages = [];
319
+ for (const sid of allSessionIds) {
320
+ try {
321
+ const ctx = await sessionComponent?.getContext(sid, { fullHistory: false, minUserMessages: 200 });
322
+ if (ctx?.messages)
323
+ allMessages.push(...ctx.messages);
324
+ } catch {}
325
+ }
326
+ if (!this.agentComponent)
327
+ return;
328
+ const input = formatExtractorInput({ task, operations, messages: allMessages });
329
+ const result = await this.agentComponent.run("workflow-extractor", input);
330
+ const workflowDef = await parseExtractorOutput(result.finalText || "");
331
+ if (!workflowDef)
332
+ return;
333
+ const workflowRepo = await this.getWorkflowRepository();
334
+ if (!workflowRepo)
335
+ return;
336
+ let version = workflowDef.version || "1.0";
337
+ const existingWf = workflowRepo.getByName(workflowDef.name);
338
+ if (existingWf) {
339
+ const parts = existingWf.version?.split(".") ?? ["1", "0"];
340
+ version = `${parts[0]}.${parseInt(parts[1] || "0") + 1}`;
341
+ }
342
+ const workflow = workflowRepo.create({
343
+ name: workflowDef.name,
344
+ version,
345
+ description: workflowDef.description,
346
+ definition: workflowDef,
347
+ config: workflowDef.config || {},
348
+ metadata: { author: "workflow-extractor", created_at: new Date().toISOString() },
349
+ tags: [`task:${taskId}`]
350
+ });
351
+ await this.taskComponent?.createOperation({
352
+ taskId,
353
+ sessionId,
354
+ actionType: "workflow_extracted",
355
+ actionTitle: `Workflow extracted: ${workflow.name}`,
356
+ actionDescription: workflow.id
357
+ });
358
+ logger.info(`Workflow extracted: ${workflow.id}`);
359
+ } catch (error) {
360
+ logger.warn(`Workflow extraction failed: ${error}`);
361
+ }
362
+ }
363
+ async getWorkflowRepository() {
364
+ const workflowComponent = this.taskComponent?.env?.getComponent("workflow");
365
+ if (workflowComponent?.workflowService?.workflowRepository) {
366
+ return workflowComponent.workflowService.workflowRepository;
367
+ }
368
+ if (!this._workflowRepo) {
369
+ try {
370
+ const sqlite = await import("./roy-agent-core-q779wnwm.js");
371
+ this.ensureDataDir();
372
+ const db = sqlite.getDatabase();
373
+ sqlite.initializeTables();
374
+ const { WorkflowRepository } = await import("./roy-agent-core-rft3fmp0.js");
375
+ this._workflowRepo = new WorkflowRepository(db);
376
+ return this._workflowRepo;
377
+ } catch {
378
+ return null;
379
+ }
380
+ }
381
+ return this._workflowRepo;
382
+ }
383
+ ensureDataDir() {
384
+ const { join } = __require("path");
385
+ const { mkdirSync, existsSync } = __require("fs");
386
+ const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
387
+ const dataDir = join(home, ".local", "share", "roy-agent");
388
+ if (!existsSync(dataDir))
389
+ mkdirSync(dataDir, { recursive: true });
390
+ }
391
+ _workflowRepo = null;
392
+ }
393
+ export { TaskPlugin, WORKFLOW_EXTRACTOR_PROMPT, createWorkflowExtractorAgent, formatExtractorInput, formatExtractorInputFromDescription, parseExtractorOutput, TaskTagPlugin };
@@ -0,0 +1,117 @@
1
+ import {
2
+ __esm
3
+ } from "./roy-agent-core-fs0mn2jk.js";
4
+
5
+ // src/env/workflow/decorators/decorator-node.ts
6
+ class DecoratorNode {
7
+ type = "decorator";
8
+ id;
9
+ methodName;
10
+ instance;
11
+ dependsOn;
12
+ timeout;
13
+ retryConfig;
14
+ constructor(definition) {
15
+ const config = definition.config;
16
+ this.id = definition.id;
17
+ this.methodName = config._methodName;
18
+ this.instance = config._instance;
19
+ this.dependsOn = definition.depends_on || [];
20
+ this.timeout = definition.timeout;
21
+ this.retryConfig = definition.retry;
22
+ }
23
+ async execute(context) {
24
+ const startTime = Date.now();
25
+ const method = this.instance[this.methodName];
26
+ if (typeof method !== "function") {
27
+ return {
28
+ success: false,
29
+ error: `Method '${this.methodName}' is not a function`,
30
+ duration: Date.now() - startTime
31
+ };
32
+ }
33
+ const input = this.prepareInput(context);
34
+ const result = await this.executeWithRetry(input, context.abort);
35
+ return {
36
+ success: !result.error,
37
+ output: result.output,
38
+ error: result.error,
39
+ duration: Date.now() - startTime,
40
+ metadata: {
41
+ methodName: this.methodName
42
+ }
43
+ };
44
+ }
45
+ prepareInput(context) {
46
+ const nodeOutputs = context.nodeOutputs;
47
+ if (this.dependsOn.length === 0) {
48
+ return context.input || {};
49
+ }
50
+ const input = {};
51
+ for (const depId of this.dependsOn) {
52
+ const depOutput = nodeOutputs instanceof Map ? nodeOutputs.get(depId) : nodeOutputs?.[depId];
53
+ if (depOutput && typeof depOutput === "object") {
54
+ if ("output" in depOutput) {
55
+ input[depId] = depOutput.output;
56
+ } else {
57
+ input[depId] = depOutput;
58
+ }
59
+ }
60
+ }
61
+ return input;
62
+ }
63
+ async executeWithRetry(input, abort) {
64
+ const maxAttempts = this.retryConfig?.max_attempts ?? 1;
65
+ const backoff = this.retryConfig?.backoff ?? "exponential";
66
+ const initialDelay = this.retryConfig?.initial_delay ?? 1000;
67
+ let lastError;
68
+ for (let attempt = 1;attempt <= maxAttempts; attempt++) {
69
+ if (abort?.aborted) {
70
+ return { error: "Execution aborted" };
71
+ }
72
+ try {
73
+ const output = await this.executeWithTimeout(input, abort);
74
+ return { output };
75
+ } catch (error) {
76
+ lastError = error instanceof Error ? error : new Error(String(error));
77
+ if (attempt < maxAttempts) {
78
+ const delay = this.calculateBackoff(backoff, initialDelay, attempt - 1);
79
+ await this.sleep(delay, abort);
80
+ }
81
+ }
82
+ }
83
+ return { error: lastError?.message || "Unknown error" };
84
+ }
85
+ async executeWithTimeout(input, abort) {
86
+ if (!this.timeout) {
87
+ return this.instance[this.methodName](input);
88
+ }
89
+ const timeoutPromise = new Promise((_, reject) => {
90
+ setTimeout(() => {
91
+ reject(new Error(`Execution timeout after ${this.timeout}ms`));
92
+ }, this.timeout);
93
+ });
94
+ return Promise.race([
95
+ this.instance[this.methodName](input),
96
+ timeoutPromise
97
+ ]);
98
+ }
99
+ calculateBackoff(backoff, initialDelay, attempt) {
100
+ if (backoff === "exponential") {
101
+ return initialDelay * Math.pow(2, attempt);
102
+ }
103
+ return initialDelay;
104
+ }
105
+ sleep(ms, abort) {
106
+ return new Promise((resolve) => {
107
+ const timeout = setTimeout(resolve, ms);
108
+ abort?.addEventListener("abort", () => {
109
+ clearTimeout(timeout);
110
+ resolve();
111
+ });
112
+ });
113
+ }
114
+ }
115
+ var init_decorator_node = () => {};
116
+
117
+ export { DecoratorNode, init_decorator_node };
@@ -0,0 +1,11 @@
1
+ // src/env/hook/types.ts
2
+ function createHook(meta, fn) {
3
+ return {
4
+ ...meta,
5
+ execute: fn
6
+ };
7
+ }
8
+ function createPriorityHook(name, fn, priority) {
9
+ return createHook({ name, priority }, fn);
10
+ }
11
+ export { createHook, createPriorityHook };