@ai-setting/roy-agent-core 1.6.1 → 1.6.2

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 (33) hide show
  1. package/dist/env/agent/index.js +2 -2
  2. package/dist/env/event-source/index.js +3 -3
  3. package/dist/env/index.js +14 -13
  4. package/dist/env/prompt/index.js +2 -2
  5. package/dist/env/task/delegate/index.js +2 -2
  6. package/dist/env/task/index.js +4 -3
  7. package/dist/env/task/plugins/index.js +2 -2
  8. package/dist/env/tool/built-in/index.js +7 -1
  9. package/dist/env/tool/index.js +3 -2
  10. package/dist/env/workflow/engine/index.js +3 -3
  11. package/dist/env/workflow/index.js +5 -5
  12. package/dist/env/workflow/nodes/index.js +1 -1
  13. package/dist/env/workflow/tools/index.js +1 -1
  14. package/dist/index.js +16 -15
  15. package/dist/shared/@ai-setting/{roy-agent-core-skfr9wjk.js → roy-agent-core-1k7z350s.js} +1 -1
  16. package/dist/shared/@ai-setting/{roy-agent-core-q79q54x2.js → roy-agent-core-2t2n1epb.js} +1 -1
  17. package/dist/shared/@ai-setting/{roy-agent-core-fzkfkd28.js → roy-agent-core-47py6rej.js} +37 -17
  18. package/dist/shared/@ai-setting/{roy-agent-core-a8pm6hya.js → roy-agent-core-6kygfd9x.js} +9 -0
  19. package/dist/shared/@ai-setting/{roy-agent-core-8cwb4fmp.js → roy-agent-core-9378eq5y.js} +139 -4
  20. package/dist/shared/@ai-setting/{roy-agent-core-vrn9qj8y.js → roy-agent-core-97x9ymda.js} +1 -1
  21. package/dist/shared/@ai-setting/roy-agent-core-amkqnyzy.js +145 -0
  22. package/dist/shared/@ai-setting/{roy-agent-core-9gde0s9d.js → roy-agent-core-ba6243hr.js} +1 -1
  23. package/dist/shared/@ai-setting/{roy-agent-core-2vhsccvz.js → roy-agent-core-caevk7xd.js} +10 -0
  24. package/dist/shared/@ai-setting/{roy-agent-core-84ex7khq.js → roy-agent-core-ekptge19.js} +3 -3
  25. package/dist/shared/@ai-setting/{roy-agent-core-8cezq5x9.js → roy-agent-core-gexpbexm.js} +1 -1
  26. package/dist/shared/@ai-setting/{roy-agent-core-415rxkzy.js → roy-agent-core-gzzvcmg3.js} +54 -20
  27. package/dist/shared/@ai-setting/{roy-agent-core-84aqc5c0.js → roy-agent-core-j25z80xr.js} +15 -1
  28. package/dist/shared/@ai-setting/{roy-agent-core-npkwftxj.js → roy-agent-core-r3209bcd.js} +5 -1
  29. package/dist/shared/@ai-setting/{roy-agent-core-mnc0hy7j.js → roy-agent-core-te3hf26b.js} +17 -6
  30. package/dist/shared/@ai-setting/{roy-agent-core-q8n1s1pb.js → roy-agent-core-vf72n6qn.js} +4 -1
  31. package/dist/shared/@ai-setting/{roy-agent-core-txk4gcwm.js → roy-agent-core-xnga0ksx.js} +9 -4
  32. package/dist/shared/@ai-setting/{roy-agent-core-57bmm0a1.js → roy-agent-core-y1m7c2v7.js} +1 -1
  33. package/package.json +1 -1
@@ -24,7 +24,7 @@ var builtInPrompts = {
24
24
 
25
25
  ## 你的工具
26
26
 
27
- 你有一组任务查询工具和两个执行工具可用:
27
+ 你有一组任务查询工具和三个执行工具可用:
28
28
 
29
29
  | 工具 | 类别 | 描述 |
30
30
  |------|------|------|
@@ -32,7 +32,8 @@ var builtInPrompts = {
32
32
  | \`task_get\` | **查询** | 获取单个任务详情(含 operations) |
33
33
  | \`task_list\` | **查询** | 按 status/priority/type/depth 列出任务,支持分页 |
34
34
  | \`task_operation_list\` | **查询** | 查看任务的操作记录 |
35
- | \`delegate_task\` | **执行** | 委托复杂/多步骤任务给子智能体执行 |
35
+ | \`delegate_task\` | **执行** | 委托复杂/多步骤任务给子智能体执行(后台模式,立即返回) |
36
+ | \`query_background_process\` | **执行** | 查询由 \`delegate_task\` 启动的后台进程当前状态(仅 default agent 可见) |
36
37
  | \`bash\` | **执行** | 仅用于执行一行简单的 shell 命令 |
37
38
 
38
39
  ### 查询工具(可直接使用)
@@ -116,8 +117,9 @@ delegate_task(
116
117
  )
117
118
  \`\`\`
118
119
 
119
- > **提示**:\`delegate_task\` 现在**总是后台模式**,立即返回。父 agent 通过返回的 \`task_id\` 用 \`task_get\` 查询进度。
120
+ > **提示**:\`delegate_task\` 现在**总是后台模式**,立即返回。父 agent 通过返回的 \`bgProcessId\` 用 \`query_background_process\` 查询后台进程**实时状态**。
120
121
  > - delegate_task 内部自动创建关联 Task,调用方无需传入 \`task_id\`
122
+ > - \`bgProcessId\` 用于查实时状态(running/completed/failed/timeout/stopped),\`task_get\` 查的是关联的 Task #N 生命周期,**两者不要混用**
121
123
  > - sub-session 始终保留(不会自动删除),可通过 \`session_get\` 查看完整执行日志
122
124
 
123
125
  ### \uD83E\uDD48 次选:\`strict-task-agent\`(需要严格验证时使用)
@@ -177,6 +179,7 @@ delegate_task(
177
179
  - 父 agent 收到通知后**自主处理**(见下一节),无需主动 sleep 轮询
178
180
  - 错误做法:\`sleep 60 && task_get <id>\`、\`while !task_complete; do sleep 5; done\`
179
181
  - 正确做法:\`delegate_task(...)\` → 立即返回 → 等待系统通知 → 收到通知后自主处理
182
+ 9. **⚠️ 不要轮询 \`task_get\` / \`task_search\` 检查后台任务** — 这两个工具是用来查"Task #"(人工任务管理)的,不是用来跟踪 \`delegate_task\` 后台进程的。如果你怀疑某个后台进程**没有按时收到通知**或**卡住了**,**应该用 \`query_background_process\` 工具**(见下方"7. 主动查询后台进程"),而不是用 \`task_get\` / \`task_search\` 反复查 Task 状态。
180
183
 
181
184
  ## 子代理通知自主处理规则
182
185
 
@@ -244,6 +247,75 @@ delegate_task({
244
247
  - 遇到阻塞:尝试绕过或选替代方案,无法绕过的暂停任务等用户回来
245
248
  - 任务完成:记录完整结果,用户回来时统一汇报
246
249
 
250
+ ### 7. 主动查询后台进程(query_background_process,2026-07 新增)
251
+
252
+ 如果你委托了一个后台任务,但**迟迟没有收到任何通知**(completed / failed / progress / timeout),可能的原因有:
253
+ - 后台任务还在运行(正常,可能耗时较长)
254
+ - 后台任务卡住了(外部资源阻塞、模型僵死、网络挂起等)
255
+ - 后台任务崩溃了但通知消息丢失
256
+ - 通知机制本身出问题了
257
+
258
+ **此时不要 sleep 轮询,也不要反复调 task_get**。使用专门的 \`query_background_process\` 工具查询后台进程**实时状态**。
259
+
260
+ #### 何时使用 query_background_process
261
+
262
+ ✅ **应该用**:
263
+ - 委托了一个**长任务**(timeout ≥ 5 分钟),过去 5+ 分钟还没收到任何通知,主动确认是否还活着
264
+ - 用户**主动问**"那个任务进展怎么样了?"——需要最新快照而不是等通知
265
+ - 怀疑后台任务**卡住**(最后一条 progress 通知是较久以前、子任务明显应该推进但没动静)
266
+ - 收到 timeout / failed 通知,但需要确认**真实状态**(避免误判 timeout 后又被通知说完成了)
267
+ - 准备做关键决策(如复用 sub session 重试)前,需要先确认原 task 真的已经结束
268
+
269
+ ❌ **不应该用**:
270
+ - 委托后**几秒就查**——99% 的情况下根本不需要这么急,等通知就行
271
+ - 每隔 30 秒就查一次——这就是 sleep 轮询的变种,浪费 token
272
+ - 每次 ReAct 迭代都查——同理,浪费 token
273
+
274
+ #### 查询频率建议
275
+
276
+ - **委托后 5 分钟内**:完全不需要查,等通知
277
+ - **5-15 分钟无通知**:可以查一次确认 alive 状态,然后继续等
278
+ - **15+ 分钟无通知**:可以每 5 分钟查一次,关注 status 是否仍为 "running"
279
+ - **收到 timeout 通知后**:立刻查一次,确认最终状态再决定下一步
280
+
281
+ #### 返回值结构
282
+
283
+ 工具返回 JSON 字符串:
284
+
285
+ \`\`\`json
286
+ {
287
+ "alive": true, // status 为 pending/running 时为 true,否则 false
288
+ "status": "running", // pending | running | completed | failed | stopped | timeout | not_found
289
+ "createdAt": 1721000000000, // 启动时间戳(ms)
290
+ "lastUpdatedAt": 1721000060000, // 最后状态更新时间戳(ms)
291
+ "description": "实现加法函数", // delegate_task 传入的 description
292
+ "result": "已完成,实现代码在 ...", // 仅 completed 状态有
293
+ "error": "..." // 仅 failed 状态有
294
+ }
295
+ \`\`\`
296
+
297
+ #### 示例
298
+
299
+ \`\`\`typescript
300
+ // 委托任务(拿 bgProcessId)
301
+ const result = await delegate_task({
302
+ description: "实现加法函数",
303
+ prompt: "...",
304
+ subagent_type: "roy",
305
+ similar_task_ids: [],
306
+ });
307
+ // result.bgProcessId 形如 "process_1721000000000_abc12345"
308
+
309
+ // ...等 10 分钟没收到通知,主动查询
310
+ const status = await query_background_process({ bgProcessId: result.bgProcessId });
311
+ // status.alive === true → 还在跑,继续等
312
+ // status.alive === false && status.status === "completed" → 任务已完成,看 status.result
313
+ // status.alive === false && status.status === "timeout" → 已超时,考虑用 subSessionId 重试
314
+ // status.status === "not_found" → 进程不存在(可能已被清理)
315
+ \`\`\`
316
+
317
+ > ⚠️ **重要**:这个工具**只有 default 接待员 agent 有**。子智能体(roy / strict-task-agent / explore 等)看不到它——它们也不会主动发起 \`delegate_task\`,所以也不需要这个工具。
318
+
247
319
 
248
320
  ## Workflow 操作指南
249
321
 
@@ -933,7 +1005,7 @@ When reusing an existing task, you MUST follow these rules:
933
1005
  - 返回值:workflow 定义(名称、版本、描述、入参 inputs schema、节点列表),或 run 的状态
934
1006
 
935
1007
  3. **\`workflow_run\`** — 运行 workflow
936
- - 参数:\`workflow_name\`(必填),\`input\`(可选 JSON),\`sync\`(是否等待完成,默认 true),\`timeout\`(可选)
1008
+ - 参数:\`workflow_name\`(必填),\`input\`(可选 JSON),\`sync\`(是否等待完成,默认 true),\`timeout\`(可选),\`session\`(resume 用,传 runId 即可),\`node_config\`(per-node 覆盖,Task #1974,JSON 对象 { "<nodeId>": { timeout: 5000 } })
937
1009
  - 返回值:run_id, status, output, error, duration_ms
938
1010
 
939
1011
  4. **\`workflow_run_status\`** — 查询 run 状态
@@ -1023,6 +1095,69 @@ workflow_run(workflow_name="strict-task-agent", input={"task_description": "修
1023
1095
  - ❌ 不要在 resume 时传 \`input\` 覆盖 query(除非用户明确说要修改任务)
1024
1096
  - ❌ 不要把 \`workflow_xxx\` 当作 workflow name 调 \`workflow_get\`(那是 runId/sessionId 不是 workflow name)
1025
1097
 
1098
+ ## \uD83D\uDD25 失败处理(Task #1974 — 强制步骤)
1099
+
1100
+ 当 \`workflow_run\` 返回 \`status="failed"\` / \`status="timeout"\` / \`status="stopped"\`,
1101
+ 或者上游报告某个 workflow run 失败、超时、卡死时,**必须**按以下顺序处理:
1102
+
1103
+ ### 步骤 ①:显式 stop,确认成功
1104
+
1105
+ \`\`\`
1106
+ workflow_run_stop(run_id="<runId>", reason="<为何 stop>")
1107
+ # 必须等待返回 success=true 才算成功
1108
+ # 如果返回 success=false 或抛错,记录错误并仍然尝试步骤 ②
1109
+ \`\`\`
1110
+
1111
+ > 为什么不直接 \`workflow_run(... session=...)\` resume?
1112
+ >
1113
+ > 因为如果原 run 还活着(特别是超时的情况),resume 会进入一个**已经死了**的
1114
+ > session,状态混乱。先 stop 把残留资源清干净,再 resume 才有干净的起点。
1115
+ > 这一步是 Task #1974 修复"workflow agent session 和 workflow run instance
1116
+ > 状态不一致"bug 的关键。
1117
+
1118
+ ### 步骤 ②:用同一个 runId resume
1119
+
1120
+ \`\`\`
1121
+ workflow_run(
1122
+ workflow_name="<原 workflow name>",
1123
+ session="<runId>", # ← 直接传 runId,runId == sessionId
1124
+ # 通常不需要 input;如需新 query 才传
1125
+ )
1126
+ \`\`\`
1127
+
1128
+ Resume 会从 last message 自动推断恢复点(start / 节点级 / ask_user interrupt),
1129
+ plan/execute/verify 三阶段已完成的会跳过,未完成的会接上。
1130
+
1131
+ ### 步骤 ③:多次 resume 都失败 → 才考虑开新 run
1132
+
1133
+ 如果步骤 ② 连续失败 ≥ 2 次(例如 session 损坏 / workflow 定义已变更),
1134
+ **才**允许用 \`workflow_run(workflow_name=..., input=...)\` 开一个全新的 run。
1135
+ 开新 run 前必须把旧的 runId 在响应里**显式说明已废弃**,避免上游误用。
1136
+
1137
+ ### 反例(禁止)
1138
+
1139
+ - ❌ 看到 timeout 立即 \`workflow_run\`(不带 \`session\`)开新 run
1140
+ → 浪费前面 plan 阶段的工作,session 树变成双胞胎,资源浪费
1141
+ - ❌ 跳过 stop 直接 resume
1142
+ → 在残留 run 还活着的瞬间 resume,状态竞争、消息重复写入
1143
+ - ❌ 用 \`bash\` 之类的工具 kill workflow 进程
1144
+ → 绕过 engine 的清理逻辑,session 永远卡在 'running'
1145
+ - ❌ 对失败假装没看见,直接向上游返回 "完成"
1146
+ → 上游基于错误结果继续决策,bug 雪球式放大
1147
+
1148
+ ### 错误识别速查
1149
+
1150
+ | 现象 | 处理 |
1151
+ | --- | --- |
1152
+ | \`workflow_run\` 返回 \`status="timeout"\` | stop → resume(同 session) |
1153
+ | \`workflow_run\` 返回 \`status="failed"\` + error 含 "timeout" | stop → resume(同 session) |
1154
+ | \`workflow_run\` 返回 \`status="failed"\` + error 是业务错误(如校验失败) | **不** resume,原样返回给上游 |
1155
+ | \`workflow_run\` 返回 \`status="paused"\`(ask_user 中断) | 用 \`session\` resume + 用户 response |
1156
+ | \`workflow_run\` 返回 \`status="running"\` 但实际卡死很久 | 先 \`workflow_run_status\` 确认;仍是 running 则 stop → resume |
1157
+ | \`workflow_run\` 抛异常(非 status=failed,是 throw) | stop → resume;resume 仍失败则开新 run |
1158
+
1159
+ 记住:**stop + resume 是默认动作**,不是例外。
1160
+
1026
1161
  ### 严格约束
1027
1162
 
1028
1163
  - ✅ **只**通过 \`workflow_run\` 工具执行 workflow
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createAutoTaskPlugin
3
- } from "./roy-agent-core-8cezq5x9.js";
3
+ } from "./roy-agent-core-gexpbexm.js";
4
4
  import {
5
5
  ContextError,
6
6
  ErrorCodes
@@ -0,0 +1,145 @@
1
+ // src/env/tool/built-in/query-background-process-tool.ts
2
+ import { z } from "zod";
3
+ var QueryBackgroundProcessParameters = z.object({
4
+ bgProcessId: z.string().min(1, "bgProcessId must not be empty").describe("The background process ID returned by delegate_task " + "(format: process_<timestamp>_<random>).")
5
+ });
6
+ function backgroundTaskToOutput(task) {
7
+ return {
8
+ alive: task.status === "pending" || task.status === "running",
9
+ status: task.status,
10
+ createdAt: task.createdAt,
11
+ lastUpdatedAt: task.lastUpdatedAt ?? task.completedAt ?? task.startedAt ?? task.createdAt,
12
+ description: task.description,
13
+ ...task.result !== undefined ? { result: task.result } : {},
14
+ ...task.error !== undefined ? { error: task.error } : {}
15
+ };
16
+ }
17
+ function notFoundOutput(bgProcessId) {
18
+ const now = Date.now();
19
+ return {
20
+ alive: false,
21
+ status: "not_found",
22
+ createdAt: now,
23
+ lastUpdatedAt: now,
24
+ description: `No background process found with id '${bgProcessId}'.`
25
+ };
26
+ }
27
+ var queryBackgroundProcessTool = {
28
+ name: "query_background_process",
29
+ description: `Query the status of a background process previously launched via delegate_task.
30
+
31
+ ` + `Use this tool when:
32
+ ` + ` - You delegated a long-running task but have NOT received any notification after a reasonable wait (5+ minutes), and want to confirm whether the process is still alive.
33
+ ` + ` - The user asks about the progress of a delegated task and you need a current snapshot.
34
+ ` + ` - You suspect a delegated task got stuck (no progress messages, no completion notification).
35
+
36
+ ` + `DO NOT poll this tool on every turn — it is meant for diagnostic checks at a reasonable cadence (e.g. every few minutes, or when you genuinely suspect the task is stuck).
37
+
38
+ ` + `Returns a JSON object with:
39
+ ` + ` - alive: boolean — true if status is 'pending' or 'running'
40
+ ` + ` - status: 'pending' | 'running' | 'completed' | 'failed' | 'stopped' | 'timeout' | 'not_found'
41
+ ` + ` - createdAt, lastUpdatedAt: timestamps (ms)
42
+ ` + ` - description: the task description you passed to delegate_task
43
+ ` + ` - result: present when status is 'completed'
44
+ ` + ` - error: present when status is 'failed'
45
+
46
+ ` + "Only the default receptionist agent has this tool. Sub-agents (roy, strict-task-agent, etc.) cannot see it because they do not need to query background tasks they themselves launched.",
47
+ parameters: QueryBackgroundProcessParameters,
48
+ permission: {
49
+ level: "safe",
50
+ requireConfirmation: false
51
+ },
52
+ metadata: {
53
+ category: "task",
54
+ tags: ["background", "delegate", "query", "status", "diagnostic"],
55
+ version: "1.0.0",
56
+ allowedAgentTypes: ["default"]
57
+ },
58
+ execute: async (args, ctx) => createQueryBackgroundProcessTool(null).execute(args, ctx)
59
+ };
60
+ function createQueryBackgroundProcessTool(manager = null) {
61
+ return {
62
+ name: "query_background_process",
63
+ description: `Query the status of a background process previously launched via delegate_task.
64
+
65
+ ` + `Use this tool when:
66
+ ` + ` - You delegated a long-running task but have NOT received any notification after a reasonable wait (5+ minutes), and want to confirm whether the process is still alive.
67
+ ` + ` - The user asks about the progress of a delegated task and you need a current snapshot.
68
+ ` + ` - You suspect a delegated task got stuck (no progress messages, no completion notification).
69
+
70
+ ` + `DO NOT poll this tool on every turn — it is meant for diagnostic checks at a reasonable cadence (e.g. every few minutes, or when you genuinely suspect the task is stuck).
71
+
72
+ ` + `Returns a JSON object with:
73
+ ` + ` - alive: boolean — true if status is 'pending' or 'running'
74
+ ` + ` - status: 'pending' | 'running' | 'completed' | 'failed' | 'stopped' | 'timeout' | 'not_found'
75
+ ` + ` - createdAt, lastUpdatedAt: timestamps (ms)
76
+ ` + ` - description: the task description you passed to delegate_task
77
+ ` + ` - result: present when status is 'completed'
78
+ ` + ` - error: present when status is 'failed'
79
+
80
+ ` + "Only the default receptionist agent has this tool. Sub-agents (roy, strict-task-agent, etc.) cannot see it because they do not need to query background tasks they themselves launched.",
81
+ parameters: QueryBackgroundProcessParameters,
82
+ permission: {
83
+ level: "safe",
84
+ requireConfirmation: false
85
+ },
86
+ metadata: {
87
+ category: "task",
88
+ tags: ["background", "delegate", "query", "status", "diagnostic"],
89
+ version: "1.0.0",
90
+ allowedAgentTypes: ["default"]
91
+ },
92
+ execute: async (args, ctx) => {
93
+ const startTime = Date.now();
94
+ const params = QueryBackgroundProcessParameters.parse(args);
95
+ const { bgProcessId } = params;
96
+ if (!manager) {
97
+ return {
98
+ success: false,
99
+ output: "",
100
+ error: "query_background_process is not initialized: no BackgroundTaskManager " + "has been bound. TaskComponent should call " + "createQueryBackgroundProcessTool(manager) and register the tool " + "during startup.",
101
+ metadata: { execution_time_ms: Date.now() - startTime }
102
+ };
103
+ }
104
+ let task;
105
+ try {
106
+ task = manager.getTask(bgProcessId);
107
+ } catch (err) {
108
+ return {
109
+ success: false,
110
+ output: "",
111
+ error: `failed to query background task: ${err.message}`,
112
+ metadata: { execution_time_ms: Date.now() - startTime }
113
+ };
114
+ }
115
+ if (task) {
116
+ const currentSessionId = ctx.session_id;
117
+ if (!currentSessionId || task.parentSessionId !== currentSessionId) {
118
+ return {
119
+ success: true,
120
+ output: JSON.stringify(notFoundOutput(bgProcessId), null, 2),
121
+ metadata: {
122
+ execution_time_ms: Date.now() - startTime,
123
+ bgProcessId,
124
+ status: "not_found",
125
+ alive: false
126
+ }
127
+ };
128
+ }
129
+ }
130
+ const output = task ? backgroundTaskToOutput(task) : notFoundOutput(bgProcessId);
131
+ return {
132
+ success: true,
133
+ output: JSON.stringify(output, null, 2),
134
+ metadata: {
135
+ execution_time_ms: Date.now() - startTime,
136
+ bgProcessId,
137
+ status: output.status,
138
+ alive: output.alive
139
+ }
140
+ };
141
+ }
142
+ };
143
+ }
144
+
145
+ export { queryBackgroundProcessTool, createQueryBackgroundProcessTool };
@@ -103,7 +103,7 @@ var init_tool_node = __esm(() => {
103
103
  nodeId: context.nodeId
104
104
  }
105
105
  };
106
- const toolTimeoutMs = getToolTimeoutMs(input, this.definition.config);
106
+ const toolTimeoutMs = getToolTimeoutMs(input, config);
107
107
  const executePromise = tool.execute(input, toolContext);
108
108
  let timeoutHandle;
109
109
  const timeoutPromise = new Promise((_, reject) => {
@@ -28,6 +28,16 @@ function inferNextNode(messages, definition) {
28
28
  };
29
29
  case "workflow.node.end":
30
30
  case "workflow.node.result":
31
+ if (metadata?.success === false) {
32
+ const failedNodeId = getWorkflowNodeIdFromMetadata(metadata);
33
+ if (failedNodeId) {
34
+ return {
35
+ type: "resume_node",
36
+ nodeId: failedNodeId,
37
+ agentSessionId: metadata.agentSessionId
38
+ };
39
+ }
40
+ }
31
41
  return getNextNodes(getWorkflowNodeIdFromMetadata(metadata), definition);
32
42
  default:
33
43
  const lastStart = findLastStartMessage(messages);
@@ -6,7 +6,7 @@ import {
6
6
  WorkflowEngine,
7
7
  exports_engine,
8
8
  init_engine
9
- } from "./roy-agent-core-415rxkzy.js";
9
+ } from "./roy-agent-core-gzzvcmg3.js";
10
10
  import {
11
11
  askUserTool,
12
12
  createRunWorkflowTool,
@@ -18,7 +18,7 @@ import {
18
18
  createWorkflowSearchTool,
19
19
  createWorkflowTagListTool,
20
20
  createWorkflowValidateTool
21
- } from "./roy-agent-core-txk4gcwm.js";
21
+ } from "./roy-agent-core-xnga0ksx.js";
22
22
  import {
23
23
  WorkflowService
24
24
  } from "./roy-agent-core-b75jtybq.js";
@@ -141,7 +141,7 @@ class WorkflowComponent extends BaseComponent {
141
141
  if (!agentRunner && this._workflowEnv) {
142
142
  const agentComponent = this._workflowEnv.getComponent("agent");
143
143
  if (agentComponent) {
144
- const { AgentComponentAdapter } = await import("./roy-agent-core-57bmm0a1.js");
144
+ const { AgentComponentAdapter } = await import("./roy-agent-core-y1m7c2v7.js");
145
145
  agentRunner = new AgentComponentAdapter(agentComponent, {}, this.sessionComponent);
146
146
  }
147
147
  }
@@ -6,7 +6,7 @@ import {
6
6
  } from "./roy-agent-core-8wd3qwx5.js";
7
7
  import {
8
8
  WORKFLOW_EXTRACT_PROMPT
9
- } from "./roy-agent-core-8cwb4fmp.js";
9
+ } from "./roy-agent-core-9378eq5y.js";
10
10
  import {
11
11
  TaskHookPoints
12
12
  } from "./roy-agent-core-1pg0fepg.js";
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  AgentComponentAdapter,
9
9
  init_agent_component_adapter
10
- } from "./roy-agent-core-q8n1s1pb.js";
10
+ } from "./roy-agent-core-vf72n6qn.js";
11
11
  import {
12
12
  TemplateResolver,
13
13
  init_template_resolver
@@ -19,7 +19,7 @@ import {
19
19
  init_skill_node,
20
20
  init_tool_node,
21
21
  init_workflow_node
22
- } from "./roy-agent-core-9gde0s9d.js";
22
+ } from "./roy-agent-core-ba6243hr.js";
23
23
  import {
24
24
  WorkflowError,
25
25
  createWorkflowEvent,
@@ -416,14 +416,17 @@ var init_executor = __esm(() => {
416
416
  await this.writeNodeStart(context.sessionId, nodeId, nodeType, context.input, agentSessionId);
417
417
  const abortController = new AbortController;
418
418
  this.abortControllers.set(nodeId, abortController);
419
- const timeout = definition.timeout ?? this.options.globalTimeout ?? undefined;
419
+ context.abortSignal ??= abortController.signal;
420
+ const ctxCfg = context.config;
421
+ const cfgTimeout = ctxCfg && typeof ctxCfg.timeout === "number" && ctxCfg.timeout > 0 ? ctxCfg.timeout : undefined;
422
+ const timeout = definition.timeout ?? cfgTimeout ?? this.options.globalTimeout ?? undefined;
420
423
  const retryConfig = definition.retry ?? this.options.globalRetry;
421
424
  try {
422
425
  let result;
423
426
  if (retryConfig && retryConfig.max_attempts > 1) {
424
- result = await this.executeWithRetry(definition, context, abortController.signal, timeout);
427
+ result = await this.executeWithRetry(definition, context, abortController, timeout);
425
428
  } else {
426
- result = await this.executeWithTimeout(definition, context, abortController.signal, timeout);
429
+ result = await this.executeWithTimeout(definition, context, abortController, timeout);
427
430
  }
428
431
  if (result.error instanceof AskUserError) {
429
432
  const interruptEvent = createNodeInterruptEvent(context.runId, nodeId, nodeType, result.error.query, result.error.agentSessionId || agentSessionId);
@@ -455,7 +458,7 @@ var init_executor = __esm(() => {
455
458
  this.abortControllers.delete(nodeId);
456
459
  }
457
460
  }
458
- async executeWithTimeout(definition, context, signal, timeout) {
461
+ async executeWithTimeout(definition, context, abortController, timeout) {
459
462
  const startTime = Date.now();
460
463
  const nodeContext = {
461
464
  runId: context.runId,
@@ -464,9 +467,13 @@ var init_executor = __esm(() => {
464
467
  debug: context.debug
465
468
  };
466
469
  const node = this.nodeRegistry.createNode(definition, nodeContext);
470
+ const signal = abortController.signal;
467
471
  if (timeout) {
468
472
  const timeoutPromise = new Promise((_, reject) => {
469
473
  const handle = setTimeout(() => {
474
+ if (!abortController.signal.aborted) {
475
+ abortController.abort(new Error(`Node execution timeout: ${timeout}ms`));
476
+ }
470
477
  reject(new Error(`Node execution timeout: ${timeout}ms`));
471
478
  }, timeout);
472
479
  signal.addEventListener("abort", () => clearTimeout(handle));
@@ -510,10 +517,11 @@ var init_executor = __esm(() => {
510
517
  }
511
518
  }
512
519
  }
513
- async executeWithRetry(definition, context, signal, timeout) {
520
+ async executeWithRetry(definition, context, abortController, timeout) {
514
521
  const retryConfig = definition.retry;
515
522
  let lastError;
516
523
  let delay = retryConfig.initial_delay;
524
+ const signal = abortController.signal;
517
525
  for (let attempt = 1;attempt <= retryConfig.max_attempts; attempt++) {
518
526
  if (signal.aborted) {
519
527
  return {
@@ -524,8 +532,25 @@ var init_executor = __esm(() => {
524
532
  }
525
533
  const attemptAbort = new AbortController;
526
534
  const combinedSignal = this.combineAbortSignals(signal, attemptAbort.signal);
535
+ const combinedController = new AbortController;
536
+ combinedSignal.addEventListener("abort", () => {
537
+ if (!combinedController.signal.aborted) {
538
+ combinedController.abort(combinedSignal.reason);
539
+ }
540
+ });
541
+ const attemptAbortController = {
542
+ get signal() {
543
+ return combinedSignal;
544
+ },
545
+ abort: (reason) => {
546
+ attemptAbort.abort(reason);
547
+ if (!combinedController.signal.aborted) {
548
+ combinedController.abort(reason);
549
+ }
550
+ }
551
+ };
527
552
  try {
528
- const result = await this.executeWithTimeout(definition, context, combinedSignal, timeout);
553
+ const result = await this.executeWithTimeout(definition, context, attemptAbortController, timeout);
529
554
  if (!result.error) {
530
555
  return result;
531
556
  }
@@ -991,6 +1016,8 @@ var init_agent_node = __esm(() => {
991
1016
  const agentName = config.agent_name || undefined;
992
1017
  const options = config.options || {};
993
1018
  const outputConfig = parseAgentOutputConfig(config);
1019
+ const flatTimeout = typeof config.timeout === "number" && config.timeout > 0 ? config.timeout : undefined;
1020
+ const resolvedTimeout = flatTimeout ?? options.timeout;
994
1021
  let resolvedPrompt;
995
1022
  if (context.resolvedConfig && context.templateResolver) {
996
1023
  resolvedPrompt = config.prompt || "";
@@ -1044,7 +1071,7 @@ var init_agent_node = __esm(() => {
1044
1071
  type: resolvedAgentType,
1045
1072
  prompt: resolvedPrompt,
1046
1073
  options: {
1047
- timeout: options.timeout,
1074
+ timeout: resolvedTimeout,
1048
1075
  model: effectiveModel,
1049
1076
  allowedTools: effectiveAllowedTools,
1050
1077
  deniedTools: effectiveDeniedTools,
@@ -1058,7 +1085,12 @@ var init_agent_node = __esm(() => {
1058
1085
  userQuery,
1059
1086
  agentSessionId
1060
1087
  };
1061
- const result = await this.agentRunner.run(agentConfig, resumeOptions);
1088
+ let result;
1089
+ if (context.abortSignal) {
1090
+ result = await this.agentRunner.run(agentConfig, resumeOptions, context.abortSignal);
1091
+ } else {
1092
+ result = await this.agentRunner.run(agentConfig, resumeOptions);
1093
+ }
1062
1094
  const duration = Date.now() - startTime;
1063
1095
  return {
1064
1096
  output: buildAgentNodeOutput(result, outputConfig),
@@ -1433,9 +1465,6 @@ var init_engine = __esm(() => {
1433
1465
  if (metadata.status === "completed") {
1434
1466
  return { runId: this.getRunIdFromSessionId(sessionId), status: "completed" };
1435
1467
  }
1436
- if (metadata.status === "failed") {
1437
- return { runId: this.getRunIdFromSessionId(sessionId), status: "failed" };
1438
- }
1439
1468
  if (options?.input && this.sessionComponent) {
1440
1469
  const hasNewInput = typeof options.input === "string" ? options.input !== undefined && options.input !== "" : Object.keys(options.input).length > 0;
1441
1470
  if (hasNewInput) {
@@ -1457,7 +1486,7 @@ var init_engine = __esm(() => {
1457
1486
  extractResumeInfo,
1458
1487
  enrichResumeInfoWithAgentSessions,
1459
1488
  enrichResumePointWithAgentSessions
1460
- } = await import("./roy-agent-core-2vhsccvz.js");
1489
+ } = await import("./roy-agent-core-caevk7xd.js");
1461
1490
  const entry = workflowDef.entry;
1462
1491
  const entryNode = Array.isArray(entry) ? entry[0] : entry;
1463
1492
  const agentSessions = metadata.agentSessions ?? [];
@@ -1496,7 +1525,7 @@ var init_engine = __esm(() => {
1496
1525
  persistedInput = rest;
1497
1526
  }
1498
1527
  }
1499
- const { stripEphemeralResumeInput } = await import("./roy-agent-core-2vhsccvz.js");
1528
+ const { stripEphemeralResumeInput } = await import("./roy-agent-core-caevk7xd.js");
1500
1529
  const { workflowInput: runtimeInput } = stripEphemeralResumeInput(rawRuntimeInput);
1501
1530
  const defaultsFromSchema = {};
1502
1531
  if (definition.inputs) {
@@ -1515,7 +1544,8 @@ var init_engine = __esm(() => {
1515
1544
  strict: options?.strict ?? definition.config?.strict ?? false,
1516
1545
  maxIterations: options?.maxIterations ?? definition.config?.maxIterations ?? 100,
1517
1546
  loopEnabled,
1518
- workflowInput
1547
+ workflowInput,
1548
+ nodeConfig: options?.nodeConfig ?? {}
1519
1549
  };
1520
1550
  const abortController = new AbortController;
1521
1551
  let resolveCompleted;
@@ -1691,6 +1721,8 @@ var init_engine = __esm(() => {
1691
1721
  status: "paused",
1692
1722
  pendingNodeId: event.node_id,
1693
1723
  pauseReason: "ask_user",
1724
+ pendingAskUserQuery: event.query,
1725
+ pendingAskUserAgentSessionId: event.agent_session_id,
1694
1726
  agentSessions
1695
1727
  }
1696
1728
  });
@@ -1712,7 +1744,7 @@ var init_engine = __esm(() => {
1712
1744
  async scheduleAndExecute(sessionState, options) {
1713
1745
  const { scheduler, executor, eventBus, abortController, nodeOutputs } = sessionState;
1714
1746
  const { input: globalInput, pendingNodeId, agentSessionId, restoredOutputs } = options || {};
1715
- const { stripEphemeralResumeInput } = await import("./roy-agent-core-2vhsccvz.js");
1747
+ const { stripEphemeralResumeInput } = await import("./roy-agent-core-caevk7xd.js");
1716
1748
  const { workflowInput: inputToPersist, userQuery: resumeUserQuery } = stripEphemeralResumeInput(globalInput);
1717
1749
  if (inputToPersist) {
1718
1750
  sessionState.config.workflowInput = {
@@ -1854,7 +1886,7 @@ var init_engine = __esm(() => {
1854
1886
  if (!agentSessionId && this.sessionComponent) {
1855
1887
  const session = await this.sessionComponent.get(sessionId);
1856
1888
  const agentSessions = session?.metadata?.agentSessions;
1857
- const { resolveAgentSessionId } = await import("./roy-agent-core-2vhsccvz.js");
1889
+ const { resolveAgentSessionId } = await import("./roy-agent-core-caevk7xd.js");
1858
1890
  agentSessionId = resolveAgentSessionId(nodeId, undefined, agentSessions);
1859
1891
  }
1860
1892
  await sessionState.executor.writeNodeResume(sessionId, nodeId, nodeDef.type, options?.userQuery ?? "", agentSessionId);
@@ -1996,6 +2028,8 @@ var init_engine = __esm(() => {
1996
2028
  const askUser = (query) => {
1997
2029
  throw new AskUserError(runId, sessionState.sessionId, nodeId, nodeDef.type, query);
1998
2030
  };
2031
+ const nodeConfigOverride = sessionState.config.nodeConfig?.[nodeId];
2032
+ const effectiveConfig = nodeConfigOverride ? { ...nodeDef.config ?? {}, ...nodeConfigOverride } : nodeDef.config ?? {};
1999
2033
  const context = {
2000
2034
  runId,
2001
2035
  sessionId: sessionState.sessionId,
@@ -2003,7 +2037,7 @@ var init_engine = __esm(() => {
2003
2037
  nodeId,
2004
2038
  input,
2005
2039
  previousOutputs: sessionState.nodeOutputs,
2006
- config: nodeDef.config ?? {},
2040
+ config: effectiveConfig,
2007
2041
  debug: sessionState.config.debug,
2008
2042
  eventBus: sessionState.eventBus,
2009
2043
  nodeOutputs: sessionState.nodeOutputs,
@@ -2015,7 +2049,7 @@ var init_engine = __esm(() => {
2015
2049
  },
2016
2050
  workflowInput,
2017
2051
  templateResolver,
2018
- resolvedConfig: templateResolver.resolveValue(nodeDef.config ?? {})
2052
+ resolvedConfig: templateResolver.resolveValue(effectiveConfig)
2019
2053
  };
2020
2054
  return context;
2021
2055
  }
@@ -1,3 +1,6 @@
1
+ import {
2
+ createQueryBackgroundProcessTool
3
+ } from "./roy-agent-core-amkqnyzy.js";
1
4
  import {
2
5
  TaskEntityEventTypes
3
6
  } from "./roy-agent-core-8gxth0eh.js";
@@ -5,7 +8,7 @@ import {
5
8
  BackgroundTaskManager,
6
9
  createDelegateTool,
7
10
  createStopTool
8
- } from "./roy-agent-core-mnc0hy7j.js";
11
+ } from "./roy-agent-core-te3hf26b.js";
9
12
  import {
10
13
  SQLiteTaskStore,
11
14
  getDefaultTaskDbPath
@@ -314,6 +317,8 @@ class TaskComponent extends BaseComponent {
314
317
  this.toolComponent = this.env?.getComponent("tool");
315
318
  if (this.toolComponent) {
316
319
  await this.registerTools();
320
+ this.toolComponent.register(createQueryBackgroundProcessTool(this.backgroundTaskManager), "built-in");
321
+ logger2.debug("[TaskComponent] Injected BackgroundTaskManager into query_background_process tool (factory pattern)");
317
322
  } else {
318
323
  logger2.warn("[TaskComponent] ToolComponent not found, skipping tool registration");
319
324
  }
@@ -323,8 +328,17 @@ class TaskComponent extends BaseComponent {
323
328
  this.configWatcher();
324
329
  this.configWatcher = undefined;
325
330
  }
331
+ if (this.toolComponent) {
332
+ try {
333
+ this.toolComponent.register(createQueryBackgroundProcessTool(null), "built-in");
334
+ logger2.debug("[TaskComponent] Reset query_background_process tool to no-manager default (cleanup)");
335
+ } catch (err) {
336
+ logger2.warn(`[TaskComponent] Failed to reset query_background_process tool: ${err.message}`);
337
+ }
338
+ }
326
339
  if (this.backgroundTaskManager) {
327
340
  this.backgroundTaskManager.dispose();
341
+ this.backgroundTaskManager = undefined;
328
342
  }
329
343
  if (this.store) {
330
344
  await this.store.close();