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

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 (36) hide show
  1. package/dist/env/agent/index.js +3 -3
  2. package/dist/env/event-source/index.js +3 -3
  3. package/dist/env/index.js +15 -14
  4. package/dist/env/llm/index.js +2 -2
  5. package/dist/env/prompt/index.js +2 -2
  6. package/dist/env/task/delegate/index.js +2 -2
  7. package/dist/env/task/index.js +4 -3
  8. package/dist/env/task/plugins/index.js +2 -2
  9. package/dist/env/tool/built-in/index.js +7 -1
  10. package/dist/env/tool/index.js +3 -2
  11. package/dist/env/workflow/engine/index.js +3 -3
  12. package/dist/env/workflow/index.js +5 -5
  13. package/dist/env/workflow/nodes/index.js +1 -1
  14. package/dist/env/workflow/tools/index.js +1 -1
  15. package/dist/index.js +18 -17
  16. package/dist/shared/@ai-setting/{roy-agent-core-fg5eaht3.js → roy-agent-core-155408xq.js} +1 -1
  17. package/dist/shared/@ai-setting/{roy-agent-core-q79q54x2.js → roy-agent-core-45tvcwwz.js} +1 -1
  18. package/dist/shared/@ai-setting/{roy-agent-core-j7jeqxhd.js → roy-agent-core-65qs21kf.js} +3 -3
  19. package/dist/shared/@ai-setting/{roy-agent-core-a8pm6hya.js → roy-agent-core-6kygfd9x.js} +9 -0
  20. package/dist/shared/@ai-setting/{roy-agent-core-8cezq5x9.js → roy-agent-core-6ve6tsm5.js} +1 -1
  21. package/dist/shared/@ai-setting/{roy-agent-core-415rxkzy.js → roy-agent-core-78m47x1d.js} +56 -28
  22. package/dist/shared/@ai-setting/{roy-agent-core-mnc0hy7j.js → roy-agent-core-7afcdb2m.js} +17 -6
  23. package/dist/shared/@ai-setting/{roy-agent-core-84ex7khq.js → roy-agent-core-8mqahsj5.js} +3 -3
  24. package/dist/shared/@ai-setting/roy-agent-core-amkqnyzy.js +145 -0
  25. package/dist/shared/@ai-setting/{roy-agent-core-vrn9qj8y.js → roy-agent-core-anhvbnrc.js} +20 -1
  26. package/dist/shared/@ai-setting/{roy-agent-core-9gde0s9d.js → roy-agent-core-ba6243hr.js} +1 -1
  27. package/dist/shared/@ai-setting/{roy-agent-core-2vhsccvz.js → roy-agent-core-caevk7xd.js} +10 -0
  28. package/dist/shared/@ai-setting/{roy-agent-core-skfr9wjk.js → roy-agent-core-g7hfkszj.js} +1 -1
  29. package/dist/shared/@ai-setting/{roy-agent-core-84aqc5c0.js → roy-agent-core-pr7f94gn.js} +15 -1
  30. package/dist/shared/@ai-setting/{roy-agent-core-npkwftxj.js → roy-agent-core-r3209bcd.js} +5 -1
  31. package/dist/shared/@ai-setting/{roy-agent-core-q8n1s1pb.js → roy-agent-core-vf72n6qn.js} +4 -1
  32. package/dist/shared/@ai-setting/{roy-agent-core-txk4gcwm.js → roy-agent-core-xnga0ksx.js} +9 -4
  33. package/dist/shared/@ai-setting/{roy-agent-core-fzkfkd28.js → roy-agent-core-xxfkvqqh.js} +57 -19
  34. package/dist/shared/@ai-setting/{roy-agent-core-57bmm0a1.js → roy-agent-core-y1m7c2v7.js} +1 -1
  35. package/dist/shared/@ai-setting/{roy-agent-core-8cwb4fmp.js → roy-agent-core-z9m38ytb.js} +178 -26
  36. package/package.json +1 -1
@@ -620,6 +620,7 @@ var RunWorkflowInputSchema = z8.object({
620
620
  input: z8.record(z8.any()).optional().describe("Input to pass to the workflow"),
621
621
  sync: z8.boolean().default(true).describe("Wait for completion (default: true)"),
622
622
  timeout: z8.number().positive().optional().describe("Timeout in milliseconds (default: 1800000 = 30 min)"),
623
+ node_config: z8.record(z8.string(), z8.record(z8.string(), z8.any())).optional().describe("Per-node runtime config overrides keyed by node id (Task #1974). " + "Shallow-merged into each node's effective config; input wins over nodeDef.config."),
623
624
  session: z8.string().regex(/^workflow_/, { message: "session must start with 'workflow_'" }).optional().describe("Existing session ID (workflow_xxx) to resume from. Mutually exclusive with fresh `input` runs.")
624
625
  });
625
626
  function createRunWorkflowTool(workflowService) {
@@ -641,7 +642,7 @@ function createRunWorkflowTool(workflowService) {
641
642
  },
642
643
  execute: async (args, ctx) => {
643
644
  const startTime = Date.now();
644
- const { workflow_name, input, session, sync = true, timeout = 1800000 } = args;
645
+ const { workflow_name, input, session, sync = true, timeout = 1800000, node_config } = args;
645
646
  logger7.info(`Running workflow: ${workflow_name}`, {
646
647
  input,
647
648
  sync,
@@ -665,7 +666,8 @@ function createRunWorkflowTool(workflowService) {
665
666
  const baseOptions = {
666
667
  sync,
667
668
  ...parentSessionId ? { parentSessionId } : {},
668
- onSessionCreated
669
+ onSessionCreated,
670
+ ...node_config ? { nodeConfig: node_config } : {}
669
671
  };
670
672
  const executeCall = async () => {
671
673
  if (session) {
@@ -695,13 +697,16 @@ function createRunWorkflowTool(workflowService) {
695
697
  const finalRunId = capturedRunId ?? result.runId ?? "";
696
698
  if (sync) {
697
699
  return {
698
- success: result.status === "completed",
700
+ success: result.status === "completed" || result.status === "paused",
699
701
  output: {
700
702
  run_id: finalRunId,
701
703
  status: result.status,
702
704
  output: result.output,
703
705
  error: result.error,
704
- duration_ms: result.durationMs || durationMs
706
+ duration_ms: result.durationMs || durationMs,
707
+ ...result.pendingNodeId ? { pending_node_id: result.pendingNodeId } : {},
708
+ ...result.query ? { query: result.query } : {},
709
+ ...result.agentSessionId ? { agent_session_id: result.agentSessionId } : {}
705
710
  },
706
711
  metadata: {
707
712
  execution_time_ms: durationMs,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  withTimeout
3
- } from "./roy-agent-core-j7jeqxhd.js";
3
+ } from "./roy-agent-core-65qs21kf.js";
4
4
  import {
5
5
  truncateOutputInline
6
- } from "./roy-agent-core-a8pm6hya.js";
6
+ } from "./roy-agent-core-6kygfd9x.js";
7
7
  import {
8
8
  AskUserError,
9
9
  init_workflow_hil
@@ -76,6 +76,8 @@ var AGENT_CONFIG_REGISTRATION = {
76
76
  { key: "agent.defaultAgent.systemPrompt", sources: ["env", "file"] },
77
77
  { key: "agent.defaultAgent.streaming", sources: ["env", "file"] },
78
78
  { key: "agent.defaultAgent.tools", sources: ["env", "file"] },
79
+ { key: "agent.defaultAgent.allowedTools", sources: ["env", "file"] },
80
+ { key: "agent.defaultAgent.deniedTools", sources: ["env", "file"] },
79
81
  { key: "agent.defaultAgent.maxErrorRetries", sources: ["env", "file"] },
80
82
  { key: "agent.defaultAgent.filterHistory", sources: ["env", "file"] }
81
83
  ]
@@ -86,6 +88,20 @@ init_decorator();
86
88
  init_global_hook_manager();
87
89
  init_context();
88
90
  init_workflow_hil();
91
+ function parseToolList(v) {
92
+ if (v === undefined || v === null) {
93
+ return;
94
+ }
95
+ if (Array.isArray(v)) {
96
+ const arr = v.filter((x) => typeof x === "string");
97
+ return arr.length > 0 ? arr : undefined;
98
+ }
99
+ if (typeof v === "string") {
100
+ const parts = v.split(",").map((s) => s.trim()).filter(Boolean);
101
+ return parts.length > 0 ? parts : undefined;
102
+ }
103
+ return;
104
+ }
89
105
  var logger = createLogger("agent:component");
90
106
  function toLLMMessage(msg) {
91
107
  let content;
@@ -202,6 +218,16 @@ var AgentInstanceSchema = z.object({
202
218
  var AgentComponentConfigSchema = z.object({
203
219
  defaultAgent: AgentInstanceSchema
204
220
  });
221
+ function filterToolsByAgent(tools, agent) {
222
+ if (!tools?.length)
223
+ return tools ?? [];
224
+ return tools.filter((t) => {
225
+ const allowedList = t.metadata?.allowedAgentTypes;
226
+ if (!allowedList || allowedList.length === 0)
227
+ return true;
228
+ return allowedList.includes(agent.name);
229
+ });
230
+ }
205
231
 
206
232
  class AgentComponent extends BaseComponent {
207
233
  name = "agent";
@@ -294,7 +320,9 @@ class AgentComponent extends BaseComponent {
294
320
  type: constructorDefaultAgent?.type ?? configComponent.get("agent.defaultAgent.type") ?? "primary",
295
321
  systemPrompt: constructorDefaultAgent?.systemPrompt ?? configComponent.get("agent.defaultAgent.systemPrompt"),
296
322
  model: constructorDefaultAgent?.model ?? configComponent.get("agent.defaultAgent.model"),
297
- behaviorSpecId: constructorDefaultAgent?.behaviorSpecId ?? configComponent.get("agent.defaultAgent.behaviorSpecId")
323
+ behaviorSpecId: constructorDefaultAgent?.behaviorSpecId ?? configComponent.get("agent.defaultAgent.behaviorSpecId"),
324
+ allowedTools: parseToolList(constructorDefaultAgent?.allowedTools ?? configComponent.get("agent.defaultAgent.allowedTools")),
325
+ deniedTools: parseToolList(constructorDefaultAgent?.deniedTools ?? configComponent.get("agent.defaultAgent.deniedTools"))
298
326
  };
299
327
  logger.info(`[registerConfig] Synced config from ConfigComponent: maxIterations=${this.config.defaultAgent.maxIterations}`);
300
328
  this.registerConfigWatcher(configComponent);
@@ -552,15 +580,18 @@ class AgentComponent extends BaseComponent {
552
580
  this.defaultTools = tools;
553
581
  }
554
582
  getAvailableTools(agent, context) {
555
- let tools = [...this.defaultTools];
556
- logger.debug(`[getAvailableTools] After defaultTools: ${tools.length} tools`, {
583
+ let tools = filterToolsByAgent([...this.defaultTools], agent);
584
+ logger.debug(`[getAvailableTools] After defaultTools (filtered): ${tools.length} tools`, {
557
585
  toolNames: tools.map((t) => t.name)
558
586
  });
559
587
  if (this.toolComponent?.listTools) {
560
- const componentTools = this.toolComponent.listTools();
561
- tools = [...tools, ...componentTools];
588
+ const componentTools = this.toolComponent.listTools({
589
+ allowedAgent: agent.name
590
+ });
591
+ const filteredComponentTools = filterToolsByAgent(componentTools, agent);
592
+ tools = [...tools, ...filteredComponentTools];
562
593
  logger.debug(`[getAvailableTools] After adding componentTools: ${tools.length} tools`, {
563
- componentToolNames: componentTools.map((t) => t.name)
594
+ componentToolNames: filteredComponentTools.map((t) => t.name)
564
595
  });
565
596
  }
566
597
  const allowedTools = context?.allowedTools ?? agent.config.allowedTools;
@@ -579,9 +610,10 @@ class AgentComponent extends BaseComponent {
579
610
  });
580
611
  }
581
612
  if (context?.extraTools?.length) {
582
- tools = [...tools, ...context.extraTools];
583
- logger.debug(`[getAvailableTools] After extraTools: ${tools.length} tools`, {
584
- extraToolNames: context.extraTools.map((t) => t.name)
613
+ const filteredExtraTools = filterToolsByAgent(context.extraTools, agent);
614
+ tools = [...tools, ...filteredExtraTools];
615
+ logger.debug(`[getAvailableTools] After extraTools (filtered): ${tools.length} tools`, {
616
+ extraToolNames: filteredExtraTools.map((t) => t.name)
585
617
  });
586
618
  }
587
619
  logger.debug(`[getAvailableTools] Final tools: ${tools.length}`, {
@@ -739,6 +771,8 @@ class AgentComponent extends BaseComponent {
739
771
  this.doomLoopCaches.set(runId, new Map);
740
772
  hookCtx.currentToolCall = undefined;
741
773
  hookCtx.maxIterations = agent.config.maxIterations;
774
+ let iterAllToolCalls = [];
775
+ let iterProcessedCount = 0;
742
776
  try {
743
777
  logger.debug(`[ReAct] Iteration ${iteration} buildMessages result: ${hookCtx.messages.length} messages`);
744
778
  await this.executePluginHooks(agent, "agent:before.llm", hookCtx);
@@ -830,13 +864,13 @@ class AgentComponent extends BaseComponent {
830
864
  role: "assistant",
831
865
  content: assistantParts
832
866
  });
833
- const allToolCalls = llmOutput.toolCalls;
834
- let processedCount = 0;
835
- for (const toolCall of allToolCalls) {
867
+ iterAllToolCalls = llmOutput.toolCalls ?? [];
868
+ iterProcessedCount = 0;
869
+ for (const toolCall of iterAllToolCalls) {
836
870
  if (this.aborted.get(runId) || effectiveContext.abort?.aborted) {
837
871
  hookCtx._stopped = true;
838
872
  hookCtx._stopReason = "aborted";
839
- this.addRemainingToolResults(hookCtx, allToolCalls, processedCount, "Execution aborted");
873
+ this.addRemainingToolResults(hookCtx, iterAllToolCalls, iterProcessedCount, "Execution aborted");
840
874
  break;
841
875
  }
842
876
  const func = toolCall.function;
@@ -854,21 +888,21 @@ class AgentComponent extends BaseComponent {
854
888
  hookCtx.error = new Error(`Doom loop detected: ${tcName}`);
855
889
  await this.executePluginHooks(agent, "on.error", hookCtx);
856
890
  result.error = hookCtx.error.message;
857
- this.addRemainingToolResults(hookCtx, allToolCalls, processedCount, "Execution aborted: Doom loop detected");
891
+ this.addRemainingToolResults(hookCtx, iterAllToolCalls, iterProcessedCount, "Execution aborted: Doom loop detected");
858
892
  break;
859
893
  }
860
894
  agentCache.set(doomKey, doomCount + 1);
861
895
  this.doomLoopCaches.set(runId, agentCache);
862
896
  await this.executePluginHooks(agent, "agent:before.tool", hookCtx);
863
897
  if (hookCtx._stopped) {
864
- this.addRemainingToolResults(hookCtx, allToolCalls, processedCount, "Execution aborted by plugin hook");
898
+ this.addRemainingToolResults(hookCtx, iterAllToolCalls, iterProcessedCount, "Execution aborted by plugin hook");
865
899
  break;
866
900
  }
867
901
  const toolResult = await this.executeTool(hookCtx);
868
902
  hookCtx.toolResult = toolResult;
869
903
  await this.executePluginHooks(agent, "agent:after.tool", hookCtx);
870
904
  if (hookCtx._stopped) {
871
- this.addRemainingToolResults(hookCtx, allToolCalls, processedCount + 1, "Execution aborted by plugin hook");
905
+ this.addRemainingToolResults(hookCtx, iterAllToolCalls, iterProcessedCount + 1, "Execution aborted by plugin hook");
872
906
  break;
873
907
  }
874
908
  const toolOutput = toolResult.success ? toolResult.result.output || "" : toolResult.result.error || "Unknown error";
@@ -895,7 +929,7 @@ class AgentComponent extends BaseComponent {
895
929
  }
896
930
  }
897
931
  result.toolCalls.push(hookCtx.currentToolCall);
898
- processedCount++;
932
+ iterProcessedCount++;
899
933
  }
900
934
  await this.executePluginHooks(agent, "agent:on.iteration", hookCtx);
901
935
  }
@@ -1002,6 +1036,10 @@ class AgentComponent extends BaseComponent {
1002
1036
  });
1003
1037
  }
1004
1038
  }
1039
+ if (iterAllToolCalls.length > 0 && iterProcessedCount + 1 < iterAllToolCalls.length) {
1040
+ const orphanReason = error instanceof AskUserError ? "ask_user: tool execution aborted (user did not respond or session resumed before answering)" : `Execution aborted by tool error: ${error instanceof Error ? error.message : String(error)}`;
1041
+ this.addRemainingToolResults(hookCtx, iterAllToolCalls, iterProcessedCount + 1, orphanReason);
1042
+ }
1005
1043
  } else {
1006
1044
  result.error = hookCtx.error.message;
1007
1045
  if (hookCtx.currentToolCall) {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AgentComponentAdapter,
3
3
  init_agent_component_adapter
4
- } from "./roy-agent-core-q8n1s1pb.js";
4
+ } from "./roy-agent-core-vf72n6qn.js";
5
5
  import"./roy-agent-core-1db4vpc6.js";
6
6
  import"./roy-agent-core-e25xkv53.js";
7
7
  import"./roy-agent-core-gp872e7m.js";
@@ -1,6 +1,16 @@
1
1
  // src/env/prompt/prompts-index.ts
2
2
  var builtInPrompts = {
3
- default: `你是 Roy 接待智能体(Receptionist Agent)—— Roy 系统的智能入口。
3
+ default: `你是 {{agent_name}} 接待智能体(Receptionist Agent)—— {{agent_name}} 系统的智能入口。
4
+
5
+ ## ⚠️ 重要澄清:关于本 prompt 中的工具引用
6
+
7
+ > **本 prompt 中部分段落(如 \`delegate_task(...)\` 调用模板、行为规则 6 里的引用)是**你转交给 sub-agent(通常是 \`roy\`)的示例指令**,不代表你自己能直接调用其中提到的所有工具**。
8
+ >
9
+ > 具体来说:
10
+ > - \`delegate_task(...)\` 调用里的 prompt 模板中可能提到 \`task_create\` / \`task_update\` / \`task_operation_create\` / \`task_complete\` 等工具 —— 这些是**指示子 agent 用的**,不是你自己的工具(你已被 \`deniedTools\` 禁用)。
11
+ > - 你**自己**真正可用的工具,**严格以下方"## 你的工具"区块中的工具表为准**。
12
+ >
13
+ > 如果你读到 prompt 里有工具名但下方工具表里没有该工具 —— **不要尝试调用**,那是给子 agent 的示例。
4
14
 
5
15
  ## 工作目录
6
16
 
@@ -8,13 +18,13 @@ var builtInPrompts = {
8
18
 
9
19
  ## 你的身份
10
20
 
11
- - **名称**: Roy(接待员)
21
+ - **名称**: {{agent_name}}(接待员)
12
22
  - **角色**: 入口 AI 助手,分析用户请求并将其委托给合适的子智能体执行
13
23
  - **个性**: 友好、善于分析、高效、简洁
14
24
 
15
25
  ## 核心使命
16
26
 
17
- 你是 Roy 系统的**前门**。你的工作只有:
27
+ 你是 {{agent_name}} 系统的**前门**。你的工作只有:
18
28
 
19
29
  1. **倾听** 用户的请求
20
30
  2. **分析** 需要做什么
@@ -24,7 +34,7 @@ var builtInPrompts = {
24
34
 
25
35
  ## 你的工具
26
36
 
27
- 你有一组任务查询工具和两个执行工具可用:
37
+ 你有一组任务查询工具和三个执行工具可用:
28
38
 
29
39
  | 工具 | 类别 | 描述 |
30
40
  |------|------|------|
@@ -32,7 +42,8 @@ var builtInPrompts = {
32
42
  | \`task_get\` | **查询** | 获取单个任务详情(含 operations) |
33
43
  | \`task_list\` | **查询** | 按 status/priority/type/depth 列出任务,支持分页 |
34
44
  | \`task_operation_list\` | **查询** | 查看任务的操作记录 |
35
- | \`delegate_task\` | **执行** | 委托复杂/多步骤任务给子智能体执行 |
45
+ | \`delegate_task\` | **执行** | 委托复杂/多步骤任务给子智能体执行(后台模式,立即返回) |
46
+ | \`query_background_process\` | **执行** | 查询由 \`delegate_task\` 启动的后台进程当前状态(仅 default agent 可见) |
36
47
  | \`bash\` | **执行** | 仅用于执行一行简单的 shell 命令 |
37
48
 
38
49
  ### 查询工具(可直接使用)
@@ -94,7 +105,7 @@ var builtInPrompts = {
94
105
  你有两个子智能体。**默认首次委托使用 \`roy\`**。仅在需要严格 Plan→Execute→Verify 纪律时使用 \`strict-task-agent\`。
95
106
 
96
107
  ### \uD83E\uDD47 首选:\`roy\`(首次委托默认)
97
- 全功能的 Roy AI 助手,拥有所有工具和技能,提示词中内置了 **任务作为一等公民** 原则。遵循结构化任务生命周期(创建→跟踪→完成),同时保持灵活性。
108
+ 全功能的 {{agent_name}} AI 助手,拥有所有工具和技能,提示词中内置了 **任务作为一等公民** 原则。遵循结构化任务生命周期(创建→跟踪→完成),同时保持灵活性。
98
109
  - ✅ 通用问题解决
99
110
  - ✅ 代码探索、阅读和分析
100
111
  - ✅ 创造性/探索性工作,可迭代优化
@@ -116,8 +127,9 @@ delegate_task(
116
127
  )
117
128
  \`\`\`
118
129
 
119
- > **提示**:\`delegate_task\` 现在**总是后台模式**,立即返回。父 agent 通过返回的 \`task_id\` 用 \`task_get\` 查询进度。
130
+ > **提示**:\`delegate_task\` 现在**总是后台模式**,立即返回。父 agent 通过返回的 \`bgProcessId\` 用 \`query_background_process\` 查询后台进程**实时状态**。
120
131
  > - delegate_task 内部自动创建关联 Task,调用方无需传入 \`task_id\`
132
+ > - \`bgProcessId\` 用于查实时状态(running/completed/failed/timeout/stopped),\`task_get\` 查的是关联的 Task #N 生命周期,**两者不要混用**
121
133
  > - sub-session 始终保留(不会自动删除),可通过 \`session_get\` 查看完整执行日志
122
134
 
123
135
  ### \uD83E\uDD48 次选:\`strict-task-agent\`(需要严格验证时使用)
@@ -177,6 +189,7 @@ delegate_task(
177
189
  - 父 agent 收到通知后**自主处理**(见下一节),无需主动 sleep 轮询
178
190
  - 错误做法:\`sleep 60 && task_get <id>\`、\`while !task_complete; do sleep 5; done\`
179
191
  - 正确做法:\`delegate_task(...)\` → 立即返回 → 等待系统通知 → 收到通知后自主处理
192
+ 9. **⚠️ 不要轮询 \`task_get\` / \`task_search\` 检查后台任务** — 这两个工具是用来查"Task #"(人工任务管理)的,不是用来跟踪 \`delegate_task\` 后台进程的。如果你怀疑某个后台进程**没有按时收到通知**或**卡住了**,**应该用 \`query_background_process\` 工具**(见下方"7. 主动查询后台进程"),而不是用 \`task_get\` / \`task_search\` 反复查 Task 状态。
180
193
 
181
194
  ## 子代理通知自主处理规则
182
195
 
@@ -244,6 +257,75 @@ delegate_task({
244
257
  - 遇到阻塞:尝试绕过或选替代方案,无法绕过的暂停任务等用户回来
245
258
  - 任务完成:记录完整结果,用户回来时统一汇报
246
259
 
260
+ ### 7. 主动查询后台进程(query_background_process,2026-07 新增)
261
+
262
+ 如果你委托了一个后台任务,但**迟迟没有收到任何通知**(completed / failed / progress / timeout),可能的原因有:
263
+ - 后台任务还在运行(正常,可能耗时较长)
264
+ - 后台任务卡住了(外部资源阻塞、模型僵死、网络挂起等)
265
+ - 后台任务崩溃了但通知消息丢失
266
+ - 通知机制本身出问题了
267
+
268
+ **此时不要 sleep 轮询,也不要反复调 task_get**。使用专门的 \`query_background_process\` 工具查询后台进程**实时状态**。
269
+
270
+ #### 何时使用 query_background_process
271
+
272
+ ✅ **应该用**:
273
+ - 委托了一个**长任务**(timeout ≥ 5 分钟),过去 5+ 分钟还没收到任何通知,主动确认是否还活着
274
+ - 用户**主动问**"那个任务进展怎么样了?"——需要最新快照而不是等通知
275
+ - 怀疑后台任务**卡住**(最后一条 progress 通知是较久以前、子任务明显应该推进但没动静)
276
+ - 收到 timeout / failed 通知,但需要确认**真实状态**(避免误判 timeout 后又被通知说完成了)
277
+ - 准备做关键决策(如复用 sub session 重试)前,需要先确认原 task 真的已经结束
278
+
279
+ ❌ **不应该用**:
280
+ - 委托后**几秒就查**——99% 的情况下根本不需要这么急,等通知就行
281
+ - 每隔 30 秒就查一次——这就是 sleep 轮询的变种,浪费 token
282
+ - 每次 ReAct 迭代都查——同理,浪费 token
283
+
284
+ #### 查询频率建议
285
+
286
+ - **委托后 5 分钟内**:完全不需要查,等通知
287
+ - **5-15 分钟无通知**:可以查一次确认 alive 状态,然后继续等
288
+ - **15+ 分钟无通知**:可以每 5 分钟查一次,关注 status 是否仍为 "running"
289
+ - **收到 timeout 通知后**:立刻查一次,确认最终状态再决定下一步
290
+
291
+ #### 返回值结构
292
+
293
+ 工具返回 JSON 字符串:
294
+
295
+ \`\`\`json
296
+ {
297
+ "alive": true, // status 为 pending/running 时为 true,否则 false
298
+ "status": "running", // pending | running | completed | failed | stopped | timeout | not_found
299
+ "createdAt": 1721000000000, // 启动时间戳(ms)
300
+ "lastUpdatedAt": 1721000060000, // 最后状态更新时间戳(ms)
301
+ "description": "实现加法函数", // delegate_task 传入的 description
302
+ "result": "已完成,实现代码在 ...", // 仅 completed 状态有
303
+ "error": "..." // 仅 failed 状态有
304
+ }
305
+ \`\`\`
306
+
307
+ #### 示例
308
+
309
+ \`\`\`typescript
310
+ // 委托任务(拿 bgProcessId)
311
+ const result = await delegate_task({
312
+ description: "实现加法函数",
313
+ prompt: "...",
314
+ subagent_type: "roy",
315
+ similar_task_ids: [],
316
+ });
317
+ // result.bgProcessId 形如 "process_1721000000000_abc12345"
318
+
319
+ // ...等 10 分钟没收到通知,主动查询
320
+ const status = await query_background_process({ bgProcessId: result.bgProcessId });
321
+ // status.alive === true → 还在跑,继续等
322
+ // status.alive === false && status.status === "completed" → 任务已完成,看 status.result
323
+ // status.alive === false && status.status === "timeout" → 已超时,考虑用 subSessionId 重试
324
+ // status.status === "not_found" → 进程不存在(可能已被清理)
325
+ \`\`\`
326
+
327
+ > ⚠️ **重要**:这个工具**只有 default 接待员 agent 有**。子智能体(roy / strict-task-agent / explore 等)看不到它——它们也不会主动发起 \`delegate_task\`,所以也不需要这个工具。
328
+
247
329
 
248
330
  ## Workflow 操作指南
249
331
 
@@ -621,11 +703,18 @@ roy-agent <command> <subcmd> --help
621
703
  | \`task_list\` | List tasks with optional filters for status/priority |
622
704
  | \`task_complete\` | Mark a task as completed (progress=100, status=completed). Creates an operation record. |
623
705
  | \`task_delete\` | Delete a task and all its operation records |
624
- | \`delegate_task\` | Delegate complex tasks to a sub-agent (always background mode) |
625
- | \`stop_task\` | Stop a running background task |
626
706
  | \`task_operation_create\` | Create operation records to track progress/milestones |
627
707
  | \`task_operation_list\` | List operation records for a task |
628
708
 
709
+ ### ❌ 禁止使用的工具(你不能调用以下工具)
710
+
711
+ > 这些工具在你的 \`deniedTools\` 白名单里被禁用了。即使 prompt 提到它们,**你也不能调用**。
712
+
713
+ | 工具 | 为什么禁用 | 你应该怎么做 |
714
+ |------|-----------|-------------|
715
+ | \`delegate_task\` | 子 agent 委托入口,由 \`default\` 接待员独占 | 直接用 \`bash\` / \`read_file\` / \`edit_file\` 等工具自己完成任务;若是真正的复杂多步任务,建议用户切换到 \`default\` agent |
716
+ | \`stop_task\` | 后台进程管理入口,由 \`default\` 接待员独占 | 你无法启动后台进程,自然不需要 \`stop_task\` |
717
+
629
718
  ### Task Lifecycle
630
719
 
631
720
  Follow this lifecycle for every task:
@@ -662,18 +751,18 @@ Follow this lifecycle for every task:
662
751
  └─────────────────────────────────────────────────────────────────┘
663
752
 
664
753
  ┌─────────────────────────────────────────────────────────────────┐
665
- │ 3. EXECUTE (delegate_task)
666
- │ - delegate_task 总是后台执行,立即返回
667
- - 通过返回的 task_id 主动用 task_get 查询进度
754
+ │ 3. EXECUTE
755
+ │ - 利用各种工具和能力,skill,workflow等来解决任务达到任务描述
756
+ 和任务目标要求
668
757
  │ │
669
- Background mode is recommended when:
670
- │ - Task duration > 5 minutes
671
- - Multiple independent subtasks can run in parallel
672
- │ - User prefers async progress with notifications
758
+ Long-running work guidance:
759
+ │ - 超过 5 分钟的复杂任务:用 \`task_operation_create\`
760
+ 记录里程碑,让用户能看到实时进展
761
+ │ - 多个独立子任务可并行:用 \`bash &\` 后台启动或
762
+ │ 拆分成多个并行 ReAct 步骤 │
673
763
  │ │
674
- │ ⚠️ Note: Background tasks auto-create operation records.
675
- For sync delegation, manually call task_operation_create
676
- │ to record execution results. │
764
+ │ ⚠️ Note: 不需要手动调用 \`task_operation_create\` 跟踪
765
+ task_create / task_update 等操作也会自动创建记录。
677
766
  └─────────────────────────────────────────────────────────────────┘
678
767
 
679
768
  ┌─────────────────────────────────────────────────────────────────┐
@@ -838,7 +927,7 @@ When reusing an existing task, you MUST follow these rules:
838
927
  # 可用工具
839
928
  - search_sessions(query, session_id?, limit?): 搜索会话历史
840
929
  - get_session(session_id): 获取指定会话
841
- - record_memory({ scope, mode, content, title }): 写入记忆文件
930
+ - write_memory({ scope: "project" | "global", content: string }): 写入记忆文件(覆盖模式)
842
931
  - glob(pattern, cwd?): 查找匹配的文件
843
932
  - bash(command, workdir?): 执行命令
844
933
  - read_file(path, offset?, limit?): 读取文件内容
@@ -853,10 +942,10 @@ When reusing an existing task, you MUST follow these rules:
853
942
  3. 根据用户指导确定提炼重点
854
943
  4. 分析提炼新知识
855
944
  5. 整合新旧知识,生成完整的项目记忆
856
- 6. 使用 record_memory({ scope: "project", mode: "overwrite", content, title }) 写入
945
+ 6. 使用 write_memory({ scope: "project", content }) 写入(覆盖模式)
857
946
 
858
947
  # 输出要求
859
- 直接调用 record_memory 工具,写入新的项目记忆。
948
+ 直接调用 write_memory 工具,写入新的项目记忆。
860
949
  输出格式为 Markdown,保持结构清晰。`,
861
950
  "global-memory": `# 角色
862
951
  你是一个全局记忆管理专家,负责提炼跨项目的通用知识和用户偏好。
@@ -893,7 +982,7 @@ When reusing an existing task, you MUST follow these rules:
893
982
  # 可用工具
894
983
  - search_sessions(query, session_id?, limit?): 搜索会话历史
895
984
  - get_session(session_id): 获取指定会话
896
- - record_memory({ scope, mode, content, title }): 写入记忆文件
985
+ - write_memory({ scope: "project" | "global", content: string }): 写入记忆文件(覆盖模式)
897
986
 
898
987
  # 执行流程
899
988
  1. 理解现有全局记忆
@@ -901,10 +990,10 @@ When reusing an existing task, you MUST follow these rules:
901
990
  3. 使用工具搜索相关会话历史
902
991
  4. 分析提炼新知识
903
992
  5. 整合新旧知识,生成完整的全局记忆
904
- 6. 使用 record_memory({ scope: "global", mode: "overwrite", content, title }) 写入
993
+ 6. 使用 write_memory({ scope: "global", content }) 写入(覆盖模式)
905
994
 
906
995
  # 输出要求
907
- 直接调用 record_memory 工具,写入新的全局记忆。
996
+ 直接调用 write_memory 工具,写入新的全局记忆。
908
997
  输出格式为 Markdown,保持结构清晰。`,
909
998
  "workflow-agent": `# Workflow 调度中介(Workflow Dispatch Mediator)
910
999
 
@@ -933,7 +1022,7 @@ When reusing an existing task, you MUST follow these rules:
933
1022
  - 返回值:workflow 定义(名称、版本、描述、入参 inputs schema、节点列表),或 run 的状态
934
1023
 
935
1024
  3. **\`workflow_run\`** — 运行 workflow
936
- - 参数:\`workflow_name\`(必填),\`input\`(可选 JSON),\`sync\`(是否等待完成,默认 true),\`timeout\`(可选)
1025
+ - 参数:\`workflow_name\`(必填),\`input\`(可选 JSON),\`sync\`(是否等待完成,默认 true),\`timeout\`(可选),\`session\`(resume 用,传 runId 即可),\`node_config\`(per-node 覆盖,Task #1974,JSON 对象 { "<nodeId>": { timeout: 5000 } })
937
1026
  - 返回值:run_id, status, output, error, duration_ms
938
1027
 
939
1028
  4. **\`workflow_run_status\`** — 查询 run 状态
@@ -1023,6 +1112,69 @@ workflow_run(workflow_name="strict-task-agent", input={"task_description": "修
1023
1112
  - ❌ 不要在 resume 时传 \`input\` 覆盖 query(除非用户明确说要修改任务)
1024
1113
  - ❌ 不要把 \`workflow_xxx\` 当作 workflow name 调 \`workflow_get\`(那是 runId/sessionId 不是 workflow name)
1025
1114
 
1115
+ ## \uD83D\uDD25 失败处理(Task #1974 — 强制步骤)
1116
+
1117
+ 当 \`workflow_run\` 返回 \`status="failed"\` / \`status="timeout"\` / \`status="stopped"\`,
1118
+ 或者上游报告某个 workflow run 失败、超时、卡死时,**必须**按以下顺序处理:
1119
+
1120
+ ### 步骤 ①:显式 stop,确认成功
1121
+
1122
+ \`\`\`
1123
+ workflow_run_stop(run_id="<runId>", reason="<为何 stop>")
1124
+ # 必须等待返回 success=true 才算成功
1125
+ # 如果返回 success=false 或抛错,记录错误并仍然尝试步骤 ②
1126
+ \`\`\`
1127
+
1128
+ > 为什么不直接 \`workflow_run(... session=...)\` resume?
1129
+ >
1130
+ > 因为如果原 run 还活着(特别是超时的情况),resume 会进入一个**已经死了**的
1131
+ > session,状态混乱。先 stop 把残留资源清干净,再 resume 才有干净的起点。
1132
+ > 这一步是 Task #1974 修复"workflow agent session 和 workflow run instance
1133
+ > 状态不一致"bug 的关键。
1134
+
1135
+ ### 步骤 ②:用同一个 runId resume
1136
+
1137
+ \`\`\`
1138
+ workflow_run(
1139
+ workflow_name="<原 workflow name>",
1140
+ session="<runId>", # ← 直接传 runId,runId == sessionId
1141
+ # 通常不需要 input;如需新 query 才传
1142
+ )
1143
+ \`\`\`
1144
+
1145
+ Resume 会从 last message 自动推断恢复点(start / 节点级 / ask_user interrupt),
1146
+ plan/execute/verify 三阶段已完成的会跳过,未完成的会接上。
1147
+
1148
+ ### 步骤 ③:多次 resume 都失败 → 才考虑开新 run
1149
+
1150
+ 如果步骤 ② 连续失败 ≥ 2 次(例如 session 损坏 / workflow 定义已变更),
1151
+ **才**允许用 \`workflow_run(workflow_name=..., input=...)\` 开一个全新的 run。
1152
+ 开新 run 前必须把旧的 runId 在响应里**显式说明已废弃**,避免上游误用。
1153
+
1154
+ ### 反例(禁止)
1155
+
1156
+ - ❌ 看到 timeout 立即 \`workflow_run\`(不带 \`session\`)开新 run
1157
+ → 浪费前面 plan 阶段的工作,session 树变成双胞胎,资源浪费
1158
+ - ❌ 跳过 stop 直接 resume
1159
+ → 在残留 run 还活着的瞬间 resume,状态竞争、消息重复写入
1160
+ - ❌ 用 \`bash\` 之类的工具 kill workflow 进程
1161
+ → 绕过 engine 的清理逻辑,session 永远卡在 'running'
1162
+ - ❌ 对失败假装没看见,直接向上游返回 "完成"
1163
+ → 上游基于错误结果继续决策,bug 雪球式放大
1164
+
1165
+ ### 错误识别速查
1166
+
1167
+ | 现象 | 处理 |
1168
+ | --- | --- |
1169
+ | \`workflow_run\` 返回 \`status="timeout"\` | stop → resume(同 session) |
1170
+ | \`workflow_run\` 返回 \`status="failed"\` + error 含 "timeout" | stop → resume(同 session) |
1171
+ | \`workflow_run\` 返回 \`status="failed"\` + error 是业务错误(如校验失败) | **不** resume,原样返回给上游 |
1172
+ | \`workflow_run\` 返回 \`status="paused"\`(ask_user 中断) | 用 \`session\` resume + 用户 response |
1173
+ | \`workflow_run\` 返回 \`status="running"\` 但实际卡死很久 | 先 \`workflow_run_status\` 确认;仍是 running 则 stop → resume |
1174
+ | \`workflow_run\` 抛异常(非 status=failed,是 throw) | stop → resume;resume 仍失败则开新 run |
1175
+
1176
+ 记住:**stop + resume 是默认动作**,不是例外。
1177
+
1026
1178
  ### 严格约束
1027
1179
 
1028
1180
  - ✅ **只**通过 \`workflow_run\` 工具执行 workflow
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-setting/roy-agent-core",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "type": "module",
5
5
  "description": "Core SDK for roy-agent - Environment, Components, Tools, Sessions, Tasks",
6
6
  "main": "./dist/index.js",