@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.
- package/dist/env/agent/index.js +3 -3
- package/dist/env/event-source/index.js +3 -3
- package/dist/env/index.js +15 -14
- package/dist/env/llm/index.js +2 -2
- package/dist/env/prompt/index.js +2 -2
- package/dist/env/task/delegate/index.js +2 -2
- package/dist/env/task/index.js +4 -3
- package/dist/env/task/plugins/index.js +2 -2
- package/dist/env/tool/built-in/index.js +7 -1
- package/dist/env/tool/index.js +3 -2
- package/dist/env/workflow/engine/index.js +3 -3
- package/dist/env/workflow/index.js +5 -5
- package/dist/env/workflow/nodes/index.js +1 -1
- package/dist/env/workflow/tools/index.js +1 -1
- package/dist/index.js +18 -17
- package/dist/shared/@ai-setting/{roy-agent-core-fg5eaht3.js → roy-agent-core-155408xq.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-q79q54x2.js → roy-agent-core-45tvcwwz.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-j7jeqxhd.js → roy-agent-core-65qs21kf.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-a8pm6hya.js → roy-agent-core-6kygfd9x.js} +9 -0
- package/dist/shared/@ai-setting/{roy-agent-core-8cezq5x9.js → roy-agent-core-6ve6tsm5.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-415rxkzy.js → roy-agent-core-78m47x1d.js} +56 -28
- package/dist/shared/@ai-setting/{roy-agent-core-mnc0hy7j.js → roy-agent-core-7afcdb2m.js} +17 -6
- package/dist/shared/@ai-setting/{roy-agent-core-84ex7khq.js → roy-agent-core-8mqahsj5.js} +3 -3
- package/dist/shared/@ai-setting/roy-agent-core-amkqnyzy.js +145 -0
- package/dist/shared/@ai-setting/{roy-agent-core-vrn9qj8y.js → roy-agent-core-anhvbnrc.js} +20 -1
- package/dist/shared/@ai-setting/{roy-agent-core-9gde0s9d.js → roy-agent-core-ba6243hr.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-2vhsccvz.js → roy-agent-core-caevk7xd.js} +10 -0
- package/dist/shared/@ai-setting/{roy-agent-core-skfr9wjk.js → roy-agent-core-g7hfkszj.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-84aqc5c0.js → roy-agent-core-pr7f94gn.js} +15 -1
- package/dist/shared/@ai-setting/{roy-agent-core-npkwftxj.js → roy-agent-core-r3209bcd.js} +5 -1
- package/dist/shared/@ai-setting/{roy-agent-core-q8n1s1pb.js → roy-agent-core-vf72n6qn.js} +4 -1
- package/dist/shared/@ai-setting/{roy-agent-core-txk4gcwm.js → roy-agent-core-xnga0ksx.js} +9 -4
- package/dist/shared/@ai-setting/{roy-agent-core-fzkfkd28.js → roy-agent-core-xxfkvqqh.js} +57 -19
- package/dist/shared/@ai-setting/{roy-agent-core-57bmm0a1.js → roy-agent-core-y1m7c2v7.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-8cwb4fmp.js → roy-agent-core-z9m38ytb.js} +178 -26
- 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-
|
|
3
|
+
} from "./roy-agent-core-65qs21kf.js";
|
|
4
4
|
import {
|
|
5
5
|
truncateOutputInline
|
|
6
|
-
} from "./roy-agent-core-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
583
|
-
|
|
584
|
-
|
|
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
|
-
|
|
834
|
-
|
|
835
|
-
for (const toolCall of
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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-
|
|
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: `你是
|
|
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
|
-
- **名称**:
|
|
21
|
+
- **名称**: {{agent_name}}(接待员)
|
|
12
22
|
- **角色**: 入口 AI 助手,分析用户请求并将其委托给合适的子智能体执行
|
|
13
23
|
- **个性**: 友好、善于分析、高效、简洁
|
|
14
24
|
|
|
15
25
|
## 核心使命
|
|
16
26
|
|
|
17
|
-
你是
|
|
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
|
-
全功能的
|
|
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 通过返回的 \`
|
|
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
|
|
666
|
-
│ -
|
|
667
|
-
│
|
|
754
|
+
│ 3. EXECUTE │
|
|
755
|
+
│ - 利用各种工具和能力,skill,workflow等来解决任务达到任务描述 │
|
|
756
|
+
│ 和任务目标要求 │
|
|
668
757
|
│ │
|
|
669
|
-
│
|
|
670
|
-
│ -
|
|
671
|
-
│
|
|
672
|
-
│ -
|
|
758
|
+
│ Long-running work guidance: │
|
|
759
|
+
│ - 超过 5 分钟的复杂任务:用 \`task_operation_create\` │
|
|
760
|
+
│ 记录里程碑,让用户能看到实时进展 │
|
|
761
|
+
│ - 多个独立子任务可并行:用 \`bash &\` 后台启动或 │
|
|
762
|
+
│ 拆分成多个并行 ReAct 步骤 │
|
|
673
763
|
│ │
|
|
674
|
-
│ ⚠️ Note:
|
|
675
|
-
│
|
|
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
|
-
-
|
|
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. 使用
|
|
945
|
+
6. 使用 write_memory({ scope: "project", content }) 写入(覆盖模式)
|
|
857
946
|
|
|
858
947
|
# 输出要求
|
|
859
|
-
直接调用
|
|
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
|
-
-
|
|
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. 使用
|
|
993
|
+
6. 使用 write_memory({ scope: "global", content }) 写入(覆盖模式)
|
|
905
994
|
|
|
906
995
|
# 输出要求
|
|
907
|
-
直接调用
|
|
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
|