@elizaos/plugin-agent-orchestrator 2.0.0-alpha.3 → 2.0.0-alpha.4
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/index.d.ts +8 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2064 -1952
- package/dist/index.js.map +14 -14
- package/dist/src/actions/messaging.d.ts.map +1 -1
- package/dist/src/actions/subagent-management.d.ts.map +1 -1
- package/dist/src/actions/task-management.d.ts.map +1 -1
- package/dist/src/providers/orchestrator-config.d.ts +1 -1
- package/dist/src/providers/orchestrator-config.d.ts.map +1 -1
- package/dist/src/services/messaging-service.d.ts +1 -1
- package/dist/src/services/messaging-service.d.ts.map +1 -1
- package/dist/src/services/sandbox-service.d.ts +2 -2
- package/dist/src/services/sandbox-service.d.ts.map +1 -1
- package/dist/src/services/subagent-service.d.ts +2 -2
- package/dist/src/services/subagent-service.d.ts.map +1 -1
- package/dist/src/types/index.d.ts +4 -4
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/messaging.d.ts.map +1 -1
- package/dist/src/types/subagent.d.ts +1 -1
- package/dist/src/types/subagent.d.ts.map +1 -1
- package/dist/src/utils/index.d.ts +1 -2
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/session.d.ts +2 -2
- package/dist/src/utils/session.d.ts.map +1 -1
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -1,293 +1,556 @@
|
|
|
1
1
|
// index.ts
|
|
2
2
|
import { getSessionProviders as getSessionProviders2 } from "@elizaos/core";
|
|
3
3
|
|
|
4
|
-
// src/actions/
|
|
5
|
-
function
|
|
6
|
-
const
|
|
7
|
-
if (!
|
|
8
|
-
|
|
4
|
+
// src/actions/messaging.ts
|
|
5
|
+
function extractMessagingParams(message, _state) {
|
|
6
|
+
const params = message.content?.params;
|
|
7
|
+
if (!params) {
|
|
8
|
+
return {};
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
let target;
|
|
11
|
+
if (params.target) {
|
|
12
|
+
target = params.target;
|
|
13
|
+
} else {
|
|
14
|
+
target = {};
|
|
15
|
+
if (params.channel)
|
|
16
|
+
target.channel = params.channel;
|
|
17
|
+
if (params.to)
|
|
18
|
+
target.to = params.to;
|
|
19
|
+
if (params.threadId !== undefined)
|
|
20
|
+
target.threadId = params.threadId;
|
|
21
|
+
if (params.replyTo)
|
|
22
|
+
target.replyToMessageId = params.replyTo;
|
|
23
|
+
}
|
|
24
|
+
let content;
|
|
25
|
+
if (params.content) {
|
|
26
|
+
content = params.content;
|
|
27
|
+
} else {
|
|
28
|
+
content = {};
|
|
29
|
+
const text = params.text ?? message.content?.text;
|
|
30
|
+
if (text)
|
|
31
|
+
content.text = text;
|
|
32
|
+
}
|
|
33
|
+
return { target, content };
|
|
14
34
|
}
|
|
15
|
-
var
|
|
16
|
-
name: "
|
|
17
|
-
similes: [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
35
|
+
var sendCrossPlatformMessageAction = {
|
|
36
|
+
name: "SEND_CROSS_PLATFORM_MESSAGE",
|
|
37
|
+
similes: [
|
|
38
|
+
"CROSS_PLATFORM_MESSAGE",
|
|
39
|
+
"UNIFIED_SEND",
|
|
40
|
+
"SEND_TO_CHANNEL",
|
|
41
|
+
"RELAY_MESSAGE",
|
|
42
|
+
"BROADCAST_MESSAGE"
|
|
43
|
+
],
|
|
44
|
+
description: "Send a message to any supported platform (Discord, Telegram, Slack, WhatsApp, Twitch). " + "Requires specifying the target channel/platform and recipient.",
|
|
45
|
+
validate: async (runtime, message, _state) => {
|
|
46
|
+
const messagingService = runtime.getService("MESSAGING");
|
|
47
|
+
if (!messagingService) {
|
|
22
48
|
return false;
|
|
23
49
|
}
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
50
|
+
const params = message.content?.params;
|
|
51
|
+
if (!params) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
const hasTarget = params.target || params.channel && params.to;
|
|
55
|
+
const hasContent = params.content || params.text || message.content?.text;
|
|
56
|
+
return !!(hasTarget && hasContent);
|
|
28
57
|
},
|
|
29
|
-
handler: async (runtime, message,
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const roomId = message.roomId;
|
|
37
|
-
const task = await svc.createTask(name, description, roomId);
|
|
38
|
-
const stepLines = Array.isArray(opts?.steps) ? opts?.steps : undefined;
|
|
39
|
-
if (stepLines && stepLines.length > 0) {
|
|
40
|
-
for (const s of stepLines) {
|
|
41
|
-
const step = String(s).trim();
|
|
42
|
-
if (!step)
|
|
43
|
-
continue;
|
|
44
|
-
await svc.addStep(task.id ?? "", step);
|
|
58
|
+
handler: async (runtime, message, state, _options, callback) => {
|
|
59
|
+
const messagingService = runtime.getService("MESSAGING");
|
|
60
|
+
if (!messagingService) {
|
|
61
|
+
if (callback) {
|
|
62
|
+
await callback({
|
|
63
|
+
text: "Messaging service is not available. Please ensure the orchestrator plugin is properly configured."
|
|
64
|
+
});
|
|
45
65
|
}
|
|
46
|
-
|
|
47
|
-
${stepLines.map((s, i) => `${i + 1}. ${s}`).join(`
|
|
48
|
-
`)}`);
|
|
66
|
+
return { success: false, error: "Messaging service not available" };
|
|
49
67
|
}
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return { success: true, text: msg, data: { taskId: task.id ?? "" } };
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
var listTasksAction = {
|
|
62
|
-
name: "LIST_TASKS",
|
|
63
|
-
similes: ["SHOW_TASKS", "GET_TASKS", "TASKS", "VIEW_TASKS"],
|
|
64
|
-
description: "List tasks managed by the orchestrator.",
|
|
65
|
-
validate: async (runtime, message) => {
|
|
66
|
-
const svc = runtime.getService("CODE_TASK");
|
|
67
|
-
if (!svc) {
|
|
68
|
-
return false;
|
|
68
|
+
const { target, content } = extractMessagingParams(message, state);
|
|
69
|
+
if (!target?.channel) {
|
|
70
|
+
if (callback) {
|
|
71
|
+
await callback({
|
|
72
|
+
text: "Please specify the target channel (discord, telegram, slack, whatsapp, twitch)."
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return { success: false, error: "Missing target channel" };
|
|
69
76
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const msg2 = "No tasks.";
|
|
78
|
-
await callback?.({ content: { text: msg2 } });
|
|
79
|
-
return { success: true, text: msg2 };
|
|
77
|
+
if (!target?.to) {
|
|
78
|
+
if (callback) {
|
|
79
|
+
await callback({
|
|
80
|
+
text: "Please specify the recipient (channel ID, chat ID, or room ID)."
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return { success: false, error: "Missing recipient" };
|
|
80
84
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
if (!content?.text) {
|
|
86
|
+
if (callback) {
|
|
87
|
+
await callback({
|
|
88
|
+
text: "Please provide the message text to send."
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return { success: false, error: "Missing message text" };
|
|
86
92
|
}
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
const sendTarget = {
|
|
94
|
+
channel: target.channel,
|
|
95
|
+
to: target.to
|
|
96
|
+
};
|
|
97
|
+
if (target.threadId !== undefined)
|
|
98
|
+
sendTarget.threadId = target.threadId;
|
|
99
|
+
if (target.replyToMessageId)
|
|
100
|
+
sendTarget.replyToMessageId = target.replyToMessageId;
|
|
101
|
+
const sendContent = {
|
|
102
|
+
text: content.text
|
|
103
|
+
};
|
|
104
|
+
if (content.attachments)
|
|
105
|
+
sendContent.attachments = content.attachments;
|
|
106
|
+
if (content.embed)
|
|
107
|
+
sendContent.embed = content.embed;
|
|
108
|
+
if (content.buttons)
|
|
109
|
+
sendContent.buttons = content.buttons;
|
|
110
|
+
if (content.disableLinkPreview !== undefined)
|
|
111
|
+
sendContent.disableLinkPreview = content.disableLinkPreview;
|
|
112
|
+
if (content.silent !== undefined)
|
|
113
|
+
sendContent.silent = content.silent;
|
|
114
|
+
const result = await messagingService.send({
|
|
115
|
+
target: sendTarget,
|
|
116
|
+
content: sendContent
|
|
117
|
+
});
|
|
118
|
+
if (callback) {
|
|
119
|
+
if (result.success) {
|
|
120
|
+
const callbackData = {};
|
|
121
|
+
if (result.messageId)
|
|
122
|
+
callbackData.messageId = result.messageId;
|
|
123
|
+
if (result.sentAt)
|
|
124
|
+
callbackData.sentAt = result.sentAt;
|
|
125
|
+
await callback({
|
|
126
|
+
text: `Message sent successfully to ${target.channel}.`,
|
|
127
|
+
data: callbackData
|
|
128
|
+
});
|
|
129
|
+
} else {
|
|
130
|
+
await callback({
|
|
131
|
+
text: `Failed to send message: ${result.error}`
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
success: result.success,
|
|
137
|
+
data: result,
|
|
138
|
+
...result.error !== undefined ? { error: result.error } : {}
|
|
139
|
+
};
|
|
140
|
+
},
|
|
141
|
+
examples: [
|
|
142
|
+
[
|
|
143
|
+
{
|
|
144
|
+
name: "{{name1}}",
|
|
145
|
+
content: {
|
|
146
|
+
text: "Send 'Hello from the agent!' to Discord channel 123456789",
|
|
147
|
+
params: {
|
|
148
|
+
channel: "discord",
|
|
149
|
+
to: "123456789",
|
|
150
|
+
text: "Hello from the agent!"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: "{{agentName}}",
|
|
156
|
+
content: {
|
|
157
|
+
text: "Message sent successfully to Discord.",
|
|
158
|
+
actions: ["SEND_CROSS_PLATFORM_MESSAGE"]
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
],
|
|
162
|
+
[
|
|
163
|
+
{
|
|
164
|
+
name: "{{name1}}",
|
|
165
|
+
content: {
|
|
166
|
+
text: "Send a Telegram message",
|
|
167
|
+
params: {
|
|
168
|
+
channel: "telegram",
|
|
169
|
+
to: "-1001234567890",
|
|
170
|
+
text: "Automated notification from your AI assistant."
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: "{{agentName}}",
|
|
176
|
+
content: {
|
|
177
|
+
text: "Message sent successfully to Telegram.",
|
|
178
|
+
actions: ["SEND_CROSS_PLATFORM_MESSAGE"]
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
]
|
|
92
183
|
};
|
|
93
|
-
var
|
|
94
|
-
name: "
|
|
95
|
-
similes: ["
|
|
96
|
-
description: "
|
|
97
|
-
validate: async (runtime, message) => {
|
|
98
|
-
const
|
|
99
|
-
if (!
|
|
184
|
+
var sendToDeliveryContextAction = {
|
|
185
|
+
name: "SEND_TO_DELIVERY_CONTEXT",
|
|
186
|
+
similes: ["DELIVER_MESSAGE", "SEND_TO_CONTEXT", "ROUTE_MESSAGE"],
|
|
187
|
+
description: "Send a message using a delivery context that specifies the target channel and recipient. " + "Useful for routing messages back to the original requester or to a specific context.",
|
|
188
|
+
validate: async (runtime, message, _state) => {
|
|
189
|
+
const messagingService = runtime.getService("MESSAGING");
|
|
190
|
+
if (!messagingService) {
|
|
100
191
|
return false;
|
|
101
192
|
}
|
|
102
|
-
const
|
|
103
|
-
|
|
193
|
+
const params = message.content?.params;
|
|
194
|
+
if (!params?.deliveryContext) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
const hasText = params.text || message.content?.text;
|
|
198
|
+
return !!hasText;
|
|
104
199
|
},
|
|
105
200
|
handler: async (runtime, message, _state, _options, callback) => {
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
201
|
+
const messagingService = runtime.getService("MESSAGING");
|
|
202
|
+
if (!messagingService) {
|
|
203
|
+
if (callback) {
|
|
204
|
+
await callback({
|
|
205
|
+
text: "Messaging service is not available."
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return { success: false, error: "Messaging service not available" };
|
|
112
209
|
}
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
210
|
+
const params = message.content?.params;
|
|
211
|
+
const deliveryContext = params?.deliveryContext;
|
|
212
|
+
const text = params?.text ?? message.content?.text;
|
|
213
|
+
if (!deliveryContext) {
|
|
214
|
+
if (callback) {
|
|
215
|
+
await callback({
|
|
216
|
+
text: "Please provide a delivery context with channel and recipient information."
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return { success: false, error: "Missing delivery context" };
|
|
119
220
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
name: "SEARCH_TASKS",
|
|
128
|
-
similes: ["FIND_TASK", "LOOKUP_TASK"],
|
|
129
|
-
description: "Search tasks by query.",
|
|
130
|
-
validate: async (runtime, message) => {
|
|
131
|
-
const svc = runtime.getService("CODE_TASK");
|
|
132
|
-
if (!svc) {
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
const t = message.content.text?.toLowerCase() ?? "";
|
|
136
|
-
return t.includes("search task") || t.includes("find task") || t.includes("look for task");
|
|
137
|
-
},
|
|
138
|
-
handler: async (runtime, message, _state, options, callback) => {
|
|
139
|
-
const svc = getService(runtime);
|
|
140
|
-
const opt = options;
|
|
141
|
-
const query = (opt?.query ?? extractQuery(message.content.text ?? "")).trim();
|
|
142
|
-
if (!query) {
|
|
143
|
-
const msg2 = "What would you like to search for?";
|
|
144
|
-
await callback?.({ content: { text: msg2 } });
|
|
145
|
-
return { success: false, text: msg2 };
|
|
146
|
-
}
|
|
147
|
-
const matches = await svc.searchTasks(query);
|
|
148
|
-
if (matches.length === 0) {
|
|
149
|
-
const msg2 = `No tasks found matching: "${query}"`;
|
|
150
|
-
await callback?.({ content: { text: msg2 } });
|
|
151
|
-
return { success: true, text: msg2 };
|
|
221
|
+
if (!text) {
|
|
222
|
+
if (callback) {
|
|
223
|
+
await callback({
|
|
224
|
+
text: "Please provide the message text to send."
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return { success: false, error: "Missing message text" };
|
|
152
228
|
}
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
229
|
+
const result = await messagingService.sendToDeliveryContext(deliveryContext, {
|
|
230
|
+
text
|
|
231
|
+
});
|
|
232
|
+
if (callback) {
|
|
233
|
+
if (result.success) {
|
|
234
|
+
const callbackData = {};
|
|
235
|
+
if (result.messageId)
|
|
236
|
+
callbackData.messageId = result.messageId;
|
|
237
|
+
await callback({
|
|
238
|
+
text: `Message delivered successfully via ${result.channel}.`,
|
|
239
|
+
data: callbackData
|
|
240
|
+
});
|
|
241
|
+
} else {
|
|
242
|
+
await callback({
|
|
243
|
+
text: `Failed to deliver message: ${result.error}`
|
|
244
|
+
});
|
|
245
|
+
}
|
|
156
246
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
247
|
+
return {
|
|
248
|
+
success: result.success,
|
|
249
|
+
data: result,
|
|
250
|
+
...result.error !== undefined ? { error: result.error } : {}
|
|
251
|
+
};
|
|
252
|
+
},
|
|
253
|
+
examples: [
|
|
254
|
+
[
|
|
255
|
+
{
|
|
256
|
+
name: "{{name1}}",
|
|
257
|
+
content: {
|
|
258
|
+
text: "Send result to delivery context",
|
|
259
|
+
params: {
|
|
260
|
+
deliveryContext: {
|
|
261
|
+
channel: "discord",
|
|
262
|
+
to: "123456789"
|
|
263
|
+
},
|
|
264
|
+
text: "Task completed successfully!"
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
name: "{{agentName}}",
|
|
270
|
+
content: {
|
|
271
|
+
text: "Message delivered successfully via discord.",
|
|
272
|
+
actions: ["SEND_TO_DELIVERY_CONTEXT"]
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
]
|
|
276
|
+
]
|
|
162
277
|
};
|
|
163
|
-
var
|
|
164
|
-
name: "
|
|
165
|
-
similes: ["
|
|
166
|
-
description: "
|
|
167
|
-
validate: async (runtime, message) => {
|
|
168
|
-
const
|
|
169
|
-
if (!
|
|
278
|
+
var sendToRoomAction = {
|
|
279
|
+
name: "SEND_TO_ROOM",
|
|
280
|
+
similes: ["MESSAGE_ROOM", "ROOM_MESSAGE", "NOTIFY_ROOM"],
|
|
281
|
+
description: "Send a message to an Eliza room. The room's metadata determines which platform and recipient to use.",
|
|
282
|
+
validate: async (runtime, message, _state) => {
|
|
283
|
+
const messagingService = runtime.getService("MESSAGING");
|
|
284
|
+
if (!messagingService) {
|
|
170
285
|
return false;
|
|
171
286
|
}
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
},
|
|
175
|
-
handler: async (runtime, message, _state, _options, callback) => {
|
|
176
|
-
const svc = getService(runtime);
|
|
177
|
-
const query = extractQuery(message.content.text ?? "");
|
|
178
|
-
const task = query ? (await svc.searchTasks(query))[0] : await svc.getCurrentTask();
|
|
179
|
-
if (!task?.id) {
|
|
180
|
-
const msg2 = "No task to pause.";
|
|
181
|
-
await callback?.({ content: { text: msg2 } });
|
|
182
|
-
return { success: false, text: msg2 };
|
|
183
|
-
}
|
|
184
|
-
await svc.pauseTask(task.id);
|
|
185
|
-
const msg = `Paused task: ${task.name}`;
|
|
186
|
-
await callback?.({ content: { text: msg } });
|
|
187
|
-
return { success: true, text: msg };
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
var resumeTaskAction = {
|
|
191
|
-
name: "RESUME_TASK",
|
|
192
|
-
similes: ["CONTINUE_TASK", "RESTART_TASK", "RUN_TASK"],
|
|
193
|
-
description: "Resume a paused task.",
|
|
194
|
-
validate: async (runtime, message) => {
|
|
195
|
-
const svc = runtime.getService("CODE_TASK");
|
|
196
|
-
if (!svc) {
|
|
287
|
+
const params = message.content?.params;
|
|
288
|
+
if (!params?.roomId) {
|
|
197
289
|
return false;
|
|
198
290
|
}
|
|
199
|
-
const
|
|
200
|
-
return
|
|
291
|
+
const hasText = params.text || message.content?.text;
|
|
292
|
+
return !!hasText;
|
|
201
293
|
},
|
|
202
294
|
handler: async (runtime, message, _state, _options, callback) => {
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
295
|
+
const messagingService = runtime.getService("MESSAGING");
|
|
296
|
+
if (!messagingService) {
|
|
297
|
+
if (callback) {
|
|
298
|
+
await callback({
|
|
299
|
+
text: "Messaging service is not available."
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return { success: false, error: "Messaging service not available" };
|
|
210
303
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
304
|
+
const params = message.content?.params;
|
|
305
|
+
const roomId = params?.roomId;
|
|
306
|
+
const text = params?.text ?? message.content?.text;
|
|
307
|
+
if (!roomId) {
|
|
308
|
+
if (callback) {
|
|
309
|
+
await callback({
|
|
310
|
+
text: "Please specify the room ID to send the message to."
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
return { success: false, error: "Missing room ID" };
|
|
314
|
+
}
|
|
315
|
+
if (!text) {
|
|
316
|
+
if (callback) {
|
|
317
|
+
await callback({
|
|
318
|
+
text: "Please provide the message text to send."
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
return { success: false, error: "Missing message text" };
|
|
322
|
+
}
|
|
323
|
+
const result = await messagingService.sendToRoom(roomId, { text });
|
|
324
|
+
if (callback) {
|
|
325
|
+
if (result.success) {
|
|
326
|
+
const callbackData = {};
|
|
327
|
+
if (result.messageId)
|
|
328
|
+
callbackData.messageId = result.messageId;
|
|
329
|
+
await callback({
|
|
330
|
+
text: `Message sent to room via ${result.channel}.`,
|
|
331
|
+
data: callbackData
|
|
332
|
+
});
|
|
333
|
+
} else {
|
|
334
|
+
await callback({
|
|
335
|
+
text: `Failed to send to room: ${result.error}`
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
success: result.success,
|
|
341
|
+
data: result,
|
|
342
|
+
...result.error !== undefined ? { error: result.error } : {}
|
|
343
|
+
};
|
|
344
|
+
},
|
|
345
|
+
examples: [
|
|
346
|
+
[
|
|
347
|
+
{
|
|
348
|
+
name: "{{name1}}",
|
|
349
|
+
content: {
|
|
350
|
+
text: "Send to room",
|
|
351
|
+
params: {
|
|
352
|
+
roomId: "550e8400-e29b-41d4-a716-446655440000",
|
|
353
|
+
text: "Hello, room!"
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
name: "{{agentName}}",
|
|
359
|
+
content: {
|
|
360
|
+
text: "Message sent to room via discord.",
|
|
361
|
+
actions: ["SEND_TO_ROOM"]
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
]
|
|
365
|
+
]
|
|
220
366
|
};
|
|
221
|
-
var
|
|
222
|
-
name: "
|
|
223
|
-
similes: ["
|
|
224
|
-
description: "
|
|
225
|
-
validate: async (runtime, message) => {
|
|
226
|
-
const
|
|
227
|
-
if (!
|
|
367
|
+
var sendToSessionMessageAction = {
|
|
368
|
+
name: "SEND_TO_SESSION_MESSAGE",
|
|
369
|
+
similes: ["SESSION_MESSAGE", "MESSAGE_SESSION", "NOTIFY_SESSION"],
|
|
370
|
+
description: "Send a message to a session by its session key. The session key is mapped to an Eliza room.",
|
|
371
|
+
validate: async (runtime, message, _state) => {
|
|
372
|
+
const messagingService = runtime.getService("MESSAGING");
|
|
373
|
+
if (!messagingService) {
|
|
228
374
|
return false;
|
|
229
375
|
}
|
|
230
|
-
const
|
|
231
|
-
|
|
376
|
+
const params = message.content?.params;
|
|
377
|
+
if (!params?.sessionKey) {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
const hasText = params.text || message.content?.text;
|
|
381
|
+
return !!hasText;
|
|
232
382
|
},
|
|
233
383
|
handler: async (runtime, message, _state, _options, callback) => {
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
384
|
+
const messagingService = runtime.getService("MESSAGING");
|
|
385
|
+
if (!messagingService) {
|
|
386
|
+
if (callback) {
|
|
387
|
+
await callback({
|
|
388
|
+
text: "Messaging service is not available."
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
return { success: false, error: "Messaging service not available" };
|
|
241
392
|
}
|
|
242
|
-
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
393
|
+
const params = message.content?.params;
|
|
394
|
+
const sessionKey = params?.sessionKey;
|
|
395
|
+
const text = params?.text ?? message.content?.text;
|
|
396
|
+
if (!sessionKey) {
|
|
397
|
+
if (callback) {
|
|
398
|
+
await callback({
|
|
399
|
+
text: "Please specify the session key to send the message to."
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
return { success: false, error: "Missing session key" };
|
|
403
|
+
}
|
|
404
|
+
if (!text) {
|
|
405
|
+
if (callback) {
|
|
406
|
+
await callback({
|
|
407
|
+
text: "Please provide the message text to send."
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
return { success: false, error: "Missing message text" };
|
|
411
|
+
}
|
|
412
|
+
const result = await messagingService.sendToSession(sessionKey, { text });
|
|
413
|
+
if (callback) {
|
|
414
|
+
if (result.success) {
|
|
415
|
+
const callbackData = {};
|
|
416
|
+
if (result.messageId)
|
|
417
|
+
callbackData.messageId = result.messageId;
|
|
418
|
+
await callback({
|
|
419
|
+
text: `Message sent to session via ${result.channel}.`,
|
|
420
|
+
data: callbackData
|
|
421
|
+
});
|
|
422
|
+
} else {
|
|
423
|
+
await callback({
|
|
424
|
+
text: `Failed to send to session: ${result.error}`
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return {
|
|
429
|
+
success: result.success,
|
|
430
|
+
data: result,
|
|
431
|
+
...result.error !== undefined ? { error: result.error } : {}
|
|
432
|
+
};
|
|
433
|
+
},
|
|
434
|
+
examples: [
|
|
435
|
+
[
|
|
436
|
+
{
|
|
437
|
+
name: "{{name1}}",
|
|
438
|
+
content: {
|
|
439
|
+
text: "Send to session",
|
|
440
|
+
params: {
|
|
441
|
+
sessionKey: "agent:main:dm:user123",
|
|
442
|
+
text: "Update from your subagent!"
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
name: "{{agentName}}",
|
|
448
|
+
content: {
|
|
449
|
+
text: "Message sent to session via discord.",
|
|
450
|
+
actions: ["SEND_TO_SESSION_MESSAGE"]
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
]
|
|
454
|
+
]
|
|
455
|
+
};
|
|
456
|
+
var listMessagingChannelsAction = {
|
|
457
|
+
name: "LIST_MESSAGING_CHANNELS",
|
|
458
|
+
similes: ["AVAILABLE_CHANNELS", "GET_CHANNELS", "MESSAGING_PLATFORMS"],
|
|
459
|
+
description: "List all available messaging channels/platforms that the agent can send messages to.",
|
|
460
|
+
validate: async (runtime, _message, _state) => {
|
|
461
|
+
const messagingService = runtime.getService("MESSAGING");
|
|
462
|
+
return !!messagingService;
|
|
463
|
+
},
|
|
464
|
+
handler: async (runtime, _message, _state, _options, callback) => {
|
|
465
|
+
const messagingService = runtime.getService("MESSAGING");
|
|
466
|
+
if (!messagingService) {
|
|
467
|
+
if (callback) {
|
|
468
|
+
await callback({
|
|
469
|
+
text: "Messaging service is not available."
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
return { success: false, error: "Messaging service not available" };
|
|
473
|
+
}
|
|
474
|
+
const channels = messagingService.getAvailableChannels();
|
|
475
|
+
if (callback) {
|
|
476
|
+
if (channels.length > 0) {
|
|
477
|
+
await callback({
|
|
478
|
+
text: `Available messaging channels: ${channels.join(", ")}`,
|
|
479
|
+
data: { channels }
|
|
480
|
+
});
|
|
481
|
+
} else {
|
|
482
|
+
await callback({
|
|
483
|
+
text: "No messaging channels are currently available.",
|
|
484
|
+
data: { channels: [] }
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return {
|
|
489
|
+
success: true,
|
|
490
|
+
data: { channels }
|
|
491
|
+
};
|
|
492
|
+
},
|
|
493
|
+
examples: [
|
|
494
|
+
[
|
|
495
|
+
{
|
|
496
|
+
name: "{{name1}}",
|
|
497
|
+
content: {
|
|
498
|
+
text: "What messaging platforms can you use?"
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: "{{agentName}}",
|
|
503
|
+
content: {
|
|
504
|
+
text: "Available messaging channels: discord, telegram, internal",
|
|
505
|
+
actions: ["LIST_MESSAGING_CHANNELS"]
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
]
|
|
509
|
+
]
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
// src/utils/session.ts
|
|
513
|
+
import crypto from "node:crypto";
|
|
514
|
+
import {
|
|
515
|
+
buildAcpSessionKey,
|
|
516
|
+
buildAgentMainSessionKey,
|
|
517
|
+
buildAgentPeerSessionKey,
|
|
518
|
+
buildAgentSessionKey,
|
|
519
|
+
buildGroupHistoryKey,
|
|
520
|
+
buildSubagentSessionKey,
|
|
521
|
+
createSendPolicyProvider,
|
|
522
|
+
createSessionEntry,
|
|
523
|
+
createSessionProvider,
|
|
524
|
+
createSessionSkillsProvider,
|
|
525
|
+
deleteSessionEntry,
|
|
526
|
+
extractSessionContext,
|
|
527
|
+
getSessionEntry,
|
|
528
|
+
getSessionProviders,
|
|
529
|
+
isAcpSessionKey,
|
|
259
530
|
isSubagentSessionKey,
|
|
531
|
+
isValidSessionEntry,
|
|
532
|
+
listSessionKeys,
|
|
533
|
+
loadSessionStore,
|
|
534
|
+
mergeSessionEntry,
|
|
535
|
+
normalizeAccountId,
|
|
260
536
|
normalizeAgentId,
|
|
261
537
|
normalizeMainKey,
|
|
262
|
-
|
|
263
|
-
toAgentRequestSessionKey,
|
|
264
|
-
toAgentStoreSessionKey,
|
|
538
|
+
parseAgentSessionKey,
|
|
265
539
|
resolveAgentIdFromSessionKey,
|
|
266
|
-
resolveThreadParentSessionKey,
|
|
267
|
-
resolveThreadSessionKeys,
|
|
268
|
-
buildGroupHistoryKey,
|
|
269
|
-
loadSessionStore,
|
|
270
|
-
saveSessionStore,
|
|
271
|
-
updateSessionStore,
|
|
272
|
-
updateSessionStoreEntry,
|
|
273
|
-
getSessionEntry,
|
|
274
|
-
upsertSessionEntry,
|
|
275
|
-
deleteSessionEntry,
|
|
276
|
-
listSessionKeys,
|
|
277
|
-
resolveStateDir,
|
|
278
540
|
resolveAgentSessionsDir,
|
|
279
541
|
resolveDefaultSessionStorePath,
|
|
280
542
|
resolveSessionTranscriptPath,
|
|
543
|
+
resolveStateDir,
|
|
281
544
|
resolveStorePath,
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
createSendPolicyProvider,
|
|
285
|
-
getSessionProviders,
|
|
286
|
-
extractSessionContext,
|
|
545
|
+
resolveThreadParentSessionKey,
|
|
546
|
+
resolveThreadSessionKeys,
|
|
287
547
|
SessionStateManager,
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
548
|
+
saveSessionStore,
|
|
549
|
+
toAgentRequestSessionKey,
|
|
550
|
+
toAgentStoreSessionKey,
|
|
551
|
+
updateSessionStore,
|
|
552
|
+
updateSessionStoreEntry,
|
|
553
|
+
upsertSessionEntry
|
|
291
554
|
} from "@elizaos/core";
|
|
292
555
|
function hashToUUID(input) {
|
|
293
556
|
const hash = crypto.createHash("sha256").update(input).digest("hex");
|
|
@@ -405,25 +668,37 @@ function normalizeDeliveryContext(context) {
|
|
|
405
668
|
}
|
|
406
669
|
const result = {};
|
|
407
670
|
if (context.channel && typeof context.channel === "string") {
|
|
408
|
-
|
|
671
|
+
const trimmed = context.channel.trim();
|
|
672
|
+
if (trimmed)
|
|
673
|
+
result.channel = trimmed;
|
|
409
674
|
}
|
|
410
675
|
if (context.accountId && typeof context.accountId === "string") {
|
|
411
|
-
|
|
676
|
+
const trimmed = context.accountId.trim();
|
|
677
|
+
if (trimmed)
|
|
678
|
+
result.accountId = trimmed;
|
|
412
679
|
}
|
|
413
680
|
if (context.to && typeof context.to === "string") {
|
|
414
|
-
|
|
681
|
+
const trimmed = context.to.trim();
|
|
682
|
+
if (trimmed)
|
|
683
|
+
result.to = trimmed;
|
|
415
684
|
}
|
|
416
685
|
if (context.threadId !== undefined && context.threadId !== null) {
|
|
417
686
|
result.threadId = context.threadId;
|
|
418
687
|
}
|
|
419
688
|
if (context.groupId && typeof context.groupId === "string") {
|
|
420
|
-
|
|
689
|
+
const trimmed = context.groupId.trim();
|
|
690
|
+
if (trimmed)
|
|
691
|
+
result.groupId = trimmed;
|
|
421
692
|
}
|
|
422
693
|
if (context.groupChannel && typeof context.groupChannel === "string") {
|
|
423
|
-
|
|
694
|
+
const trimmed = context.groupChannel.trim();
|
|
695
|
+
if (trimmed)
|
|
696
|
+
result.groupChannel = trimmed;
|
|
424
697
|
}
|
|
425
698
|
if (context.groupSpace && typeof context.groupSpace === "string") {
|
|
426
|
-
|
|
699
|
+
const trimmed = context.groupSpace.trim();
|
|
700
|
+
if (trimmed)
|
|
701
|
+
result.groupSpace = trimmed;
|
|
427
702
|
}
|
|
428
703
|
const hasValues = Object.values(result).some((v) => v !== undefined && v !== null);
|
|
429
704
|
return hasValues ? result : undefined;
|
|
@@ -438,15 +713,29 @@ function mergeDeliveryContext(primary, secondary) {
|
|
|
438
713
|
if (!secondary) {
|
|
439
714
|
return normalizeDeliveryContext(primary);
|
|
440
715
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
716
|
+
const merged = {};
|
|
717
|
+
const ch = primary.channel || secondary.channel;
|
|
718
|
+
if (ch)
|
|
719
|
+
merged.channel = ch;
|
|
720
|
+
const acct = primary.accountId || secondary.accountId;
|
|
721
|
+
if (acct)
|
|
722
|
+
merged.accountId = acct;
|
|
723
|
+
const to = primary.to || secondary.to;
|
|
724
|
+
if (to)
|
|
725
|
+
merged.to = to;
|
|
726
|
+
const tid = primary.threadId ?? secondary.threadId;
|
|
727
|
+
if (tid !== undefined)
|
|
728
|
+
merged.threadId = tid;
|
|
729
|
+
const gid = primary.groupId || secondary.groupId;
|
|
730
|
+
if (gid)
|
|
731
|
+
merged.groupId = gid;
|
|
732
|
+
const gch = primary.groupChannel || secondary.groupChannel;
|
|
733
|
+
if (gch)
|
|
734
|
+
merged.groupChannel = gch;
|
|
735
|
+
const gsp = primary.groupSpace || secondary.groupSpace;
|
|
736
|
+
if (gsp)
|
|
737
|
+
merged.groupSpace = gsp;
|
|
738
|
+
return normalizeDeliveryContext(merged);
|
|
450
739
|
}
|
|
451
740
|
function formatDurationShort(ms) {
|
|
452
741
|
if (!ms || !Number.isFinite(ms) || ms <= 0) {
|
|
@@ -485,23 +774,19 @@ function getSubagentService(runtime) {
|
|
|
485
774
|
}
|
|
486
775
|
return svc;
|
|
487
776
|
}
|
|
488
|
-
function extractSessionContext2(
|
|
777
|
+
function extractSessionContext2(_runtime, message) {
|
|
489
778
|
const metadata = message.content?.metadata;
|
|
490
779
|
const sessionKey = typeof metadata?.sessionKey === "string" ? metadata.sessionKey : undefined;
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
780
|
+
const result = {};
|
|
781
|
+
if (sessionKey)
|
|
782
|
+
result.sessionKey = sessionKey;
|
|
783
|
+
if (message.roomId)
|
|
784
|
+
result.roomId = message.roomId;
|
|
785
|
+
return result;
|
|
495
786
|
}
|
|
496
787
|
var spawnSubagentAction = {
|
|
497
788
|
name: "SPAWN_SUBAGENT",
|
|
498
|
-
similes: [
|
|
499
|
-
"SPAWN_TASK",
|
|
500
|
-
"BACKGROUND_TASK",
|
|
501
|
-
"START_SUBAGENT",
|
|
502
|
-
"SESSIONS_SPAWN",
|
|
503
|
-
"CREATE_SUBAGENT"
|
|
504
|
-
],
|
|
789
|
+
similes: ["SPAWN_TASK", "BACKGROUND_TASK", "START_SUBAGENT", "SESSIONS_SPAWN", "CREATE_SUBAGENT"],
|
|
505
790
|
description: "Spawn a background sub-agent run to execute a task asynchronously. The subagent will complete the task and announce results back.",
|
|
506
791
|
validate: async (runtime, message) => {
|
|
507
792
|
const svc = runtime.getService("SUBAGENT");
|
|
@@ -523,18 +808,20 @@ var spawnSubagentAction = {
|
|
|
523
808
|
await callback?.({ content: { text: msg2 } });
|
|
524
809
|
return { success: false, text: msg2 };
|
|
525
810
|
}
|
|
526
|
-
const
|
|
811
|
+
const spawnParams = {
|
|
527
812
|
task,
|
|
528
|
-
label: opts?.label,
|
|
529
|
-
agentId: opts?.agentId,
|
|
530
|
-
model: opts?.model,
|
|
531
|
-
thinking: opts?.thinking,
|
|
532
813
|
runTimeoutSeconds: opts?.timeoutSeconds ?? 300,
|
|
533
814
|
cleanup: opts?.cleanup ?? "keep"
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
815
|
+
};
|
|
816
|
+
if (opts?.label)
|
|
817
|
+
spawnParams.label = opts.label;
|
|
818
|
+
if (opts?.agentId)
|
|
819
|
+
spawnParams.agentId = opts.agentId;
|
|
820
|
+
if (opts?.model)
|
|
821
|
+
spawnParams.model = opts.model;
|
|
822
|
+
if (opts?.thinking)
|
|
823
|
+
spawnParams.thinking = opts.thinking;
|
|
824
|
+
const result = await svc.spawnSubagent(spawnParams, context);
|
|
538
825
|
if (result.status !== "accepted") {
|
|
539
826
|
const msg2 = `Failed to spawn subagent: ${result.error ?? "unknown error"}`;
|
|
540
827
|
await callback?.({ content: { text: msg2 } });
|
|
@@ -582,16 +869,17 @@ var sendToSessionAction = {
|
|
|
582
869
|
await callback?.({ content: { text: msg2 } });
|
|
583
870
|
return { success: false, text: msg2 };
|
|
584
871
|
}
|
|
585
|
-
const
|
|
586
|
-
sessionKey: opts?.sessionKey,
|
|
587
|
-
label: opts?.label,
|
|
588
|
-
agentId: opts?.agentId,
|
|
872
|
+
const sendParams = {
|
|
589
873
|
message: targetMessage,
|
|
590
874
|
timeoutSeconds: opts?.timeoutSeconds ?? 30
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
875
|
+
};
|
|
876
|
+
if (opts?.sessionKey)
|
|
877
|
+
sendParams.sessionKey = opts.sessionKey;
|
|
878
|
+
if (opts?.label)
|
|
879
|
+
sendParams.label = opts.label;
|
|
880
|
+
if (opts?.agentId)
|
|
881
|
+
sendParams.agentId = opts.agentId;
|
|
882
|
+
const result = await svc.sendToAgent(sendParams, context);
|
|
595
883
|
if (result.status === "forbidden") {
|
|
596
884
|
const msg2 = `Access denied: ${result.error}`;
|
|
597
885
|
await callback?.({ content: { text: msg2 } });
|
|
@@ -673,7 +961,7 @@ var cancelSubagentAction = {
|
|
|
673
961
|
const text = message.content.text?.toLowerCase() ?? "";
|
|
674
962
|
return (text.includes("cancel") || text.includes("stop") || text.includes("abort")) && (text.includes("subagent") || text.includes("background"));
|
|
675
963
|
},
|
|
676
|
-
handler: async (runtime,
|
|
964
|
+
handler: async (runtime, _message, _state, options, callback) => {
|
|
677
965
|
const svc = getSubagentService(runtime);
|
|
678
966
|
const opts = options;
|
|
679
967
|
const runId = opts?.runId;
|
|
@@ -705,7 +993,7 @@ var getSubagentStatusAction = {
|
|
|
705
993
|
const text = message.content.text?.toLowerCase() ?? "";
|
|
706
994
|
return text.includes("subagent status") || text.includes("task status") || text.includes("check subagent") || text.includes("subagent info");
|
|
707
995
|
},
|
|
708
|
-
handler: async (runtime,
|
|
996
|
+
handler: async (runtime, _message, _state, options, callback) => {
|
|
709
997
|
const svc = getSubagentService(runtime);
|
|
710
998
|
const opts = options;
|
|
711
999
|
const runId = opts?.runId;
|
|
@@ -739,491 +1027,250 @@ var getSubagentStatusAction = {
|
|
|
739
1027
|
}
|
|
740
1028
|
};
|
|
741
1029
|
|
|
742
|
-
// src/actions/
|
|
743
|
-
function
|
|
744
|
-
const
|
|
745
|
-
if (!
|
|
746
|
-
|
|
1030
|
+
// src/actions/task-management.ts
|
|
1031
|
+
function getService(runtime) {
|
|
1032
|
+
const svc = runtime.getService("CODE_TASK");
|
|
1033
|
+
if (!svc) {
|
|
1034
|
+
throw new Error("AgentOrchestratorService not available (CODE_TASK)");
|
|
747
1035
|
}
|
|
748
|
-
|
|
749
|
-
channel: params.channel,
|
|
750
|
-
to: params.to,
|
|
751
|
-
threadId: params.threadId,
|
|
752
|
-
replyToMessageId: params.replyTo
|
|
753
|
-
};
|
|
754
|
-
const content = params.content ?? {
|
|
755
|
-
text: params.text ?? message.content?.text
|
|
756
|
-
};
|
|
757
|
-
return { target, content };
|
|
1036
|
+
return svc;
|
|
758
1037
|
}
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
validate: async (runtime, message, _state) => {
|
|
770
|
-
const messagingService = runtime.getService("MESSAGING");
|
|
771
|
-
if (!messagingService) {
|
|
1038
|
+
function extractQuery(text) {
|
|
1039
|
+
return text.toLowerCase().replace(/\b(switch|select|go|change|search|find|pause|stop|halt|resume|restart|continue|start|run|begin|cancel|delete|remove|list|show|view)\b/g, "").replace(/\b(about|for|named|called|with|to|my|your|our|this|current)\b/g, "").replace(/\b(task|tasks|the|a|an)\b/g, "").replace(/\s+/g, " ").trim();
|
|
1040
|
+
}
|
|
1041
|
+
var createTaskAction = {
|
|
1042
|
+
name: "CREATE_TASK",
|
|
1043
|
+
similes: ["START_TASK", "SPAWN_TASK", "NEW_TASK", "BEGIN_TASK"],
|
|
1044
|
+
description: "Create an orchestrated background task to be executed by a selected agent provider.",
|
|
1045
|
+
validate: async (runtime, message) => {
|
|
1046
|
+
const svc = runtime.getService("CODE_TASK");
|
|
1047
|
+
if (!svc) {
|
|
772
1048
|
return false;
|
|
773
1049
|
}
|
|
774
|
-
const
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
const hasTarget = params.target || params.channel && params.to;
|
|
779
|
-
const hasContent = params.content || params.text || message.content?.text;
|
|
780
|
-
return !!(hasTarget && hasContent);
|
|
1050
|
+
const text = message.content.text?.toLowerCase() ?? "";
|
|
1051
|
+
const hasExplicit = text.includes("create task") || text.includes("new task") || text.includes("start a task");
|
|
1052
|
+
const hasIntent = text.includes("implement") || text.includes("build") || text.includes("create") || text.includes("develop") || text.includes("refactor") || text.includes("fix") || text.includes("add");
|
|
1053
|
+
return hasExplicit || hasIntent;
|
|
781
1054
|
},
|
|
782
|
-
handler: async (runtime, message,
|
|
783
|
-
const
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
1055
|
+
handler: async (runtime, message, _state, options, callback) => {
|
|
1056
|
+
const svc = getService(runtime);
|
|
1057
|
+
const raw = message.content.text ?? "";
|
|
1058
|
+
const opts = options;
|
|
1059
|
+
const name = (opts?.title ?? raw.split(`
|
|
1060
|
+
`)[0] ?? "New Task").trim().slice(0, 100) || "New Task";
|
|
1061
|
+
const description = (opts?.description ?? raw).trim().slice(0, 4000) || name;
|
|
1062
|
+
const roomId = message.roomId;
|
|
1063
|
+
const task = await svc.createTask(name, description, roomId);
|
|
1064
|
+
const stepLines = Array.isArray(opts?.steps) ? opts?.steps : undefined;
|
|
1065
|
+
if (stepLines && stepLines.length > 0) {
|
|
1066
|
+
for (const s of stepLines) {
|
|
1067
|
+
const step = String(s).trim();
|
|
1068
|
+
if (!step)
|
|
1069
|
+
continue;
|
|
1070
|
+
await svc.addStep(task.id ?? "", step);
|
|
789
1071
|
}
|
|
790
|
-
|
|
1072
|
+
await svc.appendOutput(task.id ?? "", `Plan:
|
|
1073
|
+
${stepLines.map((s, i) => `${i + 1}. ${s}`).join(`
|
|
1074
|
+
`)}`);
|
|
791
1075
|
}
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
}
|
|
799
|
-
return { success: false, error: "Missing target channel" };
|
|
800
|
-
}
|
|
801
|
-
if (!target?.to) {
|
|
802
|
-
if (callback) {
|
|
803
|
-
await callback({
|
|
804
|
-
text: "Please specify the recipient (channel ID, chat ID, or room ID)."
|
|
805
|
-
});
|
|
806
|
-
}
|
|
807
|
-
return { success: false, error: "Missing recipient" };
|
|
808
|
-
}
|
|
809
|
-
if (!content?.text) {
|
|
810
|
-
if (callback) {
|
|
811
|
-
await callback({
|
|
812
|
-
text: "Please provide the message text to send."
|
|
813
|
-
});
|
|
814
|
-
}
|
|
815
|
-
return { success: false, error: "Missing message text" };
|
|
816
|
-
}
|
|
817
|
-
const result = await messagingService.send({
|
|
818
|
-
target: {
|
|
819
|
-
channel: target.channel,
|
|
820
|
-
to: target.to,
|
|
821
|
-
threadId: target.threadId,
|
|
822
|
-
replyToMessageId: target.replyToMessageId
|
|
823
|
-
},
|
|
824
|
-
content: {
|
|
825
|
-
text: content.text,
|
|
826
|
-
attachments: content.attachments,
|
|
827
|
-
embed: content.embed,
|
|
828
|
-
buttons: content.buttons,
|
|
829
|
-
disableLinkPreview: content.disableLinkPreview,
|
|
830
|
-
silent: content.silent
|
|
831
|
-
}
|
|
1076
|
+
const msg = `Created task: ${task.name}
|
|
1077
|
+
Provider: ${task.metadata.providerLabel ?? task.metadata.providerId}
|
|
1078
|
+
Starting execution…`;
|
|
1079
|
+
await callback?.({ content: { text: msg } });
|
|
1080
|
+
svc.startTaskExecution(task.id ?? "").catch((err) => {
|
|
1081
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
1082
|
+
svc.appendOutput(task.id ?? "", `Execution error: ${errorMsg}`).catch(() => {});
|
|
832
1083
|
});
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
1084
|
+
return { success: true, text: msg, data: { taskId: task.id ?? "" } };
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
var listTasksAction = {
|
|
1088
|
+
name: "LIST_TASKS",
|
|
1089
|
+
similes: ["SHOW_TASKS", "GET_TASKS", "TASKS", "VIEW_TASKS"],
|
|
1090
|
+
description: "List tasks managed by the orchestrator.",
|
|
1091
|
+
validate: async (runtime, message) => {
|
|
1092
|
+
const svc = runtime.getService("CODE_TASK");
|
|
1093
|
+
if (!svc) {
|
|
1094
|
+
return false;
|
|
844
1095
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
data: result,
|
|
848
|
-
error: result.error
|
|
849
|
-
};
|
|
1096
|
+
const t = message.content.text?.toLowerCase() ?? "";
|
|
1097
|
+
return t.includes("list task") || t.includes("show task") || t === "tasks" || t.includes("my task");
|
|
850
1098
|
},
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
}
|
|
871
|
-
],
|
|
872
|
-
[
|
|
873
|
-
{
|
|
874
|
-
name: "{{name1}}",
|
|
875
|
-
content: {
|
|
876
|
-
text: "Send a Telegram message",
|
|
877
|
-
params: {
|
|
878
|
-
channel: "telegram",
|
|
879
|
-
to: "-1001234567890",
|
|
880
|
-
text: "Automated notification from your AI assistant."
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
},
|
|
884
|
-
{
|
|
885
|
-
name: "{{agentName}}",
|
|
886
|
-
content: {
|
|
887
|
-
text: "Message sent successfully to Telegram.",
|
|
888
|
-
actions: ["SEND_CROSS_PLATFORM_MESSAGE"]
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
]
|
|
892
|
-
]
|
|
1099
|
+
handler: async (runtime, _message, _state, _options, callback) => {
|
|
1100
|
+
const svc = getService(runtime);
|
|
1101
|
+
const tasks = await svc.getRecentTasks(20);
|
|
1102
|
+
if (tasks.length === 0) {
|
|
1103
|
+
const msg2 = "No tasks.";
|
|
1104
|
+
await callback?.({ content: { text: msg2 } });
|
|
1105
|
+
return { success: true, text: msg2 };
|
|
1106
|
+
}
|
|
1107
|
+
const lines = ["Tasks:"];
|
|
1108
|
+
const current = svc.getCurrentTaskId();
|
|
1109
|
+
for (const t of tasks) {
|
|
1110
|
+
const marker = t.id === current ? " (current)" : "";
|
|
1111
|
+
lines.push(`- ${t.name} — ${t.metadata.status} ${t.metadata.progress}%${marker}`);
|
|
1112
|
+
}
|
|
1113
|
+
const msg = lines.join(`
|
|
1114
|
+
`);
|
|
1115
|
+
await callback?.({ content: { text: msg } });
|
|
1116
|
+
return { success: true, text: msg };
|
|
1117
|
+
}
|
|
893
1118
|
};
|
|
894
|
-
var
|
|
895
|
-
name: "
|
|
896
|
-
similes: [
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
"
|
|
900
|
-
|
|
901
|
-
description: "Send a message using a delivery context that specifies the target channel and recipient. " + "Useful for routing messages back to the original requester or to a specific context.",
|
|
902
|
-
validate: async (runtime, message, _state) => {
|
|
903
|
-
const messagingService = runtime.getService("MESSAGING");
|
|
904
|
-
if (!messagingService) {
|
|
1119
|
+
var switchTaskAction = {
|
|
1120
|
+
name: "SWITCH_TASK",
|
|
1121
|
+
similes: ["SELECT_TASK", "SET_TASK", "CHANGE_TASK", "GO_TO_TASK"],
|
|
1122
|
+
description: "Switch the current task context to a different task.",
|
|
1123
|
+
validate: async (runtime, message) => {
|
|
1124
|
+
const svc = runtime.getService("CODE_TASK");
|
|
1125
|
+
if (!svc) {
|
|
905
1126
|
return false;
|
|
906
1127
|
}
|
|
907
|
-
const
|
|
908
|
-
|
|
1128
|
+
const t = message.content.text?.toLowerCase() ?? "";
|
|
1129
|
+
return t.includes("switch to task") || t.includes("select task") || t.includes("task") && t.includes("switch");
|
|
1130
|
+
},
|
|
1131
|
+
handler: async (runtime, message, _state, _options, callback) => {
|
|
1132
|
+
const svc = getService(runtime);
|
|
1133
|
+
const query = extractQuery(message.content.text ?? "");
|
|
1134
|
+
if (!query) {
|
|
1135
|
+
const msg2 = "Please specify which task to switch to (by name or id).";
|
|
1136
|
+
await callback?.({ content: { text: msg2 } });
|
|
1137
|
+
return { success: false, text: msg2 };
|
|
1138
|
+
}
|
|
1139
|
+
const matches = await svc.searchTasks(query);
|
|
1140
|
+
const chosen = matches[0];
|
|
1141
|
+
if (!chosen?.id) {
|
|
1142
|
+
const msg2 = `No task found matching: "${query}"`;
|
|
1143
|
+
await callback?.({ content: { text: msg2 } });
|
|
1144
|
+
return { success: false, text: msg2 };
|
|
1145
|
+
}
|
|
1146
|
+
svc.setCurrentTask(chosen.id);
|
|
1147
|
+
const msg = `Switched to task: ${chosen.name}`;
|
|
1148
|
+
await callback?.({ content: { text: msg } });
|
|
1149
|
+
return { success: true, text: msg, data: { taskId: chosen.id } };
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
var searchTasksAction = {
|
|
1153
|
+
name: "SEARCH_TASKS",
|
|
1154
|
+
similes: ["FIND_TASK", "LOOKUP_TASK"],
|
|
1155
|
+
description: "Search tasks by query.",
|
|
1156
|
+
validate: async (runtime, message) => {
|
|
1157
|
+
const svc = runtime.getService("CODE_TASK");
|
|
1158
|
+
if (!svc) {
|
|
909
1159
|
return false;
|
|
910
1160
|
}
|
|
911
|
-
const
|
|
912
|
-
return
|
|
1161
|
+
const t = message.content.text?.toLowerCase() ?? "";
|
|
1162
|
+
return t.includes("search task") || t.includes("find task") || t.includes("look for task");
|
|
913
1163
|
},
|
|
914
|
-
handler: async (runtime, message,
|
|
915
|
-
const
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
}
|
|
922
|
-
return { success: false, error: "Messaging service not available" };
|
|
1164
|
+
handler: async (runtime, message, _state, options, callback) => {
|
|
1165
|
+
const svc = getService(runtime);
|
|
1166
|
+
const opt = options;
|
|
1167
|
+
const query = (opt?.query ?? extractQuery(message.content.text ?? "")).trim();
|
|
1168
|
+
if (!query) {
|
|
1169
|
+
const msg2 = "What would you like to search for?";
|
|
1170
|
+
await callback?.({ content: { text: msg2 } });
|
|
1171
|
+
return { success: false, text: msg2 };
|
|
923
1172
|
}
|
|
924
|
-
const
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
await callback({
|
|
930
|
-
text: "Please provide a delivery context with channel and recipient information."
|
|
931
|
-
});
|
|
932
|
-
}
|
|
933
|
-
return { success: false, error: "Missing delivery context" };
|
|
1173
|
+
const matches = await svc.searchTasks(query);
|
|
1174
|
+
if (matches.length === 0) {
|
|
1175
|
+
const msg2 = `No tasks found matching: "${query}"`;
|
|
1176
|
+
await callback?.({ content: { text: msg2 } });
|
|
1177
|
+
return { success: true, text: msg2 };
|
|
934
1178
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
text: "Please provide the message text to send."
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
|
-
return { success: false, error: "Missing message text" };
|
|
1179
|
+
const lines = [`Found ${matches.length} task(s) matching "${query}":`];
|
|
1180
|
+
for (const t of matches.slice(0, 10)) {
|
|
1181
|
+
lines.push(`- ${t.name} — ${t.metadata.status} ${t.metadata.progress}%`);
|
|
942
1182
|
}
|
|
943
|
-
const
|
|
944
|
-
|
|
945
|
-
});
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1183
|
+
const msg = lines.join(`
|
|
1184
|
+
`);
|
|
1185
|
+
await callback?.({ content: { text: msg } });
|
|
1186
|
+
return { success: true, text: msg };
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
var pauseTaskAction = {
|
|
1190
|
+
name: "PAUSE_TASK",
|
|
1191
|
+
similes: ["STOP_TASK", "HALT_TASK"],
|
|
1192
|
+
description: "Pause a running task.",
|
|
1193
|
+
validate: async (runtime, message) => {
|
|
1194
|
+
const svc = runtime.getService("CODE_TASK");
|
|
1195
|
+
if (!svc) {
|
|
1196
|
+
return false;
|
|
957
1197
|
}
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
data: result,
|
|
961
|
-
error: result.error
|
|
962
|
-
};
|
|
1198
|
+
const t = message.content.text?.toLowerCase() ?? "";
|
|
1199
|
+
return (t.includes("pause") || t.includes("stop") || t.includes("halt")) && t.includes("task");
|
|
963
1200
|
},
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
channel: "discord",
|
|
973
|
-
to: "123456789"
|
|
974
|
-
},
|
|
975
|
-
text: "Task completed successfully!"
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
},
|
|
979
|
-
{
|
|
980
|
-
name: "{{agentName}}",
|
|
981
|
-
content: {
|
|
982
|
-
text: "Message delivered successfully via discord.",
|
|
983
|
-
actions: ["SEND_TO_DELIVERY_CONTEXT"]
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
]
|
|
987
|
-
]
|
|
988
|
-
};
|
|
989
|
-
var sendToRoomAction = {
|
|
990
|
-
name: "SEND_TO_ROOM",
|
|
991
|
-
similes: [
|
|
992
|
-
"MESSAGE_ROOM",
|
|
993
|
-
"ROOM_MESSAGE",
|
|
994
|
-
"NOTIFY_ROOM"
|
|
995
|
-
],
|
|
996
|
-
description: "Send a message to an Eliza room. The room's metadata determines which platform and recipient to use.",
|
|
997
|
-
validate: async (runtime, message, _state) => {
|
|
998
|
-
const messagingService = runtime.getService("MESSAGING");
|
|
999
|
-
if (!messagingService) {
|
|
1000
|
-
return false;
|
|
1201
|
+
handler: async (runtime, message, _state, _options, callback) => {
|
|
1202
|
+
const svc = getService(runtime);
|
|
1203
|
+
const query = extractQuery(message.content.text ?? "");
|
|
1204
|
+
const task = query ? (await svc.searchTasks(query))[0] : await svc.getCurrentTask();
|
|
1205
|
+
if (!task?.id) {
|
|
1206
|
+
const msg2 = "No task to pause.";
|
|
1207
|
+
await callback?.({ content: { text: msg2 } });
|
|
1208
|
+
return { success: false, text: msg2 };
|
|
1001
1209
|
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1210
|
+
await svc.pauseTask(task.id);
|
|
1211
|
+
const msg = `Paused task: ${task.name}`;
|
|
1212
|
+
await callback?.({ content: { text: msg } });
|
|
1213
|
+
return { success: true, text: msg };
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
var resumeTaskAction = {
|
|
1217
|
+
name: "RESUME_TASK",
|
|
1218
|
+
similes: ["CONTINUE_TASK", "RESTART_TASK", "RUN_TASK"],
|
|
1219
|
+
description: "Resume a paused task.",
|
|
1220
|
+
validate: async (runtime, message) => {
|
|
1221
|
+
const svc = runtime.getService("CODE_TASK");
|
|
1222
|
+
if (!svc) {
|
|
1004
1223
|
return false;
|
|
1005
1224
|
}
|
|
1006
|
-
const
|
|
1007
|
-
return
|
|
1225
|
+
const t = message.content.text?.toLowerCase() ?? "";
|
|
1226
|
+
return t.includes("task") && (t.includes("resume") || t.includes("restart") || t.includes("continue"));
|
|
1008
1227
|
},
|
|
1009
|
-
handler: async (runtime, message,
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
}
|
|
1017
|
-
return { success: false, error: "Messaging service not available" };
|
|
1018
|
-
}
|
|
1019
|
-
const params = message.content?.params;
|
|
1020
|
-
const roomId = params?.roomId;
|
|
1021
|
-
const text = params?.text ?? message.content?.text;
|
|
1022
|
-
if (!roomId) {
|
|
1023
|
-
if (callback) {
|
|
1024
|
-
await callback({
|
|
1025
|
-
text: "Please specify the room ID to send the message to."
|
|
1026
|
-
});
|
|
1027
|
-
}
|
|
1028
|
-
return { success: false, error: "Missing room ID" };
|
|
1029
|
-
}
|
|
1030
|
-
if (!text) {
|
|
1031
|
-
if (callback) {
|
|
1032
|
-
await callback({
|
|
1033
|
-
text: "Please provide the message text to send."
|
|
1034
|
-
});
|
|
1035
|
-
}
|
|
1036
|
-
return { success: false, error: "Missing message text" };
|
|
1037
|
-
}
|
|
1038
|
-
const result = await messagingService.sendToRoom(roomId, { text });
|
|
1039
|
-
if (callback) {
|
|
1040
|
-
if (result.success) {
|
|
1041
|
-
await callback({
|
|
1042
|
-
text: `Message sent to room via ${result.channel}.`,
|
|
1043
|
-
data: { messageId: result.messageId }
|
|
1044
|
-
});
|
|
1045
|
-
} else {
|
|
1046
|
-
await callback({
|
|
1047
|
-
text: `Failed to send to room: ${result.error}`
|
|
1048
|
-
});
|
|
1049
|
-
}
|
|
1228
|
+
handler: async (runtime, message, _state, _options, callback) => {
|
|
1229
|
+
const svc = getService(runtime);
|
|
1230
|
+
const query = extractQuery(message.content.text ?? "");
|
|
1231
|
+
const task = query ? (await svc.searchTasks(query))[0] : await svc.getCurrentTask();
|
|
1232
|
+
if (!task?.id) {
|
|
1233
|
+
const msg2 = "No task to resume.";
|
|
1234
|
+
await callback?.({ content: { text: msg2 } });
|
|
1235
|
+
return { success: false, text: msg2 };
|
|
1050
1236
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
content: {
|
|
1062
|
-
text: "Send to room",
|
|
1063
|
-
params: {
|
|
1064
|
-
roomId: "550e8400-e29b-41d4-a716-446655440000",
|
|
1065
|
-
text: "Hello, room!"
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
},
|
|
1069
|
-
{
|
|
1070
|
-
name: "{{agentName}}",
|
|
1071
|
-
content: {
|
|
1072
|
-
text: "Message sent to room via discord.",
|
|
1073
|
-
actions: ["SEND_TO_ROOM"]
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
]
|
|
1077
|
-
]
|
|
1237
|
+
await svc.resumeTask(task.id);
|
|
1238
|
+
const taskId = task.id;
|
|
1239
|
+
svc.startTaskExecution(taskId).catch((err) => {
|
|
1240
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
1241
|
+
svc.appendOutput(taskId, `Execution error: ${errorMsg}`).catch(() => {});
|
|
1242
|
+
});
|
|
1243
|
+
const msg = `Resumed task: ${task.name}`;
|
|
1244
|
+
await callback?.({ content: { text: msg } });
|
|
1245
|
+
return { success: true, text: msg };
|
|
1246
|
+
}
|
|
1078
1247
|
};
|
|
1079
|
-
var
|
|
1080
|
-
name: "
|
|
1081
|
-
similes: [
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
"
|
|
1085
|
-
|
|
1086
|
-
description: "Send a message to a session by its session key. The session key is mapped to an Eliza room.",
|
|
1087
|
-
validate: async (runtime, message, _state) => {
|
|
1088
|
-
const messagingService = runtime.getService("MESSAGING");
|
|
1089
|
-
if (!messagingService) {
|
|
1090
|
-
return false;
|
|
1091
|
-
}
|
|
1092
|
-
const params = message.content?.params;
|
|
1093
|
-
if (!params?.sessionKey) {
|
|
1248
|
+
var cancelTaskAction = {
|
|
1249
|
+
name: "CANCEL_TASK",
|
|
1250
|
+
similes: ["DELETE_TASK", "REMOVE_TASK", "ABORT_TASK"],
|
|
1251
|
+
description: "Cancel a task.",
|
|
1252
|
+
validate: async (runtime, message) => {
|
|
1253
|
+
const svc = runtime.getService("CODE_TASK");
|
|
1254
|
+
if (!svc) {
|
|
1094
1255
|
return false;
|
|
1095
1256
|
}
|
|
1096
|
-
const
|
|
1097
|
-
return
|
|
1257
|
+
const t = message.content.text?.toLowerCase() ?? "";
|
|
1258
|
+
return (t.includes("cancel") || t.includes("delete") || t.includes("remove")) && t.includes("task");
|
|
1098
1259
|
},
|
|
1099
|
-
handler: async (runtime, message,
|
|
1100
|
-
const
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
}
|
|
1107
|
-
return { success: false, error: "Messaging service not available" };
|
|
1108
|
-
}
|
|
1109
|
-
const params = message.content?.params;
|
|
1110
|
-
const sessionKey = params?.sessionKey;
|
|
1111
|
-
const text = params?.text ?? message.content?.text;
|
|
1112
|
-
if (!sessionKey) {
|
|
1113
|
-
if (callback) {
|
|
1114
|
-
await callback({
|
|
1115
|
-
text: "Please specify the session key to send the message to."
|
|
1116
|
-
});
|
|
1117
|
-
}
|
|
1118
|
-
return { success: false, error: "Missing session key" };
|
|
1119
|
-
}
|
|
1120
|
-
if (!text) {
|
|
1121
|
-
if (callback) {
|
|
1122
|
-
await callback({
|
|
1123
|
-
text: "Please provide the message text to send."
|
|
1124
|
-
});
|
|
1125
|
-
}
|
|
1126
|
-
return { success: false, error: "Missing message text" };
|
|
1127
|
-
}
|
|
1128
|
-
const result = await messagingService.sendToSession(sessionKey, { text });
|
|
1129
|
-
if (callback) {
|
|
1130
|
-
if (result.success) {
|
|
1131
|
-
await callback({
|
|
1132
|
-
text: `Message sent to session via ${result.channel}.`,
|
|
1133
|
-
data: { messageId: result.messageId }
|
|
1134
|
-
});
|
|
1135
|
-
} else {
|
|
1136
|
-
await callback({
|
|
1137
|
-
text: `Failed to send to session: ${result.error}`
|
|
1138
|
-
});
|
|
1139
|
-
}
|
|
1260
|
+
handler: async (runtime, message, _state, _options, callback) => {
|
|
1261
|
+
const svc = getService(runtime);
|
|
1262
|
+
const query = extractQuery(message.content.text ?? "");
|
|
1263
|
+
const task = query ? (await svc.searchTasks(query))[0] : await svc.getCurrentTask();
|
|
1264
|
+
if (!task?.id) {
|
|
1265
|
+
const msg2 = "No task to cancel.";
|
|
1266
|
+
await callback?.({ content: { text: msg2 } });
|
|
1267
|
+
return { success: false, text: msg2 };
|
|
1140
1268
|
}
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
},
|
|
1147
|
-
examples: [
|
|
1148
|
-
[
|
|
1149
|
-
{
|
|
1150
|
-
name: "{{name1}}",
|
|
1151
|
-
content: {
|
|
1152
|
-
text: "Send to session",
|
|
1153
|
-
params: {
|
|
1154
|
-
sessionKey: "agent:main:dm:user123",
|
|
1155
|
-
text: "Update from your subagent!"
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
},
|
|
1159
|
-
{
|
|
1160
|
-
name: "{{agentName}}",
|
|
1161
|
-
content: {
|
|
1162
|
-
text: "Message sent to session via discord.",
|
|
1163
|
-
actions: ["SEND_TO_SESSION_MESSAGE"]
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
]
|
|
1167
|
-
]
|
|
1168
|
-
};
|
|
1169
|
-
var listMessagingChannelsAction = {
|
|
1170
|
-
name: "LIST_MESSAGING_CHANNELS",
|
|
1171
|
-
similes: [
|
|
1172
|
-
"AVAILABLE_CHANNELS",
|
|
1173
|
-
"GET_CHANNELS",
|
|
1174
|
-
"MESSAGING_PLATFORMS"
|
|
1175
|
-
],
|
|
1176
|
-
description: "List all available messaging channels/platforms that the agent can send messages to.",
|
|
1177
|
-
validate: async (runtime, _message, _state) => {
|
|
1178
|
-
const messagingService = runtime.getService("MESSAGING");
|
|
1179
|
-
return !!messagingService;
|
|
1180
|
-
},
|
|
1181
|
-
handler: async (runtime, _message, _state, _options, callback) => {
|
|
1182
|
-
const messagingService = runtime.getService("MESSAGING");
|
|
1183
|
-
if (!messagingService) {
|
|
1184
|
-
if (callback) {
|
|
1185
|
-
await callback({
|
|
1186
|
-
text: "Messaging service is not available."
|
|
1187
|
-
});
|
|
1188
|
-
}
|
|
1189
|
-
return { success: false, error: "Messaging service not available" };
|
|
1190
|
-
}
|
|
1191
|
-
const channels = messagingService.getAvailableChannels();
|
|
1192
|
-
if (callback) {
|
|
1193
|
-
if (channels.length > 0) {
|
|
1194
|
-
await callback({
|
|
1195
|
-
text: `Available messaging channels: ${channels.join(", ")}`,
|
|
1196
|
-
data: { channels }
|
|
1197
|
-
});
|
|
1198
|
-
} else {
|
|
1199
|
-
await callback({
|
|
1200
|
-
text: "No messaging channels are currently available.",
|
|
1201
|
-
data: { channels: [] }
|
|
1202
|
-
});
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
return {
|
|
1206
|
-
success: true,
|
|
1207
|
-
data: { channels }
|
|
1208
|
-
};
|
|
1209
|
-
},
|
|
1210
|
-
examples: [
|
|
1211
|
-
[
|
|
1212
|
-
{
|
|
1213
|
-
name: "{{name1}}",
|
|
1214
|
-
content: {
|
|
1215
|
-
text: "What messaging platforms can you use?"
|
|
1216
|
-
}
|
|
1217
|
-
},
|
|
1218
|
-
{
|
|
1219
|
-
name: "{{agentName}}",
|
|
1220
|
-
content: {
|
|
1221
|
-
text: "Available messaging channels: discord, telegram, internal",
|
|
1222
|
-
actions: ["LIST_MESSAGING_CHANNELS"]
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
]
|
|
1226
|
-
]
|
|
1269
|
+
await svc.cancelTask(task.id);
|
|
1270
|
+
const msg = `Cancelled task: ${task.name}`;
|
|
1271
|
+
await callback?.({ content: { text: msg } });
|
|
1272
|
+
return { success: true, text: msg };
|
|
1273
|
+
}
|
|
1227
1274
|
};
|
|
1228
1275
|
|
|
1229
1276
|
// src/config.ts
|
|
@@ -1235,61 +1282,6 @@ function getConfiguredAgentOrchestratorOptions() {
|
|
|
1235
1282
|
return globalOptions;
|
|
1236
1283
|
}
|
|
1237
1284
|
|
|
1238
|
-
// src/providers/task-context.ts
|
|
1239
|
-
function getService2(runtime) {
|
|
1240
|
-
return runtime.getService("CODE_TASK");
|
|
1241
|
-
}
|
|
1242
|
-
function formatStatus(status) {
|
|
1243
|
-
switch (status) {
|
|
1244
|
-
case "pending":
|
|
1245
|
-
return "⏳ pending";
|
|
1246
|
-
case "running":
|
|
1247
|
-
return "\uD83D\uDD04 running";
|
|
1248
|
-
case "paused":
|
|
1249
|
-
return "⏸️ paused";
|
|
1250
|
-
case "completed":
|
|
1251
|
-
return "✅ completed";
|
|
1252
|
-
case "failed":
|
|
1253
|
-
return "❌ failed";
|
|
1254
|
-
case "cancelled":
|
|
1255
|
-
return "\uD83D\uDED1 cancelled";
|
|
1256
|
-
default:
|
|
1257
|
-
return status;
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
var taskContextProvider = {
|
|
1261
|
-
name: "TASK_CONTEXT",
|
|
1262
|
-
description: "Summary of orchestrated tasks and current selection",
|
|
1263
|
-
dynamic: true,
|
|
1264
|
-
get: async (runtime, _message, _state) => {
|
|
1265
|
-
const svc = getService2(runtime);
|
|
1266
|
-
if (!svc) {
|
|
1267
|
-
return { text: "Task service not available." };
|
|
1268
|
-
}
|
|
1269
|
-
const current = await svc.getCurrentTask();
|
|
1270
|
-
const tasks = await svc.getRecentTasks(10);
|
|
1271
|
-
if (tasks.length === 0) {
|
|
1272
|
-
return { text: "No tasks have been created yet." };
|
|
1273
|
-
}
|
|
1274
|
-
const lines = [];
|
|
1275
|
-
if (current) {
|
|
1276
|
-
lines.push(`## Current Task`);
|
|
1277
|
-
lines.push(`- Name: ${current.name}`);
|
|
1278
|
-
lines.push(`- Status: ${formatStatus(current.metadata.status)}`);
|
|
1279
|
-
lines.push(`- Progress: ${current.metadata.progress}%`);
|
|
1280
|
-
lines.push(`- Provider: ${current.metadata.providerLabel ?? current.metadata.providerId}`);
|
|
1281
|
-
lines.push("");
|
|
1282
|
-
}
|
|
1283
|
-
lines.push("## Recent Tasks");
|
|
1284
|
-
for (const t of tasks) {
|
|
1285
|
-
const marker = current?.id === t.id ? " (current)" : "";
|
|
1286
|
-
lines.push(`- ${t.name} — ${formatStatus(t.metadata.status)} ${t.metadata.progress}%${marker}`);
|
|
1287
|
-
}
|
|
1288
|
-
return { text: lines.join(`
|
|
1289
|
-
`).trim() };
|
|
1290
|
-
}
|
|
1291
|
-
};
|
|
1292
|
-
|
|
1293
1285
|
// src/providers/orchestrator-config.ts
|
|
1294
1286
|
var DEFAULT_CONFIG = {
|
|
1295
1287
|
subagents: {
|
|
@@ -1316,15 +1308,18 @@ function getOrchestratorConfig(runtime) {
|
|
|
1316
1308
|
const subagentsRaw = settings.subagents ?? {};
|
|
1317
1309
|
const a2aRaw = settings.agentToAgent ?? {};
|
|
1318
1310
|
const sandboxRaw = settings.sandbox ?? {};
|
|
1311
|
+
const subagents = {
|
|
1312
|
+
enabled: subagentsRaw.enabled ?? true,
|
|
1313
|
+
timeoutSeconds: subagentsRaw.timeoutSeconds ?? 300,
|
|
1314
|
+
allowAgents: subagentsRaw.allowAgents ?? [],
|
|
1315
|
+
archiveAfterMinutes: subagentsRaw.archiveAfterMinutes ?? 60
|
|
1316
|
+
};
|
|
1317
|
+
if (subagentsRaw.model)
|
|
1318
|
+
subagents.model = subagentsRaw.model;
|
|
1319
|
+
if (subagentsRaw.thinking)
|
|
1320
|
+
subagents.thinking = subagentsRaw.thinking;
|
|
1319
1321
|
return {
|
|
1320
|
-
subagents
|
|
1321
|
-
enabled: subagentsRaw.enabled ?? DEFAULT_CONFIG.subagents.enabled,
|
|
1322
|
-
model: subagentsRaw.model,
|
|
1323
|
-
thinking: subagentsRaw.thinking,
|
|
1324
|
-
timeoutSeconds: subagentsRaw.timeoutSeconds ?? DEFAULT_CONFIG.subagents.timeoutSeconds,
|
|
1325
|
-
allowAgents: subagentsRaw.allowAgents ?? DEFAULT_CONFIG.subagents.allowAgents,
|
|
1326
|
-
archiveAfterMinutes: subagentsRaw.archiveAfterMinutes ?? DEFAULT_CONFIG.subagents.archiveAfterMinutes
|
|
1327
|
-
},
|
|
1322
|
+
subagents,
|
|
1328
1323
|
agentToAgent: {
|
|
1329
1324
|
enabled: a2aRaw.enabled ?? DEFAULT_CONFIG.agentToAgent.enabled,
|
|
1330
1325
|
allow: a2aRaw.allow ?? DEFAULT_CONFIG.agentToAgent.allow
|
|
@@ -1373,7 +1368,62 @@ var orchestratorConfigProvider = {
|
|
|
1373
1368
|
description: "Provides orchestrator configuration including subagents, A2A, and sandbox settings",
|
|
1374
1369
|
get: async (runtime, _message, _state) => {
|
|
1375
1370
|
const config = getOrchestratorConfig(runtime);
|
|
1376
|
-
return formatConfigContext(config);
|
|
1371
|
+
return { text: formatConfigContext(config) };
|
|
1372
|
+
}
|
|
1373
|
+
};
|
|
1374
|
+
|
|
1375
|
+
// src/providers/task-context.ts
|
|
1376
|
+
function getService2(runtime) {
|
|
1377
|
+
return runtime.getService("CODE_TASK");
|
|
1378
|
+
}
|
|
1379
|
+
function formatStatus(status) {
|
|
1380
|
+
switch (status) {
|
|
1381
|
+
case "pending":
|
|
1382
|
+
return "⏳ pending";
|
|
1383
|
+
case "running":
|
|
1384
|
+
return "\uD83D\uDD04 running";
|
|
1385
|
+
case "paused":
|
|
1386
|
+
return "⏸️ paused";
|
|
1387
|
+
case "completed":
|
|
1388
|
+
return "✅ completed";
|
|
1389
|
+
case "failed":
|
|
1390
|
+
return "❌ failed";
|
|
1391
|
+
case "cancelled":
|
|
1392
|
+
return "\uD83D\uDED1 cancelled";
|
|
1393
|
+
default:
|
|
1394
|
+
return status;
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
var taskContextProvider = {
|
|
1398
|
+
name: "TASK_CONTEXT",
|
|
1399
|
+
description: "Summary of orchestrated tasks and current selection",
|
|
1400
|
+
dynamic: true,
|
|
1401
|
+
get: async (runtime, _message, _state) => {
|
|
1402
|
+
const svc = getService2(runtime);
|
|
1403
|
+
if (!svc) {
|
|
1404
|
+
return { text: "Task service not available." };
|
|
1405
|
+
}
|
|
1406
|
+
const current = await svc.getCurrentTask();
|
|
1407
|
+
const tasks = await svc.getRecentTasks(10);
|
|
1408
|
+
if (tasks.length === 0) {
|
|
1409
|
+
return { text: "No tasks have been created yet." };
|
|
1410
|
+
}
|
|
1411
|
+
const lines = [];
|
|
1412
|
+
if (current) {
|
|
1413
|
+
lines.push(`## Current Task`);
|
|
1414
|
+
lines.push(`- Name: ${current.name}`);
|
|
1415
|
+
lines.push(`- Status: ${formatStatus(current.metadata.status)}`);
|
|
1416
|
+
lines.push(`- Progress: ${current.metadata.progress}%`);
|
|
1417
|
+
lines.push(`- Provider: ${current.metadata.providerLabel ?? current.metadata.providerId}`);
|
|
1418
|
+
lines.push("");
|
|
1419
|
+
}
|
|
1420
|
+
lines.push("## Recent Tasks");
|
|
1421
|
+
for (const t of tasks) {
|
|
1422
|
+
const marker = current?.id === t.id ? " (current)" : "";
|
|
1423
|
+
lines.push(`- ${t.name} — ${formatStatus(t.metadata.status)} ${t.metadata.progress}%${marker}`);
|
|
1424
|
+
}
|
|
1425
|
+
return { text: lines.join(`
|
|
1426
|
+
`).trim() };
|
|
1377
1427
|
}
|
|
1378
1428
|
};
|
|
1379
1429
|
|
|
@@ -1809,694 +1859,584 @@ Provider: ${provider.label} (${provider.id})`);
|
|
|
1809
1859
|
const roomId = task.roomId ?? undefined;
|
|
1810
1860
|
const worldId = task.worldId ?? undefined;
|
|
1811
1861
|
const execCtxBase = {
|
|
1812
|
-
runtimeAgentId: this.runtime.agentId,
|
|
1813
|
-
workingDirectory: task.metadata.workingDirectory,
|
|
1814
|
-
appendOutput: async (line) => this.appendOutput(taskId, line),
|
|
1815
|
-
updateProgress: async (p) => this.updateTaskProgress(taskId, p),
|
|
1816
|
-
updateStep: async (stepId, status, output) => this.updateStep(taskId, stepId, status, output),
|
|
1817
|
-
isCancelled: () => this.isTaskCancelled(taskId),
|
|
1818
|
-
isPaused: () => this.isTaskPaused(taskId)
|
|
1819
|
-
};
|
|
1820
|
-
const execCtx = {
|
|
1821
|
-
...execCtxBase,
|
|
1822
|
-
...roomId ? { roomId } : {},
|
|
1823
|
-
...worldId ? { worldId } : {}
|
|
1824
|
-
};
|
|
1825
|
-
const result = await provider.executeTask(task, execCtx);
|
|
1826
|
-
await this.setTaskResult(taskId, result);
|
|
1827
|
-
} catch (e) {
|
|
1828
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
1829
|
-
await this.setTaskError(taskId, msg);
|
|
1830
|
-
} finally {
|
|
1831
|
-
this.clearControl(taskId);
|
|
1832
|
-
}
|
|
1833
|
-
}
|
|
1834
|
-
on(event, handler) {
|
|
1835
|
-
this.emitter.on(event, handler);
|
|
1836
|
-
}
|
|
1837
|
-
off(event, handler) {
|
|
1838
|
-
this.emitter.off(event, handler);
|
|
1839
|
-
}
|
|
1840
|
-
emit(type, taskId, data) {
|
|
1841
|
-
const event = data ? { type, taskId, data } : { type, taskId };
|
|
1842
|
-
this.emitter.emit(type, event);
|
|
1843
|
-
this.emitter.emit("task", event);
|
|
1844
|
-
}
|
|
1845
|
-
async stop() {
|
|
1846
|
-
this.emitter.removeAllListeners();
|
|
1847
|
-
this.controlStates.clear();
|
|
1848
|
-
this.executions.clear();
|
|
1849
|
-
}
|
|
1850
|
-
async getTaskContext() {
|
|
1851
|
-
const current = await this.getCurrentTask();
|
|
1852
|
-
const tasks = await this.getRecentTasks(10);
|
|
1853
|
-
if (tasks.length === 0) {
|
|
1854
|
-
return "No tasks have been created yet.";
|
|
1855
|
-
}
|
|
1856
|
-
const lines = [];
|
|
1857
|
-
const active = current ?? tasks[0] ?? null;
|
|
1858
|
-
if (active) {
|
|
1859
|
-
const m = active.metadata;
|
|
1860
|
-
lines.push(`## Current Task (selected): ${active.name}`);
|
|
1861
|
-
lines.push(`- **Execution status**: ${m.status}`);
|
|
1862
|
-
lines.push(`- **Progress**: ${m.progress}%`);
|
|
1863
|
-
lines.push(`- **Provider**: ${m.providerLabel ?? m.providerId}`);
|
|
1864
|
-
lines.push("");
|
|
1865
|
-
if (active.description) {
|
|
1866
|
-
lines.push("### Description");
|
|
1867
|
-
lines.push(active.description);
|
|
1868
|
-
lines.push("");
|
|
1869
|
-
}
|
|
1870
|
-
if (m.steps.length > 0) {
|
|
1871
|
-
lines.push("### Plan / Steps");
|
|
1872
|
-
for (const s of m.steps) {
|
|
1873
|
-
lines.push(`- [${s.status}] ${s.description}`);
|
|
1874
|
-
}
|
|
1875
|
-
lines.push("");
|
|
1876
|
-
}
|
|
1877
|
-
if (m.output.length > 0) {
|
|
1878
|
-
lines.push("### Task Output (history)");
|
|
1879
|
-
lines.push("```");
|
|
1880
|
-
lines.push(...m.output.slice(-200));
|
|
1881
|
-
lines.push("```");
|
|
1882
|
-
lines.push("");
|
|
1883
|
-
}
|
|
1884
|
-
}
|
|
1885
|
-
return lines.join(`
|
|
1886
|
-
`).trim();
|
|
1887
|
-
}
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
|
-
// src/services/subagent-service.ts
|
|
1891
|
-
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
1892
|
-
import crypto2 from "node:crypto";
|
|
1893
|
-
import {
|
|
1894
|
-
EventType,
|
|
1895
|
-
ChannelType,
|
|
1896
|
-
Service as Service2
|
|
1897
|
-
} from "@elizaos/core";
|
|
1898
|
-
class SubagentService extends Service2 {
|
|
1899
|
-
static serviceType = "SUBAGENT";
|
|
1900
|
-
capabilityDescription = "Manages subagent spawning, lifecycle, and communication";
|
|
1901
|
-
emitter = new EventEmitter2;
|
|
1902
|
-
subagentRuns = new Map;
|
|
1903
|
-
activeRuns = new Map;
|
|
1904
|
-
sweeper = null;
|
|
1905
|
-
initialized = false;
|
|
1906
|
-
static async start(runtime) {
|
|
1907
|
-
const service = new SubagentService(runtime);
|
|
1908
|
-
await service.initialize();
|
|
1909
|
-
return service;
|
|
1910
|
-
}
|
|
1911
|
-
async initialize() {
|
|
1912
|
-
if (this.initialized) {
|
|
1913
|
-
return;
|
|
1914
|
-
}
|
|
1915
|
-
this.initialized = true;
|
|
1916
|
-
this.runtime.registerEvent(EventType.RUN_ENDED, async (payload) => {
|
|
1917
|
-
await this.handleRunEnded(payload);
|
|
1918
|
-
});
|
|
1919
|
-
this.runtime.registerEvent(EventType.RUN_TIMEOUT, async (payload) => {
|
|
1920
|
-
await this.handleRunTimeout(payload);
|
|
1921
|
-
});
|
|
1922
|
-
this.startSweeper();
|
|
1923
|
-
}
|
|
1924
|
-
getConfig() {
|
|
1925
|
-
const settings = this.runtime.character?.settings;
|
|
1926
|
-
const subagents = settings?.subagents ?? {};
|
|
1927
|
-
return {
|
|
1928
|
-
enabled: subagents.enabled !== false,
|
|
1929
|
-
model: subagents.model,
|
|
1930
|
-
thinking: subagents.thinking,
|
|
1931
|
-
timeoutSeconds: subagents.timeoutSeconds ?? 300,
|
|
1932
|
-
allowAgents: subagents.allowAgents ?? [],
|
|
1933
|
-
archiveAfterMinutes: subagents.archiveAfterMinutes ?? 60
|
|
1934
|
-
};
|
|
1935
|
-
}
|
|
1936
|
-
getAgentToAgentPolicy() {
|
|
1937
|
-
const settings = this.runtime.character?.settings;
|
|
1938
|
-
const a2aConfig = settings?.agentToAgent ?? {};
|
|
1939
|
-
const enabled = a2aConfig.enabled === true;
|
|
1940
|
-
const allowRules = (a2aConfig.allow ?? []).map((rule) => ({
|
|
1941
|
-
source: rule.source ?? "*",
|
|
1942
|
-
target: rule.target ?? "*"
|
|
1943
|
-
}));
|
|
1944
|
-
return {
|
|
1945
|
-
enabled,
|
|
1946
|
-
allowRules,
|
|
1947
|
-
isAllowed: (sourceAgentId, targetAgentId) => {
|
|
1948
|
-
if (!enabled) {
|
|
1949
|
-
return false;
|
|
1950
|
-
}
|
|
1951
|
-
if (sourceAgentId === targetAgentId) {
|
|
1952
|
-
return true;
|
|
1953
|
-
}
|
|
1954
|
-
const sourceNorm = normalizeAgentId2(sourceAgentId);
|
|
1955
|
-
const targetNorm = normalizeAgentId2(targetAgentId);
|
|
1956
|
-
for (const rule of allowRules) {
|
|
1957
|
-
const sourceMatch = rule.source === "*" || normalizeAgentId2(rule.source) === sourceNorm;
|
|
1958
|
-
const targetMatch = rule.target === "*" || normalizeAgentId2(rule.target) === targetNorm;
|
|
1959
|
-
if (sourceMatch && targetMatch) {
|
|
1960
|
-
return true;
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
return false;
|
|
1964
|
-
}
|
|
1965
|
-
};
|
|
1966
|
-
}
|
|
1967
|
-
async spawnSubagent(params, requesterContext) {
|
|
1968
|
-
const config = this.getConfig();
|
|
1969
|
-
if (!config.enabled) {
|
|
1970
|
-
return {
|
|
1971
|
-
status: "forbidden",
|
|
1972
|
-
error: "Subagent spawning is disabled"
|
|
1973
|
-
};
|
|
1974
|
-
}
|
|
1975
|
-
if (requesterContext.sessionKey && isSubagentSessionKey2(requesterContext.sessionKey)) {
|
|
1976
|
-
return {
|
|
1977
|
-
status: "forbidden",
|
|
1978
|
-
error: "sessions_spawn is not allowed from sub-agent sessions"
|
|
1979
|
-
};
|
|
1980
|
-
}
|
|
1981
|
-
const requesterAgentId = requesterContext.sessionKey ? extractAgentIdFromSessionKey(requesterContext.sessionKey) : this.runtime.character?.name ?? "unknown";
|
|
1982
|
-
const targetAgentId = params.agentId ? normalizeAgentId2(params.agentId) : requesterAgentId;
|
|
1983
|
-
if (targetAgentId !== requesterAgentId) {
|
|
1984
|
-
const allowAgents = config.allowAgents ?? [];
|
|
1985
|
-
const allowAny = allowAgents.some((v) => v.trim() === "*");
|
|
1986
|
-
const allowSet = new Set(allowAgents.filter((v) => v.trim() && v.trim() !== "*").map((v) => normalizeAgentId2(v)));
|
|
1987
|
-
if (!allowAny && !allowSet.has(targetAgentId)) {
|
|
1988
|
-
return {
|
|
1989
|
-
status: "forbidden",
|
|
1990
|
-
error: `agentId "${targetAgentId}" is not allowed for subagent spawning`
|
|
1991
|
-
};
|
|
1992
|
-
}
|
|
1993
|
-
}
|
|
1994
|
-
const childSessionKey = createSubagentSessionKey(targetAgentId);
|
|
1995
|
-
const runId = crypto2.randomUUID();
|
|
1996
|
-
const childRoomId = sessionKeyToRoomId(childSessionKey, targetAgentId);
|
|
1997
|
-
const roomMetadata = {
|
|
1998
|
-
isSubagent: true,
|
|
1999
|
-
sessionKey: childSessionKey,
|
|
2000
|
-
parentRoomId: requesterContext.roomId,
|
|
2001
|
-
parentSessionKey: requesterContext.sessionKey,
|
|
2002
|
-
task: params.task,
|
|
2003
|
-
label: params.label,
|
|
2004
|
-
spawnedAt: Date.now(),
|
|
2005
|
-
cleanup: params.cleanup ?? "keep"
|
|
2006
|
-
};
|
|
2007
|
-
const childRoom = {
|
|
2008
|
-
id: childRoomId,
|
|
2009
|
-
name: params.label || `Subagent: ${params.task.slice(0, 50)}`,
|
|
2010
|
-
type: ChannelType.SELF,
|
|
2011
|
-
channelId: childSessionKey,
|
|
2012
|
-
agentId: this.runtime.agentId,
|
|
2013
|
-
worldId: this.runtime.agentId,
|
|
2014
|
-
metadata: roomMetadata
|
|
2015
|
-
};
|
|
2016
|
-
await this.runtime.ensureRoomExists(childRoom);
|
|
2017
|
-
const now2 = Date.now();
|
|
2018
|
-
const archiveAfterMs = config.archiveAfterMinutes ? config.archiveAfterMinutes * 60000 : undefined;
|
|
2019
|
-
const record = {
|
|
2020
|
-
runId,
|
|
2021
|
-
childSessionKey,
|
|
2022
|
-
requesterSessionKey: requesterContext.sessionKey ?? "unknown",
|
|
2023
|
-
requesterOrigin: normalizeDeliveryContext(requesterContext.origin),
|
|
2024
|
-
requesterDisplayKey: requesterContext.sessionKey ?? "main",
|
|
2025
|
-
task: params.task,
|
|
2026
|
-
cleanup: params.cleanup ?? "keep",
|
|
2027
|
-
label: params.label,
|
|
2028
|
-
createdAt: now2,
|
|
2029
|
-
startedAt: now2,
|
|
2030
|
-
archiveAtMs: archiveAfterMs ? now2 + archiveAfterMs : undefined,
|
|
2031
|
-
cleanupHandled: false,
|
|
2032
|
-
roomId: childRoomId,
|
|
2033
|
-
worldId: this.runtime.agentId
|
|
2034
|
-
};
|
|
2035
|
-
this.subagentRuns.set(runId, record);
|
|
2036
|
-
this.emitSubagentEvent("SUBAGENT_SPAWN_REQUESTED", {
|
|
2037
|
-
runId,
|
|
2038
|
-
childSessionKey,
|
|
2039
|
-
childRoomId,
|
|
2040
|
-
requesterSessionKey: requesterContext.sessionKey,
|
|
2041
|
-
requesterRoomId: requesterContext.roomId,
|
|
2042
|
-
task: params.task,
|
|
2043
|
-
label: params.label
|
|
2044
|
-
});
|
|
2045
|
-
const systemPrompt = this.buildSubagentSystemPrompt({
|
|
2046
|
-
requesterSessionKey: requesterContext.sessionKey,
|
|
2047
|
-
requesterOrigin: requesterContext.origin,
|
|
2048
|
-
childSessionKey,
|
|
2049
|
-
label: params.label,
|
|
2050
|
-
task: params.task
|
|
2051
|
-
});
|
|
2052
|
-
const initialMessage = {
|
|
2053
|
-
id: hashToUUID(`${runId}-initial`),
|
|
2054
|
-
entityId: this.runtime.agentId,
|
|
2055
|
-
agentId: this.runtime.agentId,
|
|
2056
|
-
roomId: childRoomId,
|
|
2057
|
-
content: {
|
|
2058
|
-
text: params.task,
|
|
2059
|
-
type: "text",
|
|
2060
|
-
metadata: {
|
|
2061
|
-
isSubagentTask: true,
|
|
2062
|
-
runId,
|
|
2063
|
-
systemPromptOverride: systemPrompt,
|
|
2064
|
-
modelOverride: params.model || config.model,
|
|
2065
|
-
thinkingOverride: params.thinking || config.thinking
|
|
2066
|
-
}
|
|
2067
|
-
}
|
|
2068
|
-
};
|
|
2069
|
-
this.executeSubagentRun(runId, initialMessage, params.runTimeoutSeconds).catch((error) => {
|
|
2070
|
-
this.runtime.logger.error("Subagent execution error", { runId, error });
|
|
2071
|
-
this.handleSubagentError(runId, error);
|
|
2072
|
-
});
|
|
2073
|
-
return {
|
|
2074
|
-
status: "accepted",
|
|
2075
|
-
childSessionKey,
|
|
2076
|
-
childRoomId,
|
|
2077
|
-
runId,
|
|
2078
|
-
modelApplied: !!(params.model || config.model)
|
|
2079
|
-
};
|
|
2080
|
-
}
|
|
2081
|
-
async executeSubagentRun(runId, initialMessage, timeoutSeconds) {
|
|
2082
|
-
const config = this.getConfig();
|
|
2083
|
-
const timeout = (timeoutSeconds ?? config.timeoutSeconds ?? 300) * 1000;
|
|
2084
|
-
const controller = new AbortController;
|
|
2085
|
-
this.activeRuns.set(runId, controller);
|
|
2086
|
-
const timeoutId = timeout > 0 ? setTimeout(() => {
|
|
2087
|
-
controller.abort();
|
|
2088
|
-
this.handleSubagentTimeout(runId);
|
|
2089
|
-
}, timeout) : null;
|
|
2090
|
-
try {
|
|
2091
|
-
await this.runtime.emitEvent(EventType.MESSAGE_RECEIVED, {
|
|
2092
|
-
runtime: this.runtime,
|
|
2093
|
-
message: initialMessage,
|
|
2094
|
-
source: "subagent"
|
|
2095
|
-
});
|
|
2096
|
-
await this.waitForCompletion(runId, timeout, controller.signal);
|
|
1862
|
+
runtimeAgentId: this.runtime.agentId,
|
|
1863
|
+
workingDirectory: task.metadata.workingDirectory,
|
|
1864
|
+
appendOutput: async (line) => this.appendOutput(taskId, line),
|
|
1865
|
+
updateProgress: async (p) => this.updateTaskProgress(taskId, p),
|
|
1866
|
+
updateStep: async (stepId, status, output) => this.updateStep(taskId, stepId, status, output),
|
|
1867
|
+
isCancelled: () => this.isTaskCancelled(taskId),
|
|
1868
|
+
isPaused: () => this.isTaskPaused(taskId)
|
|
1869
|
+
};
|
|
1870
|
+
const execCtx = {
|
|
1871
|
+
...execCtxBase,
|
|
1872
|
+
...roomId ? { roomId } : {},
|
|
1873
|
+
...worldId ? { worldId } : {}
|
|
1874
|
+
};
|
|
1875
|
+
const result = await provider.executeTask(task, execCtx);
|
|
1876
|
+
await this.setTaskResult(taskId, result);
|
|
1877
|
+
} catch (e) {
|
|
1878
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1879
|
+
await this.setTaskError(taskId, msg);
|
|
2097
1880
|
} finally {
|
|
2098
|
-
|
|
2099
|
-
clearTimeout(timeoutId);
|
|
2100
|
-
}
|
|
2101
|
-
this.activeRuns.delete(runId);
|
|
1881
|
+
this.clearControl(taskId);
|
|
2102
1882
|
}
|
|
2103
1883
|
}
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
1884
|
+
on(event, handler) {
|
|
1885
|
+
this.emitter.on(event, handler);
|
|
1886
|
+
}
|
|
1887
|
+
off(event, handler) {
|
|
1888
|
+
this.emitter.off(event, handler);
|
|
1889
|
+
}
|
|
1890
|
+
emit(type, taskId, data) {
|
|
1891
|
+
const event = data ? { type, taskId, data } : { type, taskId };
|
|
1892
|
+
this.emitter.emit(type, event);
|
|
1893
|
+
this.emitter.emit("task", event);
|
|
1894
|
+
}
|
|
1895
|
+
async stop() {
|
|
1896
|
+
this.emitter.removeAllListeners();
|
|
1897
|
+
this.controlStates.clear();
|
|
1898
|
+
this.executions.clear();
|
|
1899
|
+
}
|
|
1900
|
+
async getTaskContext() {
|
|
1901
|
+
const current = await this.getCurrentTask();
|
|
1902
|
+
const tasks = await this.getRecentTasks(10);
|
|
1903
|
+
if (tasks.length === 0) {
|
|
1904
|
+
return "No tasks have been created yet.";
|
|
1905
|
+
}
|
|
1906
|
+
const lines = [];
|
|
1907
|
+
const active = current ?? tasks[0] ?? null;
|
|
1908
|
+
if (active) {
|
|
1909
|
+
const m = active.metadata;
|
|
1910
|
+
lines.push(`## Current Task (selected): ${active.name}`);
|
|
1911
|
+
lines.push(`- **Execution status**: ${m.status}`);
|
|
1912
|
+
lines.push(`- **Progress**: ${m.progress}%`);
|
|
1913
|
+
lines.push(`- **Provider**: ${m.providerLabel ?? m.providerId}`);
|
|
1914
|
+
lines.push("");
|
|
1915
|
+
if (active.description) {
|
|
1916
|
+
lines.push("### Description");
|
|
1917
|
+
lines.push(active.description);
|
|
1918
|
+
lines.push("");
|
|
2111
1919
|
}
|
|
2112
|
-
if (
|
|
2113
|
-
|
|
1920
|
+
if (m.steps.length > 0) {
|
|
1921
|
+
lines.push("### Plan / Steps");
|
|
1922
|
+
for (const s of m.steps) {
|
|
1923
|
+
lines.push(`- [${s.status}] ${s.description}`);
|
|
1924
|
+
}
|
|
1925
|
+
lines.push("");
|
|
2114
1926
|
}
|
|
2115
|
-
if (
|
|
2116
|
-
|
|
1927
|
+
if (m.output.length > 0) {
|
|
1928
|
+
lines.push("### Task Output (history)");
|
|
1929
|
+
lines.push("```");
|
|
1930
|
+
lines.push(...m.output.slice(-200));
|
|
1931
|
+
lines.push("```");
|
|
1932
|
+
lines.push("");
|
|
2117
1933
|
}
|
|
2118
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
2119
1934
|
}
|
|
1935
|
+
return lines.join(`
|
|
1936
|
+
`).trim();
|
|
2120
1937
|
}
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
// src/services/messaging-service.ts
|
|
1941
|
+
import crypto2 from "node:crypto";
|
|
1942
|
+
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
1943
|
+
import { EventType, Service as Service2 } from "@elizaos/core";
|
|
1944
|
+
class MessagingService extends Service2 {
|
|
1945
|
+
static serviceType = "MESSAGING";
|
|
1946
|
+
capabilityDescription = "Unified cross-platform messaging for sending messages to any supported channel";
|
|
1947
|
+
emitter = new EventEmitter2;
|
|
1948
|
+
adapters = new Map;
|
|
1949
|
+
pendingDeliveries = new Map;
|
|
1950
|
+
initialized = false;
|
|
1951
|
+
static async start(runtime) {
|
|
1952
|
+
const service = new MessagingService(runtime);
|
|
1953
|
+
await service.initialize();
|
|
1954
|
+
return service;
|
|
1955
|
+
}
|
|
1956
|
+
async initialize() {
|
|
1957
|
+
if (this.initialized) {
|
|
2124
1958
|
return;
|
|
2125
1959
|
}
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
1960
|
+
this.initialized = true;
|
|
1961
|
+
this.registerBuiltInAdapters();
|
|
1962
|
+
}
|
|
1963
|
+
registerBuiltInAdapters() {
|
|
1964
|
+
this.registerAdapter({
|
|
1965
|
+
channel: "discord",
|
|
1966
|
+
isAvailable: () => {
|
|
1967
|
+
const service = this.runtime.getService("DISCORD");
|
|
1968
|
+
return !!service;
|
|
1969
|
+
},
|
|
1970
|
+
send: async (params) => this.sendViaDiscord(params)
|
|
2134
1971
|
});
|
|
2135
|
-
this.
|
|
2136
|
-
|
|
1972
|
+
this.registerAdapter({
|
|
1973
|
+
channel: "telegram",
|
|
1974
|
+
isAvailable: () => {
|
|
1975
|
+
const service = this.runtime.getService("TELEGRAM");
|
|
1976
|
+
return !!service;
|
|
1977
|
+
},
|
|
1978
|
+
send: async (params) => this.sendViaTelegram(params)
|
|
2137
1979
|
});
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
record.outcome = {
|
|
2146
|
-
status: "error",
|
|
2147
|
-
error: error instanceof Error ? error.message : String(error)
|
|
2148
|
-
};
|
|
2149
|
-
this.emitSubagentEvent("SUBAGENT_RUN_FAILED", {
|
|
2150
|
-
runId,
|
|
2151
|
-
childSessionKey: record.childSessionKey,
|
|
2152
|
-
childRoomId: record.roomId,
|
|
2153
|
-
task: record.task,
|
|
2154
|
-
status: "error",
|
|
2155
|
-
error: record.outcome.error
|
|
1980
|
+
this.registerAdapter({
|
|
1981
|
+
channel: "slack",
|
|
1982
|
+
isAvailable: () => {
|
|
1983
|
+
const service = this.runtime.getService("slack");
|
|
1984
|
+
return !!service;
|
|
1985
|
+
},
|
|
1986
|
+
send: async (params) => this.sendViaSlack(params)
|
|
2156
1987
|
});
|
|
2157
|
-
this.
|
|
2158
|
-
|
|
1988
|
+
this.registerAdapter({
|
|
1989
|
+
channel: "whatsapp",
|
|
1990
|
+
isAvailable: () => {
|
|
1991
|
+
const service = this.runtime.getService("whatsapp");
|
|
1992
|
+
return !!service;
|
|
1993
|
+
},
|
|
1994
|
+
send: async (params) => this.sendViaWhatsApp(params)
|
|
1995
|
+
});
|
|
1996
|
+
this.registerAdapter({
|
|
1997
|
+
channel: "twitch",
|
|
1998
|
+
isAvailable: () => {
|
|
1999
|
+
const service = this.runtime.getService("twitch");
|
|
2000
|
+
return !!service;
|
|
2001
|
+
},
|
|
2002
|
+
send: async (params) => this.sendViaTwitch(params)
|
|
2003
|
+
});
|
|
2004
|
+
this.registerAdapter({
|
|
2005
|
+
channel: "internal",
|
|
2006
|
+
isAvailable: () => true,
|
|
2007
|
+
send: async (params) => this.sendViaInternal(params)
|
|
2159
2008
|
});
|
|
2160
2009
|
}
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
childSessionKey: record.childSessionKey,
|
|
2173
|
-
childRoomId: record.roomId,
|
|
2174
|
-
task: record.task,
|
|
2175
|
-
status: "completed",
|
|
2176
|
-
startedAt: record.startedAt,
|
|
2177
|
-
endedAt: record.endedAt,
|
|
2178
|
-
durationMs: record.endedAt - (record.startedAt ?? record.createdAt)
|
|
2179
|
-
});
|
|
2180
|
-
await this.announceSubagentResult(runId);
|
|
2181
|
-
break;
|
|
2010
|
+
registerAdapter(adapter) {
|
|
2011
|
+
this.adapters.set(adapter.channel, adapter);
|
|
2012
|
+
}
|
|
2013
|
+
getAdapter(channel) {
|
|
2014
|
+
return this.adapters.get(channel);
|
|
2015
|
+
}
|
|
2016
|
+
getAvailableChannels() {
|
|
2017
|
+
const channels = [];
|
|
2018
|
+
for (const [channel, adapter] of this.adapters) {
|
|
2019
|
+
if (adapter.isAvailable()) {
|
|
2020
|
+
channels.push(channel);
|
|
2182
2021
|
}
|
|
2183
2022
|
}
|
|
2023
|
+
return channels;
|
|
2184
2024
|
}
|
|
2185
|
-
async
|
|
2186
|
-
const
|
|
2187
|
-
|
|
2188
|
-
|
|
2025
|
+
async send(params) {
|
|
2026
|
+
const idempotencyKey = params.idempotencyKey ?? crypto2.randomUUID();
|
|
2027
|
+
const channel = params.target.channel;
|
|
2028
|
+
const existing = this.pendingDeliveries.get(idempotencyKey);
|
|
2029
|
+
if (existing) {
|
|
2030
|
+
const result = {
|
|
2031
|
+
success: existing.status.status === "sent" || existing.status.status === "delivered",
|
|
2032
|
+
channel,
|
|
2033
|
+
targetId: params.target.to
|
|
2034
|
+
};
|
|
2035
|
+
if (existing.status.messageId)
|
|
2036
|
+
result.messageId = existing.status.messageId;
|
|
2037
|
+
if (existing.status.error)
|
|
2038
|
+
result.error = existing.status.error;
|
|
2039
|
+
if (existing.status.status === "sent")
|
|
2040
|
+
result.sentAt = existing.status.updatedAt;
|
|
2041
|
+
return result;
|
|
2042
|
+
}
|
|
2043
|
+
const status = {
|
|
2044
|
+
status: "pending",
|
|
2045
|
+
updatedAt: Date.now()
|
|
2046
|
+
};
|
|
2047
|
+
this.pendingDeliveries.set(idempotencyKey, { params, status });
|
|
2048
|
+
this.emitMessagingEvent("MESSAGING_SEND_REQUESTED", {
|
|
2049
|
+
idempotencyKey,
|
|
2050
|
+
channel,
|
|
2051
|
+
targetId: params.target.to,
|
|
2052
|
+
status: "pending"
|
|
2053
|
+
});
|
|
2054
|
+
const adapter = this.adapters.get(channel);
|
|
2055
|
+
if (!adapter) {
|
|
2056
|
+
const errorMsg = `No adapter registered for channel: ${channel}`;
|
|
2057
|
+
const result = {
|
|
2058
|
+
success: false,
|
|
2059
|
+
channel,
|
|
2060
|
+
targetId: params.target.to,
|
|
2061
|
+
error: errorMsg
|
|
2062
|
+
};
|
|
2063
|
+
status.status = "failed";
|
|
2064
|
+
status.error = errorMsg;
|
|
2065
|
+
status.updatedAt = Date.now();
|
|
2066
|
+
this.emitMessagingEvent("MESSAGING_SEND_FAILED", {
|
|
2067
|
+
idempotencyKey,
|
|
2068
|
+
channel,
|
|
2069
|
+
targetId: params.target.to,
|
|
2070
|
+
status: "failed",
|
|
2071
|
+
error: errorMsg
|
|
2072
|
+
});
|
|
2073
|
+
return result;
|
|
2074
|
+
}
|
|
2075
|
+
if (!adapter.isAvailable()) {
|
|
2076
|
+
const errorMsg = `${channel} service is not available`;
|
|
2077
|
+
const result = {
|
|
2078
|
+
success: false,
|
|
2079
|
+
channel,
|
|
2080
|
+
targetId: params.target.to,
|
|
2081
|
+
error: errorMsg
|
|
2082
|
+
};
|
|
2083
|
+
status.status = "failed";
|
|
2084
|
+
status.error = errorMsg;
|
|
2085
|
+
status.updatedAt = Date.now();
|
|
2086
|
+
this.emitMessagingEvent("MESSAGING_SEND_FAILED", {
|
|
2087
|
+
idempotencyKey,
|
|
2088
|
+
channel,
|
|
2089
|
+
targetId: params.target.to,
|
|
2090
|
+
status: "failed",
|
|
2091
|
+
error: errorMsg
|
|
2092
|
+
});
|
|
2093
|
+
return result;
|
|
2189
2094
|
}
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2095
|
+
try {
|
|
2096
|
+
const result = await adapter.send({ ...params, idempotencyKey });
|
|
2097
|
+
status.status = result.success ? "sent" : "failed";
|
|
2098
|
+
if (result.messageId)
|
|
2099
|
+
status.messageId = result.messageId;
|
|
2100
|
+
if (result.error)
|
|
2101
|
+
status.error = result.error;
|
|
2102
|
+
status.updatedAt = Date.now();
|
|
2103
|
+
if (result.success) {
|
|
2104
|
+
const sentPayload = {
|
|
2105
|
+
idempotencyKey,
|
|
2106
|
+
channel,
|
|
2107
|
+
targetId: params.target.to,
|
|
2108
|
+
status: "sent"
|
|
2109
|
+
};
|
|
2110
|
+
if (result.messageId)
|
|
2111
|
+
sentPayload.messageId = result.messageId;
|
|
2112
|
+
if (result.sentAt)
|
|
2113
|
+
sentPayload.sentAt = result.sentAt;
|
|
2114
|
+
this.emitMessagingEvent("MESSAGING_SENT", sentPayload);
|
|
2115
|
+
} else {
|
|
2116
|
+
const failedPayload = {
|
|
2117
|
+
idempotencyKey,
|
|
2118
|
+
channel,
|
|
2119
|
+
targetId: params.target.to,
|
|
2120
|
+
status: "failed"
|
|
2121
|
+
};
|
|
2122
|
+
if (result.error)
|
|
2123
|
+
failedPayload.error = result.error;
|
|
2124
|
+
this.emitMessagingEvent("MESSAGING_SEND_FAILED", failedPayload);
|
|
2194
2125
|
}
|
|
2126
|
+
return result;
|
|
2127
|
+
} catch (error) {
|
|
2128
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2129
|
+
status.status = "failed";
|
|
2130
|
+
status.error = errorMessage;
|
|
2131
|
+
status.updatedAt = Date.now();
|
|
2132
|
+
this.emitMessagingEvent("MESSAGING_SEND_FAILED", {
|
|
2133
|
+
idempotencyKey,
|
|
2134
|
+
channel,
|
|
2135
|
+
targetId: params.target.to,
|
|
2136
|
+
status: "failed",
|
|
2137
|
+
error: errorMessage
|
|
2138
|
+
});
|
|
2139
|
+
return {
|
|
2140
|
+
success: false,
|
|
2141
|
+
channel,
|
|
2142
|
+
targetId: params.target.to,
|
|
2143
|
+
error: errorMessage
|
|
2144
|
+
};
|
|
2195
2145
|
}
|
|
2196
2146
|
}
|
|
2197
|
-
async
|
|
2198
|
-
const
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2147
|
+
async sendToDeliveryContext(deliveryContext, content, options) {
|
|
2148
|
+
const channel = this.normalizeChannel(deliveryContext.channel);
|
|
2149
|
+
const to = deliveryContext.to ?? deliveryContext.accountId ?? "";
|
|
2150
|
+
if (!to) {
|
|
2151
|
+
return {
|
|
2152
|
+
success: false,
|
|
2153
|
+
channel,
|
|
2154
|
+
targetId: "",
|
|
2155
|
+
error: "No recipient specified in delivery context"
|
|
2156
|
+
};
|
|
2204
2157
|
}
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
}
|
|
2212
|
-
|
|
2213
|
-
|
|
2158
|
+
return this.send({
|
|
2159
|
+
target: {
|
|
2160
|
+
channel,
|
|
2161
|
+
to,
|
|
2162
|
+
...deliveryContext.accountId ? { accountId: deliveryContext.accountId } : {},
|
|
2163
|
+
...deliveryContext.threadId !== undefined ? { threadId: deliveryContext.threadId } : {}
|
|
2164
|
+
},
|
|
2165
|
+
content,
|
|
2166
|
+
...options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {},
|
|
2167
|
+
...options?.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}
|
|
2168
|
+
});
|
|
2169
|
+
}
|
|
2170
|
+
async sendToRoom(roomId, content, options) {
|
|
2171
|
+
const room = await this.runtime.getRoom(roomId);
|
|
2172
|
+
if (!room) {
|
|
2173
|
+
return {
|
|
2174
|
+
success: false,
|
|
2175
|
+
channel: "unknown",
|
|
2176
|
+
targetId: roomId,
|
|
2177
|
+
error: `Room not found: ${roomId}`
|
|
2178
|
+
};
|
|
2214
2179
|
}
|
|
2215
|
-
const
|
|
2216
|
-
const
|
|
2217
|
-
const
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
reply || "(no output)",
|
|
2225
|
-
"",
|
|
2226
|
-
statsLine,
|
|
2227
|
-
"",
|
|
2228
|
-
"Summarize this naturally for the user. Keep it brief (1-2 sentences).",
|
|
2229
|
-
"Do not mention technical details like tokens, stats, or that this was a background task.",
|
|
2230
|
-
"You can respond with NO_REPLY if no announcement is needed."
|
|
2231
|
-
].join(`
|
|
2232
|
-
`);
|
|
2233
|
-
if (record.requesterSessionKey && record.requesterSessionKey !== "unknown") {
|
|
2234
|
-
const requesterRoomId = sessionKeyToRoomId(record.requesterSessionKey, extractAgentIdFromSessionKey(record.requesterSessionKey));
|
|
2235
|
-
const announceMessage = {
|
|
2236
|
-
id: hashToUUID(`${runId}-announce`),
|
|
2237
|
-
entityId: this.runtime.agentId,
|
|
2238
|
-
agentId: this.runtime.agentId,
|
|
2239
|
-
roomId: requesterRoomId,
|
|
2240
|
-
content: {
|
|
2241
|
-
text: triggerMessage,
|
|
2242
|
-
type: "text",
|
|
2243
|
-
metadata: {
|
|
2244
|
-
isSubagentAnnouncement: true,
|
|
2245
|
-
subagentRunId: runId,
|
|
2246
|
-
deliveryContext: record.requesterOrigin
|
|
2247
|
-
}
|
|
2248
|
-
}
|
|
2180
|
+
const metadata = room.metadata;
|
|
2181
|
+
const channel = this.normalizeChannel(metadata?.messagingChannel);
|
|
2182
|
+
const to = metadata?.messagingTo ?? room.channelId ?? "";
|
|
2183
|
+
if (!to) {
|
|
2184
|
+
return {
|
|
2185
|
+
success: false,
|
|
2186
|
+
channel,
|
|
2187
|
+
targetId: roomId,
|
|
2188
|
+
error: "Room has no messaging target configured"
|
|
2249
2189
|
};
|
|
2250
|
-
await this.runtime.emitEvent(EventType.MESSAGE_RECEIVED, {
|
|
2251
|
-
runtime: this.runtime,
|
|
2252
|
-
message: announceMessage,
|
|
2253
|
-
source: "subagent_announce"
|
|
2254
|
-
});
|
|
2255
2190
|
}
|
|
2256
|
-
this.
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2191
|
+
return this.send({
|
|
2192
|
+
target: {
|
|
2193
|
+
channel,
|
|
2194
|
+
to,
|
|
2195
|
+
...metadata?.messagingAccountId ? { accountId: metadata.messagingAccountId } : {},
|
|
2196
|
+
...metadata?.messagingThreadId !== undefined ? { threadId: metadata.messagingThreadId } : {}
|
|
2197
|
+
},
|
|
2198
|
+
content,
|
|
2199
|
+
...options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {},
|
|
2200
|
+
...options?.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}
|
|
2262
2201
|
});
|
|
2263
|
-
record.cleanupCompletedAt = Date.now();
|
|
2264
|
-
if (record.cleanup === "delete") {
|
|
2265
|
-
this.subagentRuns.delete(runId);
|
|
2266
|
-
}
|
|
2267
|
-
return true;
|
|
2268
2202
|
}
|
|
2269
|
-
|
|
2270
|
-
const
|
|
2271
|
-
const
|
|
2272
|
-
|
|
2273
|
-
"",
|
|
2274
|
-
"You are a **subagent** spawned by the main agent for a specific task.",
|
|
2275
|
-
"",
|
|
2276
|
-
"## Your Role",
|
|
2277
|
-
`- You were created to handle: ${taskText}`,
|
|
2278
|
-
"- Complete this task. That's your entire purpose.",
|
|
2279
|
-
"- You are NOT the main agent. Don't try to be.",
|
|
2280
|
-
"",
|
|
2281
|
-
"## Rules",
|
|
2282
|
-
"1. **Stay focused** - Do your assigned task, nothing else",
|
|
2283
|
-
"2. **Complete the task** - Your final message will be automatically reported to the main agent",
|
|
2284
|
-
"3. **Don't initiate** - No heartbeats, no proactive actions, no side quests",
|
|
2285
|
-
"4. **Be ephemeral** - You may be terminated after task completion. That's fine.",
|
|
2286
|
-
"",
|
|
2287
|
-
"## Output Format",
|
|
2288
|
-
"When complete, your final response should include:",
|
|
2289
|
-
"- What you accomplished or found",
|
|
2290
|
-
"- Any relevant details the main agent should know",
|
|
2291
|
-
"- Keep it concise but informative",
|
|
2292
|
-
"",
|
|
2293
|
-
"## What You DON'T Do",
|
|
2294
|
-
"- NO user conversations (that's main agent's job)",
|
|
2295
|
-
"- NO external messages unless explicitly tasked with a specific recipient",
|
|
2296
|
-
"- NO cron jobs or persistent state",
|
|
2297
|
-
"- NO pretending to be the main agent",
|
|
2298
|
-
"",
|
|
2299
|
-
"## Session Context",
|
|
2300
|
-
params.label ? `- Label: ${params.label}` : undefined,
|
|
2301
|
-
params.requesterSessionKey ? `- Requester session: ${params.requesterSessionKey}` : undefined,
|
|
2302
|
-
params.requesterOrigin?.channel ? `- Requester channel: ${params.requesterOrigin.channel}` : undefined,
|
|
2303
|
-
`- Your session: ${params.childSessionKey}`,
|
|
2304
|
-
""
|
|
2305
|
-
].filter((line) => line !== undefined);
|
|
2306
|
-
return lines.join(`
|
|
2307
|
-
`);
|
|
2203
|
+
async sendToSession(sessionKey, content, options) {
|
|
2204
|
+
const agentId = extractAgentIdFromSessionKey(sessionKey);
|
|
2205
|
+
const roomId = sessionKeyToRoomId(sessionKey, agentId);
|
|
2206
|
+
return this.sendToRoom(roomId, content, options);
|
|
2308
2207
|
}
|
|
2309
|
-
async
|
|
2310
|
-
const
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
}
|
|
2208
|
+
async sendViaDiscord(params) {
|
|
2209
|
+
const discordService = this.runtime.getService("DISCORD");
|
|
2210
|
+
if (!discordService?.client) {
|
|
2211
|
+
return {
|
|
2212
|
+
success: false,
|
|
2213
|
+
channel: "discord",
|
|
2214
|
+
targetId: params.target.to,
|
|
2215
|
+
error: "Discord service not available"
|
|
2216
|
+
};
|
|
2217
|
+
}
|
|
2218
|
+
try {
|
|
2219
|
+
const channel = await discordService.client.channels.fetch(params.target.to);
|
|
2220
|
+
if (!channel?.send) {
|
|
2318
2221
|
return {
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2222
|
+
success: false,
|
|
2223
|
+
channel: "discord",
|
|
2224
|
+
targetId: params.target.to,
|
|
2225
|
+
error: "Channel not found or not a text channel"
|
|
2322
2226
|
};
|
|
2323
2227
|
}
|
|
2228
|
+
const message = await channel.send({
|
|
2229
|
+
content: params.content.text,
|
|
2230
|
+
...params.target.replyToMessageId ? { reply: { messageReference: params.target.replyToMessageId } } : {}
|
|
2231
|
+
});
|
|
2232
|
+
return {
|
|
2233
|
+
success: true,
|
|
2234
|
+
messageId: message.id,
|
|
2235
|
+
channel: "discord",
|
|
2236
|
+
targetId: params.target.to,
|
|
2237
|
+
sentAt: Date.now()
|
|
2238
|
+
};
|
|
2239
|
+
} catch (error) {
|
|
2240
|
+
return {
|
|
2241
|
+
success: false,
|
|
2242
|
+
channel: "discord",
|
|
2243
|
+
targetId: params.target.to,
|
|
2244
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2245
|
+
};
|
|
2324
2246
|
}
|
|
2325
|
-
|
|
2247
|
+
}
|
|
2248
|
+
async sendViaTelegram(params) {
|
|
2249
|
+
const telegramService = this.runtime.getService("TELEGRAM");
|
|
2250
|
+
if (!telegramService?.bot?.telegram) {
|
|
2251
|
+
return {
|
|
2252
|
+
success: false,
|
|
2253
|
+
channel: "telegram",
|
|
2254
|
+
targetId: params.target.to,
|
|
2255
|
+
error: "Telegram service not available"
|
|
2256
|
+
};
|
|
2257
|
+
}
|
|
2258
|
+
try {
|
|
2259
|
+
const chatId = Number.isNaN(Number(params.target.to)) ? params.target.to : Number(params.target.to);
|
|
2260
|
+
const result = await telegramService.bot.telegram.sendMessage(chatId, params.content.text, {
|
|
2261
|
+
reply_to_message_id: params.target.replyToMessageId ? Number(params.target.replyToMessageId) : undefined,
|
|
2262
|
+
disable_web_page_preview: params.content.disableLinkPreview,
|
|
2263
|
+
disable_notification: params.content.silent
|
|
2264
|
+
});
|
|
2265
|
+
return {
|
|
2266
|
+
success: true,
|
|
2267
|
+
messageId: String(result.message_id),
|
|
2268
|
+
channel: "telegram",
|
|
2269
|
+
targetId: params.target.to,
|
|
2270
|
+
sentAt: Date.now()
|
|
2271
|
+
};
|
|
2272
|
+
} catch (error) {
|
|
2326
2273
|
return {
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2274
|
+
success: false,
|
|
2275
|
+
channel: "telegram",
|
|
2276
|
+
targetId: params.target.to,
|
|
2277
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2330
2278
|
};
|
|
2331
2279
|
}
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
}
|
|
2342
|
-
if (!policy.isAllowed(requesterAgentId, targetAgentId)) {
|
|
2343
|
-
return {
|
|
2344
|
-
status: "forbidden",
|
|
2345
|
-
runId,
|
|
2346
|
-
error: "Agent-to-agent messaging denied by policy."
|
|
2347
|
-
};
|
|
2348
|
-
}
|
|
2280
|
+
}
|
|
2281
|
+
async sendViaSlack(params) {
|
|
2282
|
+
const slackService = this.runtime.getService("slack");
|
|
2283
|
+
if (!slackService?.sendMessage) {
|
|
2284
|
+
return {
|
|
2285
|
+
success: false,
|
|
2286
|
+
channel: "slack",
|
|
2287
|
+
targetId: params.target.to,
|
|
2288
|
+
error: "Slack service not available or sendMessage method not found"
|
|
2289
|
+
};
|
|
2349
2290
|
}
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
});
|
|
2355
|
-
const message = {
|
|
2356
|
-
id: hashToUUID(`${runId}-a2a`),
|
|
2357
|
-
entityId: this.runtime.agentId,
|
|
2358
|
-
agentId: this.runtime.agentId,
|
|
2359
|
-
roomId: targetRoomId,
|
|
2360
|
-
content: {
|
|
2361
|
-
text: params.message,
|
|
2362
|
-
type: "text",
|
|
2363
|
-
metadata: {
|
|
2364
|
-
isAgentToAgent: true,
|
|
2365
|
-
runId,
|
|
2366
|
-
senderSessionKey: requesterContext.sessionKey,
|
|
2367
|
-
senderRoomId: requesterContext.roomId,
|
|
2368
|
-
systemPromptOverride: contextMessage
|
|
2369
|
-
}
|
|
2370
|
-
}
|
|
2371
|
-
};
|
|
2372
|
-
const timeoutMs = (params.timeoutSeconds ?? 30) * 1000;
|
|
2373
|
-
if (params.timeoutSeconds === 0) {
|
|
2374
|
-
this.runtime.emitEvent(EventType.MESSAGE_RECEIVED, {
|
|
2375
|
-
runtime: this.runtime,
|
|
2376
|
-
message,
|
|
2377
|
-
source: "a2a"
|
|
2378
|
-
}).catch((err) => {
|
|
2379
|
-
this.runtime.logger.error("A2A send error", { runId, error: err });
|
|
2380
|
-
});
|
|
2381
|
-
this.emitSubagentEvent("A2A_MESSAGE_SENT", {
|
|
2382
|
-
runId,
|
|
2383
|
-
childSessionKey: targetSessionKey,
|
|
2384
|
-
requesterSessionKey: requesterContext.sessionKey,
|
|
2385
|
-
task: params.message
|
|
2291
|
+
try {
|
|
2292
|
+
const result = await slackService.sendMessage(params.target.to, params.content.text, {
|
|
2293
|
+
...params.target.threadId ? { threadTs: String(params.target.threadId) } : {},
|
|
2294
|
+
replyBroadcast: false
|
|
2386
2295
|
});
|
|
2387
2296
|
return {
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2297
|
+
success: true,
|
|
2298
|
+
messageId: result.ts,
|
|
2299
|
+
channel: "slack",
|
|
2300
|
+
targetId: params.target.to,
|
|
2301
|
+
sentAt: Date.now()
|
|
2302
|
+
};
|
|
2303
|
+
} catch (error) {
|
|
2304
|
+
return {
|
|
2305
|
+
success: false,
|
|
2306
|
+
channel: "slack",
|
|
2307
|
+
targetId: params.target.to,
|
|
2308
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2392
2309
|
};
|
|
2393
2310
|
}
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
2405
|
-
const memories = await this.runtime.getMemories({
|
|
2406
|
-
roomId: targetRoomId,
|
|
2407
|
-
count: 10
|
|
2408
|
-
});
|
|
2409
|
-
const newReplies = memories.filter((m) => m.entityId === this.runtime.agentId && m.id !== message.id && m.createdAt && m.createdAt > sentAt);
|
|
2410
|
-
if (newReplies.length > 0) {
|
|
2411
|
-
lastReply = newReplies.sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0))[0];
|
|
2412
|
-
break;
|
|
2413
|
-
}
|
|
2311
|
+
}
|
|
2312
|
+
async sendViaWhatsApp(params) {
|
|
2313
|
+
const whatsappService = this.runtime.getService("whatsapp");
|
|
2314
|
+
if (!whatsappService?.sendText) {
|
|
2315
|
+
return {
|
|
2316
|
+
success: false,
|
|
2317
|
+
channel: "whatsapp",
|
|
2318
|
+
targetId: params.target.to,
|
|
2319
|
+
error: "WhatsApp service not available or sendText method not found"
|
|
2320
|
+
};
|
|
2414
2321
|
}
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
requesterSessionKey: requesterContext.sessionKey,
|
|
2419
|
-
task: params.message
|
|
2420
|
-
});
|
|
2421
|
-
if (!lastReply) {
|
|
2322
|
+
try {
|
|
2323
|
+
const result = await whatsappService.sendText(params.target.to, params.content.text);
|
|
2324
|
+
const messageId = result.messages?.[0]?.id;
|
|
2422
2325
|
return {
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2326
|
+
success: true,
|
|
2327
|
+
...messageId ? { messageId } : {},
|
|
2328
|
+
channel: "whatsapp",
|
|
2329
|
+
targetId: params.target.to,
|
|
2330
|
+
sentAt: Date.now()
|
|
2331
|
+
};
|
|
2332
|
+
} catch (error) {
|
|
2333
|
+
return {
|
|
2334
|
+
success: false,
|
|
2335
|
+
channel: "whatsapp",
|
|
2336
|
+
targetId: params.target.to,
|
|
2337
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2428
2338
|
};
|
|
2429
2339
|
}
|
|
2430
|
-
return {
|
|
2431
|
-
status: "ok",
|
|
2432
|
-
runId,
|
|
2433
|
-
sessionKey: targetSessionKey,
|
|
2434
|
-
reply: lastReply.content?.text,
|
|
2435
|
-
delivery: { status: "delivered", mode: "sync" }
|
|
2436
|
-
};
|
|
2437
|
-
}
|
|
2438
|
-
buildAgentToAgentContext(params) {
|
|
2439
|
-
return [
|
|
2440
|
-
"# Agent-to-Agent Message Context",
|
|
2441
|
-
"",
|
|
2442
|
-
"This message was sent by another agent session.",
|
|
2443
|
-
params.requesterSessionKey ? `- Sender: ${params.requesterSessionKey}` : undefined,
|
|
2444
|
-
`- Target: ${params.targetSessionKey}`,
|
|
2445
|
-
"",
|
|
2446
|
-
"Process this message and respond appropriately."
|
|
2447
|
-
].filter((l) => l !== undefined).join(`
|
|
2448
|
-
`);
|
|
2449
|
-
}
|
|
2450
|
-
getSubagentRun(runId) {
|
|
2451
|
-
return this.subagentRuns.get(runId);
|
|
2452
2340
|
}
|
|
2453
|
-
|
|
2454
|
-
const
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2341
|
+
async sendViaTwitch(params) {
|
|
2342
|
+
const twitchService = this.runtime.getService("twitch");
|
|
2343
|
+
if (!twitchService?.sendMessage) {
|
|
2344
|
+
return {
|
|
2345
|
+
success: false,
|
|
2346
|
+
channel: "twitch",
|
|
2347
|
+
targetId: params.target.to,
|
|
2348
|
+
error: "Twitch service not available or sendMessage method not found"
|
|
2349
|
+
};
|
|
2350
|
+
}
|
|
2351
|
+
try {
|
|
2352
|
+
const result = await twitchService.sendMessage(params.content.text, {
|
|
2353
|
+
channel: params.target.to,
|
|
2354
|
+
...params.target.replyToMessageId ? { replyTo: params.target.replyToMessageId } : {}
|
|
2355
|
+
});
|
|
2356
|
+
return {
|
|
2357
|
+
success: result.success,
|
|
2358
|
+
...result.messageId !== undefined ? { messageId: result.messageId } : {},
|
|
2359
|
+
channel: "twitch",
|
|
2360
|
+
targetId: params.target.to,
|
|
2361
|
+
sentAt: Date.now()
|
|
2362
|
+
};
|
|
2363
|
+
} catch (error) {
|
|
2364
|
+
return {
|
|
2365
|
+
success: false,
|
|
2366
|
+
channel: "twitch",
|
|
2367
|
+
targetId: params.target.to,
|
|
2368
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2369
|
+
};
|
|
2470
2370
|
}
|
|
2471
|
-
const completedRuns = [...this.subagentRuns.values()].filter((run) => {
|
|
2472
|
-
const runLabel = run.label?.toLowerCase().trim();
|
|
2473
|
-
if (runLabel !== normalizedLabel) {
|
|
2474
|
-
return false;
|
|
2475
|
-
}
|
|
2476
|
-
if (normalizedAgentId) {
|
|
2477
|
-
const runAgentId = extractAgentIdFromSessionKey(run.childSessionKey);
|
|
2478
|
-
if (normalizeAgentId2(runAgentId) !== normalizedAgentId) {
|
|
2479
|
-
return false;
|
|
2480
|
-
}
|
|
2481
|
-
}
|
|
2482
|
-
return true;
|
|
2483
|
-
}).sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0));
|
|
2484
|
-
return completedRuns[0];
|
|
2485
2371
|
}
|
|
2486
|
-
|
|
2487
|
-
const
|
|
2488
|
-
|
|
2489
|
-
|
|
2372
|
+
async sendViaInternal(params) {
|
|
2373
|
+
const roomId = params.target.to;
|
|
2374
|
+
const messageId = crypto2.randomUUID();
|
|
2375
|
+
try {
|
|
2376
|
+
const memory = {
|
|
2377
|
+
id: messageId,
|
|
2378
|
+
entityId: this.runtime.agentId,
|
|
2379
|
+
agentId: this.runtime.agentId,
|
|
2380
|
+
roomId,
|
|
2381
|
+
content: {
|
|
2382
|
+
text: params.content.text,
|
|
2383
|
+
type: "text",
|
|
2384
|
+
source: "internal",
|
|
2385
|
+
metadata: {
|
|
2386
|
+
isInternalMessage: true,
|
|
2387
|
+
idempotencyKey: params.idempotencyKey
|
|
2388
|
+
}
|
|
2389
|
+
},
|
|
2390
|
+
createdAt: Date.now()
|
|
2391
|
+
};
|
|
2392
|
+
await this.runtime.emitEvent(EventType.MESSAGE_RECEIVED, {
|
|
2393
|
+
runtime: this.runtime,
|
|
2394
|
+
message: memory,
|
|
2395
|
+
source: "internal_messaging"
|
|
2396
|
+
});
|
|
2397
|
+
return {
|
|
2398
|
+
success: true,
|
|
2399
|
+
messageId,
|
|
2400
|
+
channel: "internal",
|
|
2401
|
+
targetId: params.target.to,
|
|
2402
|
+
sentAt: Date.now()
|
|
2403
|
+
};
|
|
2404
|
+
} catch (error) {
|
|
2405
|
+
return {
|
|
2406
|
+
success: false,
|
|
2407
|
+
channel: "internal",
|
|
2408
|
+
targetId: params.target.to,
|
|
2409
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2410
|
+
};
|
|
2490
2411
|
}
|
|
2491
|
-
return runs.filter((r) => r.requesterSessionKey === requesterSessionKey);
|
|
2492
2412
|
}
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
controller.abort();
|
|
2497
|
-
return true;
|
|
2413
|
+
normalizeChannel(channel) {
|
|
2414
|
+
if (!channel) {
|
|
2415
|
+
return "unknown";
|
|
2498
2416
|
}
|
|
2499
|
-
|
|
2417
|
+
const lower = channel.toLowerCase();
|
|
2418
|
+
if (lower === "discord" || lower.includes("discord")) {
|
|
2419
|
+
return "discord";
|
|
2420
|
+
}
|
|
2421
|
+
if (lower === "telegram" || lower.includes("telegram")) {
|
|
2422
|
+
return "telegram";
|
|
2423
|
+
}
|
|
2424
|
+
if (lower === "slack" || lower.includes("slack")) {
|
|
2425
|
+
return "slack";
|
|
2426
|
+
}
|
|
2427
|
+
if (lower === "whatsapp" || lower.includes("whatsapp")) {
|
|
2428
|
+
return "whatsapp";
|
|
2429
|
+
}
|
|
2430
|
+
if (lower === "twitch" || lower.includes("twitch")) {
|
|
2431
|
+
return "twitch";
|
|
2432
|
+
}
|
|
2433
|
+
if (lower === "google_chat" || lower.includes("google") || lower.includes("gchat")) {
|
|
2434
|
+
return "google_chat";
|
|
2435
|
+
}
|
|
2436
|
+
if (lower === "internal" || lower === "a2a") {
|
|
2437
|
+
return "internal";
|
|
2438
|
+
}
|
|
2439
|
+
return "unknown";
|
|
2500
2440
|
}
|
|
2501
2441
|
on(event, handler) {
|
|
2502
2442
|
this.emitter.on(event, handler);
|
|
@@ -2504,46 +2444,22 @@ class SubagentService extends Service2 {
|
|
|
2504
2444
|
off(event, handler) {
|
|
2505
2445
|
this.emitter.off(event, handler);
|
|
2506
2446
|
}
|
|
2507
|
-
|
|
2447
|
+
emitMessagingEvent(type, payload) {
|
|
2508
2448
|
this.emitter.emit(type, payload);
|
|
2509
|
-
this.emitter.emit("
|
|
2510
|
-
}
|
|
2511
|
-
startSweeper() {
|
|
2512
|
-
if (this.sweeper) {
|
|
2513
|
-
return;
|
|
2514
|
-
}
|
|
2515
|
-
this.sweeper = setInterval(() => {
|
|
2516
|
-
this.sweepOldRuns();
|
|
2517
|
-
}, 60000);
|
|
2518
|
-
this.sweeper.unref?.();
|
|
2519
|
-
}
|
|
2520
|
-
sweepOldRuns() {
|
|
2521
|
-
const now2 = Date.now();
|
|
2522
|
-
for (const [runId, record] of this.subagentRuns.entries()) {
|
|
2523
|
-
if (record.archiveAtMs && record.archiveAtMs <= now2) {
|
|
2524
|
-
this.subagentRuns.delete(runId);
|
|
2525
|
-
}
|
|
2526
|
-
}
|
|
2449
|
+
this.emitter.emit("messaging", { type, ...payload });
|
|
2527
2450
|
}
|
|
2528
2451
|
async stop() {
|
|
2529
|
-
|
|
2530
|
-
clearInterval(this.sweeper);
|
|
2531
|
-
this.sweeper = null;
|
|
2532
|
-
}
|
|
2533
|
-
for (const controller of this.activeRuns.values()) {
|
|
2534
|
-
controller.abort();
|
|
2535
|
-
}
|
|
2536
|
-
this.activeRuns.clear();
|
|
2452
|
+
this.pendingDeliveries.clear();
|
|
2537
2453
|
this.emitter.removeAllListeners();
|
|
2538
2454
|
}
|
|
2539
2455
|
}
|
|
2540
2456
|
|
|
2541
2457
|
// src/services/sandbox-service.ts
|
|
2542
|
-
import { EventEmitter as EventEmitter3 } from "node:events";
|
|
2543
2458
|
import { spawn } from "node:child_process";
|
|
2459
|
+
import { EventEmitter as EventEmitter3 } from "node:events";
|
|
2544
2460
|
import fs from "node:fs/promises";
|
|
2545
|
-
import path from "node:path";
|
|
2546
2461
|
import os from "node:os";
|
|
2462
|
+
import path from "node:path";
|
|
2547
2463
|
import { Service as Service3 } from "@elizaos/core";
|
|
2548
2464
|
var DEFAULT_DOCKER_CONFIG = {
|
|
2549
2465
|
image: "ubuntu:22.04",
|
|
@@ -2684,7 +2600,7 @@ class SandboxService extends Service3 {
|
|
|
2684
2600
|
this.contexts.set(trimmedKey, context);
|
|
2685
2601
|
this.emitSandboxEvent("SANDBOX_CREATED", {
|
|
2686
2602
|
sessionKey: trimmedKey,
|
|
2687
|
-
roomId: context.roomId,
|
|
2603
|
+
...context.roomId !== undefined ? { roomId: context.roomId } : {},
|
|
2688
2604
|
containerName
|
|
2689
2605
|
});
|
|
2690
2606
|
return context;
|
|
@@ -2716,7 +2632,7 @@ class SandboxService extends Service3 {
|
|
|
2716
2632
|
this.contexts.delete(sessionKey);
|
|
2717
2633
|
this.emitSandboxEvent("SANDBOX_DESTROYED", {
|
|
2718
2634
|
sessionKey,
|
|
2719
|
-
roomId: context.roomId,
|
|
2635
|
+
...context.roomId !== undefined ? { roomId: context.roomId } : {},
|
|
2720
2636
|
containerName: context.containerName
|
|
2721
2637
|
});
|
|
2722
2638
|
}
|
|
@@ -2728,7 +2644,7 @@ class SandboxService extends Service3 {
|
|
|
2728
2644
|
const startTime = Date.now();
|
|
2729
2645
|
this.emitSandboxEvent("SANDBOX_COMMAND_STARTED", {
|
|
2730
2646
|
sessionKey,
|
|
2731
|
-
roomId: context.roomId,
|
|
2647
|
+
...context.roomId !== undefined ? { roomId: context.roomId } : {},
|
|
2732
2648
|
containerName: context.containerName,
|
|
2733
2649
|
command: params.command
|
|
2734
2650
|
});
|
|
@@ -2736,7 +2652,7 @@ class SandboxService extends Service3 {
|
|
|
2736
2652
|
const result = await this.executeInContainer(context, params);
|
|
2737
2653
|
this.emitSandboxEvent("SANDBOX_COMMAND_COMPLETED", {
|
|
2738
2654
|
sessionKey,
|
|
2739
|
-
roomId: context.roomId,
|
|
2655
|
+
...context.roomId !== undefined ? { roomId: context.roomId } : {},
|
|
2740
2656
|
containerName: context.containerName,
|
|
2741
2657
|
command: params.command,
|
|
2742
2658
|
result
|
|
@@ -2755,7 +2671,7 @@ class SandboxService extends Service3 {
|
|
|
2755
2671
|
};
|
|
2756
2672
|
this.emitSandboxEvent("SANDBOX_COMMAND_FAILED", {
|
|
2757
2673
|
sessionKey,
|
|
2758
|
-
roomId: context.roomId,
|
|
2674
|
+
...context.roomId !== undefined ? { roomId: context.roomId } : {},
|
|
2759
2675
|
containerName: context.containerName,
|
|
2760
2676
|
command: params.command,
|
|
2761
2677
|
result,
|
|
@@ -2792,15 +2708,17 @@ class SandboxService extends Service3 {
|
|
|
2792
2708
|
}
|
|
2793
2709
|
child.on("close", (code) => {
|
|
2794
2710
|
clearTimeout(timeoutId);
|
|
2795
|
-
|
|
2711
|
+
const result = {
|
|
2796
2712
|
success: code === 0 && !timedOut,
|
|
2797
2713
|
exitCode: code ?? 1,
|
|
2798
2714
|
stdout: stdout.slice(0, 1e5),
|
|
2799
2715
|
stderr: stderr.slice(0, 1e5),
|
|
2800
2716
|
durationMs: Date.now() - startTime,
|
|
2801
|
-
timedOut
|
|
2802
|
-
|
|
2803
|
-
|
|
2717
|
+
timedOut
|
|
2718
|
+
};
|
|
2719
|
+
if (timedOut)
|
|
2720
|
+
result.error = "Command timed out";
|
|
2721
|
+
resolve(result);
|
|
2804
2722
|
});
|
|
2805
2723
|
child.on("error", (error) => {
|
|
2806
2724
|
clearTimeout(timeoutId);
|
|
@@ -2838,15 +2756,17 @@ class SandboxService extends Service3 {
|
|
|
2838
2756
|
});
|
|
2839
2757
|
child.on("close", (code) => {
|
|
2840
2758
|
clearTimeout(timeoutId);
|
|
2841
|
-
|
|
2759
|
+
const result = {
|
|
2842
2760
|
success: code === 0 && !timedOut,
|
|
2843
2761
|
exitCode: code ?? 1,
|
|
2844
2762
|
stdout: stdout.slice(0, 1e5),
|
|
2845
2763
|
stderr: stderr.slice(0, 1e5),
|
|
2846
2764
|
durationMs: Date.now() - startTime,
|
|
2847
|
-
timedOut
|
|
2848
|
-
|
|
2849
|
-
|
|
2765
|
+
timedOut
|
|
2766
|
+
};
|
|
2767
|
+
if (timedOut)
|
|
2768
|
+
result.error = "Command timed out";
|
|
2769
|
+
resolve(result);
|
|
2850
2770
|
});
|
|
2851
2771
|
child.on("error", (error) => {
|
|
2852
2772
|
clearTimeout(timeoutId);
|
|
@@ -2897,15 +2817,17 @@ class SandboxService extends Service3 {
|
|
|
2897
2817
|
}
|
|
2898
2818
|
child.on("close", (code) => {
|
|
2899
2819
|
clearTimeout(timeoutId);
|
|
2900
|
-
|
|
2820
|
+
const result = {
|
|
2901
2821
|
success: code === 0 && !timedOut,
|
|
2902
2822
|
exitCode: code ?? 1,
|
|
2903
2823
|
stdout: stdout.slice(0, 1e5),
|
|
2904
2824
|
stderr: stderr.slice(0, 1e5),
|
|
2905
2825
|
durationMs: Date.now() - startTime,
|
|
2906
|
-
timedOut
|
|
2907
|
-
|
|
2908
|
-
|
|
2826
|
+
timedOut
|
|
2827
|
+
};
|
|
2828
|
+
if (timedOut)
|
|
2829
|
+
result.error = "Command timed out";
|
|
2830
|
+
resolve(result);
|
|
2909
2831
|
});
|
|
2910
2832
|
child.on("error", (error) => {
|
|
2911
2833
|
clearTimeout(timeoutId);
|
|
@@ -2950,10 +2872,7 @@ class SandboxService extends Service3 {
|
|
|
2950
2872
|
`name=^${context.containerName}$`
|
|
2951
2873
|
]);
|
|
2952
2874
|
if (checkResult.stdout.trim()) {
|
|
2953
|
-
const startResult = await this.executeDockerCommand([
|
|
2954
|
-
"start",
|
|
2955
|
-
context.containerName
|
|
2956
|
-
]);
|
|
2875
|
+
const startResult = await this.executeDockerCommand(["start", context.containerName]);
|
|
2957
2876
|
if (startResult.success) {
|
|
2958
2877
|
this.activeContainers.add(context.containerName);
|
|
2959
2878
|
return;
|
|
@@ -3020,21 +2939,21 @@ class SandboxService extends Service3 {
|
|
|
3020
2939
|
browserArgs.push(config.browser.image);
|
|
3021
2940
|
const result = await this.executeDockerCommand(browserArgs);
|
|
3022
2941
|
if (!result.success) {
|
|
3023
|
-
this.runtime.logger.error(
|
|
2942
|
+
this.runtime.logger.error({
|
|
3024
2943
|
sessionKey,
|
|
3025
2944
|
error: result.stderr
|
|
3026
|
-
});
|
|
2945
|
+
}, "Failed to start browser container");
|
|
3027
2946
|
return null;
|
|
3028
2947
|
}
|
|
3029
2948
|
const browserContext = {
|
|
3030
2949
|
bridgeUrl: `http://localhost:${config.browser.cdpPort}`,
|
|
3031
|
-
|
|
2950
|
+
...config.browser.enableNoVnc ? { noVncUrl: `http://localhost:${config.browser.noVncPort}` } : {},
|
|
3032
2951
|
containerName: browserContainerName
|
|
3033
2952
|
};
|
|
3034
2953
|
context.browser = browserContext;
|
|
3035
2954
|
this.emitSandboxEvent("SANDBOX_BROWSER_STARTED", {
|
|
3036
2955
|
sessionKey,
|
|
3037
|
-
roomId: context.roomId,
|
|
2956
|
+
...context.roomId !== undefined ? { roomId: context.roomId } : {},
|
|
3038
2957
|
containerName: browserContainerName
|
|
3039
2958
|
});
|
|
3040
2959
|
return browserContext;
|
|
@@ -3047,10 +2966,10 @@ class SandboxService extends Service3 {
|
|
|
3047
2966
|
await this.stopContainer(context.browser.containerName);
|
|
3048
2967
|
this.emitSandboxEvent("SANDBOX_BROWSER_STOPPED", {
|
|
3049
2968
|
sessionKey,
|
|
3050
|
-
roomId: context.roomId,
|
|
2969
|
+
...context.roomId !== undefined ? { roomId: context.roomId } : {},
|
|
3051
2970
|
containerName: context.browser.containerName
|
|
3052
2971
|
});
|
|
3053
|
-
context.browser
|
|
2972
|
+
delete context.browser;
|
|
3054
2973
|
}
|
|
3055
2974
|
startSweeper() {
|
|
3056
2975
|
if (this.sweeper) {
|
|
@@ -3073,10 +2992,10 @@ class SandboxService extends Service3 {
|
|
|
3073
2992
|
const tooOld = now2 - context.createdAt > maxAgeMs;
|
|
3074
2993
|
if (idle || tooOld) {
|
|
3075
2994
|
this.destroySandbox(sessionKey).catch((err) => {
|
|
3076
|
-
this.runtime.logger.error(
|
|
2995
|
+
this.runtime.logger.error({
|
|
3077
2996
|
sessionKey,
|
|
3078
|
-
error: err
|
|
3079
|
-
});
|
|
2997
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2998
|
+
}, "Failed to destroy idle sandbox");
|
|
3080
2999
|
});
|
|
3081
3000
|
}
|
|
3082
3001
|
}
|
|
@@ -3103,19 +3022,24 @@ class SandboxService extends Service3 {
|
|
|
3103
3022
|
}
|
|
3104
3023
|
}
|
|
3105
3024
|
|
|
3106
|
-
// src/services/
|
|
3107
|
-
import { EventEmitter as EventEmitter4 } from "node:events";
|
|
3025
|
+
// src/services/subagent-service.ts
|
|
3108
3026
|
import crypto3 from "node:crypto";
|
|
3109
|
-
import {
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3027
|
+
import { EventEmitter as EventEmitter4 } from "node:events";
|
|
3028
|
+
import {
|
|
3029
|
+
ChannelType,
|
|
3030
|
+
EventType as EventType2,
|
|
3031
|
+
Service as Service4
|
|
3032
|
+
} from "@elizaos/core";
|
|
3033
|
+
class SubagentService extends Service4 {
|
|
3034
|
+
static serviceType = "SUBAGENT";
|
|
3035
|
+
capabilityDescription = "Manages subagent spawning, lifecycle, and communication";
|
|
3113
3036
|
emitter = new EventEmitter4;
|
|
3114
|
-
|
|
3115
|
-
|
|
3037
|
+
subagentRuns = new Map;
|
|
3038
|
+
activeRuns = new Map;
|
|
3039
|
+
sweeper = null;
|
|
3116
3040
|
initialized = false;
|
|
3117
3041
|
static async start(runtime) {
|
|
3118
|
-
const service = new
|
|
3042
|
+
const service = new SubagentService(runtime);
|
|
3119
3043
|
await service.initialize();
|
|
3120
3044
|
return service;
|
|
3121
3045
|
}
|
|
@@ -3124,472 +3048,636 @@ class MessagingService extends Service4 {
|
|
|
3124
3048
|
return;
|
|
3125
3049
|
}
|
|
3126
3050
|
this.initialized = true;
|
|
3127
|
-
this.
|
|
3128
|
-
|
|
3129
|
-
registerBuiltInAdapters() {
|
|
3130
|
-
this.registerAdapter({
|
|
3131
|
-
channel: "discord",
|
|
3132
|
-
isAvailable: () => {
|
|
3133
|
-
const service = this.runtime.getService("DISCORD");
|
|
3134
|
-
return !!service;
|
|
3135
|
-
},
|
|
3136
|
-
send: async (params) => this.sendViaDiscord(params)
|
|
3137
|
-
});
|
|
3138
|
-
this.registerAdapter({
|
|
3139
|
-
channel: "telegram",
|
|
3140
|
-
isAvailable: () => {
|
|
3141
|
-
const service = this.runtime.getService("TELEGRAM");
|
|
3142
|
-
return !!service;
|
|
3143
|
-
},
|
|
3144
|
-
send: async (params) => this.sendViaTelegram(params)
|
|
3145
|
-
});
|
|
3146
|
-
this.registerAdapter({
|
|
3147
|
-
channel: "slack",
|
|
3148
|
-
isAvailable: () => {
|
|
3149
|
-
const service = this.runtime.getService("slack");
|
|
3150
|
-
return !!service;
|
|
3151
|
-
},
|
|
3152
|
-
send: async (params) => this.sendViaSlack(params)
|
|
3153
|
-
});
|
|
3154
|
-
this.registerAdapter({
|
|
3155
|
-
channel: "whatsapp",
|
|
3156
|
-
isAvailable: () => {
|
|
3157
|
-
const service = this.runtime.getService("whatsapp");
|
|
3158
|
-
return !!service;
|
|
3159
|
-
},
|
|
3160
|
-
send: async (params) => this.sendViaWhatsApp(params)
|
|
3161
|
-
});
|
|
3162
|
-
this.registerAdapter({
|
|
3163
|
-
channel: "twitch",
|
|
3164
|
-
isAvailable: () => {
|
|
3165
|
-
const service = this.runtime.getService("twitch");
|
|
3166
|
-
return !!service;
|
|
3167
|
-
},
|
|
3168
|
-
send: async (params) => this.sendViaTwitch(params)
|
|
3051
|
+
this.runtime.registerEvent(EventType2.RUN_ENDED, async (payload) => {
|
|
3052
|
+
await this.handleRunEnded(payload);
|
|
3169
3053
|
});
|
|
3170
|
-
this.
|
|
3171
|
-
|
|
3172
|
-
isAvailable: () => true,
|
|
3173
|
-
send: async (params) => this.sendViaInternal(params)
|
|
3054
|
+
this.runtime.registerEvent(EventType2.RUN_TIMEOUT, async (payload) => {
|
|
3055
|
+
await this.handleRunTimeout(payload);
|
|
3174
3056
|
});
|
|
3057
|
+
this.startSweeper();
|
|
3175
3058
|
}
|
|
3176
|
-
|
|
3177
|
-
this.
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
channels.push(channel);
|
|
3187
|
-
}
|
|
3188
|
-
}
|
|
3189
|
-
return channels;
|
|
3190
|
-
}
|
|
3191
|
-
async send(params) {
|
|
3192
|
-
const idempotencyKey = params.idempotencyKey ?? crypto3.randomUUID();
|
|
3193
|
-
const channel = params.target.channel;
|
|
3194
|
-
const existing = this.pendingDeliveries.get(idempotencyKey);
|
|
3195
|
-
if (existing) {
|
|
3196
|
-
return {
|
|
3197
|
-
success: existing.status.status === "sent" || existing.status.status === "delivered",
|
|
3198
|
-
messageId: existing.status.messageId,
|
|
3199
|
-
channel,
|
|
3200
|
-
targetId: params.target.to,
|
|
3201
|
-
error: existing.status.error,
|
|
3202
|
-
sentAt: existing.status.status === "sent" ? existing.status.updatedAt : undefined
|
|
3203
|
-
};
|
|
3204
|
-
}
|
|
3205
|
-
const status = {
|
|
3206
|
-
status: "pending",
|
|
3207
|
-
updatedAt: Date.now()
|
|
3059
|
+
getConfig() {
|
|
3060
|
+
const settings = this.runtime.character?.settings;
|
|
3061
|
+
const subagents = settings?.subagents ?? {};
|
|
3062
|
+
return {
|
|
3063
|
+
enabled: subagents.enabled !== false,
|
|
3064
|
+
...subagents.model !== undefined ? { model: subagents.model } : {},
|
|
3065
|
+
...subagents.thinking !== undefined ? { thinking: subagents.thinking } : {},
|
|
3066
|
+
timeoutSeconds: subagents.timeoutSeconds ?? 300,
|
|
3067
|
+
allowAgents: subagents.allowAgents ?? [],
|
|
3068
|
+
archiveAfterMinutes: subagents.archiveAfterMinutes ?? 60
|
|
3208
3069
|
};
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
success: false,
|
|
3239
|
-
channel,
|
|
3240
|
-
targetId: params.target.to,
|
|
3241
|
-
error: `${channel} service is not available`
|
|
3242
|
-
};
|
|
3243
|
-
status.status = "failed";
|
|
3244
|
-
status.error = result.error;
|
|
3245
|
-
status.updatedAt = Date.now();
|
|
3246
|
-
this.emitMessagingEvent("MESSAGING_SEND_FAILED", {
|
|
3247
|
-
idempotencyKey,
|
|
3248
|
-
channel,
|
|
3249
|
-
targetId: params.target.to,
|
|
3250
|
-
status: "failed",
|
|
3251
|
-
error: result.error
|
|
3252
|
-
});
|
|
3253
|
-
return result;
|
|
3254
|
-
}
|
|
3255
|
-
try {
|
|
3256
|
-
const result = await adapter.send({ ...params, idempotencyKey });
|
|
3257
|
-
status.status = result.success ? "sent" : "failed";
|
|
3258
|
-
status.messageId = result.messageId;
|
|
3259
|
-
status.error = result.error;
|
|
3260
|
-
status.updatedAt = Date.now();
|
|
3261
|
-
if (result.success) {
|
|
3262
|
-
this.emitMessagingEvent("MESSAGING_SENT", {
|
|
3263
|
-
idempotencyKey,
|
|
3264
|
-
messageId: result.messageId,
|
|
3265
|
-
channel,
|
|
3266
|
-
targetId: params.target.to,
|
|
3267
|
-
status: "sent",
|
|
3268
|
-
sentAt: result.sentAt
|
|
3269
|
-
});
|
|
3270
|
-
} else {
|
|
3271
|
-
this.emitMessagingEvent("MESSAGING_SEND_FAILED", {
|
|
3272
|
-
idempotencyKey,
|
|
3273
|
-
channel,
|
|
3274
|
-
targetId: params.target.to,
|
|
3275
|
-
status: "failed",
|
|
3276
|
-
error: result.error
|
|
3277
|
-
});
|
|
3070
|
+
}
|
|
3071
|
+
getAgentToAgentPolicy() {
|
|
3072
|
+
const settings = this.runtime.character?.settings;
|
|
3073
|
+
const a2aConfig = settings?.agentToAgent ?? {};
|
|
3074
|
+
const enabled = a2aConfig.enabled === true;
|
|
3075
|
+
const allowRules = (a2aConfig.allow ?? []).map((rule) => ({
|
|
3076
|
+
source: rule.source ?? "*",
|
|
3077
|
+
target: rule.target ?? "*"
|
|
3078
|
+
}));
|
|
3079
|
+
return {
|
|
3080
|
+
enabled,
|
|
3081
|
+
allowRules,
|
|
3082
|
+
isAllowed: (sourceAgentId, targetAgentId) => {
|
|
3083
|
+
if (!enabled) {
|
|
3084
|
+
return false;
|
|
3085
|
+
}
|
|
3086
|
+
if (sourceAgentId === targetAgentId) {
|
|
3087
|
+
return true;
|
|
3088
|
+
}
|
|
3089
|
+
const sourceNorm = normalizeAgentId2(sourceAgentId);
|
|
3090
|
+
const targetNorm = normalizeAgentId2(targetAgentId);
|
|
3091
|
+
for (const rule of allowRules) {
|
|
3092
|
+
const sourceMatch = rule.source === "*" || normalizeAgentId2(rule.source) === sourceNorm;
|
|
3093
|
+
const targetMatch = rule.target === "*" || normalizeAgentId2(rule.target) === targetNorm;
|
|
3094
|
+
if (sourceMatch && targetMatch) {
|
|
3095
|
+
return true;
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
return false;
|
|
3278
3099
|
}
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
status.updatedAt = Date.now();
|
|
3285
|
-
this.emitMessagingEvent("MESSAGING_SEND_FAILED", {
|
|
3286
|
-
idempotencyKey,
|
|
3287
|
-
channel,
|
|
3288
|
-
targetId: params.target.to,
|
|
3289
|
-
status: "failed",
|
|
3290
|
-
error: errorMessage
|
|
3291
|
-
});
|
|
3100
|
+
};
|
|
3101
|
+
}
|
|
3102
|
+
async spawnSubagent(params, requesterContext) {
|
|
3103
|
+
const config = this.getConfig();
|
|
3104
|
+
if (!config.enabled) {
|
|
3292
3105
|
return {
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
targetId: params.target.to,
|
|
3296
|
-
error: errorMessage
|
|
3106
|
+
status: "forbidden",
|
|
3107
|
+
error: "Subagent spawning is disabled"
|
|
3297
3108
|
};
|
|
3298
3109
|
}
|
|
3299
|
-
|
|
3300
|
-
async sendToDeliveryContext(deliveryContext, content, options) {
|
|
3301
|
-
const channel = this.normalizeChannel(deliveryContext.channel);
|
|
3302
|
-
const to = deliveryContext.to ?? deliveryContext.accountId ?? "";
|
|
3303
|
-
if (!to) {
|
|
3110
|
+
if (requesterContext.sessionKey && isSubagentSessionKey2(requesterContext.sessionKey)) {
|
|
3304
3111
|
return {
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
targetId: "",
|
|
3308
|
-
error: "No recipient specified in delivery context"
|
|
3112
|
+
status: "forbidden",
|
|
3113
|
+
error: "sessions_spawn is not allowed from sub-agent sessions"
|
|
3309
3114
|
};
|
|
3310
3115
|
}
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3116
|
+
const requesterAgentId = requesterContext.sessionKey ? extractAgentIdFromSessionKey(requesterContext.sessionKey) : this.runtime.character?.name ?? "unknown";
|
|
3117
|
+
const targetAgentId = params.agentId ? normalizeAgentId2(params.agentId) : requesterAgentId;
|
|
3118
|
+
if (targetAgentId !== requesterAgentId) {
|
|
3119
|
+
const allowAgents = config.allowAgents ?? [];
|
|
3120
|
+
const allowAny = allowAgents.some((v) => v.trim() === "*");
|
|
3121
|
+
const allowSet = new Set(allowAgents.filter((v) => v.trim() && v.trim() !== "*").map((v) => normalizeAgentId2(v)));
|
|
3122
|
+
if (!allowAny && !allowSet.has(targetAgentId)) {
|
|
3123
|
+
return {
|
|
3124
|
+
status: "forbidden",
|
|
3125
|
+
error: `agentId "${targetAgentId}" is not allowed for subagent spawning`
|
|
3126
|
+
};
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3129
|
+
const childSessionKey = createSubagentSessionKey(targetAgentId);
|
|
3130
|
+
const runId = crypto3.randomUUID();
|
|
3131
|
+
const childRoomId = sessionKeyToRoomId(childSessionKey, targetAgentId);
|
|
3132
|
+
const roomMetadata = {
|
|
3133
|
+
isSubagent: true,
|
|
3134
|
+
sessionKey: childSessionKey,
|
|
3135
|
+
task: params.task,
|
|
3136
|
+
spawnedAt: Date.now(),
|
|
3137
|
+
cleanup: params.cleanup ?? "keep"
|
|
3138
|
+
};
|
|
3139
|
+
if (requesterContext.roomId)
|
|
3140
|
+
roomMetadata.parentRoomId = requesterContext.roomId;
|
|
3141
|
+
if (requesterContext.sessionKey)
|
|
3142
|
+
roomMetadata.parentSessionKey = requesterContext.sessionKey;
|
|
3143
|
+
if (params.label)
|
|
3144
|
+
roomMetadata.label = params.label;
|
|
3145
|
+
const childRoom = {
|
|
3146
|
+
id: childRoomId,
|
|
3147
|
+
name: params.label || `Subagent: ${params.task.slice(0, 50)}`,
|
|
3148
|
+
source: "subagent",
|
|
3149
|
+
type: ChannelType.SELF,
|
|
3150
|
+
channelId: childSessionKey,
|
|
3151
|
+
agentId: this.runtime.agentId,
|
|
3152
|
+
worldId: this.runtime.agentId,
|
|
3153
|
+
metadata: roomMetadata
|
|
3154
|
+
};
|
|
3155
|
+
await this.runtime.ensureRoomExists(childRoom);
|
|
3156
|
+
const now2 = Date.now();
|
|
3157
|
+
const archiveAfterMs = config.archiveAfterMinutes ? config.archiveAfterMinutes * 60000 : undefined;
|
|
3158
|
+
const record = {
|
|
3159
|
+
runId,
|
|
3160
|
+
childSessionKey,
|
|
3161
|
+
requesterSessionKey: requesterContext.sessionKey ?? "unknown",
|
|
3162
|
+
requesterDisplayKey: requesterContext.sessionKey ?? "main",
|
|
3163
|
+
task: params.task,
|
|
3164
|
+
cleanup: params.cleanup ?? "keep",
|
|
3165
|
+
createdAt: now2,
|
|
3166
|
+
startedAt: now2,
|
|
3167
|
+
cleanupHandled: false,
|
|
3168
|
+
roomId: childRoomId,
|
|
3169
|
+
worldId: this.runtime.agentId
|
|
3170
|
+
};
|
|
3171
|
+
const normalizedOrigin = normalizeDeliveryContext(requesterContext.origin);
|
|
3172
|
+
if (normalizedOrigin)
|
|
3173
|
+
record.requesterOrigin = normalizedOrigin;
|
|
3174
|
+
if (params.label)
|
|
3175
|
+
record.label = params.label;
|
|
3176
|
+
if (archiveAfterMs)
|
|
3177
|
+
record.archiveAtMs = now2 + archiveAfterMs;
|
|
3178
|
+
this.subagentRuns.set(runId, record);
|
|
3179
|
+
const spawnPayload = {
|
|
3180
|
+
runId,
|
|
3181
|
+
childSessionKey,
|
|
3182
|
+
childRoomId,
|
|
3183
|
+
task: params.task
|
|
3184
|
+
};
|
|
3185
|
+
if (requesterContext.sessionKey)
|
|
3186
|
+
spawnPayload.requesterSessionKey = requesterContext.sessionKey;
|
|
3187
|
+
if (requesterContext.roomId)
|
|
3188
|
+
spawnPayload.requesterRoomId = requesterContext.roomId;
|
|
3189
|
+
if (params.label)
|
|
3190
|
+
spawnPayload.label = params.label;
|
|
3191
|
+
this.emitSubagentEvent("SUBAGENT_SPAWN_REQUESTED", spawnPayload);
|
|
3192
|
+
const systemPromptParams = {
|
|
3193
|
+
childSessionKey,
|
|
3194
|
+
task: params.task
|
|
3195
|
+
};
|
|
3196
|
+
if (requesterContext.sessionKey)
|
|
3197
|
+
systemPromptParams.requesterSessionKey = requesterContext.sessionKey;
|
|
3198
|
+
if (requesterContext.origin)
|
|
3199
|
+
systemPromptParams.requesterOrigin = requesterContext.origin;
|
|
3200
|
+
if (params.label)
|
|
3201
|
+
systemPromptParams.label = params.label;
|
|
3202
|
+
const systemPrompt = this.buildSubagentSystemPrompt(systemPromptParams);
|
|
3203
|
+
const taskMetadata = {
|
|
3204
|
+
isSubagentTask: true,
|
|
3205
|
+
runId,
|
|
3206
|
+
systemPromptOverride: systemPrompt
|
|
3207
|
+
};
|
|
3208
|
+
const modelOverride = params.model || config.model;
|
|
3209
|
+
const thinkingOverride = params.thinking || config.thinking;
|
|
3210
|
+
if (modelOverride)
|
|
3211
|
+
taskMetadata.modelOverride = modelOverride;
|
|
3212
|
+
if (thinkingOverride)
|
|
3213
|
+
taskMetadata.thinkingOverride = thinkingOverride;
|
|
3214
|
+
const initialMessage = {
|
|
3215
|
+
id: hashToUUID(`${runId}-initial`),
|
|
3216
|
+
entityId: this.runtime.agentId,
|
|
3217
|
+
agentId: this.runtime.agentId,
|
|
3218
|
+
roomId: childRoomId,
|
|
3219
|
+
content: {
|
|
3220
|
+
text: params.task,
|
|
3221
|
+
type: "text",
|
|
3222
|
+
metadata: taskMetadata
|
|
3223
|
+
}
|
|
3224
|
+
};
|
|
3225
|
+
this.executeSubagentRun(runId, initialMessage, params.runTimeoutSeconds).catch((error) => {
|
|
3226
|
+
this.runtime.logger.error(`Subagent execution error [runId=${runId}]: ${error}`);
|
|
3227
|
+
this.handleSubagentError(runId, error);
|
|
3321
3228
|
});
|
|
3229
|
+
return {
|
|
3230
|
+
status: "accepted",
|
|
3231
|
+
childSessionKey,
|
|
3232
|
+
childRoomId,
|
|
3233
|
+
runId,
|
|
3234
|
+
modelApplied: !!(params.model || config.model)
|
|
3235
|
+
};
|
|
3322
3236
|
}
|
|
3323
|
-
async
|
|
3324
|
-
const
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3237
|
+
async executeSubagentRun(runId, initialMessage, timeoutSeconds) {
|
|
3238
|
+
const config = this.getConfig();
|
|
3239
|
+
const timeout = (timeoutSeconds ?? config.timeoutSeconds ?? 300) * 1000;
|
|
3240
|
+
const controller = new AbortController;
|
|
3241
|
+
this.activeRuns.set(runId, controller);
|
|
3242
|
+
const timeoutId = timeout > 0 ? setTimeout(() => {
|
|
3243
|
+
controller.abort();
|
|
3244
|
+
this.handleSubagentTimeout(runId);
|
|
3245
|
+
}, timeout) : null;
|
|
3246
|
+
try {
|
|
3247
|
+
await this.runtime.emitEvent(EventType2.MESSAGE_RECEIVED, {
|
|
3248
|
+
runtime: this.runtime,
|
|
3249
|
+
message: initialMessage,
|
|
3250
|
+
source: "subagent"
|
|
3251
|
+
});
|
|
3252
|
+
await this.waitForCompletion(runId, timeout, controller.signal);
|
|
3253
|
+
} finally {
|
|
3254
|
+
if (timeoutId) {
|
|
3255
|
+
clearTimeout(timeoutId);
|
|
3256
|
+
}
|
|
3257
|
+
this.activeRuns.delete(runId);
|
|
3332
3258
|
}
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
const
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3259
|
+
}
|
|
3260
|
+
async waitForCompletion(runId, timeoutMs, signal) {
|
|
3261
|
+
const startTime = Date.now();
|
|
3262
|
+
const pollInterval = 500;
|
|
3263
|
+
while (!signal.aborted) {
|
|
3264
|
+
const record = this.subagentRuns.get(runId);
|
|
3265
|
+
if (!record) {
|
|
3266
|
+
return;
|
|
3267
|
+
}
|
|
3268
|
+
if (record.endedAt) {
|
|
3269
|
+
return;
|
|
3270
|
+
}
|
|
3271
|
+
if (Date.now() - startTime > timeoutMs + 5000) {
|
|
3272
|
+
return;
|
|
3273
|
+
}
|
|
3274
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
3343
3275
|
}
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3276
|
+
}
|
|
3277
|
+
handleSubagentTimeout(runId) {
|
|
3278
|
+
const record = this.subagentRuns.get(runId);
|
|
3279
|
+
if (!record || record.endedAt) {
|
|
3280
|
+
return;
|
|
3281
|
+
}
|
|
3282
|
+
record.endedAt = Date.now();
|
|
3283
|
+
record.outcome = { status: "timeout" };
|
|
3284
|
+
const timeoutPayload = {
|
|
3285
|
+
runId,
|
|
3286
|
+
childSessionKey: record.childSessionKey,
|
|
3287
|
+
task: record.task,
|
|
3288
|
+
status: "timeout"
|
|
3289
|
+
};
|
|
3290
|
+
if (record.roomId)
|
|
3291
|
+
timeoutPayload.childRoomId = record.roomId;
|
|
3292
|
+
this.emitSubagentEvent("SUBAGENT_RUN_TIMEOUT", timeoutPayload);
|
|
3293
|
+
this.announceSubagentResult(runId).catch((err) => {
|
|
3294
|
+
this.runtime.logger.error(`Failed to announce timeout [runId=${runId}]: ${err}`);
|
|
3354
3295
|
});
|
|
3355
3296
|
}
|
|
3356
|
-
|
|
3357
|
-
const
|
|
3358
|
-
|
|
3359
|
-
|
|
3297
|
+
handleSubagentError(runId, error) {
|
|
3298
|
+
const record = this.subagentRuns.get(runId);
|
|
3299
|
+
if (!record) {
|
|
3300
|
+
return;
|
|
3301
|
+
}
|
|
3302
|
+
record.endedAt = Date.now();
|
|
3303
|
+
record.outcome = {
|
|
3304
|
+
status: "error",
|
|
3305
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3306
|
+
};
|
|
3307
|
+
const errorPayload = {
|
|
3308
|
+
runId,
|
|
3309
|
+
childSessionKey: record.childSessionKey,
|
|
3310
|
+
task: record.task,
|
|
3311
|
+
status: "error"
|
|
3312
|
+
};
|
|
3313
|
+
if (record.outcome.error)
|
|
3314
|
+
errorPayload.error = record.outcome.error;
|
|
3315
|
+
if (record.roomId)
|
|
3316
|
+
errorPayload.childRoomId = record.roomId;
|
|
3317
|
+
this.emitSubagentEvent("SUBAGENT_RUN_FAILED", errorPayload);
|
|
3318
|
+
this.announceSubagentResult(runId).catch((err) => {
|
|
3319
|
+
this.runtime.logger.error(`Failed to announce error [runId=${runId}]: ${err}`);
|
|
3320
|
+
});
|
|
3360
3321
|
}
|
|
3361
|
-
async
|
|
3362
|
-
const
|
|
3363
|
-
if (!
|
|
3364
|
-
return
|
|
3365
|
-
success: false,
|
|
3366
|
-
channel: "discord",
|
|
3367
|
-
targetId: params.target.to,
|
|
3368
|
-
error: "Discord service not available"
|
|
3369
|
-
};
|
|
3322
|
+
async handleRunEnded(payload) {
|
|
3323
|
+
const p = payload;
|
|
3324
|
+
if (!p.roomId) {
|
|
3325
|
+
return;
|
|
3370
3326
|
}
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3327
|
+
for (const [runId, record] of this.subagentRuns.entries()) {
|
|
3328
|
+
if (record.roomId === p.roomId && !record.endedAt) {
|
|
3329
|
+
record.endedAt = Date.now();
|
|
3330
|
+
record.outcome = { status: "ok" };
|
|
3331
|
+
const completedPayload = {
|
|
3332
|
+
runId,
|
|
3333
|
+
childSessionKey: record.childSessionKey,
|
|
3334
|
+
childRoomId: record.roomId,
|
|
3335
|
+
task: record.task,
|
|
3336
|
+
status: "completed",
|
|
3337
|
+
endedAt: record.endedAt,
|
|
3338
|
+
durationMs: record.endedAt - (record.startedAt ?? record.createdAt)
|
|
3379
3339
|
};
|
|
3340
|
+
if (record.startedAt)
|
|
3341
|
+
completedPayload.startedAt = record.startedAt;
|
|
3342
|
+
this.emitSubagentEvent("SUBAGENT_RUN_COMPLETED", completedPayload);
|
|
3343
|
+
await this.announceSubagentResult(runId);
|
|
3344
|
+
break;
|
|
3380
3345
|
}
|
|
3381
|
-
const message = await channel.send({
|
|
3382
|
-
content: params.content.text,
|
|
3383
|
-
...params.target.replyToMessageId ? { reply: { messageReference: params.target.replyToMessageId } } : {}
|
|
3384
|
-
});
|
|
3385
|
-
return {
|
|
3386
|
-
success: true,
|
|
3387
|
-
messageId: message.id,
|
|
3388
|
-
channel: "discord",
|
|
3389
|
-
targetId: params.target.to,
|
|
3390
|
-
sentAt: Date.now()
|
|
3391
|
-
};
|
|
3392
|
-
} catch (error) {
|
|
3393
|
-
return {
|
|
3394
|
-
success: false,
|
|
3395
|
-
channel: "discord",
|
|
3396
|
-
targetId: params.target.to,
|
|
3397
|
-
error: error instanceof Error ? error.message : String(error)
|
|
3398
|
-
};
|
|
3399
3346
|
}
|
|
3400
3347
|
}
|
|
3401
|
-
async
|
|
3402
|
-
const
|
|
3403
|
-
if (!
|
|
3404
|
-
return
|
|
3405
|
-
success: false,
|
|
3406
|
-
channel: "telegram",
|
|
3407
|
-
targetId: params.target.to,
|
|
3408
|
-
error: "Telegram service not available"
|
|
3409
|
-
};
|
|
3348
|
+
async handleRunTimeout(payload) {
|
|
3349
|
+
const p = payload;
|
|
3350
|
+
if (!p.roomId) {
|
|
3351
|
+
return;
|
|
3410
3352
|
}
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
disable_notification: params.content.silent
|
|
3417
|
-
});
|
|
3418
|
-
return {
|
|
3419
|
-
success: true,
|
|
3420
|
-
messageId: String(result.message_id),
|
|
3421
|
-
channel: "telegram",
|
|
3422
|
-
targetId: params.target.to,
|
|
3423
|
-
sentAt: Date.now()
|
|
3424
|
-
};
|
|
3425
|
-
} catch (error) {
|
|
3426
|
-
return {
|
|
3427
|
-
success: false,
|
|
3428
|
-
channel: "telegram",
|
|
3429
|
-
targetId: params.target.to,
|
|
3430
|
-
error: error instanceof Error ? error.message : String(error)
|
|
3431
|
-
};
|
|
3353
|
+
for (const [runId, record] of this.subagentRuns.entries()) {
|
|
3354
|
+
if (record.roomId === p.roomId && !record.endedAt) {
|
|
3355
|
+
this.handleSubagentTimeout(runId);
|
|
3356
|
+
break;
|
|
3357
|
+
}
|
|
3432
3358
|
}
|
|
3433
3359
|
}
|
|
3434
|
-
async
|
|
3435
|
-
const
|
|
3436
|
-
if (!
|
|
3437
|
-
return
|
|
3438
|
-
success: false,
|
|
3439
|
-
channel: "slack",
|
|
3440
|
-
targetId: params.target.to,
|
|
3441
|
-
error: "Slack service not available or sendMessage method not found"
|
|
3442
|
-
};
|
|
3360
|
+
async announceSubagentResult(runId) {
|
|
3361
|
+
const record = this.subagentRuns.get(runId);
|
|
3362
|
+
if (!record) {
|
|
3363
|
+
return false;
|
|
3443
3364
|
}
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
threadTs: params.target.threadId ? String(params.target.threadId) : undefined,
|
|
3447
|
-
replyBroadcast: false
|
|
3448
|
-
});
|
|
3449
|
-
return {
|
|
3450
|
-
success: true,
|
|
3451
|
-
messageId: result.ts,
|
|
3452
|
-
channel: "slack",
|
|
3453
|
-
targetId: params.target.to,
|
|
3454
|
-
sentAt: Date.now()
|
|
3455
|
-
};
|
|
3456
|
-
} catch (error) {
|
|
3457
|
-
return {
|
|
3458
|
-
success: false,
|
|
3459
|
-
channel: "slack",
|
|
3460
|
-
targetId: params.target.to,
|
|
3461
|
-
error: error instanceof Error ? error.message : String(error)
|
|
3462
|
-
};
|
|
3365
|
+
if (record.cleanupCompletedAt || record.cleanupHandled) {
|
|
3366
|
+
return false;
|
|
3463
3367
|
}
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3368
|
+
record.cleanupHandled = true;
|
|
3369
|
+
let reply;
|
|
3370
|
+
if (record.roomId) {
|
|
3371
|
+
const memories = await this.runtime.getMemories({
|
|
3372
|
+
tableName: "messages",
|
|
3373
|
+
roomId: record.roomId,
|
|
3374
|
+
count: 10
|
|
3375
|
+
});
|
|
3376
|
+
const lastAssistant = memories.filter((m) => m.entityId === this.runtime.agentId).sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0))[0];
|
|
3377
|
+
reply = lastAssistant?.content?.text;
|
|
3474
3378
|
}
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3379
|
+
const durationMs = record.endedAt ? record.endedAt - (record.startedAt ?? record.createdAt) : undefined;
|
|
3380
|
+
const statsLine = `Runtime: ${formatDurationShort(durationMs) ?? "n/a"} • Session: ${record.childSessionKey}`;
|
|
3381
|
+
const outcome = record.outcome ?? { status: "unknown" };
|
|
3382
|
+
const statusLabel = outcome.status === "ok" ? "completed successfully" : outcome.status === "timeout" ? "timed out" : outcome.status === "error" ? `failed: ${outcome.error || "unknown error"}` : "finished with unknown status";
|
|
3383
|
+
const taskLabel = record.label || record.task || "background task";
|
|
3384
|
+
const triggerMessage = [
|
|
3385
|
+
`A background task "${taskLabel}" just ${statusLabel}.`,
|
|
3386
|
+
"",
|
|
3387
|
+
"Findings:",
|
|
3388
|
+
reply || "(no output)",
|
|
3389
|
+
"",
|
|
3390
|
+
statsLine,
|
|
3391
|
+
"",
|
|
3392
|
+
"Summarize this naturally for the user. Keep it brief (1-2 sentences).",
|
|
3393
|
+
"Do not mention technical details like tokens, stats, or that this was a background task.",
|
|
3394
|
+
"You can respond with NO_REPLY if no announcement is needed."
|
|
3395
|
+
].join(`
|
|
3396
|
+
`);
|
|
3397
|
+
if (record.requesterSessionKey && record.requesterSessionKey !== "unknown") {
|
|
3398
|
+
const requesterRoomId = sessionKeyToRoomId(record.requesterSessionKey, extractAgentIdFromSessionKey(record.requesterSessionKey));
|
|
3399
|
+
const metadata = {
|
|
3400
|
+
isSubagentAnnouncement: true,
|
|
3401
|
+
subagentRunId: runId
|
|
3484
3402
|
};
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3403
|
+
if (record.requesterOrigin) {
|
|
3404
|
+
metadata.deliveryContext = record.requesterOrigin;
|
|
3405
|
+
}
|
|
3406
|
+
const announceMessage = {
|
|
3407
|
+
id: hashToUUID(`${runId}-announce`),
|
|
3408
|
+
entityId: this.runtime.agentId,
|
|
3409
|
+
agentId: this.runtime.agentId,
|
|
3410
|
+
roomId: requesterRoomId,
|
|
3411
|
+
content: {
|
|
3412
|
+
text: triggerMessage,
|
|
3413
|
+
type: "text",
|
|
3414
|
+
metadata
|
|
3415
|
+
}
|
|
3491
3416
|
};
|
|
3417
|
+
await this.runtime.emitEvent(EventType2.MESSAGE_RECEIVED, {
|
|
3418
|
+
runtime: this.runtime,
|
|
3419
|
+
message: announceMessage,
|
|
3420
|
+
source: "subagent_announce"
|
|
3421
|
+
});
|
|
3492
3422
|
}
|
|
3423
|
+
const announcePayload = {
|
|
3424
|
+
runId,
|
|
3425
|
+
childSessionKey: record.childSessionKey,
|
|
3426
|
+
task: record.task,
|
|
3427
|
+
outcome
|
|
3428
|
+
};
|
|
3429
|
+
if (record.requesterSessionKey)
|
|
3430
|
+
announcePayload.requesterSessionKey = record.requesterSessionKey;
|
|
3431
|
+
this.emitSubagentEvent("SUBAGENT_ANNOUNCE_SENT", announcePayload);
|
|
3432
|
+
record.cleanupCompletedAt = Date.now();
|
|
3433
|
+
if (record.cleanup === "delete") {
|
|
3434
|
+
this.subagentRuns.delete(runId);
|
|
3435
|
+
}
|
|
3436
|
+
return true;
|
|
3493
3437
|
}
|
|
3494
|
-
|
|
3495
|
-
const
|
|
3496
|
-
|
|
3438
|
+
buildSubagentSystemPrompt(params) {
|
|
3439
|
+
const taskText = typeof params.task === "string" && params.task.trim() ? params.task.replace(/\s+/g, " ").trim() : "{{TASK_DESCRIPTION}}";
|
|
3440
|
+
const lines = [
|
|
3441
|
+
"# Subagent Context",
|
|
3442
|
+
"",
|
|
3443
|
+
"You are a **subagent** spawned by the main agent for a specific task.",
|
|
3444
|
+
"",
|
|
3445
|
+
"## Your Role",
|
|
3446
|
+
`- You were created to handle: ${taskText}`,
|
|
3447
|
+
"- Complete this task. That's your entire purpose.",
|
|
3448
|
+
"- You are NOT the main agent. Don't try to be.",
|
|
3449
|
+
"",
|
|
3450
|
+
"## Rules",
|
|
3451
|
+
"1. **Stay focused** - Do your assigned task, nothing else",
|
|
3452
|
+
"2. **Complete the task** - Your final message will be automatically reported to the main agent",
|
|
3453
|
+
"3. **Don't initiate** - No heartbeats, no proactive actions, no side quests",
|
|
3454
|
+
"4. **Be ephemeral** - You may be terminated after task completion. That's fine.",
|
|
3455
|
+
"",
|
|
3456
|
+
"## Output Format",
|
|
3457
|
+
"When complete, your final response should include:",
|
|
3458
|
+
"- What you accomplished or found",
|
|
3459
|
+
"- Any relevant details the main agent should know",
|
|
3460
|
+
"- Keep it concise but informative",
|
|
3461
|
+
"",
|
|
3462
|
+
"## What You DON'T Do",
|
|
3463
|
+
"- NO user conversations (that's main agent's job)",
|
|
3464
|
+
"- NO external messages unless explicitly tasked with a specific recipient",
|
|
3465
|
+
"- NO cron jobs or persistent state",
|
|
3466
|
+
"- NO pretending to be the main agent",
|
|
3467
|
+
"",
|
|
3468
|
+
"## Session Context",
|
|
3469
|
+
params.label ? `- Label: ${params.label}` : undefined,
|
|
3470
|
+
params.requesterSessionKey ? `- Requester session: ${params.requesterSessionKey}` : undefined,
|
|
3471
|
+
params.requesterOrigin?.channel ? `- Requester channel: ${params.requesterOrigin.channel}` : undefined,
|
|
3472
|
+
`- Your session: ${params.childSessionKey}`,
|
|
3473
|
+
""
|
|
3474
|
+
].filter((line) => line !== undefined);
|
|
3475
|
+
return lines.join(`
|
|
3476
|
+
`);
|
|
3477
|
+
}
|
|
3478
|
+
async sendToAgent(params, requesterContext) {
|
|
3479
|
+
const runId = crypto3.randomUUID();
|
|
3480
|
+
const policy = this.getAgentToAgentPolicy();
|
|
3481
|
+
let targetSessionKey = params.sessionKey;
|
|
3482
|
+
if (!targetSessionKey && params.label) {
|
|
3483
|
+
const matchingRun = this.findSubagentRunByLabel(params.label, params.agentId);
|
|
3484
|
+
if (matchingRun) {
|
|
3485
|
+
targetSessionKey = matchingRun.childSessionKey;
|
|
3486
|
+
} else {
|
|
3487
|
+
return {
|
|
3488
|
+
status: "error",
|
|
3489
|
+
runId,
|
|
3490
|
+
error: `No subagent found with label "${params.label}"`
|
|
3491
|
+
};
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
if (!targetSessionKey) {
|
|
3497
3495
|
return {
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
error: "Twitch service not available or sendMessage method not found"
|
|
3496
|
+
status: "error",
|
|
3497
|
+
runId,
|
|
3498
|
+
error: "Either sessionKey or label is required"
|
|
3502
3499
|
};
|
|
3503
3500
|
}
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3501
|
+
const requesterAgentId = requesterContext.sessionKey ? extractAgentIdFromSessionKey(requesterContext.sessionKey) : this.runtime.character?.name ?? "unknown";
|
|
3502
|
+
const targetAgentId = extractAgentIdFromSessionKey(targetSessionKey);
|
|
3503
|
+
if (requesterAgentId !== targetAgentId) {
|
|
3504
|
+
if (!policy.enabled) {
|
|
3505
|
+
return {
|
|
3506
|
+
status: "forbidden",
|
|
3507
|
+
runId,
|
|
3508
|
+
error: "Agent-to-agent messaging is disabled. Set settings.agentToAgent.enabled=true to allow cross-agent sends."
|
|
3509
|
+
};
|
|
3510
|
+
}
|
|
3511
|
+
if (!policy.isAllowed(requesterAgentId, targetAgentId)) {
|
|
3512
|
+
return {
|
|
3513
|
+
status: "forbidden",
|
|
3514
|
+
runId,
|
|
3515
|
+
error: "Agent-to-agent messaging denied by policy."
|
|
3516
|
+
};
|
|
3517
|
+
}
|
|
3518
|
+
}
|
|
3519
|
+
const targetRoomId = sessionKeyToRoomId(targetSessionKey, targetAgentId);
|
|
3520
|
+
const a2aContextParams = {
|
|
3521
|
+
targetSessionKey
|
|
3522
|
+
};
|
|
3523
|
+
if (requesterContext.sessionKey)
|
|
3524
|
+
a2aContextParams.requesterSessionKey = requesterContext.sessionKey;
|
|
3525
|
+
const contextMessage = this.buildAgentToAgentContext(a2aContextParams);
|
|
3526
|
+
const a2aMetadata = {
|
|
3527
|
+
isAgentToAgent: true,
|
|
3528
|
+
runId,
|
|
3529
|
+
systemPromptOverride: contextMessage
|
|
3530
|
+
};
|
|
3531
|
+
if (requesterContext.sessionKey)
|
|
3532
|
+
a2aMetadata.senderSessionKey = requesterContext.sessionKey;
|
|
3533
|
+
if (requesterContext.roomId)
|
|
3534
|
+
a2aMetadata.senderRoomId = requesterContext.roomId;
|
|
3535
|
+
const message = {
|
|
3536
|
+
id: hashToUUID(`${runId}-a2a`),
|
|
3537
|
+
entityId: this.runtime.agentId,
|
|
3538
|
+
agentId: this.runtime.agentId,
|
|
3539
|
+
roomId: targetRoomId,
|
|
3540
|
+
content: {
|
|
3541
|
+
text: params.message,
|
|
3542
|
+
type: "text",
|
|
3543
|
+
metadata: a2aMetadata
|
|
3544
|
+
}
|
|
3545
|
+
};
|
|
3546
|
+
const timeoutMs = (params.timeoutSeconds ?? 30) * 1000;
|
|
3547
|
+
if (params.timeoutSeconds === 0) {
|
|
3548
|
+
this.runtime.emitEvent(EventType2.MESSAGE_RECEIVED, {
|
|
3549
|
+
runtime: this.runtime,
|
|
3550
|
+
message,
|
|
3551
|
+
source: "a2a"
|
|
3552
|
+
}).catch((err) => {
|
|
3553
|
+
this.runtime.logger.error(`A2A send error [runId=${runId}]: ${err}`);
|
|
3508
3554
|
});
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
targetId: params.target.to,
|
|
3514
|
-
sentAt: Date.now()
|
|
3555
|
+
const asyncPayload = {
|
|
3556
|
+
runId,
|
|
3557
|
+
childSessionKey: targetSessionKey,
|
|
3558
|
+
task: params.message
|
|
3515
3559
|
};
|
|
3516
|
-
|
|
3560
|
+
if (requesterContext.sessionKey)
|
|
3561
|
+
asyncPayload.requesterSessionKey = requesterContext.sessionKey;
|
|
3562
|
+
this.emitSubagentEvent("A2A_MESSAGE_SENT", asyncPayload);
|
|
3517
3563
|
return {
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3564
|
+
status: "accepted",
|
|
3565
|
+
runId,
|
|
3566
|
+
sessionKey: targetSessionKey,
|
|
3567
|
+
delivery: { status: "pending", mode: "async" }
|
|
3522
3568
|
};
|
|
3523
3569
|
}
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
isInternalMessage: true,
|
|
3540
|
-
idempotencyKey: params.idempotencyKey
|
|
3541
|
-
}
|
|
3542
|
-
},
|
|
3543
|
-
createdAt: Date.now()
|
|
3544
|
-
};
|
|
3545
|
-
await this.runtime.emitEvent(EventType2.MESSAGE_RECEIVED, {
|
|
3546
|
-
runtime: this.runtime,
|
|
3547
|
-
message: memory,
|
|
3548
|
-
source: "internal_messaging"
|
|
3570
|
+
const sentAt = Date.now();
|
|
3571
|
+
await this.runtime.emitEvent(EventType2.MESSAGE_RECEIVED, {
|
|
3572
|
+
runtime: this.runtime,
|
|
3573
|
+
message,
|
|
3574
|
+
source: "a2a"
|
|
3575
|
+
});
|
|
3576
|
+
const pollIntervalMs = 500;
|
|
3577
|
+
const maxPolls = Math.ceil(timeoutMs / pollIntervalMs);
|
|
3578
|
+
let lastReply;
|
|
3579
|
+
for (let poll = 0;poll < maxPolls; poll++) {
|
|
3580
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
3581
|
+
const memories = await this.runtime.getMemories({
|
|
3582
|
+
tableName: "messages",
|
|
3583
|
+
roomId: targetRoomId,
|
|
3584
|
+
count: 10
|
|
3549
3585
|
});
|
|
3586
|
+
const newReplies = memories.filter((m) => m.entityId === this.runtime.agentId && m.id !== message.id && m.createdAt && m.createdAt > sentAt);
|
|
3587
|
+
if (newReplies.length > 0) {
|
|
3588
|
+
lastReply = newReplies.sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0))[0];
|
|
3589
|
+
break;
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
const syncPayload = {
|
|
3593
|
+
runId,
|
|
3594
|
+
childSessionKey: targetSessionKey,
|
|
3595
|
+
task: params.message
|
|
3596
|
+
};
|
|
3597
|
+
if (requesterContext.sessionKey)
|
|
3598
|
+
syncPayload.requesterSessionKey = requesterContext.sessionKey;
|
|
3599
|
+
this.emitSubagentEvent("A2A_MESSAGE_SENT", syncPayload);
|
|
3600
|
+
if (!lastReply) {
|
|
3550
3601
|
return {
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
};
|
|
3557
|
-
} catch (error) {
|
|
3558
|
-
return {
|
|
3559
|
-
success: false,
|
|
3560
|
-
channel: "internal",
|
|
3561
|
-
targetId: params.target.to,
|
|
3562
|
-
error: error instanceof Error ? error.message : String(error)
|
|
3602
|
+
status: "timeout",
|
|
3603
|
+
runId,
|
|
3604
|
+
sessionKey: targetSessionKey,
|
|
3605
|
+
error: `No response received within ${params.timeoutSeconds ?? 30} seconds`,
|
|
3606
|
+
delivery: { status: "timeout", mode: "sync" }
|
|
3563
3607
|
};
|
|
3564
3608
|
}
|
|
3609
|
+
const result = {
|
|
3610
|
+
status: "ok",
|
|
3611
|
+
runId,
|
|
3612
|
+
sessionKey: targetSessionKey,
|
|
3613
|
+
delivery: { status: "delivered", mode: "sync" }
|
|
3614
|
+
};
|
|
3615
|
+
if (lastReply.content?.text)
|
|
3616
|
+
result.reply = lastReply.content.text;
|
|
3617
|
+
return result;
|
|
3565
3618
|
}
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3619
|
+
buildAgentToAgentContext(params) {
|
|
3620
|
+
return [
|
|
3621
|
+
"# Agent-to-Agent Message Context",
|
|
3622
|
+
"",
|
|
3623
|
+
"This message was sent by another agent session.",
|
|
3624
|
+
params.requesterSessionKey ? `- Sender: ${params.requesterSessionKey}` : undefined,
|
|
3625
|
+
`- Target: ${params.targetSessionKey}`,
|
|
3626
|
+
"",
|
|
3627
|
+
"Process this message and respond appropriately."
|
|
3628
|
+
].filter((l) => l !== undefined).join(`
|
|
3629
|
+
`);
|
|
3630
|
+
}
|
|
3631
|
+
getSubagentRun(runId) {
|
|
3632
|
+
return this.subagentRuns.get(runId);
|
|
3633
|
+
}
|
|
3634
|
+
findSubagentRunByLabel(label, agentId) {
|
|
3635
|
+
const normalizedLabel = label.toLowerCase().trim();
|
|
3636
|
+
const normalizedAgentId = agentId ? normalizeAgentId2(agentId) : undefined;
|
|
3637
|
+
for (const run of this.subagentRuns.values()) {
|
|
3638
|
+
const runLabel = run.label?.toLowerCase().trim();
|
|
3639
|
+
if (runLabel !== normalizedLabel) {
|
|
3640
|
+
continue;
|
|
3641
|
+
}
|
|
3642
|
+
if (normalizedAgentId) {
|
|
3643
|
+
const runAgentId = extractAgentIdFromSessionKey(run.childSessionKey);
|
|
3644
|
+
if (normalizeAgentId2(runAgentId) !== normalizedAgentId) {
|
|
3645
|
+
continue;
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
if (!run.endedAt) {
|
|
3649
|
+
return run;
|
|
3650
|
+
}
|
|
3585
3651
|
}
|
|
3586
|
-
|
|
3587
|
-
|
|
3652
|
+
const completedRuns = [...this.subagentRuns.values()].filter((run) => {
|
|
3653
|
+
const runLabel = run.label?.toLowerCase().trim();
|
|
3654
|
+
if (runLabel !== normalizedLabel) {
|
|
3655
|
+
return false;
|
|
3656
|
+
}
|
|
3657
|
+
if (normalizedAgentId) {
|
|
3658
|
+
const runAgentId = extractAgentIdFromSessionKey(run.childSessionKey);
|
|
3659
|
+
if (normalizeAgentId2(runAgentId) !== normalizedAgentId) {
|
|
3660
|
+
return false;
|
|
3661
|
+
}
|
|
3662
|
+
}
|
|
3663
|
+
return true;
|
|
3664
|
+
}).sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0));
|
|
3665
|
+
return completedRuns[0];
|
|
3666
|
+
}
|
|
3667
|
+
listSubagentRuns(requesterSessionKey) {
|
|
3668
|
+
const runs = [...this.subagentRuns.values()];
|
|
3669
|
+
if (!requesterSessionKey) {
|
|
3670
|
+
return runs;
|
|
3588
3671
|
}
|
|
3589
|
-
|
|
3590
|
-
|
|
3672
|
+
return runs.filter((r) => r.requesterSessionKey === requesterSessionKey);
|
|
3673
|
+
}
|
|
3674
|
+
cancelSubagentRun(runId) {
|
|
3675
|
+
const controller = this.activeRuns.get(runId);
|
|
3676
|
+
if (controller) {
|
|
3677
|
+
controller.abort();
|
|
3678
|
+
return true;
|
|
3591
3679
|
}
|
|
3592
|
-
return
|
|
3680
|
+
return false;
|
|
3593
3681
|
}
|
|
3594
3682
|
on(event, handler) {
|
|
3595
3683
|
this.emitter.on(event, handler);
|
|
@@ -3597,25 +3685,46 @@ class MessagingService extends Service4 {
|
|
|
3597
3685
|
off(event, handler) {
|
|
3598
3686
|
this.emitter.off(event, handler);
|
|
3599
3687
|
}
|
|
3600
|
-
|
|
3688
|
+
emitSubagentEvent(type, payload) {
|
|
3601
3689
|
this.emitter.emit(type, payload);
|
|
3602
|
-
this.emitter.emit("
|
|
3690
|
+
this.emitter.emit("task", { type, ...payload });
|
|
3691
|
+
}
|
|
3692
|
+
startSweeper() {
|
|
3693
|
+
if (this.sweeper) {
|
|
3694
|
+
return;
|
|
3695
|
+
}
|
|
3696
|
+
this.sweeper = setInterval(() => {
|
|
3697
|
+
this.sweepOldRuns();
|
|
3698
|
+
}, 60000);
|
|
3699
|
+
this.sweeper.unref?.();
|
|
3700
|
+
}
|
|
3701
|
+
sweepOldRuns() {
|
|
3702
|
+
const now2 = Date.now();
|
|
3703
|
+
for (const [runId, record] of this.subagentRuns.entries()) {
|
|
3704
|
+
if (record.archiveAtMs && record.archiveAtMs <= now2) {
|
|
3705
|
+
this.subagentRuns.delete(runId);
|
|
3706
|
+
}
|
|
3707
|
+
}
|
|
3603
3708
|
}
|
|
3604
3709
|
async stop() {
|
|
3605
|
-
this.
|
|
3710
|
+
if (this.sweeper) {
|
|
3711
|
+
clearInterval(this.sweeper);
|
|
3712
|
+
this.sweeper = null;
|
|
3713
|
+
}
|
|
3714
|
+
for (const controller of this.activeRuns.values()) {
|
|
3715
|
+
controller.abort();
|
|
3716
|
+
}
|
|
3717
|
+
this.activeRuns.clear();
|
|
3606
3718
|
this.emitter.removeAllListeners();
|
|
3607
3719
|
}
|
|
3608
3720
|
}
|
|
3609
|
-
// src/types/
|
|
3610
|
-
var
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
ANNOUNCE_SENT: "SUBAGENT_ANNOUNCE_SENT",
|
|
3617
|
-
A2A_MESSAGE_SENT: "A2A_MESSAGE_SENT",
|
|
3618
|
-
A2A_MESSAGE_RECEIVED: "A2A_MESSAGE_RECEIVED"
|
|
3721
|
+
// src/types/messaging.ts
|
|
3722
|
+
var MessagingEventType = {
|
|
3723
|
+
SEND_REQUESTED: "MESSAGING_SEND_REQUESTED",
|
|
3724
|
+
SENT: "MESSAGING_SENT",
|
|
3725
|
+
SEND_FAILED: "MESSAGING_SEND_FAILED",
|
|
3726
|
+
DELIVERED: "MESSAGING_DELIVERED",
|
|
3727
|
+
READ: "MESSAGING_READ"
|
|
3619
3728
|
};
|
|
3620
3729
|
// src/types/sandbox.ts
|
|
3621
3730
|
var SandboxEventType = {
|
|
@@ -3627,13 +3736,16 @@ var SandboxEventType = {
|
|
|
3627
3736
|
BROWSER_STARTED: "SANDBOX_BROWSER_STARTED",
|
|
3628
3737
|
BROWSER_STOPPED: "SANDBOX_BROWSER_STOPPED"
|
|
3629
3738
|
};
|
|
3630
|
-
// src/types/
|
|
3631
|
-
var
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3739
|
+
// src/types/subagent.ts
|
|
3740
|
+
var SubagentEventType = {
|
|
3741
|
+
SPAWN_REQUESTED: "SUBAGENT_SPAWN_REQUESTED",
|
|
3742
|
+
RUN_STARTED: "SUBAGENT_RUN_STARTED",
|
|
3743
|
+
RUN_COMPLETED: "SUBAGENT_RUN_COMPLETED",
|
|
3744
|
+
RUN_FAILED: "SUBAGENT_RUN_FAILED",
|
|
3745
|
+
RUN_TIMEOUT: "SUBAGENT_RUN_TIMEOUT",
|
|
3746
|
+
ANNOUNCE_SENT: "SUBAGENT_ANNOUNCE_SENT",
|
|
3747
|
+
A2A_MESSAGE_SENT: "A2A_MESSAGE_SENT",
|
|
3748
|
+
A2A_MESSAGE_RECEIVED: "A2A_MESSAGE_RECEIVED"
|
|
3637
3749
|
};
|
|
3638
3750
|
// index.ts
|
|
3639
3751
|
var sessionProviders = getSessionProviders2();
|
|
@@ -3748,4 +3860,4 @@ export {
|
|
|
3748
3860
|
AgentOrchestratorService
|
|
3749
3861
|
};
|
|
3750
3862
|
|
|
3751
|
-
//# debugId=
|
|
3863
|
+
//# debugId=4AD40853FB59A54864756E2164756E21
|