@ai-setting/roy-agent-core 1.5.88 → 1.5.90
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.
- package/dist/env/agent/index.js +8 -8
- package/dist/env/event-source/index.js +12 -4
- package/dist/env/index.js +20 -15
- package/dist/env/llm/index.js +4 -2
- package/dist/env/prompt/index.js +2 -1
- package/dist/env/session/index.js +3 -4
- package/dist/env/session/storage/index.js +2 -2
- package/dist/env/task/delegate/index.js +3 -2
- package/dist/env/task/index.js +4 -3
- package/dist/env/task/plugins/index.js +7 -4
- package/dist/env/tool/built-in/index.js +2 -1
- package/dist/env/tool/index.js +11 -8
- package/dist/env/workflow/engine/index.js +5 -3
- package/dist/env/workflow/index.js +6 -4
- package/dist/env/workflow/nodes/index.js +1 -1
- package/dist/env/workflow/tools/index.js +7 -1
- package/dist/env/workflow/utils/index.js +5 -0
- package/dist/index.js +144 -32
- package/dist/shared/@ai-setting/{roy-agent-core-r0m0at3x.js → roy-agent-core-0r4ndyn9.js} +119 -7
- package/dist/shared/@ai-setting/{roy-agent-core-jymz9fzp.js → roy-agent-core-2c8eraxq.js} +126 -41
- package/dist/shared/@ai-setting/{roy-agent-core-0y64qaac.js → roy-agent-core-32m0nb9j.js} +119 -30
- package/dist/shared/@ai-setting/roy-agent-core-4yq23m5g.js +421 -0
- package/dist/shared/@ai-setting/{roy-agent-core-h2d1s8yd.js → roy-agent-core-5ykms33a.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-mmkyydw7.js → roy-agent-core-83d035pp.js} +91 -579
- package/dist/shared/@ai-setting/roy-agent-core-8wd3qwx5.js +35 -0
- package/dist/shared/@ai-setting/{roy-agent-core-yx0vw1aw.js → roy-agent-core-8zjntsbb.js} +102 -32
- package/dist/shared/@ai-setting/{roy-agent-core-29fh9mxg.js → roy-agent-core-bwjpte58.js} +1 -2
- package/dist/shared/@ai-setting/{roy-agent-core-vneyghpg.js → roy-agent-core-ddq5hcp5.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-qhhxx2x2.js → roy-agent-core-ds5f75pg.js} +2 -1
- package/dist/shared/@ai-setting/{roy-agent-core-4cdtdxqx.js → roy-agent-core-ewr1nw7t.js} +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-hvdfgvfz.js +114 -0
- package/dist/shared/@ai-setting/{roy-agent-core-3arrpf7n.js → roy-agent-core-hxsbegfc.js} +229 -9
- package/dist/shared/@ai-setting/{roy-agent-core-9y09xfav.js → roy-agent-core-j0107ww1.js} +6 -418
- package/dist/shared/@ai-setting/{roy-agent-core-6mk0m4t3.js → roy-agent-core-m683wd1n.js} +283 -15
- package/dist/shared/@ai-setting/{roy-agent-core-bgw4dq11.js → roy-agent-core-mw4ty0ba.js} +44 -5
- package/dist/shared/@ai-setting/{roy-agent-core-7z4xtrmw.js → roy-agent-core-nqzt9ne4.js} +53 -0
- package/dist/shared/@ai-setting/roy-agent-core-pt7as39r.js +0 -0
- package/dist/shared/@ai-setting/{roy-agent-core-6n7xwv4v.js → roy-agent-core-rkz8r2sx.js} +5 -3
- package/dist/shared/@ai-setting/{roy-agent-core-c1j7ev4e.js → roy-agent-core-txwf64pd.js} +70 -0
- package/dist/shared/@ai-setting/{roy-agent-core-7fdzfsm6.js → roy-agent-core-w0kb72ve.js} +42 -213
- package/dist/shared/@ai-setting/roy-agent-core-w6bmrgap.js +581 -0
- package/dist/shared/@ai-setting/{roy-agent-core-qhjb153z.js → roy-agent-core-xnxyzaw4.js} +27 -4
- package/dist/shared/@ai-setting/roy-agent-core-yanpq5gb.js +116 -0
- package/dist/shared/@ai-setting/{roy-agent-core-hc20420t.js → roy-agent-core-z240ts1r.js} +27 -3
- package/dist/shared/@ai-setting/{roy-agent-core-q7sqeax6.js → roy-agent-core-zky9jse4.js} +163 -3
- package/package.json +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-x3gtyqax.js +0 -378
- /package/dist/shared/@ai-setting/{roy-agent-core-4f3976cd.js → roy-agent-core-k5hxvaf0.js} +0 -0
|
@@ -5,6 +5,41 @@ import {
|
|
|
5
5
|
// src/env/session/session-message-converter.ts
|
|
6
6
|
import { randomUUID } from "crypto";
|
|
7
7
|
var DEFAULT_REASONING_BUDGET_TOKENS = 1e4;
|
|
8
|
+
function toModelImagePart(imagePart) {
|
|
9
|
+
return {
|
|
10
|
+
type: "image",
|
|
11
|
+
image: normalizeImagePayload(imagePart.image, imagePart.mimeType),
|
|
12
|
+
mimeType: imagePart.mimeType
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function isLegacyBufferShape(v) {
|
|
16
|
+
return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Uint8Array) && !(v instanceof URL) && v.type === "Buffer" && Array.isArray(v.data);
|
|
17
|
+
}
|
|
18
|
+
function normalizeImagePayload(image, mimeType) {
|
|
19
|
+
if (typeof image === "string" || image instanceof URL) {
|
|
20
|
+
return image;
|
|
21
|
+
}
|
|
22
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
|
|
23
|
+
const mime = mimeType ?? "image/jpeg";
|
|
24
|
+
return `data:${mime};base64,${image.toString("base64")}`;
|
|
25
|
+
}
|
|
26
|
+
if (image instanceof Uint8Array) {
|
|
27
|
+
if (typeof Buffer !== "undefined") {
|
|
28
|
+
const mime2 = mimeType ?? "image/jpeg";
|
|
29
|
+
return `data:${mime2};base64,${Buffer.from(image).toString("base64")}`;
|
|
30
|
+
}
|
|
31
|
+
let binary = "";
|
|
32
|
+
for (let i = 0;i < image.length; i++) {
|
|
33
|
+
binary += String.fromCharCode(image[i]);
|
|
34
|
+
}
|
|
35
|
+
const mime = mimeType ?? "image/jpeg";
|
|
36
|
+
return `data:${mime};base64,${globalThis.btoa?.(binary) ?? binary}`;
|
|
37
|
+
}
|
|
38
|
+
if (isLegacyBufferShape(image)) {
|
|
39
|
+
return new Uint8Array(image.data);
|
|
40
|
+
}
|
|
41
|
+
return image;
|
|
42
|
+
}
|
|
8
43
|
|
|
9
44
|
class SessionMessageConverter {
|
|
10
45
|
toModelMessage(msg) {
|
|
@@ -47,6 +82,8 @@ class SessionMessageConverter {
|
|
|
47
82
|
mimeType: filePart.mime,
|
|
48
83
|
filename: filePart.filename
|
|
49
84
|
});
|
|
85
|
+
} else if (part.type === "image") {
|
|
86
|
+
content.push(toModelImagePart(part));
|
|
50
87
|
} else if (part.type === "tool-result" || part.type === "checkpoint") {} else {
|
|
51
88
|
console.debug(`[session-message-converter] Skipping unsupported part type in assistant: ${part.type}`);
|
|
52
89
|
}
|
|
@@ -68,6 +105,32 @@ class SessionMessageConverter {
|
|
|
68
105
|
}]
|
|
69
106
|
};
|
|
70
107
|
}
|
|
108
|
+
if (msg.role === "user" || msg.role === "system") {
|
|
109
|
+
const parts = msg.parts || [];
|
|
110
|
+
const hasMultimodal = parts.some((p) => p.type === "image" || p.type === "file");
|
|
111
|
+
if (hasMultimodal) {
|
|
112
|
+
const content = [];
|
|
113
|
+
for (const part of parts) {
|
|
114
|
+
if (part.type === "text") {
|
|
115
|
+
content.push({ type: "text", text: part.content });
|
|
116
|
+
} else if (part.type === "image") {
|
|
117
|
+
content.push(toModelImagePart(part));
|
|
118
|
+
} else if (part.type === "file") {
|
|
119
|
+
const filePart = part;
|
|
120
|
+
content.push({
|
|
121
|
+
type: "file",
|
|
122
|
+
url: filePart.url,
|
|
123
|
+
mimeType: filePart.mime,
|
|
124
|
+
filename: filePart.filename
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
role: msg.role,
|
|
130
|
+
content
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
71
134
|
return {
|
|
72
135
|
role: msg.role,
|
|
73
136
|
content: msg.content || ""
|
|
@@ -121,6 +184,13 @@ class SessionMessageConverter {
|
|
|
121
184
|
url: p.url,
|
|
122
185
|
filename: p.filename
|
|
123
186
|
});
|
|
187
|
+
} else if (p.type === "image") {
|
|
188
|
+
const imageData = normalizeImagePayload(p.image, p.mimeType);
|
|
189
|
+
parts.push({
|
|
190
|
+
type: "image",
|
|
191
|
+
image: imageData,
|
|
192
|
+
mimeType: p.mimeType
|
|
193
|
+
});
|
|
124
194
|
} else {
|
|
125
195
|
console.debug(`[session-message-converter] Unknown part type: ${p.type}`);
|
|
126
196
|
}
|
|
@@ -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 =
|
|
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-
|
|
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-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
454
|
+
logger2.debug(`No replyChannel available for ${type}`);
|
|
631
455
|
return;
|
|
632
456
|
}
|
|
633
457
|
const message = `${title}
|
|
@@ -635,21 +459,23 @@ class LarkCliTaskNotifyHook {
|
|
|
635
459
|
${content}`;
|
|
636
460
|
try {
|
|
637
461
|
if (isTaskNotifyDebugEnabled()) {
|
|
638
|
-
|
|
462
|
+
logger2.debug(`Sending message - messageId: ${messageId}`);
|
|
639
463
|
}
|
|
464
|
+
const profile = replyChannel?.profile;
|
|
640
465
|
await this.sendLarkMessage({
|
|
641
466
|
chatId,
|
|
642
467
|
messageId,
|
|
643
|
-
content: message
|
|
468
|
+
content: message,
|
|
469
|
+
profile
|
|
644
470
|
});
|
|
645
|
-
|
|
471
|
+
logger2.info(`Notification sent: ${type}`);
|
|
646
472
|
} catch (error) {
|
|
647
|
-
|
|
473
|
+
logger2.error(`Failed to send notification: ${error}`);
|
|
648
474
|
}
|
|
649
475
|
}
|
|
650
476
|
sendLarkMessage(options) {
|
|
651
477
|
return new Promise((resolve, reject) => {
|
|
652
|
-
const { chatId, messageId, content } = options;
|
|
478
|
+
const { chatId, messageId, content, profile } = options;
|
|
653
479
|
let args;
|
|
654
480
|
if (messageId) {
|
|
655
481
|
args = [
|
|
@@ -672,6 +498,9 @@ ${content}`;
|
|
|
672
498
|
content
|
|
673
499
|
];
|
|
674
500
|
}
|
|
501
|
+
if (profile) {
|
|
502
|
+
args.unshift("--profile", profile);
|
|
503
|
+
}
|
|
675
504
|
const proc = spawn("lark-cli", args, {
|
|
676
505
|
shell: false,
|
|
677
506
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -686,7 +515,7 @@ ${content}`;
|
|
|
686
515
|
});
|
|
687
516
|
proc.on("close", (code) => {
|
|
688
517
|
if (code === 0) {
|
|
689
|
-
|
|
518
|
+
logger2.debug(`lark-cli output: ${stdout}`);
|
|
690
519
|
resolve();
|
|
691
520
|
} else {
|
|
692
521
|
reject(new Error(`lark-cli exited with code ${code}: ${stderr}`));
|
|
@@ -770,7 +599,7 @@ ${content}`;
|
|
|
770
599
|
const now = Date.now();
|
|
771
600
|
const lastTime = this.lastNotifyTimestamps.get(key);
|
|
772
601
|
if (lastTime && now - lastTime < throttleMs) {
|
|
773
|
-
|
|
602
|
+
logger2.debug(`[throttle] Skipping OPERATION_CREATED notify for task #${operation.taskId}, last notified ${now - lastTime}ms ago`);
|
|
774
603
|
return true;
|
|
775
604
|
}
|
|
776
605
|
this.lastNotifyTimestamps.set(key, now);
|
|
@@ -811,4 +640,4 @@ __legacyDecorateClassTS([
|
|
|
811
640
|
function createLarkCliTaskNotifyHook(config = {}) {
|
|
812
641
|
return new LarkCliTaskNotifyHook(config);
|
|
813
642
|
}
|
|
814
|
-
export {
|
|
643
|
+
export { WORKFLOW_EXTRACTOR_PROMPT, formatExtractorInput, formatExtractorInputFromDescription, parseExtractorOutput, TaskTagPlugin, NotifyType, LarkCliTaskNotifyHook, createLarkCliTaskNotifyHook };
|