@ai-setting/roy-agent-core 1.5.15-test → 1.5.17-beta.1
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/config/index.d.ts +1250 -0
- package/dist/config/index.js +32 -0
- package/dist/env/agent/index.d.ts +2279 -0
- package/dist/env/agent/index.js +24 -0
- package/dist/env/commands/index.d.ts +1131 -0
- package/dist/env/commands/index.js +14 -0
- package/dist/env/debug/formatters/index.d.ts +236 -0
- package/dist/env/debug/formatters/index.js +11 -0
- package/dist/env/debug/index.d.ts +1652 -0
- package/dist/env/debug/index.js +26 -0
- package/dist/env/hook/index.d.ts +279 -0
- package/dist/env/hook/index.js +29 -0
- package/dist/env/index.d.ts +3481 -0
- package/dist/env/index.js +82 -0
- package/dist/env/llm/index.d.ts +1760 -0
- package/dist/env/llm/index.js +40 -0
- package/dist/env/log-trace/index.d.ts +1574 -0
- package/dist/env/log-trace/index.js +83 -0
- package/dist/env/mcp/index.d.ts +1331 -0
- package/dist/env/mcp/index.js +39 -0
- package/dist/env/mcp/tool/index.d.ts +183 -0
- package/dist/env/mcp/tool/index.js +14 -0
- package/dist/env/memory/built-in/index.d.ts +232 -0
- package/dist/env/memory/built-in/index.js +11 -0
- package/dist/env/memory/index.d.ts +1799 -0
- package/dist/env/memory/index.js +56 -0
- package/dist/env/memory/plugin/index.d.ts +747 -0
- package/dist/env/memory/plugin/index.js +36 -0
- package/dist/env/prompt/index.d.ts +1164 -0
- package/dist/env/prompt/index.js +20 -0
- package/dist/env/session/index.d.ts +1908 -0
- package/dist/env/session/index.js +25 -0
- package/dist/env/session/storage/index.d.ts +564 -0
- package/dist/env/session/storage/index.js +18 -0
- package/dist/env/skill/index.d.ts +1266 -0
- package/dist/env/skill/index.js +34 -0
- package/dist/env/skill/tool/index.d.ts +193 -0
- package/dist/env/skill/tool/index.js +9 -0
- package/dist/env/task/delegate/index.d.ts +1612 -0
- package/dist/env/task/delegate/index.js +18 -0
- package/dist/env/task/events/index.d.ts +171 -0
- package/dist/env/task/events/index.js +7 -0
- package/dist/env/task/hooks/index.d.ts +624 -0
- package/dist/env/task/hooks/index.js +7 -0
- package/dist/env/task/index.d.ts +1553 -0
- package/dist/env/task/index.js +34 -0
- package/dist/env/task/plugins/index.d.ts +466 -0
- package/dist/env/task/plugins/index.js +23 -0
- package/dist/env/task/storage/index.d.ts +241 -0
- package/dist/env/task/storage/index.js +14 -0
- package/dist/env/task/tools/index.d.ts +1485 -0
- package/dist/env/task/tools/index.js +17 -0
- package/dist/env/task/tools/operation/index.d.ts +1484 -0
- package/dist/env/task/tools/operation/index.js +15 -0
- package/dist/env/tool/built-in/index.d.ts +218 -0
- package/dist/env/tool/built-in/index.js +25 -0
- package/dist/env/tool/index.d.ts +1396 -0
- package/dist/env/tool/index.js +39 -0
- package/dist/env/workflow/decorators/index.d.ts +2161 -0
- package/dist/env/workflow/decorators/index.js +27 -0
- package/dist/env/workflow/engine/index.d.ts +3453 -0
- package/dist/env/workflow/engine/index.js +28 -0
- package/dist/env/workflow/index.d.ts +3546 -0
- package/dist/env/workflow/index.js +136 -0
- package/dist/env/workflow/nodes/index.d.ts +2092 -0
- package/dist/env/workflow/nodes/index.js +19 -0
- package/dist/env/workflow/service/index.d.ts +227 -0
- package/dist/env/workflow/service/index.js +13 -0
- package/dist/env/workflow/storage/index.d.ts +165 -0
- package/dist/env/workflow/storage/index.js +27 -0
- package/dist/env/workflow/tools/index.d.ts +416 -0
- package/dist/env/workflow/tools/index.js +159 -0
- package/dist/env/workflow/types/index.d.ts +2255 -0
- package/dist/env/workflow/types/index.js +98 -0
- package/dist/env/workflow/utils/index.d.ts +2031 -0
- package/dist/env/workflow/utils/index.js +637 -0
- package/dist/index.d.ts +7858 -0
- package/dist/index.js +399 -0
- package/dist/shared/@ai-setting/roy-agent-core-0rtxwr28.js +258 -0
- package/dist/shared/@ai-setting/roy-agent-core-0vbdz0x7.js +36 -0
- package/dist/shared/@ai-setting/roy-agent-core-1akcqxj9.js +349 -0
- package/dist/shared/@ai-setting/roy-agent-core-1ce3fqrk.js +117 -0
- package/dist/shared/@ai-setting/roy-agent-core-2dhd60aw.js +11 -0
- package/dist/shared/@ai-setting/roy-agent-core-3jywqmdd.js +393 -0
- package/dist/shared/@ai-setting/roy-agent-core-3rr5k71j.js +200 -0
- package/dist/shared/@ai-setting/roy-agent-core-44hnfb02.js +299 -0
- package/dist/shared/@ai-setting/roy-agent-core-4t40mkpv.js +206 -0
- package/dist/shared/@ai-setting/roy-agent-core-4txzpsbt.js +393 -0
- package/dist/shared/@ai-setting/roy-agent-core-5x94xmt6.js +350 -0
- package/dist/shared/@ai-setting/roy-agent-core-69jskqjg.js +180 -0
- package/dist/shared/@ai-setting/roy-agent-core-6kvtahqv.js +408 -0
- package/dist/shared/@ai-setting/roy-agent-core-7fgf85wc.js +284 -0
- package/dist/shared/@ai-setting/roy-agent-core-81w1963m.js +762 -0
- package/dist/shared/@ai-setting/roy-agent-core-8gxth0eh.js +10 -0
- package/dist/shared/@ai-setting/roy-agent-core-92z6t4he.js +14 -0
- package/dist/shared/@ai-setting/roy-agent-core-93zfb3r1.js +922 -0
- package/dist/shared/@ai-setting/roy-agent-core-9yxb3ty9.js +15 -0
- package/dist/shared/@ai-setting/roy-agent-core-b0x5dda6.js +1130 -0
- package/dist/shared/@ai-setting/roy-agent-core-bcbqy27c.js +14 -0
- package/dist/shared/@ai-setting/roy-agent-core-bvr1761x.js +653 -0
- package/dist/shared/@ai-setting/roy-agent-core-ctdhjv68.js +93 -0
- package/dist/shared/@ai-setting/roy-agent-core-d7cyjkf7.js +872 -0
- package/dist/shared/@ai-setting/roy-agent-core-dh9d7a3m.js +11 -0
- package/dist/shared/@ai-setting/roy-agent-core-e25xkv53.js +64 -0
- package/dist/shared/@ai-setting/roy-agent-core-eajcvp4e.js +378 -0
- package/dist/shared/@ai-setting/roy-agent-core-f7q2x5z6.js +492 -0
- package/dist/shared/@ai-setting/roy-agent-core-fs0mn2jk.js +52 -0
- package/dist/shared/@ai-setting/roy-agent-core-g1s2h0e5.js +171 -0
- package/dist/shared/@ai-setting/roy-agent-core-g99pxzn5.js +862 -0
- package/dist/shared/@ai-setting/roy-agent-core-gbqcyegm.js +1387 -0
- package/dist/shared/@ai-setting/roy-agent-core-gjq1yk68.js +208 -0
- package/dist/shared/@ai-setting/roy-agent-core-gq20wsgv.js +139 -0
- package/dist/shared/@ai-setting/roy-agent-core-gwc4h96n.js +534 -0
- package/dist/shared/@ai-setting/roy-agent-core-jfh9q2qh.js +204 -0
- package/dist/shared/@ai-setting/roy-agent-core-jvatggbb.js +603 -0
- package/dist/shared/@ai-setting/roy-agent-core-kkbwepqb.js +97 -0
- package/dist/shared/@ai-setting/roy-agent-core-pjr12nnd.js +587 -0
- package/dist/shared/@ai-setting/roy-agent-core-psv4v63c.js +176 -0
- package/dist/shared/@ai-setting/roy-agent-core-psvxt4c9.js +60 -0
- package/dist/shared/@ai-setting/roy-agent-core-qqceba6k.js +442 -0
- package/dist/shared/@ai-setting/roy-agent-core-qxhq8ven.js +57 -0
- package/dist/shared/@ai-setting/roy-agent-core-qxnbvgwe.js +66 -0
- package/dist/shared/@ai-setting/roy-agent-core-r9ezzemr.js +10 -0
- package/dist/shared/@ai-setting/roy-agent-core-rhmtwnw1.js +267 -0
- package/dist/shared/@ai-setting/roy-agent-core-rvv6ydff.js +584 -0
- package/dist/shared/@ai-setting/roy-agent-core-rvxg1wps.js +102 -0
- package/dist/shared/@ai-setting/roy-agent-core-satmq6sh.js +549 -0
- package/dist/shared/@ai-setting/roy-agent-core-sx7wsvnn.js +15 -0
- package/dist/shared/@ai-setting/roy-agent-core-t94ktchq.js +213 -0
- package/dist/shared/@ai-setting/roy-agent-core-vf215qfv.js +812 -0
- package/dist/shared/@ai-setting/roy-agent-core-vkz81f7v.js +1316 -0
- package/dist/shared/@ai-setting/roy-agent-core-vn2bc59q.js +1205 -0
- package/dist/shared/@ai-setting/roy-agent-core-wa1kzqky.js +328 -0
- package/dist/shared/@ai-setting/roy-agent-core-wft9ra24.js +20 -0
- package/dist/shared/@ai-setting/roy-agent-core-wrcy0h6z.js +2098 -0
- package/dist/shared/@ai-setting/roy-agent-core-xq8hhqb8.js +419 -0
- package/dist/shared/@ai-setting/roy-agent-core-xs5rsgat.js +368 -0
- package/dist/shared/@ai-setting/roy-agent-core-zbkpc41z.js +377 -0
- package/dist/shared/@ai-setting/roy-agent-core-zgypchmt.js +172 -0
- package/dist/shared/@ai-setting/roy-agent-core-zpn0bqa8.js +103 -0
- package/package.json +29 -8
|
@@ -0,0 +1,812 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TaskHookPoints
|
|
3
|
+
} from "./roy-agent-core-92z6t4he.js";
|
|
4
|
+
import {
|
|
5
|
+
globalHookManager
|
|
6
|
+
} from "./roy-agent-core-gjq1yk68.js";
|
|
7
|
+
import {
|
|
8
|
+
createLogger,
|
|
9
|
+
init_logger
|
|
10
|
+
} from "./roy-agent-core-44hnfb02.js";
|
|
11
|
+
|
|
12
|
+
// src/env/task/delegate/delegate-tool.ts
|
|
13
|
+
init_logger();
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
var logger = createLogger("task:delegate");
|
|
16
|
+
var BackgroundTaskEventTypes = {
|
|
17
|
+
STARTED: "task.background.started",
|
|
18
|
+
PROGRESS: "task.background.progress",
|
|
19
|
+
COMPLETED: "task.background.completed",
|
|
20
|
+
FAILED: "task.background.failed",
|
|
21
|
+
TIMEOUT: "task.background.timeout",
|
|
22
|
+
STOPPED: "task.background.stopped"
|
|
23
|
+
};
|
|
24
|
+
var builtInSubAgents = [
|
|
25
|
+
{
|
|
26
|
+
id: "general",
|
|
27
|
+
name: "general",
|
|
28
|
+
mode: "subagent",
|
|
29
|
+
description: "General-purpose agent for researching complex questions and executing multi-step tasks.",
|
|
30
|
+
promptOverride: `You are a subagent created by the main agent to handle a specific task.
|
|
31
|
+
|
|
32
|
+
## Your Role
|
|
33
|
+
- You were created to handle: {task_description}
|
|
34
|
+
- Complete this task. That's your entire purpose.
|
|
35
|
+
- You are NOT the main agent. Don't try to be.
|
|
36
|
+
|
|
37
|
+
## Task Context Awareness (Required Behavior)
|
|
38
|
+
|
|
39
|
+
**IMPORTANT: Before starting any work, you MUST gather task context to avoid working with outdated or missing information.**
|
|
40
|
+
|
|
41
|
+
1. **Read task details first**: Use \`task_get\` to read the task's:
|
|
42
|
+
- \`description\`: Detailed description of what needs to be done
|
|
43
|
+
- \`goals_and_expected_deliverables\`: Clear success criteria and expected outputs
|
|
44
|
+
- \`current_status\`: Current work progress
|
|
45
|
+
- \`parent_task_id\`: If exists, this is a sub-task
|
|
46
|
+
|
|
47
|
+
2. **Read recent operations**: Use \`task_operation_list\` to get the last ~15 operation records
|
|
48
|
+
- These provide history, progress, decisions, and context from previous work
|
|
49
|
+
|
|
50
|
+
3. **Read parent task context** (if \`parent_task_id\` exists):
|
|
51
|
+
- Use \`task_get\` to read the parent task's description and goals
|
|
52
|
+
- Use \`task_operation_list\` to get parent's recent operations
|
|
53
|
+
- This forms the overall task background and ensures alignment
|
|
54
|
+
|
|
55
|
+
**Why this matters**:
|
|
56
|
+
- The main agent may have made critical decisions recorded in operations
|
|
57
|
+
- Parent task goals provide the broader context for your sub-task
|
|
58
|
+
- Without this context, you risk working on wrong/outdated goals
|
|
59
|
+
|
|
60
|
+
## Rules
|
|
61
|
+
1. **Gather context first** - Always read task details and operations before starting
|
|
62
|
+
2. **Stay focused** - Do your assigned task, nothing else
|
|
63
|
+
3. **Complete the task** - Your final message will be automatically reported to the main agent
|
|
64
|
+
4. **Don't initiate** - No heartbeats, no proactive actions, no side quests
|
|
65
|
+
5. **Be ephemeral** - You may be terminated after task completion. That's fine.
|
|
66
|
+
6. **No nested delegation** - Do NOT use delegate_task or stop_task tools. Complete the task yourself.
|
|
67
|
+
|
|
68
|
+
## Execution
|
|
69
|
+
- Use the available tools to complete the task
|
|
70
|
+
- If you need more information, ask the main agent through the result
|
|
71
|
+
- Return a clear summary of what you did and the results`,
|
|
72
|
+
deniedTools: ["delegate_task", "stop_task"]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: "explore",
|
|
76
|
+
name: "explore",
|
|
77
|
+
mode: "subagent",
|
|
78
|
+
description: "Fast agent specialized for exploring codebases, finding files, and searching for patterns.",
|
|
79
|
+
allowedTools: ["glob", "grep", "read", "bash"],
|
|
80
|
+
deniedTools: ["delegate_task", "stop_task"]
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: "file_agent",
|
|
84
|
+
name: "file_agent",
|
|
85
|
+
mode: "subagent",
|
|
86
|
+
description: "File operation expert, skilled at reading, writing, searching and organizing files.",
|
|
87
|
+
allowedTools: ["file_read", "file_write", "file_glob", "grep", "glob", "read"],
|
|
88
|
+
deniedTools: ["delegate_task", "stop_task"]
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "web_search_agent",
|
|
92
|
+
name: "web_search_agent",
|
|
93
|
+
mode: "subagent",
|
|
94
|
+
description: "Web search expert, using Exa search engine to get latest information.",
|
|
95
|
+
allowedTools: ["exa_web_search_exa"],
|
|
96
|
+
deniedTools: ["delegate_task", "stop_task"]
|
|
97
|
+
}
|
|
98
|
+
];
|
|
99
|
+
function getSubAgentSpec(id) {
|
|
100
|
+
return builtInSubAgents.find((agent) => agent.id === id);
|
|
101
|
+
}
|
|
102
|
+
function getSubAgentToolDescription() {
|
|
103
|
+
return builtInSubAgents.map((agent) => `- ${agent.id}: ${agent.description}`).join(`
|
|
104
|
+
`);
|
|
105
|
+
}
|
|
106
|
+
function ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgent, deniedTools) {
|
|
107
|
+
let agentInstance = agentComponent.getAgent(subagentType);
|
|
108
|
+
if (!agentInstance) {
|
|
109
|
+
const agentConfig = {
|
|
110
|
+
type: "sub",
|
|
111
|
+
systemPrompt: basePrompt
|
|
112
|
+
};
|
|
113
|
+
if (subAgent?.allowedTools && subAgent.allowedTools.length > 0) {
|
|
114
|
+
agentConfig.allowedTools = subAgent.allowedTools;
|
|
115
|
+
}
|
|
116
|
+
if (deniedTools.length > 0) {
|
|
117
|
+
agentConfig.deniedTools = deniedTools;
|
|
118
|
+
}
|
|
119
|
+
agentInstance = agentComponent.registerAgent(subagentType, agentConfig);
|
|
120
|
+
logger.debug(`[delegate] Registered subagent: ${subagentType}`);
|
|
121
|
+
}
|
|
122
|
+
return agentInstance;
|
|
123
|
+
}
|
|
124
|
+
var DelegateToolParameters = z.object({
|
|
125
|
+
description: z.string().describe("A short (3-5 words) description of the task"),
|
|
126
|
+
prompt: z.string().describe("The task for the agent to perform"),
|
|
127
|
+
subagent_type: z.string().describe("The type of specialized agent to use for this task").default("general"),
|
|
128
|
+
background: z.boolean().describe("Whether to run the task in background. If true, returns immediately and notifies when complete (default: false)").default(false),
|
|
129
|
+
timeout: z.number().describe("Task timeout in milliseconds. If set, task will be terminated after timeout (optional)").optional(),
|
|
130
|
+
cleanup: z.enum(["delete", "keep"]).describe("Whether to delete sub session after completion. 'delete' removes the session, 'keep' retains it (default: keep)").default("keep").optional(),
|
|
131
|
+
task_id: z.number().describe("Optional task ID to associate with this delegate task, for tracking in operation records").optional(),
|
|
132
|
+
reason: z.string().describe("Brief reason for calling this tool (max 30 chars, e.g., 'Delegate refactor task')").optional()
|
|
133
|
+
});
|
|
134
|
+
var DEFAULT_TIMEOUT = 900000;
|
|
135
|
+
var PROGRESS_INTERVAL = 120000;
|
|
136
|
+
|
|
137
|
+
class BackgroundTaskManager {
|
|
138
|
+
env;
|
|
139
|
+
tasks = new Map;
|
|
140
|
+
abortControllers = new Map;
|
|
141
|
+
progressTimers = new Map;
|
|
142
|
+
constructor(env) {
|
|
143
|
+
this.env = env;
|
|
144
|
+
}
|
|
145
|
+
getSessionComponent() {
|
|
146
|
+
return this.env?.getComponent?.("session");
|
|
147
|
+
}
|
|
148
|
+
publishBackgroundEvent(type, payload, parentSessionId) {
|
|
149
|
+
if (this.env?.pushEnvEvent) {
|
|
150
|
+
this.env.pushEnvEvent({
|
|
151
|
+
type,
|
|
152
|
+
payload,
|
|
153
|
+
metadata: {
|
|
154
|
+
source: "task.background",
|
|
155
|
+
trigger_session_id: parentSessionId
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
logger.info(`[BackgroundTaskManager] Event published: ${type}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async createTask(options) {
|
|
162
|
+
const { parentSessionId, description, prompt, subagentType, timeout, cleanup, taskId } = options;
|
|
163
|
+
const taskIdGen = `task_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
|
|
164
|
+
const sessionComponent = this.getSessionComponent();
|
|
165
|
+
if (!sessionComponent) {
|
|
166
|
+
throw new Error("SessionComponent not found");
|
|
167
|
+
}
|
|
168
|
+
const parentSession = await sessionComponent.get(parentSessionId);
|
|
169
|
+
if (!parentSession) {
|
|
170
|
+
throw new Error(`Parent session not found: ${parentSessionId}`);
|
|
171
|
+
}
|
|
172
|
+
const metadata = {
|
|
173
|
+
subagent_type: subagentType,
|
|
174
|
+
created_by: "subagent",
|
|
175
|
+
task_description: description
|
|
176
|
+
};
|
|
177
|
+
if (taskId) {
|
|
178
|
+
metadata.task_id = taskId;
|
|
179
|
+
}
|
|
180
|
+
const subSession = await sessionComponent.create({
|
|
181
|
+
title: `${description} (@${subagentType} subagent)`,
|
|
182
|
+
metadata
|
|
183
|
+
});
|
|
184
|
+
if (!subSession) {
|
|
185
|
+
throw new Error("Failed to create sub-session");
|
|
186
|
+
}
|
|
187
|
+
const abortController = new AbortController;
|
|
188
|
+
const task = {
|
|
189
|
+
id: taskIdGen,
|
|
190
|
+
subSessionId: subSession.id,
|
|
191
|
+
parentSessionId,
|
|
192
|
+
description,
|
|
193
|
+
subagentType,
|
|
194
|
+
status: "pending",
|
|
195
|
+
createdAt: Date.now(),
|
|
196
|
+
abortController,
|
|
197
|
+
taskId
|
|
198
|
+
};
|
|
199
|
+
this.tasks.set(taskIdGen, task);
|
|
200
|
+
this.abortControllers.set(taskIdGen, abortController);
|
|
201
|
+
const startedPayload = {
|
|
202
|
+
backgroundTaskId: taskIdGen,
|
|
203
|
+
subSessionId: subSession.id,
|
|
204
|
+
parentSessionId,
|
|
205
|
+
description,
|
|
206
|
+
subagentType,
|
|
207
|
+
associatedTaskId: taskId
|
|
208
|
+
};
|
|
209
|
+
this.publishBackgroundEvent(BackgroundTaskEventTypes.STARTED, startedPayload, parentSessionId);
|
|
210
|
+
this.executeTask(taskIdGen, prompt, timeout, cleanup, parentSessionId).catch((err) => {
|
|
211
|
+
logger.error(`[BackgroundTaskManager] executeTask unhandled rejection`, {
|
|
212
|
+
taskId: taskIdGen,
|
|
213
|
+
error: err instanceof Error ? err.message : String(err)
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
return { taskId: taskIdGen, subSessionId: subSession.id };
|
|
217
|
+
}
|
|
218
|
+
async executeTask(taskId, prompt, timeout, cleanup, parentSessionId) {
|
|
219
|
+
const task = this.tasks.get(taskId);
|
|
220
|
+
if (!task) {
|
|
221
|
+
logger.warn(`[BackgroundTaskManager] executeTask: Task not found`, { taskId });
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
task.status = "running";
|
|
225
|
+
task.startedAt = Date.now();
|
|
226
|
+
const timeoutMs = timeout || DEFAULT_TIMEOUT;
|
|
227
|
+
const abortController = this.abortControllers.get(taskId);
|
|
228
|
+
this.startProgressReporter(taskId, parentSessionId || task.parentSessionId);
|
|
229
|
+
try {
|
|
230
|
+
const sessionComponent = this.getSessionComponent();
|
|
231
|
+
const subSession = await sessionComponent.get(task.subSessionId);
|
|
232
|
+
if (!subSession) {
|
|
233
|
+
throw new Error(`Sub session not found: ${task.subSessionId}`);
|
|
234
|
+
}
|
|
235
|
+
const result = await this.executeWithAbort(subSession, prompt, timeoutMs, abortController?.signal);
|
|
236
|
+
if (abortController?.signal.aborted) {
|
|
237
|
+
logger.info(`[BackgroundTaskManager] Task was aborted`, { taskId });
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
task.status = "completed";
|
|
241
|
+
task.completedAt = Date.now();
|
|
242
|
+
task.result = result;
|
|
243
|
+
const executionTimeMs = task.completedAt - task.startedAt;
|
|
244
|
+
const completedPayload = {
|
|
245
|
+
backgroundTaskId: task.id,
|
|
246
|
+
subSessionId: task.subSessionId,
|
|
247
|
+
parentSessionId: parentSessionId || task.parentSessionId,
|
|
248
|
+
status: "completed",
|
|
249
|
+
result: task.result,
|
|
250
|
+
description: task.description,
|
|
251
|
+
executionTimeMs,
|
|
252
|
+
associatedTaskId: task.taskId
|
|
253
|
+
};
|
|
254
|
+
this.publishBackgroundEvent(BackgroundTaskEventTypes.COMPLETED, completedPayload, parentSessionId || task.parentSessionId);
|
|
255
|
+
logger.info(`[BackgroundTaskManager] Task completed successfully`, {
|
|
256
|
+
taskId,
|
|
257
|
+
executionTimeMs
|
|
258
|
+
});
|
|
259
|
+
} catch (error) {
|
|
260
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
261
|
+
const isStoppedError = errorMessage.toLowerCase().includes("stopped") || errorMessage.toLowerCase().includes("aborted");
|
|
262
|
+
const executionTimeMs = task.startedAt ? Date.now() - task.startedAt : 0;
|
|
263
|
+
if (isStoppedError) {
|
|
264
|
+
task.status = "stopped";
|
|
265
|
+
const stoppedPayload = {
|
|
266
|
+
backgroundTaskId: task.id,
|
|
267
|
+
subSessionId: task.subSessionId,
|
|
268
|
+
parentSessionId: parentSessionId || task.parentSessionId,
|
|
269
|
+
status: "stopped",
|
|
270
|
+
description: task.description,
|
|
271
|
+
error: errorMessage,
|
|
272
|
+
executionTimeMs,
|
|
273
|
+
associatedTaskId: task.taskId
|
|
274
|
+
};
|
|
275
|
+
this.publishBackgroundEvent(BackgroundTaskEventTypes.STOPPED, stoppedPayload, parentSessionId || task.parentSessionId);
|
|
276
|
+
} else if (errorMessage.includes("timeout")) {
|
|
277
|
+
task.status = "timeout";
|
|
278
|
+
const timeoutPayload = {
|
|
279
|
+
backgroundTaskId: task.id,
|
|
280
|
+
subSessionId: task.subSessionId,
|
|
281
|
+
parentSessionId: parentSessionId || task.parentSessionId,
|
|
282
|
+
status: "timeout",
|
|
283
|
+
description: task.description,
|
|
284
|
+
error: errorMessage,
|
|
285
|
+
executionTimeMs,
|
|
286
|
+
associatedTaskId: task.taskId
|
|
287
|
+
};
|
|
288
|
+
this.publishBackgroundEvent(BackgroundTaskEventTypes.TIMEOUT, timeoutPayload, parentSessionId || task.parentSessionId);
|
|
289
|
+
} else {
|
|
290
|
+
task.status = "failed";
|
|
291
|
+
const failedPayload = {
|
|
292
|
+
backgroundTaskId: task.id,
|
|
293
|
+
subSessionId: task.subSessionId,
|
|
294
|
+
parentSessionId: parentSessionId || task.parentSessionId,
|
|
295
|
+
status: "failed",
|
|
296
|
+
description: task.description,
|
|
297
|
+
error: errorMessage,
|
|
298
|
+
executionTimeMs,
|
|
299
|
+
associatedTaskId: task.taskId
|
|
300
|
+
};
|
|
301
|
+
this.publishBackgroundEvent(BackgroundTaskEventTypes.FAILED, failedPayload, parentSessionId || task.parentSessionId);
|
|
302
|
+
}
|
|
303
|
+
task.error = errorMessage;
|
|
304
|
+
task.completedAt = Date.now();
|
|
305
|
+
logger.error(`[BackgroundTaskManager] Task execution error`, {
|
|
306
|
+
taskId,
|
|
307
|
+
status: task.status,
|
|
308
|
+
error: errorMessage
|
|
309
|
+
});
|
|
310
|
+
} finally {
|
|
311
|
+
this.stopProgressReporter(taskId);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
startProgressReporter(taskId, parentSessionId) {
|
|
315
|
+
const timer = setInterval(() => {
|
|
316
|
+
const task = this.tasks.get(taskId);
|
|
317
|
+
if (!task || task.status !== "running") {
|
|
318
|
+
this.stopProgressReporter(taskId);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (task.startedAt) {
|
|
322
|
+
const elapsedMs = Date.now() - task.startedAt;
|
|
323
|
+
task.progress = Math.min(95, Math.floor(elapsedMs / PROGRESS_INTERVAL * 100));
|
|
324
|
+
}
|
|
325
|
+
const progressPayload = {
|
|
326
|
+
backgroundTaskId: taskId,
|
|
327
|
+
subSessionId: task.subSessionId,
|
|
328
|
+
parentSessionId,
|
|
329
|
+
status: task.status,
|
|
330
|
+
progress: task.progress
|
|
331
|
+
};
|
|
332
|
+
this.publishBackgroundEvent(BackgroundTaskEventTypes.PROGRESS, progressPayload, parentSessionId);
|
|
333
|
+
}, PROGRESS_INTERVAL);
|
|
334
|
+
this.progressTimers.set(taskId, timer);
|
|
335
|
+
}
|
|
336
|
+
stopProgressReporter(taskId) {
|
|
337
|
+
const timer = this.progressTimers.get(taskId);
|
|
338
|
+
if (timer) {
|
|
339
|
+
clearInterval(timer);
|
|
340
|
+
this.progressTimers.delete(taskId);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async executeWithAbort(subSession, prompt, timeoutMs, signal) {
|
|
344
|
+
return new Promise((resolve, reject) => {
|
|
345
|
+
const timer = setTimeout(() => {
|
|
346
|
+
reject(new Error(`Task execution timeout after ${timeoutMs}ms`));
|
|
347
|
+
}, timeoutMs);
|
|
348
|
+
signal?.addEventListener("abort", () => {
|
|
349
|
+
clearTimeout(timer);
|
|
350
|
+
reject(new Error("Task execution stopped"));
|
|
351
|
+
});
|
|
352
|
+
const metadata = subSession.info?.metadata || {};
|
|
353
|
+
const taskId = metadata.task_id;
|
|
354
|
+
const taskDescription = metadata.task_description || "";
|
|
355
|
+
const sessionId = subSession.id;
|
|
356
|
+
const subagentType = metadata.subagent_type || "general";
|
|
357
|
+
const subAgent = getSubAgentSpec(subagentType);
|
|
358
|
+
let basePrompt = subAgent?.promptOverride || `You are a subagent. Complete this task: {task_description}`;
|
|
359
|
+
const deniedTools = subAgent?.deniedTools || [];
|
|
360
|
+
let fullPrompt = basePrompt.replace(/{task_description}/g, taskDescription || "N/A");
|
|
361
|
+
fullPrompt += `
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
# Session Info
|
|
366
|
+
- task_id: ${taskId || "N/A"}
|
|
367
|
+
- session_id: ${sessionId}
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## 用户指令
|
|
372
|
+
${prompt}
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## 执行规范
|
|
377
|
+
- 使用可用工具完成任务
|
|
378
|
+
- 返回清晰的任务执行结果摘要
|
|
379
|
+
- 适时调用 task_operation_create 记录进展`;
|
|
380
|
+
const agentComponent = this.env?.getComponent?.("agent");
|
|
381
|
+
if (!agentComponent) {
|
|
382
|
+
clearTimeout(timer);
|
|
383
|
+
reject(new Error("AgentComponent not found"));
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgent, deniedTools);
|
|
387
|
+
this.env.handle_query?.(fullPrompt, {
|
|
388
|
+
sessionId,
|
|
389
|
+
deniedTools: deniedTools.length > 0 ? deniedTools : undefined,
|
|
390
|
+
agentType: subagentType
|
|
391
|
+
}).then((result) => {
|
|
392
|
+
clearTimeout(timer);
|
|
393
|
+
resolve(result);
|
|
394
|
+
}).catch((error) => {
|
|
395
|
+
clearTimeout(timer);
|
|
396
|
+
reject(error);
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
stopTask(taskId) {
|
|
401
|
+
const task = this.tasks.get(taskId);
|
|
402
|
+
if (!task) {
|
|
403
|
+
return { success: false, message: "Task not found" };
|
|
404
|
+
}
|
|
405
|
+
if (task.status === "completed" || task.status === "failed" || task.status === "stopped" || task.status === "timeout") {
|
|
406
|
+
return {
|
|
407
|
+
success: false,
|
|
408
|
+
task,
|
|
409
|
+
message: `Cannot stop task with status: ${task.status}`
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
task.status = "stopped";
|
|
413
|
+
task.abortController?.abort();
|
|
414
|
+
task.completedAt = Date.now();
|
|
415
|
+
const stoppedPayload = {
|
|
416
|
+
backgroundTaskId: task.id,
|
|
417
|
+
subSessionId: task.subSessionId,
|
|
418
|
+
parentSessionId: task.parentSessionId,
|
|
419
|
+
status: "stopped",
|
|
420
|
+
description: task.description,
|
|
421
|
+
error: "Task stopped by user",
|
|
422
|
+
executionTimeMs: task.startedAt ? task.completedAt - task.startedAt : 0,
|
|
423
|
+
associatedTaskId: task.taskId
|
|
424
|
+
};
|
|
425
|
+
this.publishBackgroundEvent(BackgroundTaskEventTypes.STOPPED, stoppedPayload, task.parentSessionId);
|
|
426
|
+
return { success: true, task, message: "Task has been stopped" };
|
|
427
|
+
}
|
|
428
|
+
getTask(taskId) {
|
|
429
|
+
return this.tasks.get(taskId);
|
|
430
|
+
}
|
|
431
|
+
listTasks() {
|
|
432
|
+
return Array.from(this.tasks.values());
|
|
433
|
+
}
|
|
434
|
+
dispose() {
|
|
435
|
+
for (const [taskId, controller] of this.abortControllers) {
|
|
436
|
+
controller.abort();
|
|
437
|
+
logger.debug(`[BackgroundTaskManager] Aborted task: ${taskId}`);
|
|
438
|
+
}
|
|
439
|
+
this.abortControllers.clear();
|
|
440
|
+
this.tasks.clear();
|
|
441
|
+
logger.info(`[BackgroundTaskManager] Disposed`);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function createDelegateTool(taskComponent) {
|
|
445
|
+
const env = taskComponent.env;
|
|
446
|
+
const backgroundTaskManager = new BackgroundTaskManager(env);
|
|
447
|
+
taskComponent._backgroundTaskManager = backgroundTaskManager;
|
|
448
|
+
const tool = {
|
|
449
|
+
name: "delegate_task",
|
|
450
|
+
description: `Launch a new sub-agent to handle complex, multistep tasks autonomously.
|
|
451
|
+
|
|
452
|
+
Available agent types:
|
|
453
|
+
${getSubAgentToolDescription()}
|
|
454
|
+
|
|
455
|
+
When using the delegate_task tool, you must specify a subagent_type parameter to select which agent type to use.
|
|
456
|
+
|
|
457
|
+
## When to use delegate_task:
|
|
458
|
+
- When you need to perform complex, multi-step tasks that require independent execution
|
|
459
|
+
- When you need to explore a codebase thoroughly (use "explore" subagent)
|
|
460
|
+
- When you need to run long-running tasks without blocking the main agent (use background=true)
|
|
461
|
+
|
|
462
|
+
## Parameters:
|
|
463
|
+
- **description**: A short (3-5 words) description of the task
|
|
464
|
+
- **prompt**: The task for the agent to perform
|
|
465
|
+
- **subagent_type**: The type of specialized agent to use (e.g., "general", "explore")
|
|
466
|
+
- **background**: Whether to run in background (default: false)
|
|
467
|
+
- **timeout**: Task timeout in milliseconds (optional)
|
|
468
|
+
- **task_id**: Optional task ID to associate with this delegate task
|
|
469
|
+
|
|
470
|
+
## Synchronous vs Background mode:
|
|
471
|
+
**Synchronous mode (default)**: Waits for subagent to complete and returns result directly
|
|
472
|
+
**Background mode (background=true)**: Returns immediately with "accepted" status, runs independently`,
|
|
473
|
+
parameters: DelegateToolParameters,
|
|
474
|
+
execute: async (args, ctx) => {
|
|
475
|
+
const startTime = Date.now();
|
|
476
|
+
const params = DelegateToolParameters.parse(args);
|
|
477
|
+
const { description, prompt, subagent_type = "general", background = false, timeout, cleanup, task_id, reason } = params;
|
|
478
|
+
const parentSessionId = ctx.session_id || "default";
|
|
479
|
+
logger.info(`[delegate_task] Called: description=${description}, subagent_type=${subagent_type}, background=${background}, task_id=${task_id}`);
|
|
480
|
+
const subAgent = getSubAgentSpec(subagent_type);
|
|
481
|
+
if (!subAgent) {
|
|
482
|
+
return {
|
|
483
|
+
success: false,
|
|
484
|
+
output: "",
|
|
485
|
+
error: `Unknown subagent type: ${subagent_type}`,
|
|
486
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
const tagService = taskComponent.getTagService();
|
|
490
|
+
let promptWithTaskInfo = prompt;
|
|
491
|
+
const delegateCtx = {
|
|
492
|
+
taskId: task_id,
|
|
493
|
+
prompt: promptWithTaskInfo,
|
|
494
|
+
subagentType: subagent_type,
|
|
495
|
+
background,
|
|
496
|
+
timeout,
|
|
497
|
+
cleanup,
|
|
498
|
+
reason,
|
|
499
|
+
tagService
|
|
500
|
+
};
|
|
501
|
+
const hookCtx = {
|
|
502
|
+
component: { name: "task", version: "1.0.0" },
|
|
503
|
+
data: delegateCtx,
|
|
504
|
+
metadata: { sessionId: parentSessionId },
|
|
505
|
+
phase: "before",
|
|
506
|
+
hookPoint: TaskHookPoints.DELEGATE_BEFORE
|
|
507
|
+
};
|
|
508
|
+
await globalHookManager.execute(TaskHookPoints.DELEGATE_BEFORE, hookCtx, { sessionId: parentSessionId });
|
|
509
|
+
promptWithTaskInfo = delegateCtx.prompt;
|
|
510
|
+
if (background) {
|
|
511
|
+
return await handleBackgroundTask(taskComponent, backgroundTaskManager, parentSessionId, description, promptWithTaskInfo, delegateCtx.subagentType, delegateCtx.timeout, delegateCtx.cleanup, delegateCtx.taskId);
|
|
512
|
+
} else {
|
|
513
|
+
return await handleSyncTask(taskComponent, parentSessionId, description, promptWithTaskInfo, delegateCtx.subagentType, delegateCtx.timeout, delegateCtx.taskId);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
return tool;
|
|
518
|
+
}
|
|
519
|
+
async function handleSyncTask(taskComponent, parentSessionId, description, prompt, subagentType, timeout, taskId) {
|
|
520
|
+
const startTime = Date.now();
|
|
521
|
+
try {
|
|
522
|
+
const sessionComponent = taskComponent.env?.getComponent?.("session");
|
|
523
|
+
if (!sessionComponent) {
|
|
524
|
+
return {
|
|
525
|
+
success: false,
|
|
526
|
+
output: "",
|
|
527
|
+
error: "SessionComponent not found",
|
|
528
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
const parentSession = await sessionComponent.get(parentSessionId);
|
|
532
|
+
if (!parentSession) {
|
|
533
|
+
return {
|
|
534
|
+
success: false,
|
|
535
|
+
output: "",
|
|
536
|
+
error: `Parent session not found: ${parentSessionId}`,
|
|
537
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
const metadata = {
|
|
541
|
+
subagent_type: subagentType,
|
|
542
|
+
created_by: "subagent",
|
|
543
|
+
task_description: description
|
|
544
|
+
};
|
|
545
|
+
if (taskId) {
|
|
546
|
+
metadata.task_id = taskId;
|
|
547
|
+
}
|
|
548
|
+
const subSession = await sessionComponent.create({
|
|
549
|
+
parentID: parentSessionId,
|
|
550
|
+
title: `${description} (@${subagentType} subagent)`,
|
|
551
|
+
metadata
|
|
552
|
+
});
|
|
553
|
+
if (!subSession) {
|
|
554
|
+
return {
|
|
555
|
+
success: false,
|
|
556
|
+
output: "",
|
|
557
|
+
error: "Failed to create sub-session",
|
|
558
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
const subAgent = getSubAgentSpec(subagentType);
|
|
562
|
+
let basePrompt = subAgent?.promptOverride || `You are a subagent. Complete this task: {task_description}`;
|
|
563
|
+
const deniedTools = subAgent?.deniedTools || [];
|
|
564
|
+
let fullPrompt = basePrompt.replace(/{task_description}/g, description || "N/A");
|
|
565
|
+
fullPrompt += `
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
569
|
+
# Session Info
|
|
570
|
+
- task_id: ${taskId || "N/A"}
|
|
571
|
+
- session_id: ${subSession.id}
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## 用户指令
|
|
576
|
+
${prompt}
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## 执行规范
|
|
581
|
+
- 使用可用工具完成任务
|
|
582
|
+
- 返回清晰的任务执行结果摘要
|
|
583
|
+
- 适时调用 task_operation_create 记录进展`;
|
|
584
|
+
const agentComponent = taskComponent.env?.getComponent?.("agent");
|
|
585
|
+
if (!agentComponent) {
|
|
586
|
+
return {
|
|
587
|
+
success: false,
|
|
588
|
+
output: "",
|
|
589
|
+
error: "AgentComponent not found",
|
|
590
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgent, deniedTools);
|
|
594
|
+
const timeoutMs = timeout || DEFAULT_TIMEOUT;
|
|
595
|
+
let result;
|
|
596
|
+
try {
|
|
597
|
+
result = await Promise.race([
|
|
598
|
+
taskComponent.env?.handle_query?.(fullPrompt, {
|
|
599
|
+
sessionId: subSession.id,
|
|
600
|
+
deniedTools: deniedTools.length > 0 ? deniedTools : undefined,
|
|
601
|
+
agentType: subagentType
|
|
602
|
+
}),
|
|
603
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`Task execution timeout after ${timeoutMs}ms`)), timeoutMs))
|
|
604
|
+
]);
|
|
605
|
+
} catch (error) {
|
|
606
|
+
result = error instanceof Error ? error.message : String(error);
|
|
607
|
+
}
|
|
608
|
+
await sessionComponent.addMessage(subSession.id, {
|
|
609
|
+
role: "assistant",
|
|
610
|
+
content: result
|
|
611
|
+
});
|
|
612
|
+
return {
|
|
613
|
+
success: true,
|
|
614
|
+
output: result + `
|
|
615
|
+
|
|
616
|
+
` + [
|
|
617
|
+
"<task_metadata>",
|
|
618
|
+
`session_id: ${subSession.id}`,
|
|
619
|
+
`subagent_type: ${subagentType}`,
|
|
620
|
+
"</task_metadata>"
|
|
621
|
+
].join(`
|
|
622
|
+
`),
|
|
623
|
+
metadata: {
|
|
624
|
+
execution_time_ms: Date.now() - startTime,
|
|
625
|
+
sessionId: subSession.id
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
} catch (error) {
|
|
629
|
+
return {
|
|
630
|
+
success: false,
|
|
631
|
+
output: "",
|
|
632
|
+
error: error instanceof Error ? error.message : String(error),
|
|
633
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
async function handleBackgroundTask(taskComponent, backgroundTaskManager, parentSessionId, description, prompt, subagentType, timeout, cleanup, taskId) {
|
|
638
|
+
const startTime = Date.now();
|
|
639
|
+
try {
|
|
640
|
+
let associatedTaskId = taskId;
|
|
641
|
+
if (!associatedTaskId) {
|
|
642
|
+
const newTask = await taskComponent.createTask({
|
|
643
|
+
title: description,
|
|
644
|
+
description: `Background task delegated to ${subagentType} subagent`,
|
|
645
|
+
priority: "medium",
|
|
646
|
+
goals_and_expected_deliverables: prompt,
|
|
647
|
+
sessionId: parentSessionId,
|
|
648
|
+
project_path: "unknown",
|
|
649
|
+
context: "unknown"
|
|
650
|
+
});
|
|
651
|
+
associatedTaskId = newTask.id;
|
|
652
|
+
await taskComponent.createOperation({
|
|
653
|
+
taskId: associatedTaskId,
|
|
654
|
+
sessionId: parentSessionId,
|
|
655
|
+
actionType: "create",
|
|
656
|
+
actionTitle: `Delegated to ${subagentType} subagent`,
|
|
657
|
+
actionDescription: `Background task started: ${description}`
|
|
658
|
+
});
|
|
659
|
+
} else {
|
|
660
|
+
await taskComponent.updateTask(associatedTaskId, {
|
|
661
|
+
status: "active",
|
|
662
|
+
current_status: `Running ${subagentType} subagent`
|
|
663
|
+
});
|
|
664
|
+
await taskComponent.createOperation({
|
|
665
|
+
taskId: associatedTaskId,
|
|
666
|
+
sessionId: parentSessionId,
|
|
667
|
+
actionType: "progress",
|
|
668
|
+
actionTitle: `Started ${subagentType} subagent`,
|
|
669
|
+
actionDescription: `Background task: ${description}`
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
const { taskId: bgTaskId, subSessionId } = await backgroundTaskManager.createTask({
|
|
673
|
+
parentSessionId,
|
|
674
|
+
description,
|
|
675
|
+
prompt,
|
|
676
|
+
subagentType,
|
|
677
|
+
timeout,
|
|
678
|
+
cleanup,
|
|
679
|
+
taskId: associatedTaskId
|
|
680
|
+
});
|
|
681
|
+
const output = [
|
|
682
|
+
`✅ Background task accepted`,
|
|
683
|
+
"",
|
|
684
|
+
`\uD83D\uDCCB Task ID: ${bgTaskId}`,
|
|
685
|
+
`\uD83D\uDCDD Description: ${description}`,
|
|
686
|
+
`\uD83E\uDD16 Sub-agent: ${subagentType}`,
|
|
687
|
+
associatedTaskId ? `\uD83D\uDCCC Associated Task: #${associatedTaskId}` : "",
|
|
688
|
+
`⏱️ Timeout: ${(timeout || DEFAULT_TIMEOUT) / 1000}s`,
|
|
689
|
+
"",
|
|
690
|
+
`Use stop_task with task_id="${bgTaskId}" to cancel this task.`
|
|
691
|
+
].filter(Boolean).join(`
|
|
692
|
+
`);
|
|
693
|
+
return {
|
|
694
|
+
success: true,
|
|
695
|
+
output,
|
|
696
|
+
metadata: {
|
|
697
|
+
execution_time_ms: Date.now() - startTime,
|
|
698
|
+
sessionId: subSessionId,
|
|
699
|
+
background: true,
|
|
700
|
+
status: "accepted",
|
|
701
|
+
task_id: associatedTaskId,
|
|
702
|
+
bgTaskId
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
} catch (error) {
|
|
706
|
+
return {
|
|
707
|
+
success: false,
|
|
708
|
+
output: "",
|
|
709
|
+
error: error instanceof Error ? error.message : String(error),
|
|
710
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
// src/env/task/delegate/stop-tool.ts
|
|
715
|
+
import { z as z2 } from "zod";
|
|
716
|
+
var StopTaskToolParameters = z2.object({
|
|
717
|
+
task_id: z2.string().describe("The ID of the background task to stop")
|
|
718
|
+
});
|
|
719
|
+
var STOP_TASK_DESCRIPTION = `Stop a running background task.
|
|
720
|
+
|
|
721
|
+
Use this tool to stop a background task that is currently running. This is useful when:
|
|
722
|
+
- The user wants to cancel a long-running task
|
|
723
|
+
- The task is taking too long and needs to be stopped
|
|
724
|
+
- The user wants to change direction and doesn't need the task result anymore
|
|
725
|
+
|
|
726
|
+
When stopped, the task will be terminated immediately and you will receive a confirmation.
|
|
727
|
+
|
|
728
|
+
Parameters:
|
|
729
|
+
- task_id: The ID of the background task to stop (obtained from the delegate_task response)`;
|
|
730
|
+
function formatDuration(ms) {
|
|
731
|
+
const seconds = Math.floor(ms / 1000);
|
|
732
|
+
const minutes = Math.floor(seconds / 60);
|
|
733
|
+
const hours = Math.floor(minutes / 60);
|
|
734
|
+
if (hours > 0) {
|
|
735
|
+
return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
|
|
736
|
+
} else if (minutes > 0) {
|
|
737
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
738
|
+
} else {
|
|
739
|
+
return `${seconds}s`;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
function createStopTool(taskManager) {
|
|
743
|
+
return {
|
|
744
|
+
name: "stop_task",
|
|
745
|
+
description: STOP_TASK_DESCRIPTION,
|
|
746
|
+
parameters: StopTaskToolParameters,
|
|
747
|
+
execute: async (args, ctx) => {
|
|
748
|
+
const startTime = Date.now();
|
|
749
|
+
const params = StopTaskToolParameters.parse(args);
|
|
750
|
+
const { task_id } = params;
|
|
751
|
+
const result = taskManager.stopTask(task_id);
|
|
752
|
+
if (result.success) {
|
|
753
|
+
const task = result.task;
|
|
754
|
+
const elapsedMs = task.startedAt ? Date.now() - task.startedAt : Date.now() - task.createdAt;
|
|
755
|
+
const output = [
|
|
756
|
+
`✅ Task stopped successfully`,
|
|
757
|
+
"",
|
|
758
|
+
`\uD83D\uDCCB Task ID: ${task_id}`,
|
|
759
|
+
`\uD83D\uDCDD Description: ${task.description}`,
|
|
760
|
+
`\uD83D\uDD04 Status: ${task.status} → stopped`,
|
|
761
|
+
`⏱️ Elapsed Time: ${formatDuration(elapsedMs)}`,
|
|
762
|
+
"",
|
|
763
|
+
result.message
|
|
764
|
+
].join(`
|
|
765
|
+
`);
|
|
766
|
+
return {
|
|
767
|
+
success: true,
|
|
768
|
+
output,
|
|
769
|
+
metadata: {
|
|
770
|
+
execution_time_ms: Date.now() - startTime,
|
|
771
|
+
task_id,
|
|
772
|
+
previous_status: task.status
|
|
773
|
+
}
|
|
774
|
+
};
|
|
775
|
+
} else {
|
|
776
|
+
const task = result.task;
|
|
777
|
+
let output;
|
|
778
|
+
if (task) {
|
|
779
|
+
output = [
|
|
780
|
+
`⚠️ Cannot stop task`,
|
|
781
|
+
"",
|
|
782
|
+
`\uD83D\uDCCB Task ID: ${task_id}`,
|
|
783
|
+
`\uD83D\uDCDD Description: ${task.description}`,
|
|
784
|
+
`\uD83D\uDD04 Current Status: ${task.status}`,
|
|
785
|
+
"",
|
|
786
|
+
result.message
|
|
787
|
+
].join(`
|
|
788
|
+
`);
|
|
789
|
+
} else {
|
|
790
|
+
output = [
|
|
791
|
+
`❌ Task not found`,
|
|
792
|
+
"",
|
|
793
|
+
`\uD83D\uDCCB Task ID: ${task_id}`,
|
|
794
|
+
"",
|
|
795
|
+
result.message
|
|
796
|
+
].join(`
|
|
797
|
+
`);
|
|
798
|
+
}
|
|
799
|
+
return {
|
|
800
|
+
success: false,
|
|
801
|
+
output,
|
|
802
|
+
error: result.message,
|
|
803
|
+
metadata: {
|
|
804
|
+
execution_time_ms: Date.now() - startTime,
|
|
805
|
+
task_id
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
export { BackgroundTaskEventTypes, BackgroundTaskManager, createDelegateTool, createStopTool };
|