@elizaos/plugin-agent-orchestrator 2.0.0-alpha.6 → 2.0.0-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/index.d.ts +3 -3
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1587 -1535
  4. package/dist/index.js.map +28 -28
  5. package/dist/src/actions/messaging.d.ts.map +1 -1
  6. package/dist/src/actions/peek-subagent.d.ts.map +1 -1
  7. package/dist/src/actions/subagent-management.d.ts.map +1 -1
  8. package/dist/src/actions/task-management.d.ts.map +1 -1
  9. package/dist/src/config.d.ts.map +1 -1
  10. package/dist/src/providers/orchestrator-config.d.ts.map +1 -1
  11. package/dist/src/providers/task-context.d.ts.map +1 -1
  12. package/dist/src/services/agent-orchestrator-service.d.ts.map +1 -1
  13. package/dist/src/services/messaging-service.d.ts.map +1 -1
  14. package/dist/src/services/sandbox-service.d.ts.map +1 -1
  15. package/dist/src/services/subagent-service.d.ts.map +1 -1
  16. package/dist/src/sub-agents/adapter.d.ts +5 -5
  17. package/dist/src/sub-agents/adapter.d.ts.map +1 -1
  18. package/dist/src/sub-agents/claude-agent-sdk-sub-agent.d.ts +1 -2
  19. package/dist/src/sub-agents/claude-agent-sdk-sub-agent.d.ts.map +1 -1
  20. package/dist/src/sub-agents/codex-sdk-sub-agent.d.ts +1 -2
  21. package/dist/src/sub-agents/codex-sdk-sub-agent.d.ts.map +1 -1
  22. package/dist/src/sub-agents/eliza-sub-agent.d.ts +1 -2
  23. package/dist/src/sub-agents/eliza-sub-agent.d.ts.map +1 -1
  24. package/dist/src/sub-agents/elizaos-native-sub-agent.d.ts +1 -2
  25. package/dist/src/sub-agents/elizaos-native-sub-agent.d.ts.map +1 -1
  26. package/dist/src/sub-agents/opencode-sub-agent.d.ts +1 -2
  27. package/dist/src/sub-agents/opencode-sub-agent.d.ts.map +1 -1
  28. package/dist/src/sub-agents/registry.d.ts.map +1 -1
  29. package/dist/src/sub-agents/sweagent-sub-agent.d.ts +1 -2
  30. package/dist/src/sub-agents/sweagent-sub-agent.d.ts.map +1 -1
  31. package/dist/src/sub-agents/tools.d.ts.map +1 -1
  32. package/dist/src/sub-agents/types.d.ts +11 -11
  33. package/dist/src/sub-agents/types.d.ts.map +1 -1
  34. package/dist/src/types/index.d.ts.map +1 -1
  35. package/dist/src/types/messaging.d.ts.map +1 -1
  36. package/dist/src/types/sandbox.d.ts.map +1 -1
  37. package/dist/src/types/subagent.d.ts.map +1 -1
  38. package/dist/src/types.d.ts.map +1 -1
  39. package/dist/src/utils/index.d.ts.map +1 -1
  40. package/dist/src/utils/session.d.ts +79 -1
  41. package/dist/src/utils/session.d.ts.map +1 -1
  42. package/package.json +73 -73
package/dist/index.js CHANGED
@@ -24,89 +24,482 @@ var __export = (target, all) => {
24
24
  set: (newValue) => all[name] = () => newValue
25
25
  });
26
26
  };
27
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
27
28
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
28
29
 
29
- // index.ts
30
- import { getSessionProviders as getSessionProviders2 } from "@elizaos/core";
31
-
32
- // src/actions/messaging.ts
33
- function extractMessagingParams(message, _state) {
34
- const params = message.content?.params;
35
- if (!params) {
36
- return {};
30
+ // src/sub-agents/sweagent-sub-agent.ts
31
+ var exports_sweagent_sub_agent = {};
32
+ __export(exports_sweagent_sub_agent, {
33
+ createSweAgentSubAgent: () => createSweAgentSubAgent,
34
+ SweAgentSubAgent: () => SweAgentSubAgent
35
+ });
36
+ import * as fs3 from "node:fs/promises";
37
+ import * as path8 from "node:path";
38
+ import {
39
+ AbstractModel,
40
+ DefaultAgent,
41
+ TextProblemStatement,
42
+ ToolHandler
43
+ } from "@elizaos/sweagent-root";
44
+ function getEnvInt4(key, defaultValue) {
45
+ const raw = process.env[key];
46
+ if (!raw)
47
+ return defaultValue;
48
+ const parsed = Number.parseInt(raw, 10);
49
+ if (!Number.isFinite(parsed) || parsed < 1)
50
+ return defaultValue;
51
+ return parsed;
52
+ }
53
+ function truncate(text, maxChars) {
54
+ if (text.length <= maxChars)
55
+ return text;
56
+ return `${text.slice(0, Math.max(0, maxChars - 1))}…`;
57
+ }
58
+ function redactSensitiveText4(text) {
59
+ let out = text;
60
+ out = out.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, "[REDACTED:PRIVATE_KEY]");
61
+ out = out.replace(/\bsk-[A-Za-z0-9]{16,}\b/g, "[REDACTED:API_KEY]");
62
+ out = out.replace(/\bAKIA[0-9A-Z]{16}\b/g, "[REDACTED:AWS_ACCESS_KEY_ID]");
63
+ out = out.replace(/\bASIA[0-9A-Z]{16}\b/g, "[REDACTED:AWS_ACCESS_KEY_ID]");
64
+ out = out.replace(/\bghp_[A-Za-z0-9]{20,}\b/g, "[REDACTED:GITHUB_TOKEN]");
65
+ out = out.replace(/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, "[REDACTED:GITHUB_TOKEN]");
66
+ out = out.replace(/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, "[REDACTED:SLACK_TOKEN]");
67
+ out = out.replace(/\bBearer\s+[A-Za-z0-9._-]{10,}\b/g, "Bearer [REDACTED]");
68
+ out = out.replace(/\bBasic\s+[A-Za-z0-9+/=]{10,}\b/g, "Basic [REDACTED]");
69
+ out = out.replace(/(password\s*[:=]\s*)(\S+)/gi, "$1[REDACTED]");
70
+ for (const [key, value] of Object.entries(process.env)) {
71
+ if (!value || value.length < 12)
72
+ continue;
73
+ const upper = key.toUpperCase();
74
+ if (upper.includes("KEY") || upper.includes("TOKEN") || upper.includes("SECRET") || upper.includes("PASSWORD") || upper.includes("PASSWD") || upper.includes("AUTH")) {
75
+ out = out.split(value).join(`[REDACTED:${key}]`);
76
+ }
37
77
  }
38
- let target;
39
- if (params.target) {
40
- target = params.target;
41
- } else {
42
- target = {};
43
- if (params.channel)
44
- target.channel = params.channel;
45
- if (params.to)
46
- target.to = params.to;
47
- if (params.threadId !== undefined)
48
- target.threadId = params.threadId;
49
- if (params.replyTo)
50
- target.replyToMessageId = params.replyTo;
78
+ return out;
79
+ }
80
+ async function ensureDir(dir) {
81
+ if (!dir || dir.trim() === "") {
82
+ throw new Error("Directory path cannot be empty");
51
83
  }
52
- let content;
53
- if (params.content) {
54
- content = params.content;
55
- } else {
56
- content = {};
57
- const text = params.text ?? message.content?.text;
58
- if (text)
59
- content.text = text;
84
+ await fs3.mkdir(dir, { recursive: true });
85
+ }
86
+ function findTool(tools, name) {
87
+ const tool2 = tools.find((t) => t.name === name);
88
+ if (!tool2)
89
+ throw new Error(`Required tool not available: ${name}`);
90
+ return tool2;
91
+ }
92
+ function parseGitStatusPorcelain(output) {
93
+ const created = [];
94
+ const modified = [];
95
+ const lines = output.split(`
96
+ `).map((l) => l.trimEnd());
97
+ for (const line of lines) {
98
+ if (!line)
99
+ continue;
100
+ const status = line.slice(0, 2);
101
+ const file2 = line.slice(3).trim();
102
+ if (!file2)
103
+ continue;
104
+ if (status.includes("?") || status.includes("A")) {
105
+ created.push(file2);
106
+ } else {
107
+ modified.push(file2);
108
+ }
60
109
  }
61
- return { target, content };
110
+ return { created, modified };
62
111
  }
63
- var sendCrossPlatformMessageAction = {
64
- name: "SEND_CROSS_PLATFORM_MESSAGE",
65
- similes: [
66
- "CROSS_PLATFORM_MESSAGE",
67
- "UNIFIED_SEND",
68
- "SEND_TO_CHANNEL",
69
- "RELAY_MESSAGE",
70
- "BROADCAST_MESSAGE"
71
- ],
72
- description: "Send a message to any supported platform (Discord, Telegram, Slack, WhatsApp, Twitch). " + "Requires specifying the target channel/platform and recipient.",
73
- validate: async (runtime, message, state, options) => {
74
- const __avTextRaw = typeof message?.content?.text === "string" ? message.content.text : "";
75
- const __avText = __avTextRaw.toLowerCase();
76
- const __avKeywords = ["send", "cross", "platform", "message"];
77
- const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
78
- const __avRegex = new RegExp("\\b(?:send|cross|platform|message)\\b", "i");
79
- const __avRegexOk = __avRegex.test(__avText);
80
- const __avSource = String(message?.content?.source ?? message?.source ?? "");
81
- const __avExpectedSource = "";
82
- const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || runtime?.agentId || runtime?.getService);
83
- const __avOptions = options && typeof options === "object" ? options : {};
84
- const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean(message?.content && typeof message.content === "object");
85
- if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
86
- return false;
112
+ async function isGitRepo(shellTool) {
113
+ const res = await shellTool.execute({
114
+ command: "git rev-parse --is-inside-work-tree"
115
+ });
116
+ return res.success && res.output.includes("true");
117
+ }
118
+ function extractShellStdout(toolOutput) {
119
+ const idx = toolOutput.indexOf(`
120
+ `);
121
+ return idx === -1 ? "" : toolOutput.slice(idx + 1);
122
+ }
123
+ async function getGitStatus(shellTool) {
124
+ const res = await shellTool.execute({ command: "git status --porcelain" });
125
+ if (!res.success)
126
+ throw new Error(`git status failed: ${res.output}`);
127
+ return extractShellStdout(res.output);
128
+ }
129
+ async function buildPatch(shellTool) {
130
+ const unstaged = await shellTool.execute({ command: "git diff" });
131
+ const staged = await shellTool.execute({ command: "git diff --cached" });
132
+ const parts = [];
133
+ if (unstaged.success)
134
+ parts.push(extractShellStdout(unstaged.output));
135
+ if (staged.success)
136
+ parts.push(extractShellStdout(staged.output));
137
+ return parts.join(`
138
+ `).trim();
139
+ }
140
+
141
+ class LocalToolEnvironment {
142
+ workingDirectory;
143
+ shellTool;
144
+ patchPath;
145
+ submitCommand;
146
+ constructor(args) {
147
+ this.workingDirectory = args.workingDirectory;
148
+ this.shellTool = args.shellTool;
149
+ this.patchPath = args.patchPath;
150
+ this.submitCommand = args.submitCommand;
151
+ this.repo = { repoName: path8.basename(this.workingDirectory) };
152
+ this.name = "local";
153
+ }
154
+ repo;
155
+ name;
156
+ getCwd = () => this.workingDirectory;
157
+ async communicate(command) {
158
+ const cmd = command.trim();
159
+ if (cmd === this.submitCommand) {
160
+ const patch = await buildPatch(this.shellTool);
161
+ await ensureDir(path8.dirname(this.patchPath));
162
+ await fs3.writeFile(this.patchPath, patch, "utf-8");
163
+ return SUBMISSION_MARKER;
87
164
  }
88
- const __avLegacyValidate = async (runtime2, message2, _state, _options) => {
89
- const messagingService = runtime2.getService("MESSAGING");
90
- if (!messagingService) {
91
- return false;
92
- }
93
- const params = message2.content?.params;
94
- if (!params) {
95
- return true;
96
- }
97
- const hasTarget = params.target || params.channel && params.to;
98
- const hasContent = params.content || params.text || message2.content?.text;
99
- return !!(hasTarget && hasContent);
100
- };
101
- try {
102
- return Boolean(await __avLegacyValidate(runtime, message, state, options));
103
- } catch {
104
- return false;
165
+ const result = await this.shellTool.execute({ command: cmd });
166
+ return result.output;
167
+ }
168
+ async readFile(p, encoding = "utf-8") {
169
+ const resolved = p === "/root/model.patch" ? this.patchPath : path8.resolve(this.workingDirectory, p);
170
+ return await fs3.readFile(resolved, encoding);
171
+ }
172
+ async writeFile(p, content) {
173
+ const resolved = p === "/root/model.patch" ? this.patchPath : path8.resolve(this.workingDirectory, p);
174
+ await ensureDir(path8.dirname(resolved));
175
+ await fs3.writeFile(resolved, content, "utf-8");
176
+ }
177
+ async setEnvVariables(_vars) {
178
+ return;
179
+ }
180
+ async executeCommand(command) {
181
+ await this.communicate(command);
182
+ }
183
+ async interruptSession() {
184
+ return;
185
+ }
186
+ }
187
+
188
+ class SweAgentSubAgent {
189
+ name = "SWE-agent Worker";
190
+ type = "sweagent";
191
+ cancelled = false;
192
+ maxIterations;
193
+ debug;
194
+ constructor(config2) {
195
+ this.maxIterations = config2?.maxIterations ?? getEnvInt4("ELIZA_CODE_SWEAGENT_MAX_ITERATIONS", 30);
196
+ this.debug = config2?.debug ?? process.env.ELIZA_CODE_DEBUG === "1";
197
+ }
198
+ cancel() {
199
+ this.cancelled = true;
200
+ }
201
+ async execute(task, context) {
202
+ this.cancelled = false;
203
+ const {
204
+ runtime,
205
+ workingDirectory,
206
+ tools,
207
+ onProgress,
208
+ onMessage,
209
+ onTrace,
210
+ isCancelled,
211
+ isPaused
212
+ } = context;
213
+ const shellTool = findTool(tools, "shell");
214
+ if (!await isGitRepo(shellTool)) {
215
+ return {
216
+ success: false,
217
+ summary: "SWE-agent requires a git repository",
218
+ filesCreated: [],
219
+ filesModified: [],
220
+ error: "Not a git repository (git rev-parse --is-inside-work-tree returned false)"
221
+ };
105
222
  }
106
- },
107
- handler: async (runtime, message, state, _options, callback) => {
108
- const messagingService = runtime.getService("MESSAGING");
109
- if (!messagingService) {
223
+ const beforeStatus = await getGitStatus(shellTool);
224
+ const patchPath = path8.resolve(workingDirectory, ".eliza/sweagent/model.patch");
225
+ const env = new LocalToolEnvironment({
226
+ workingDirectory,
227
+ shellTool,
228
+ patchPath,
229
+ submitCommand: "submit"
230
+ });
231
+ const toolConfig = {
232
+ commands: [],
233
+ parseFunction: "thought_action",
234
+ executionTimeout: 55,
235
+ maxConsecutiveExecutionTimeouts: 2,
236
+ totalExecutionTimeout: 60 * 60,
237
+ submitCommand: "submit",
238
+ useFunctionCalling: false,
239
+ formatErrorTemplate: "Your output was not formatted correctly. Use DISCUSSION then one command in a code block.",
240
+ filter: {
241
+ blocklistErrorTemplate: "That command is not allowed. Choose a safer alternative.",
242
+ blocklist: ["rm -rf", "sudo rm", "mkfs", "dd "],
243
+ blocklistStandalone: ["shutdown", "reboot"]
244
+ },
245
+ envVariables: {}
246
+ };
247
+ const modelConfig = {
248
+ name: "runtime",
249
+ perInstanceCostLimit: 0,
250
+ totalCostLimit: 0,
251
+ perInstanceCallLimit: 0,
252
+ temperature: 0.1,
253
+ topP: 1,
254
+ apiBase: null,
255
+ apiVersion: null,
256
+ apiKey: null,
257
+ stop: [],
258
+ completionKwargs: {},
259
+ convertSystemToUser: false,
260
+ retry: { retries: 0, minWait: 0, maxWait: 0 },
261
+ delay: 0,
262
+ fallbacks: [],
263
+ chooseApiKeyByThread: false,
264
+ maxInputTokens: null,
265
+ maxOutputTokens: null,
266
+ litellmModelRegistry: null,
267
+ customTokenizer: null
268
+ };
269
+ const model = new RuntimeModel(runtime, modelConfig, toolConfig);
270
+ const agent = new DefaultAgent({
271
+ templates: DEFAULT_TEMPLATES,
272
+ tools: new ToolHandler(toolConfig),
273
+ historyProcessors: [],
274
+ model,
275
+ maxRequeries: 3,
276
+ name: "sweagent"
277
+ });
278
+ const outputDir = path8.resolve(workingDirectory, ".eliza/sweagent/runs");
279
+ await ensureDir(outputDir);
280
+ const ps = new TextProblemStatement({
281
+ text: `${task.name}
282
+
283
+ ${task.description ?? ""}`.trim(),
284
+ id: task.id ?? "task"
285
+ });
286
+ await agent.setup(env, ps, outputDir);
287
+ let iteration = 0;
288
+ while (!this.cancelled) {
289
+ if (isCancelled()) {
290
+ return {
291
+ success: false,
292
+ summary: "Cancelled",
293
+ filesCreated: [],
294
+ filesModified: [],
295
+ error: "Cancelled by user"
296
+ };
297
+ }
298
+ if (isPaused?.()) {
299
+ await new Promise((r) => setTimeout(r, 250));
300
+ continue;
301
+ }
302
+ iteration += 1;
303
+ onProgress({
304
+ taskId: task.id ?? "",
305
+ progress: Math.min(90, Math.round(iteration / this.maxIterations * 80))
306
+ });
307
+ const step = await agent.step();
308
+ const thoughtPreview = truncate(step.thought ?? "", 220);
309
+ const actionPreview = truncate(step.action ?? "", 220);
310
+ if (this.debug) {
311
+ onMessage(`DISCUSSION: ${thoughtPreview}`, "info");
312
+ onMessage(`COMMAND: ${actionPreview}`, "info");
313
+ }
314
+ onTrace?.({
315
+ kind: "note",
316
+ level: "info",
317
+ message: `step ${iteration}: ${truncate(redactSensitiveText4(thoughtPreview), 160)}`,
318
+ ts: Date.now(),
319
+ seq: iteration
320
+ });
321
+ if (step.done)
322
+ break;
323
+ if (iteration >= this.maxIterations)
324
+ break;
325
+ }
326
+ const afterStatus = await getGitStatus(shellTool);
327
+ const delta = parseGitStatusPorcelain(afterStatus);
328
+ let patchExists = false;
329
+ try {
330
+ await fs3.stat(patchPath);
331
+ patchExists = true;
332
+ } catch {
333
+ patchExists = false;
334
+ }
335
+ const success2 = patchExists || delta.created.length + delta.modified.length > 0;
336
+ if (!success2) {
337
+ return {
338
+ success: false,
339
+ summary: "No patch produced",
340
+ filesCreated: delta.created,
341
+ filesModified: delta.modified,
342
+ error: `No submission patch produced.
343
+ Before status:
344
+ ${beforeStatus}
345
+ After status:
346
+ ${afterStatus}`
347
+ };
348
+ }
349
+ return {
350
+ success: true,
351
+ summary: "Submitted patch",
352
+ filesCreated: delta.created,
353
+ filesModified: delta.modified
354
+ };
355
+ }
356
+ }
357
+ function createSweAgentSubAgent(config2) {
358
+ return new SweAgentSubAgent(config2);
359
+ }
360
+ var SUBMISSION_MARKER = "<<SWE_AGENT_SUBMISSION>>", RuntimeModel, DEFAULT_TEMPLATES;
361
+ var init_sweagent_sub_agent = __esm(() => {
362
+ RuntimeModel = class RuntimeModel extends AbstractModel {
363
+ runtime;
364
+ modelType;
365
+ stats = { apiCalls: 0, inputTokens: 0, outputTokens: 0 };
366
+ constructor(runtime, config2, tools) {
367
+ super(config2, tools);
368
+ this.runtime = runtime;
369
+ this.modelType = runtime.getModel("TEXT_REASONING_LARGE") ? "TEXT_REASONING_LARGE" : "TEXT_LARGE";
370
+ }
371
+ async query(history) {
372
+ this.stats.apiCalls += 1;
373
+ const prompt = history.map((m) => {
374
+ const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
375
+ return `${m.role.toUpperCase()}: ${content}`;
376
+ }).join(`
377
+
378
+ `);
379
+ const response = await this.runtime.useModel(this.modelType, {
380
+ prompt,
381
+ maxTokens: 4096,
382
+ temperature: 0.1
383
+ });
384
+ return { message: response };
385
+ }
386
+ };
387
+ DEFAULT_TEMPLATES = {
388
+ systemTemplate: `You are SWE-agent. Follow the format strictly.
389
+
390
+ DISCUSSION
391
+ Explain what you will do.
392
+
393
+ \`\`\`
394
+ <one shell command>
395
+ \`\`\`
396
+
397
+ When finished, run:
398
+
399
+ \`\`\`
400
+ submit
401
+ \`\`\`
402
+ `,
403
+ instanceTemplate: `Task:
404
+ {{problemStatement}}
405
+
406
+ Repository: {{repo}}
407
+ Working directory: {{workingDir}}
408
+ `,
409
+ nextStepTemplate: "Observation: {{observation}}",
410
+ nextStepTruncatedObservationTemplate: "Observation: {{observation[:max_observation_length]}}<response clipped>",
411
+ maxObservationLength: 50000,
412
+ demonstrations: [],
413
+ putDemosInHistory: false,
414
+ disableImageProcessing: true,
415
+ shellCheckErrorTemplate: `Your command contains syntax errors. Please fix them.
416
+ Error: {{error_message}}
417
+ Hint: {{hint}}`,
418
+ commandCancelledTimeoutTemplate: "Command cancelled after {{timeout}} seconds. The command was: {{command}}",
419
+ nextStepNoOutputTemplate: "Observation: (no output)",
420
+ strategyTemplate: undefined,
421
+ demonstrationTemplate: undefined
422
+ };
423
+ });
424
+
425
+ // src/actions/messaging.ts
426
+ function extractMessagingParams(message, _state) {
427
+ const params = message.content?.params;
428
+ if (!params) {
429
+ return {};
430
+ }
431
+ let target;
432
+ if (params.target) {
433
+ target = params.target;
434
+ } else {
435
+ target = {};
436
+ if (params.channel)
437
+ target.channel = params.channel;
438
+ if (params.to)
439
+ target.to = params.to;
440
+ if (params.threadId !== undefined)
441
+ target.threadId = params.threadId;
442
+ if (params.replyTo)
443
+ target.replyToMessageId = params.replyTo;
444
+ }
445
+ let content;
446
+ if (params.content) {
447
+ content = params.content;
448
+ } else {
449
+ content = {};
450
+ const text = params.text ?? message.content?.text;
451
+ if (text)
452
+ content.text = text;
453
+ }
454
+ return { target, content };
455
+ }
456
+ var sendCrossPlatformMessageAction = {
457
+ name: "SEND_CROSS_PLATFORM_MESSAGE",
458
+ similes: [
459
+ "CROSS_PLATFORM_MESSAGE",
460
+ "UNIFIED_SEND",
461
+ "SEND_TO_CHANNEL",
462
+ "RELAY_MESSAGE",
463
+ "BROADCAST_MESSAGE"
464
+ ],
465
+ description: "Send a message to any supported platform (Discord, Telegram, Slack, WhatsApp, Twitch). " + "Requires specifying the target channel/platform and recipient.",
466
+ validate: async (runtime, message, state, options) => {
467
+ const __avTextRaw = typeof message?.content?.text === "string" ? message.content.text : "";
468
+ const __avText = __avTextRaw.toLowerCase();
469
+ const __avKeywords = ["send", "cross", "platform", "message"];
470
+ const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
471
+ const __avRegex = /\b(?:send|cross|platform|message)\b/i;
472
+ const __avRegexOk = __avRegex.test(__avText);
473
+ const __avSource = String(message?.content?.source ?? message?.source ?? "");
474
+ const __avExpectedSource = "";
475
+ const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || runtime?.agentId || runtime?.getService);
476
+ const __avOptions = options && typeof options === "object" ? options : {};
477
+ const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean(message?.content && typeof message.content === "object");
478
+ if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
479
+ return false;
480
+ }
481
+ const __avLegacyValidate = async (runtime2, message2, _state, _options) => {
482
+ const messagingService = runtime2.getService("MESSAGING");
483
+ if (!messagingService) {
484
+ return false;
485
+ }
486
+ const params = message2.content?.params;
487
+ if (!params) {
488
+ return true;
489
+ }
490
+ const hasTarget = params.target || params.channel && params.to;
491
+ const hasContent = params.content || params.text || message2.content?.text;
492
+ return !!(hasTarget && hasContent);
493
+ };
494
+ try {
495
+ return Boolean(await __avLegacyValidate(runtime, message, state, options));
496
+ } catch {
497
+ return false;
498
+ }
499
+ },
500
+ handler: async (runtime, message, state, _options, callback) => {
501
+ const messagingService = runtime.getService("MESSAGING");
502
+ if (!messagingService) {
110
503
  if (callback) {
111
504
  await callback({
112
505
  text: "Messaging service is not available. Please ensure the orchestrator plugin is properly configured."
@@ -239,7 +632,7 @@ var sendToDeliveryContextAction = {
239
632
  const __avText = __avTextRaw.toLowerCase();
240
633
  const __avKeywords = ["send", "delivery", "context"];
241
634
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
242
- const __avRegex = new RegExp("\\b(?:send|delivery|context)\\b", "i");
635
+ const __avRegex = /\b(?:send|delivery|context)\b/i;
243
636
  const __avRegexOk = __avRegex.test(__avText);
244
637
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
245
638
  const __avExpectedSource = "";
@@ -354,7 +747,7 @@ var sendToRoomAction = {
354
747
  const __avText = __avTextRaw.toLowerCase();
355
748
  const __avKeywords = ["send", "room"];
356
749
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
357
- const __avRegex = new RegExp("\\b(?:send|room)\\b", "i");
750
+ const __avRegex = /\b(?:send|room)\b/i;
358
751
  const __avRegexOk = __avRegex.test(__avText);
359
752
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
360
753
  const __avExpectedSource = "";
@@ -464,7 +857,7 @@ var sendToSessionMessageAction = {
464
857
  const __avText = __avTextRaw.toLowerCase();
465
858
  const __avKeywords = ["send", "session", "message"];
466
859
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
467
- const __avRegex = new RegExp("\\b(?:send|session|message)\\b", "i");
860
+ const __avRegex = /\b(?:send|session|message)\b/i;
468
861
  const __avRegexOk = __avRegex.test(__avText);
469
862
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
470
863
  const __avExpectedSource = "";
@@ -574,7 +967,7 @@ var listMessagingChannelsAction = {
574
967
  const __avText = __avTextRaw.toLowerCase();
575
968
  const __avKeywords = ["list", "messaging", "channels"];
576
969
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
577
- const __avRegex = new RegExp("\\b(?:list|messaging|channels)\\b", "i");
970
+ const __avRegex = /\b(?:list|messaging|channels)\b/i;
578
971
  const __avRegexOk = __avRegex.test(__avText);
579
972
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
580
973
  const __avExpectedSource = "";
@@ -644,47 +1037,68 @@ var listMessagingChannelsAction = {
644
1037
 
645
1038
  // src/utils/session.ts
646
1039
  import crypto from "node:crypto";
647
- import {
648
- buildAcpSessionKey,
649
- buildAgentMainSessionKey,
650
- buildAgentPeerSessionKey,
651
- buildAgentSessionKey,
652
- buildGroupHistoryKey,
653
- buildSubagentSessionKey,
654
- createSendPolicyProvider,
655
- createSessionEntry,
656
- createSessionProvider,
657
- createSessionSkillsProvider,
658
- deleteSessionEntry,
659
- extractSessionContext,
660
- getSessionEntry,
661
- getSessionProviders,
662
- isAcpSessionKey,
663
- isSubagentSessionKey,
664
- isValidSessionEntry,
665
- listSessionKeys,
666
- loadSessionStore,
667
- mergeSessionEntry,
668
- normalizeAccountId,
669
- normalizeAgentId,
670
- normalizeMainKey,
671
- parseAgentSessionKey,
672
- resolveAgentIdFromSessionKey,
673
- resolveAgentSessionsDir,
674
- resolveDefaultSessionStorePath,
675
- resolveSessionTranscriptPath,
676
- resolveStateDir,
677
- resolveStorePath,
678
- resolveThreadParentSessionKey,
679
- resolveThreadSessionKeys,
680
- SessionStateManager,
681
- saveSessionStore,
682
- toAgentRequestSessionKey,
683
- toAgentStoreSessionKey,
684
- updateSessionStore,
685
- updateSessionStoreEntry,
686
- upsertSessionEntry
687
- } from "@elizaos/core";
1040
+
1041
+ class SessionStateManager {
1042
+ async getEntry(_key) {
1043
+ return;
1044
+ }
1045
+ async setEntry(_key, _entry) {}
1046
+ }
1047
+ var getSessionProviders = () => [];
1048
+ var buildAcpSessionKey = (..._args) => "";
1049
+ var buildAgentMainSessionKey = (..._args) => "";
1050
+ var buildAgentPeerSessionKey = (..._args) => "";
1051
+ var buildAgentSessionKey = (..._args) => "";
1052
+ var buildGroupHistoryKey = (..._args) => "";
1053
+ var buildSubagentSessionKey = (..._args) => "";
1054
+ var createSendPolicyProvider = () => ({
1055
+ name: "stub-send-policy",
1056
+ get: async () => ({ text: "" })
1057
+ });
1058
+ var createSessionEntry = () => ({});
1059
+ var createSessionProvider = () => ({
1060
+ name: "stub-session",
1061
+ get: async () => ({ text: "" })
1062
+ });
1063
+ var createSessionSkillsProvider = () => ({
1064
+ name: "stub-skills",
1065
+ get: async () => ({ text: "" })
1066
+ });
1067
+ var deleteSessionEntry = async () => {};
1068
+ var extractSessionContext = () => ({});
1069
+ var getSessionEntry = async () => {
1070
+ return;
1071
+ };
1072
+ var isAcpSessionKey = () => false;
1073
+ var isCoreSubagentSessionKey = () => false;
1074
+ var isValidSessionEntry = () => false;
1075
+ var listSessionKeys = async () => [];
1076
+ var loadSessionStore = async () => ({ entries: {} });
1077
+ var mergeSessionEntry = () => ({});
1078
+ var normalizeAccountId = (id) => id;
1079
+ var normalizeCoreAgentId = (id) => id;
1080
+ var normalizeMainKey = (key) => key;
1081
+ var parseAgentSessionKey = () => ({
1082
+ agentId: "",
1083
+ keyType: "",
1084
+ identifier: ""
1085
+ });
1086
+ var resolveAgentIdFromSessionKey = () => "";
1087
+ var resolveAgentSessionsDir = () => "";
1088
+ var resolveDefaultSessionStorePath = () => "";
1089
+ var resolveSessionTranscriptPath = () => "";
1090
+ var resolveStateDir = () => "";
1091
+ var resolveStorePath = () => "";
1092
+ var resolveThreadParentSessionKey = () => {
1093
+ return;
1094
+ };
1095
+ var resolveThreadSessionKeys = async () => [];
1096
+ var saveSessionStore = async () => {};
1097
+ var toAgentRequestSessionKey = () => "";
1098
+ var toAgentStoreSessionKey = () => "";
1099
+ var updateSessionStore = async () => {};
1100
+ var updateSessionStoreEntry = async () => {};
1101
+ var upsertSessionEntry = async () => {};
688
1102
  function hashToUUID(input) {
689
1103
  const hash = crypto.createHash("sha256").update(input).digest("hex");
690
1104
  const uuid = [
@@ -777,13 +1191,13 @@ function normalizeKeyType(raw) {
777
1191
  }
778
1192
  }
779
1193
  function buildSessionKey(agentId, keyType, identifier) {
780
- const normalizedAgentId = normalizeAgentId2(agentId);
1194
+ const normalizedAgentId = normalizeAgentId(agentId);
781
1195
  return `agent:${normalizedAgentId}:${keyType}:${identifier}`;
782
1196
  }
783
- function normalizeAgentId2(agentId) {
1197
+ function normalizeAgentId(agentId) {
784
1198
  return agentId.trim().toLowerCase();
785
1199
  }
786
- function isSubagentSessionKey2(sessionKey) {
1200
+ function isSubagentSessionKey(sessionKey) {
787
1201
  const parsed = parseSessionKey(sessionKey);
788
1202
  return parsed.keyType === "subagent";
789
1203
  }
@@ -899,7 +1313,7 @@ function formatTokenCount(count) {
899
1313
  return String(Math.round(count));
900
1314
  }
901
1315
 
902
- // src/actions/subagent-management.ts
1316
+ // src/actions/peek-subagent.ts
903
1317
  function getSubagentService(runtime) {
904
1318
  const svc = runtime.getService("SUBAGENT");
905
1319
  if (!svc) {
@@ -907,6 +1321,98 @@ function getSubagentService(runtime) {
907
1321
  }
908
1322
  return svc;
909
1323
  }
1324
+ var peekSubagentAction = {
1325
+ name: "PEEK_SUBAGENT",
1326
+ similes: [
1327
+ "CHECK_LOGS",
1328
+ "READ_SUBAGENT",
1329
+ "VIEW_OUTPUT",
1330
+ "MONITOR_TASK",
1331
+ "INSPECT_SUBAGENT"
1332
+ ],
1333
+ description: "Peek at the recent internal monologue and logs of a running subagent. Use this to check progress without interrupting.",
1334
+ validate: async (runtime, message, state, options) => {
1335
+ const __avTextRaw = typeof message?.content?.text === "string" ? message.content.text : "";
1336
+ const __avText = __avTextRaw.toLowerCase();
1337
+ const __avKeywords = ["peek", "subagent"];
1338
+ const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1339
+ const __avRegex = /\b(?:peek|subagent)\b/i;
1340
+ const __avRegexOk = __avRegex.test(__avText);
1341
+ const __avSource = String(message?.content?.source ?? message?.source ?? "");
1342
+ const __avExpectedSource = "";
1343
+ const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || runtime?.agentId || runtime?.getService);
1344
+ const __avOptions = options && typeof options === "object" ? options : {};
1345
+ const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean(message?.content && typeof message.content === "object");
1346
+ if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
1347
+ return false;
1348
+ }
1349
+ const __avLegacyValidate = async (runtime2, message2, _state, _options) => {
1350
+ const svc = runtime2.getService("SUBAGENT");
1351
+ if (!svc)
1352
+ return false;
1353
+ const text = message2.content.text?.toLowerCase() ?? "";
1354
+ return text.includes("peek") || text.includes("check logs") || text.includes("view output") || text.includes("monitor") || text.includes("inspect");
1355
+ };
1356
+ try {
1357
+ return Boolean(await __avLegacyValidate(runtime, message, state, options));
1358
+ } catch {
1359
+ return false;
1360
+ }
1361
+ },
1362
+ handler: async (runtime, _message, _state, options, callback) => {
1363
+ const svc = getSubagentService(runtime);
1364
+ const opts = options;
1365
+ const runId = opts?.runId;
1366
+ if (!runId) {
1367
+ const msg2 = "Please specify the run ID to peek. Use LIST_SUBAGENTS to see active runs.";
1368
+ await callback?.({ content: { text: msg2 } });
1369
+ return { success: false, text: msg2 };
1370
+ }
1371
+ const result = await svc.peekSubagent(runId, opts?.count ?? 5);
1372
+ if (!result) {
1373
+ const msg2 = `No active run found with ID: ${runId.slice(0, 8)}...`;
1374
+ await callback?.({ content: { text: msg2 } });
1375
+ return { success: false, text: msg2 };
1376
+ }
1377
+ const lines = [
1378
+ `## Subagent Peek: ${runId.slice(0, 8)}...`,
1379
+ `**Status:** ${result.status.toUpperCase()}`,
1380
+ `**Last Activity:** ${result.lastActivityAt ? `${formatDurationShort(Date.now() - result.lastActivityAt)} ago` : "Never"}`,
1381
+ "",
1382
+ "**Recent Logs:**"
1383
+ ];
1384
+ if (result.messages.length === 0) {
1385
+ lines.push("(No output yet)");
1386
+ } else {
1387
+ for (const m of result.messages) {
1388
+ const time = new Date(m.createdAt ?? 0).toLocaleTimeString();
1389
+ const text = m.content.text?.replace(/\n/g, " ") ?? "...";
1390
+ lines.push(`[${time}] ${text.slice(0, 100)}${text.length > 100 ? "..." : ""}`);
1391
+ }
1392
+ }
1393
+ const msg = lines.join(`
1394
+ `);
1395
+ await callback?.({ content: { text: msg } });
1396
+ return {
1397
+ success: true,
1398
+ text: msg,
1399
+ data: {
1400
+ runId,
1401
+ status: result.status,
1402
+ logs: result.messages.map((m) => m.content.text)
1403
+ }
1404
+ };
1405
+ }
1406
+ };
1407
+
1408
+ // src/actions/subagent-management.ts
1409
+ function getSubagentService2(runtime) {
1410
+ const svc = runtime.getService("SUBAGENT");
1411
+ if (!svc) {
1412
+ throw new Error("SubagentService not available (SUBAGENT)");
1413
+ }
1414
+ return svc;
1415
+ }
910
1416
  function extractSessionContext2(_runtime, message) {
911
1417
  const metadata = message.content?.metadata;
912
1418
  const sessionKey = typeof metadata?.sessionKey === "string" ? metadata.sessionKey : undefined;
@@ -932,7 +1438,7 @@ var spawnSubagentAction = {
932
1438
  const __avText = __avTextRaw.toLowerCase();
933
1439
  const __avKeywords = ["spawn", "subagent"];
934
1440
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
935
- const __avRegex = new RegExp("\\b(?:spawn|subagent)\\b", "i");
1441
+ const __avRegex = /\b(?:spawn|subagent)\b/i;
936
1442
  const __avRegexOk = __avRegex.test(__avText);
937
1443
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
938
1444
  const __avExpectedSource = "";
@@ -959,7 +1465,7 @@ var spawnSubagentAction = {
959
1465
  }
960
1466
  },
961
1467
  handler: async (runtime, message, _state, options, callback) => {
962
- const svc = getSubagentService(runtime);
1468
+ const svc = getSubagentService2(runtime);
963
1469
  const context = extractSessionContext2(runtime, message);
964
1470
  const opts = options;
965
1471
  const task = opts?.task ?? message.content.text ?? "";
@@ -1011,7 +1517,7 @@ var sendToSessionAction = {
1011
1517
  const __avText = __avTextRaw.toLowerCase();
1012
1518
  const __avKeywords = ["send", "session"];
1013
1519
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1014
- const __avRegex = new RegExp("\\b(?:send|session)\\b", "i");
1520
+ const __avRegex = /\b(?:send|session)\b/i;
1015
1521
  const __avRegexOk = __avRegex.test(__avText);
1016
1522
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
1017
1523
  const __avExpectedSource = "";
@@ -1036,7 +1542,7 @@ var sendToSessionAction = {
1036
1542
  }
1037
1543
  },
1038
1544
  handler: async (runtime, message, _state, options, callback) => {
1039
- const svc = getSubagentService(runtime);
1545
+ const svc = getSubagentService2(runtime);
1040
1546
  const context = extractSessionContext2(runtime, message);
1041
1547
  const opts = options;
1042
1548
  const targetMessage = opts?.message ?? message.content.text ?? "";
@@ -1101,7 +1607,7 @@ var listSubagentsAction = {
1101
1607
  const __avText = __avTextRaw.toLowerCase();
1102
1608
  const __avKeywords = ["list", "subagents"];
1103
1609
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1104
- const __avRegex = new RegExp("\\b(?:list|subagents)\\b", "i");
1610
+ const __avRegex = /\b(?:list|subagents)\b/i;
1105
1611
  const __avRegexOk = __avRegex.test(__avText);
1106
1612
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
1107
1613
  const __avExpectedSource = "";
@@ -1126,7 +1632,7 @@ var listSubagentsAction = {
1126
1632
  }
1127
1633
  },
1128
1634
  handler: async (runtime, message, _state, _options, callback) => {
1129
- const svc = getSubagentService(runtime);
1635
+ const svc = getSubagentService2(runtime);
1130
1636
  const context = extractSessionContext2(runtime, message);
1131
1637
  const runs = svc.listSubagentRuns(context.sessionKey);
1132
1638
  if (runs.length === 0) {
@@ -1160,7 +1666,7 @@ var cancelSubagentAction = {
1160
1666
  const __avText = __avTextRaw.toLowerCase();
1161
1667
  const __avKeywords = ["cancel", "subagent"];
1162
1668
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1163
- const __avRegex = new RegExp("\\b(?:cancel|subagent)\\b", "i");
1669
+ const __avRegex = /\b(?:cancel|subagent)\b/i;
1164
1670
  const __avRegexOk = __avRegex.test(__avText);
1165
1671
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
1166
1672
  const __avExpectedSource = "";
@@ -1185,7 +1691,7 @@ var cancelSubagentAction = {
1185
1691
  }
1186
1692
  },
1187
1693
  handler: async (runtime, _message, _state, options, callback) => {
1188
- const svc = getSubagentService(runtime);
1694
+ const svc = getSubagentService2(runtime);
1189
1695
  const opts = options;
1190
1696
  const runId = opts?.runId;
1191
1697
  if (!runId) {
@@ -1213,7 +1719,7 @@ var getSubagentStatusAction = {
1213
1719
  const __avText = __avTextRaw.toLowerCase();
1214
1720
  const __avKeywords = ["get", "subagent", "status"];
1215
1721
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1216
- const __avRegex = new RegExp("\\b(?:get|subagent|status)\\b", "i");
1722
+ const __avRegex = /\b(?:get|subagent|status)\b/i;
1217
1723
  const __avRegexOk = __avRegex.test(__avText);
1218
1724
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
1219
1725
  const __avExpectedSource = "";
@@ -1238,7 +1744,7 @@ var getSubagentStatusAction = {
1238
1744
  }
1239
1745
  },
1240
1746
  handler: async (runtime, _message, _state, options, callback) => {
1241
- const svc = getSubagentService(runtime);
1747
+ const svc = getSubagentService2(runtime);
1242
1748
  const opts = options;
1243
1749
  const runId = opts?.runId;
1244
1750
  if (!runId) {
@@ -1271,98 +1777,6 @@ var getSubagentStatusAction = {
1271
1777
  }
1272
1778
  };
1273
1779
 
1274
- // src/actions/peek-subagent.ts
1275
- function getSubagentService2(runtime) {
1276
- const svc = runtime.getService("SUBAGENT");
1277
- if (!svc) {
1278
- throw new Error("SubagentService not available (SUBAGENT)");
1279
- }
1280
- return svc;
1281
- }
1282
- var peekSubagentAction = {
1283
- name: "PEEK_SUBAGENT",
1284
- similes: [
1285
- "CHECK_LOGS",
1286
- "READ_SUBAGENT",
1287
- "VIEW_OUTPUT",
1288
- "MONITOR_TASK",
1289
- "INSPECT_SUBAGENT"
1290
- ],
1291
- description: "Peek at the recent internal monologue and logs of a running subagent. Use this to check progress without interrupting.",
1292
- validate: async (runtime, message, state, options) => {
1293
- const __avTextRaw = typeof message?.content?.text === "string" ? message.content.text : "";
1294
- const __avText = __avTextRaw.toLowerCase();
1295
- const __avKeywords = ["peek", "subagent"];
1296
- const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1297
- const __avRegex = new RegExp("\\b(?:peek|subagent)\\b", "i");
1298
- const __avRegexOk = __avRegex.test(__avText);
1299
- const __avSource = String(message?.content?.source ?? message?.source ?? "");
1300
- const __avExpectedSource = "";
1301
- const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || runtime?.agentId || runtime?.getService);
1302
- const __avOptions = options && typeof options === "object" ? options : {};
1303
- const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean(message?.content && typeof message.content === "object");
1304
- if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
1305
- return false;
1306
- }
1307
- const __avLegacyValidate = async (runtime2, message2, _state, _options) => {
1308
- const svc = runtime2.getService("SUBAGENT");
1309
- if (!svc)
1310
- return false;
1311
- const text = message2.content.text?.toLowerCase() ?? "";
1312
- return text.includes("peek") || text.includes("check logs") || text.includes("view output") || text.includes("monitor") || text.includes("inspect");
1313
- };
1314
- try {
1315
- return Boolean(await __avLegacyValidate(runtime, message, state, options));
1316
- } catch {
1317
- return false;
1318
- }
1319
- },
1320
- handler: async (runtime, message, _state, options, callback) => {
1321
- const svc = getSubagentService2(runtime);
1322
- const opts = options;
1323
- const runId = opts?.runId;
1324
- if (!runId) {
1325
- const msg2 = "Please specify the run ID to peek. Use LIST_SUBAGENTS to see active runs.";
1326
- await callback?.({ content: { text: msg2 } });
1327
- return { success: false, text: msg2 };
1328
- }
1329
- const result = await svc.peekSubagent(runId, opts?.count ?? 5);
1330
- if (!result) {
1331
- const msg2 = `No active run found with ID: ${runId.slice(0, 8)}...`;
1332
- await callback?.({ content: { text: msg2 } });
1333
- return { success: false, text: msg2 };
1334
- }
1335
- const lines = [
1336
- `## Subagent Peek: ${runId.slice(0, 8)}...`,
1337
- `**Status:** ${result.status.toUpperCase()}`,
1338
- `**Last Activity:** ${result.lastActivityAt ? formatDurationShort(Date.now() - result.lastActivityAt) + " ago" : "Never"}`,
1339
- "",
1340
- "**Recent Logs:**"
1341
- ];
1342
- if (result.messages.length === 0) {
1343
- lines.push("(No output yet)");
1344
- } else {
1345
- for (const m of result.messages) {
1346
- const time = new Date(m.createdAt ?? 0).toLocaleTimeString();
1347
- const text = m.content.text?.replace(/\n/g, " ") ?? "...";
1348
- lines.push(`[${time}] ${text.slice(0, 100)}${text.length > 100 ? "..." : ""}`);
1349
- }
1350
- }
1351
- const msg = lines.join(`
1352
- `);
1353
- await callback?.({ content: { text: msg } });
1354
- return {
1355
- success: true,
1356
- text: msg,
1357
- data: {
1358
- runId,
1359
- status: result.status,
1360
- logs: result.messages.map((m) => m.content.text)
1361
- }
1362
- };
1363
- }
1364
- };
1365
-
1366
1780
  // src/actions/task-management.ts
1367
1781
  function getService(runtime) {
1368
1782
  const svc = runtime.getService("CODE_TASK");
@@ -1393,7 +1807,14 @@ function needsClarification(text) {
1393
1807
  "refactor",
1394
1808
  "research"
1395
1809
  ].some((word) => t.includes(word));
1396
- const hasConstraint = ["by", "for", "with", "using", "priority", "deadline"].some((word) => t.includes(word));
1810
+ const hasConstraint = [
1811
+ "by",
1812
+ "for",
1813
+ "with",
1814
+ "using",
1815
+ "priority",
1816
+ "deadline"
1817
+ ].some((word) => t.includes(word));
1397
1818
  return hasVagueMarker || hasAction && !hasConstraint && t.split(/\s+/).length < 10;
1398
1819
  }
1399
1820
  var createTaskAction = {
@@ -1405,7 +1826,7 @@ var createTaskAction = {
1405
1826
  const __avText = __avTextRaw.toLowerCase();
1406
1827
  const __avKeywords = ["create", "task"];
1407
1828
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1408
- const __avRegex = new RegExp("\\b(?:create|task)\\b", "i");
1829
+ const __avRegex = /\b(?:create|task)\b/i;
1409
1830
  const __avRegexOk = __avRegex.test(__avText);
1410
1831
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
1411
1832
  const __avExpectedSource = "";
@@ -1482,7 +1903,7 @@ var listTasksAction = {
1482
1903
  const __avText = __avTextRaw.toLowerCase();
1483
1904
  const __avKeywords = ["list", "tasks"];
1484
1905
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1485
- const __avRegex = new RegExp("\\b(?:list|tasks)\\b", "i");
1906
+ const __avRegex = /\b(?:list|tasks)\b/i;
1486
1907
  const __avRegexOk = __avRegex.test(__avText);
1487
1908
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
1488
1909
  const __avExpectedSource = "";
@@ -1550,7 +1971,7 @@ var switchTaskAction = {
1550
1971
  const __avText = __avTextRaw.toLowerCase();
1551
1972
  const __avKeywords = ["switch", "task"];
1552
1973
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1553
- const __avRegex = new RegExp("\\b(?:switch|task)\\b", "i");
1974
+ const __avRegex = /\b(?:switch|task)\b/i;
1554
1975
  const __avRegexOk = __avRegex.test(__avText);
1555
1976
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
1556
1977
  const __avExpectedSource = "";
@@ -1604,7 +2025,7 @@ var searchTasksAction = {
1604
2025
  const __avText = __avTextRaw.toLowerCase();
1605
2026
  const __avKeywords = ["search", "tasks"];
1606
2027
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1607
- const __avRegex = new RegExp("\\b(?:search|tasks)\\b", "i");
2028
+ const __avRegex = /\b(?:search|tasks)\b/i;
1608
2029
  const __avRegexOk = __avRegex.test(__avText);
1609
2030
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
1610
2031
  const __avExpectedSource = "";
@@ -1664,7 +2085,7 @@ var pauseTaskAction = {
1664
2085
  const __avText = __avTextRaw.toLowerCase();
1665
2086
  const __avKeywords = ["pause", "task"];
1666
2087
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1667
- const __avRegex = new RegExp("\\b(?:pause|task)\\b", "i");
2088
+ const __avRegex = /\b(?:pause|task)\b/i;
1668
2089
  const __avRegexOk = __avRegex.test(__avText);
1669
2090
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
1670
2091
  const __avExpectedSource = "";
@@ -1712,7 +2133,7 @@ var resumeTaskAction = {
1712
2133
  const __avText = __avTextRaw.toLowerCase();
1713
2134
  const __avKeywords = ["resume", "task"];
1714
2135
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1715
- const __avRegex = new RegExp("\\b(?:resume|task)\\b", "i");
2136
+ const __avRegex = /\b(?:resume|task)\b/i;
1716
2137
  const __avRegexOk = __avRegex.test(__avText);
1717
2138
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
1718
2139
  const __avExpectedSource = "";
@@ -1765,7 +2186,7 @@ var cancelTaskAction = {
1765
2186
  const __avText = __avTextRaw.toLowerCase();
1766
2187
  const __avKeywords = ["cancel", "task"];
1767
2188
  const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
1768
- const __avRegex = new RegExp("\\b(?:cancel|task)\\b", "i");
2189
+ const __avRegex = /\b(?:cancel|task)\b/i;
1769
2190
  const __avRegexOk = __avRegex.test(__avText);
1770
2191
  const __avSource = String(message?.content?.source ?? message?.source ?? "");
1771
2192
  const __avExpectedSource = "";
@@ -3708,11 +4129,11 @@ class SubagentService extends Service4 {
3708
4129
  if (sourceAgentId === targetAgentId) {
3709
4130
  return true;
3710
4131
  }
3711
- const sourceNorm = normalizeAgentId2(sourceAgentId);
3712
- const targetNorm = normalizeAgentId2(targetAgentId);
4132
+ const sourceNorm = normalizeAgentId(sourceAgentId);
4133
+ const targetNorm = normalizeAgentId(targetAgentId);
3713
4134
  for (const rule of allowRules) {
3714
- const sourceMatch = rule.source === "*" || normalizeAgentId2(rule.source) === sourceNorm;
3715
- const targetMatch = rule.target === "*" || normalizeAgentId2(rule.target) === targetNorm;
4135
+ const sourceMatch = rule.source === "*" || normalizeAgentId(rule.source) === sourceNorm;
4136
+ const targetMatch = rule.target === "*" || normalizeAgentId(rule.target) === targetNorm;
3716
4137
  if (sourceMatch && targetMatch) {
3717
4138
  return true;
3718
4139
  }
@@ -3729,18 +4150,18 @@ class SubagentService extends Service4 {
3729
4150
  error: "Subagent spawning is disabled"
3730
4151
  };
3731
4152
  }
3732
- if (requesterContext.sessionKey && isSubagentSessionKey2(requesterContext.sessionKey)) {
4153
+ if (requesterContext.sessionKey && isSubagentSessionKey(requesterContext.sessionKey)) {
3733
4154
  return {
3734
4155
  status: "forbidden",
3735
4156
  error: "sessions_spawn is not allowed from sub-agent sessions"
3736
4157
  };
3737
4158
  }
3738
4159
  const requesterAgentId = requesterContext.sessionKey ? extractAgentIdFromSessionKey(requesterContext.sessionKey) : this.runtime.character?.name ?? "unknown";
3739
- const targetAgentId = params.agentId ? normalizeAgentId2(params.agentId) : requesterAgentId;
4160
+ const targetAgentId = params.agentId ? normalizeAgentId(params.agentId) : requesterAgentId;
3740
4161
  if (targetAgentId !== requesterAgentId) {
3741
4162
  const allowAgents = config.allowAgents ?? [];
3742
4163
  const allowAny = allowAgents.some((v) => v.trim() === "*");
3743
- const allowSet = new Set(allowAgents.filter((v) => v.trim() && v.trim() !== "*").map((v) => normalizeAgentId2(v)));
4164
+ const allowSet = new Set(allowAgents.filter((v) => v.trim() && v.trim() !== "*").map((v) => normalizeAgentId(v)));
3744
4165
  if (!allowAny && !allowSet.has(targetAgentId)) {
3745
4166
  return {
3746
4167
  status: "forbidden",
@@ -4310,7 +4731,7 @@ class SubagentService extends Service4 {
4310
4731
  }
4311
4732
  findSubagentRunByLabel(label, agentId) {
4312
4733
  const normalizedLabel = label.toLowerCase().trim();
4313
- const normalizedAgentId = agentId ? normalizeAgentId2(agentId) : undefined;
4734
+ const normalizedAgentId = agentId ? normalizeAgentId(agentId) : undefined;
4314
4735
  for (const run of this.subagentRuns.values()) {
4315
4736
  const runLabel = run.label?.toLowerCase().trim();
4316
4737
  if (runLabel !== normalizedLabel) {
@@ -4318,7 +4739,7 @@ class SubagentService extends Service4 {
4318
4739
  }
4319
4740
  if (normalizedAgentId) {
4320
4741
  const runAgentId = extractAgentIdFromSessionKey(run.childSessionKey);
4321
- if (normalizeAgentId2(runAgentId) !== normalizedAgentId) {
4742
+ if (normalizeAgentId(runAgentId) !== normalizedAgentId) {
4322
4743
  continue;
4323
4744
  }
4324
4745
  }
@@ -4333,7 +4754,7 @@ class SubagentService extends Service4 {
4333
4754
  }
4334
4755
  if (normalizedAgentId) {
4335
4756
  const runAgentId = extractAgentIdFromSessionKey(run.childSessionKey);
4336
- if (normalizeAgentId2(runAgentId) !== normalizedAgentId) {
4757
+ if (normalizeAgentId(runAgentId) !== normalizedAgentId) {
4337
4758
  return false;
4338
4759
  }
4339
4760
  }
@@ -4433,7 +4854,10 @@ class SubagentService extends Service4 {
4433
4854
  const timeoutMs = (config.timeoutSeconds ?? 300) * 1000;
4434
4855
  if (now2 - record.createdAt > timeoutMs) {
4435
4856
  record.endedAt = now2;
4436
- record.outcome = { status: "error", error: "System restarted during execution (Zombie Recovery)" };
4857
+ record.outcome = {
4858
+ status: "error",
4859
+ error: "System restarted during execution (Zombie Recovery)"
4860
+ };
4437
4861
  zombieCount++;
4438
4862
  await this.updateRunState(record.runId, {
4439
4863
  endedAt: record.endedAt,
@@ -4441,7 +4865,10 @@ class SubagentService extends Service4 {
4441
4865
  }, true);
4442
4866
  } else {
4443
4867
  record.endedAt = now2;
4444
- record.outcome = { status: "error", error: "Process restarted (Interrupted)" };
4868
+ record.outcome = {
4869
+ status: "error",
4870
+ error: "Process restarted (Interrupted)"
4871
+ };
4445
4872
  zombieCount++;
4446
4873
  await this.updateRunState(record.runId, {
4447
4874
  endedAt: record.endedAt,
@@ -4507,35 +4934,6 @@ class SubagentService extends Service4 {
4507
4934
  }
4508
4935
  }
4509
4936
  }
4510
- // src/types/messaging.ts
4511
- var MessagingEventType = {
4512
- SEND_REQUESTED: "MESSAGING_SEND_REQUESTED",
4513
- SENT: "MESSAGING_SENT",
4514
- SEND_FAILED: "MESSAGING_SEND_FAILED",
4515
- DELIVERED: "MESSAGING_DELIVERED",
4516
- READ: "MESSAGING_READ"
4517
- };
4518
- // src/types/sandbox.ts
4519
- var SandboxEventType = {
4520
- CREATED: "SANDBOX_CREATED",
4521
- DESTROYED: "SANDBOX_DESTROYED",
4522
- COMMAND_STARTED: "SANDBOX_COMMAND_STARTED",
4523
- COMMAND_COMPLETED: "SANDBOX_COMMAND_COMPLETED",
4524
- COMMAND_FAILED: "SANDBOX_COMMAND_FAILED",
4525
- BROWSER_STARTED: "SANDBOX_BROWSER_STARTED",
4526
- BROWSER_STOPPED: "SANDBOX_BROWSER_STOPPED"
4527
- };
4528
- // src/types/subagent.ts
4529
- var SubagentEventType = {
4530
- SPAWN_REQUESTED: "SUBAGENT_SPAWN_REQUESTED",
4531
- RUN_STARTED: "SUBAGENT_RUN_STARTED",
4532
- RUN_COMPLETED: "SUBAGENT_RUN_COMPLETED",
4533
- RUN_FAILED: "SUBAGENT_RUN_FAILED",
4534
- RUN_TIMEOUT: "SUBAGENT_RUN_TIMEOUT",
4535
- ANNOUNCE_SENT: "SUBAGENT_ANNOUNCE_SENT",
4536
- A2A_MESSAGE_SENT: "A2A_MESSAGE_SENT",
4537
- A2A_MESSAGE_RECEIVED: "A2A_MESSAGE_RECEIVED"
4538
- };
4539
4937
  // src/sub-agents/claude-agent-sdk-sub-agent.ts
4540
4938
  import * as path2 from "node:path";
4541
4939
  import { pathToFileURL } from "node:url";
@@ -19243,877 +19641,182 @@ CONTENT_END
19243
19641
  [When finished:]
19244
19642
  DONE: Brief summary of what was accomplished
19245
19643
 
19246
- ## WORKING DIRECTORY
19247
-
19248
- {cwd}
19249
-
19250
- Now, let's solve the task methodically.`;
19251
- function parseThinkingBlocks(response) {
19252
- const blocks = [];
19253
- const regex = /<thinking>([\s\S]*?)<\/thinking>/g;
19254
- let match;
19255
- while ((match = regex.exec(response)) !== null) {
19256
- blocks.push(match[1].trim());
19257
- }
19258
- return blocks;
19259
- }
19260
- function parsePlan(response) {
19261
- const steps = [];
19262
- const planMatch = response.match(/<plan>([\s\S]*?)<\/plan>/);
19263
- if (planMatch) {
19264
- const lines = planMatch[1].split(`
19265
- `);
19266
- let id = 1;
19267
- for (const line of lines) {
19268
- const trimmed = line.trim();
19269
- const stepMatch = trimmed.match(/^\d+\.\s*\[([ x])\]\s*(.+)$/);
19270
- if (stepMatch) {
19271
- steps.push({
19272
- id: id++,
19273
- description: stepMatch[2],
19274
- completed: stepMatch[1] === "x"
19275
- });
19276
- }
19277
- }
19278
- }
19279
- return steps;
19280
- }
19281
- function parseToolCalls2(response) {
19282
- const calls = [];
19283
- const toolMatches = response.matchAll(/TOOL:\s*([A-Za-z0-9_:/.-]+)\s*\(([^)]*)\)/g);
19284
- for (const match of toolMatches) {
19285
- const name = match[1];
19286
- const argsStr = match[2];
19287
- const args = {};
19288
- const argMatches = argsStr.matchAll(/(\w+)="([^"]*)"/g);
19289
- for (const argMatch of argMatches) {
19290
- args[argMatch[1]] = argMatch[2];
19291
- }
19292
- let content;
19293
- if (name === "write_file") {
19294
- const fullMatch = match[0];
19295
- const afterTool = response.slice(response.indexOf(fullMatch) + fullMatch.length);
19296
- const contentMatch = afterTool.match(/CONTENT_START\s*([\s\S]*?)\s*CONTENT_END/);
19297
- if (contentMatch) {
19298
- content = contentMatch[1];
19299
- }
19300
- }
19301
- calls.push({ name, args, content });
19302
- }
19303
- return calls;
19304
- }
19305
- function generateContext7Docs(mcpTools) {
19306
- if (!mcpTools || mcpTools.length === 0) {
19307
- return "";
19308
- }
19309
- const context7Tools = mcpTools.filter((t) => t.server === "context7");
19310
- if (context7Tools.length === 0) {
19311
- return "";
19312
- }
19313
- return `
19314
- ### Documentation Lookup (Context7 MCP)
19315
- When you need documentation for a library or API:
19316
- - Use Context7 tools via MCP, for example:
19317
- - TOOL: MCP:context7/resolve-library-id(query="...", libraryName="...")
19318
- - TOOL: MCP:context7/query-docs(libraryId="...", query="...")
19319
- - This is especially useful for unfamiliar libraries or APIs
19320
- - Always check documentation when unsure about API usage`;
19321
- }
19322
- function generateMcpToolsDocs(mcpTools) {
19323
- if (!mcpTools || mcpTools.length === 0) {
19324
- return "";
19325
- }
19326
- const toolDocs = mcpTools.map((t) => {
19327
- const params = Object.entries(t.inputSchema.properties).map(([name, prop]) => `${name}="${prop.description}"`).join(", ");
19328
- return `- \`MCP:${t.server}/${t.name}(${params})\` - ${t.description}`;
19329
- }).join(`
19330
- `);
19331
- return `
19332
- ### MCP Tools (External Services)
19333
- Use these via TOOL calls like:
19334
- TOOL: MCP:context7/query-docs(libraryId="...", query="...")
19335
-
19336
- ${toolDocs}`;
19337
- }
19338
- function generateGoalsContext(goals) {
19339
- if (!goals || goals.length === 0) {
19340
- return "";
19341
- }
19342
- const activeGoals = goals.filter((g) => !g.isCompleted);
19343
- if (activeGoals.length === 0) {
19344
- return "";
19345
- }
19346
- const goalsList = activeGoals.map((g) => `- ${g.name}${g.description ? `: ${g.description}` : ""}`).join(`
19347
- `);
19348
- return `
19349
- ## ACTIVE GOALS
19350
-
19351
- Consider how this task contributes to your active goals:
19352
- ${goalsList}`;
19353
- }
19354
- function generateTodoInstructions(context) {
19355
- if (!context.createTodo) {
19356
- return "";
19357
- }
19358
- return `
19359
- You can create todos to track progress on complex tasks using the createTodo tool.`;
19360
- }
19361
-
19362
- class ElizaOSNativeSubAgent {
19363
- name = "ElizaOS Native Worker";
19364
- type = "elizaos-native";
19365
- cancelled = false;
19366
- plan = [];
19367
- thinkingHistory = [];
19368
- maxIterations;
19369
- debug;
19370
- enableThinking;
19371
- constructor(config2) {
19372
- this.maxIterations = config2?.maxIterations ?? getEnvInt2("ELIZA_CODE_NATIVE_MAX_ITERATIONS", 30);
19373
- this.debug = config2?.debug ?? process.env.ELIZA_CODE_DEBUG === "1";
19374
- this.enableThinking = config2?.enableThinking ?? true;
19375
- }
19376
- cancel() {
19377
- this.cancelled = true;
19378
- }
19379
- async execute(task, context) {
19380
- this.cancelled = false;
19381
- this.plan = [];
19382
- this.thinkingHistory = [];
19383
- const {
19384
- runtime,
19385
- workingDirectory,
19386
- tools,
19387
- mcpTools,
19388
- goals,
19389
- onProgress,
19390
- onMessage,
19391
- onTrace,
19392
- createTodo,
19393
- completeTodo,
19394
- callMcpTool,
19395
- isCancelled,
19396
- isPaused
19397
- } = context;
19398
- const filesCreated = [];
19399
- const filesModified = [];
19400
- const createdTodos = [];
19401
- const maxTraceResponseChars = getEnvInt2("ELIZA_CODE_TRACE_MAX_RESPONSE_CHARS", this.debug ? 20000 : 4000);
19402
- const maxTracePromptChars = getEnvInt2("ELIZA_CODE_TRACE_MAX_PROMPT_CHARS", 20000);
19403
- const maxTraceToolOutputChars = getEnvInt2("ELIZA_CODE_TRACE_MAX_TOOL_OUTPUT_CHARS", 8000);
19404
- const maxUiPreviewChars = getEnvInt2("ELIZA_CODE_TRACE_UI_PREVIEW_CHARS", 180);
19405
- let traceSeq = 0;
19406
- const base = () => {
19407
- traceSeq += 1;
19408
- return { ts: Date.now(), seq: traceSeq };
19409
- };
19410
- onProgress({ taskId: task.id ?? "", progress: 0 });
19411
- const systemPrompt = ELIZAOS_NATIVE_SYSTEM_PROMPT.replace("{cwd}", workingDirectory).replace("{context7_docs}", generateContext7Docs(mcpTools)).replace("{mcp_tools_docs}", generateMcpToolsDocs(mcpTools)).replace("{goals_context}", generateGoalsContext(goals)).replace("{todo_instructions}", generateTodoInstructions(context));
19412
- const messages = [
19413
- {
19414
- role: "user",
19415
- content: `## TASK
19416
-
19417
- **${task.name}**
19418
-
19419
- ${task.description ?? "No additional description provided."}
19420
-
19421
- Begin by analyzing the task in a <thinking> block, then explore the codebase to understand what needs to be done.`
19422
- }
19423
- ];
19424
- let iteration = 0;
19425
- let wasPaused = false;
19426
- while (iteration < this.maxIterations && !this.cancelled) {
19427
- if (isCancelled()) {
19428
- onMessage("Task cancelled", "warning");
19429
- onTrace?.({
19430
- kind: "status",
19431
- status: "cancelled",
19432
- message: "Task cancelled",
19433
- ...base()
19434
- });
19435
- return {
19436
- success: false,
19437
- summary: "Task was cancelled",
19438
- filesCreated,
19439
- filesModified,
19440
- error: "Cancelled by user"
19441
- };
19442
- }
19443
- if (isPaused?.()) {
19444
- if (!wasPaused) {
19445
- wasPaused = true;
19446
- onMessage("Task paused", "warning");
19447
- onTrace?.({
19448
- kind: "status",
19449
- status: "paused",
19450
- message: "Task paused",
19451
- ...base()
19452
- });
19453
- }
19454
- await sleep2(300);
19455
- continue;
19456
- }
19457
- if (wasPaused) {
19458
- wasPaused = false;
19459
- onMessage("Task resumed", "info");
19460
- onTrace?.({
19461
- kind: "status",
19462
- status: "resumed",
19463
- message: "Task resumed",
19464
- ...base()
19465
- });
19466
- }
19467
- iteration++;
19468
- onProgress({
19469
- taskId: task.id ?? "",
19470
- progress: Math.min(90, Math.round(iteration / this.maxIterations * 80))
19471
- });
19472
- const history = messages.map((m) => m.role === "user" ? `User: ${m.content}` : `Assistant: ${m.content}`).join(`
19473
-
19474
- `);
19475
- const prompt = `${systemPrompt}
19476
-
19477
- ${history}
19478
-
19479
- Assistant:`;
19480
- const modelType = runtime.getModel(ModelType2.TEXT_REASONING_LARGE) ? ModelType2.TEXT_REASONING_LARGE : ModelType2.TEXT_LARGE;
19481
- let response;
19482
- try {
19483
- response = await runtime.useModel(modelType, {
19484
- prompt,
19485
- maxTokens: 4096,
19486
- temperature: 0.15
19487
- });
19488
- } catch (error48) {
19489
- const errorMsg = error48 instanceof Error ? error48.message : String(error48);
19490
- onMessage(`LLM error: ${errorMsg}`, "error");
19491
- onTrace?.({
19492
- kind: "note",
19493
- level: "error",
19494
- message: errorMsg,
19495
- ...base()
19496
- });
19497
- return {
19498
- success: false,
19499
- summary: `Failed: ${errorMsg}`,
19500
- filesCreated,
19501
- filesModified,
19502
- error: errorMsg
19503
- };
19504
- }
19505
- const thinkingBlocks = parseThinkingBlocks(response);
19506
- for (const thinking of thinkingBlocks) {
19507
- this.thinkingHistory.push(thinking);
19508
- if (this.debug || this.enableThinking)
19509
- onMessage(`THINKING: ${truncateText2(thinking, 300)}`, "info");
19510
- }
19511
- const parsedPlan = parsePlan(response);
19512
- if (parsedPlan.length > 0) {
19513
- this.plan = parsedPlan;
19514
- if (createTodo && createdTodos.length === 0) {
19515
- for (const step of this.plan) {
19516
- const todo = await createTodo(step.description, `Step ${step.id} of task: ${task.name}`);
19517
- createdTodos.push(todo);
19518
- }
19519
- }
19520
- }
19521
- const responseRedacted = redactSensitiveText2(response);
19522
- const responseStored = truncateText2(responseRedacted, maxTraceResponseChars);
19523
- const responsePreview = truncateText2(collapseWhitespace2(firstNonEmptyLine2(responseStored)), maxUiPreviewChars);
19524
- const llmTrace = this.debug ? {
19525
- kind: "llm",
19526
- iteration,
19527
- modelType: String(modelType),
19528
- response: responseStored,
19529
- responsePreview,
19530
- prompt: truncateText2(redactSensitiveText2(prompt), maxTracePromptChars),
19531
- ...base()
19532
- } : {
19533
- kind: "llm",
19534
- iteration,
19535
- modelType: String(modelType),
19536
- response: responseStored,
19537
- responsePreview,
19538
- ...base()
19539
- };
19540
- onTrace?.(llmTrace);
19541
- if (response.includes("DONE:")) {
19542
- const summary2 = response.split("DONE:")[1]?.trim().split(`
19543
- `)[0] ?? "Task completed";
19544
- onMessage(`Done: ${summary2}`, "info");
19545
- onTrace?.({
19546
- kind: "note",
19547
- level: "info",
19548
- message: `Done: ${summary2}`,
19549
- ...base()
19550
- });
19551
- if (completeTodo) {
19552
- for (const todo of createdTodos) {
19553
- if (!todo.isCompleted) {
19554
- await completeTodo(todo.id);
19555
- }
19556
- }
19557
- }
19558
- return {
19559
- success: true,
19560
- summary: summary2,
19561
- filesCreated,
19562
- filesModified
19563
- };
19564
- }
19565
- const toolCalls = parseToolCalls2(response);
19566
- if (toolCalls.length === 0) {
19567
- messages.push({ role: "assistant", content: response });
19568
- messages.push({
19569
- role: "user",
19570
- content: `Please continue with the task.
19571
-
19572
- Remember to:
19573
- 1. Start with a <thinking> block to reason about your next step
19574
- 2. Execute ONE tool using the TOOL: syntax
19575
- 3. Or say DONE: when the task is complete`
19576
- });
19577
- continue;
19578
- }
19579
- const call = toolCalls[0];
19580
- onTrace?.({
19581
- kind: "tool_call",
19582
- iteration,
19583
- name: call.name,
19584
- args: call.args,
19585
- ...base()
19586
- });
19587
- if (this.debug)
19588
- onMessage(`TOOL: ${call.name}(${JSON.stringify(call.args)})`, "info");
19589
- let result;
19590
- if (call.name.startsWith("MCP:") || call.name.includes("/")) {
19591
- if (callMcpTool) {
19592
- const [server, toolName] = call.name.replace("MCP:", "").split("/");
19593
- result = await callMcpTool(server, toolName, call.args);
19594
- } else {
19595
- result = { success: false, output: "MCP tools not available" };
19596
- }
19597
- } else {
19598
- result = await this.executeTool(call.name, call.args, call.content, tools, workingDirectory, filesCreated, filesModified, onMessage);
19599
- }
19600
- const outputRedacted = redactSensitiveText2(result.output);
19601
- const outputStored = truncateText2(outputRedacted, maxTraceToolOutputChars);
19602
- const outputPreview = truncateText2(collapseWhitespace2(firstNonEmptyLine2(outputStored)), maxUiPreviewChars);
19603
- onTrace?.({
19604
- kind: "tool_result",
19605
- iteration,
19606
- name: call.name,
19607
- success: result.success,
19608
- output: outputStored,
19609
- outputPreview,
19610
- ...base()
19611
- });
19612
- const completedSteps = this.plan.filter((s) => s.completed).length;
19613
- if (completeTodo && completedSteps > createdTodos.filter((t) => t.isCompleted).length) {
19614
- const todoToComplete = createdTodos.find((t) => !t.isCompleted);
19615
- if (todoToComplete) {
19616
- await completeTodo(todoToComplete.id);
19617
- todoToComplete.isCompleted = true;
19618
- }
19619
- }
19620
- messages.push({ role: "assistant", content: response });
19621
- messages.push({
19622
- role: "user",
19623
- content: `**Tool Result:**
19624
- \`\`\`
19625
- ${truncateText2(result.output, 8000)}
19626
- \`\`\`
19627
-
19628
- ${result.success ? "✓ Command executed successfully." : "✗ Command failed."}
19629
-
19630
- Continue with the next step. Remember to start with a <thinking> block.`
19631
- });
19632
- }
19633
- const summary = `Completed after ${iteration} iterations (max reached)`;
19634
- onMessage(`Warning: ${summary}`, "warning");
19635
- onTrace?.({ kind: "note", level: "warning", message: summary, ...base() });
19636
- return {
19637
- success: true,
19638
- summary,
19639
- filesCreated,
19640
- filesModified
19641
- };
19642
- }
19643
- async executeTool(name, args, content, tools, workingDirectory, filesCreated, filesModified, onMessage) {
19644
- if (name === "write_file" && content !== undefined) {
19645
- const tool3 = tools.find((t) => t.name === "write_file");
19646
- if (!tool3) {
19647
- return { success: false, output: "write_file tool not available" };
19648
- }
19649
- const result2 = await tool3.execute({ ...args, content });
19650
- if (result2.success && args.filepath) {
19651
- if (!filesCreated.includes(args.filepath)) {
19652
- filesCreated.push(args.filepath);
19653
- }
19654
- const abs = path6.resolve(workingDirectory, args.filepath);
19655
- const link = pathToFileURL4(abs).toString();
19656
- const sizeValue = result2.data?.size;
19657
- const sizeSuffix = typeof sizeValue === "number" ? ` (${sizeValue} chars)` : "";
19658
- onMessage(`FILE write: ${args.filepath}${sizeSuffix} — ${link}`, "info");
19659
- }
19660
- return result2;
19661
- }
19662
- const tool2 = tools.find((t) => t.name === name || t.name === name.toLowerCase());
19663
- if (!tool2) {
19664
- return { success: false, output: `Unknown tool: ${name}` };
19665
- }
19666
- const result = await tool2.execute(args);
19667
- const filepath = result.data?.filepath;
19668
- if (result.success && typeof filepath === "string") {
19669
- if (name === "write_file" || name.includes("write")) {
19670
- if (!filesCreated.includes(filepath)) {
19671
- filesCreated.push(filepath);
19672
- }
19673
- const abs = path6.resolve(workingDirectory, filepath);
19674
- const link = pathToFileURL4(abs).toString();
19675
- const sizeValue = result.data?.size;
19676
- const sizeSuffix = typeof sizeValue === "number" ? ` (${sizeValue} chars)` : "";
19677
- onMessage(`FILE write: ${filepath}${sizeSuffix} — ${link}`, "info");
19678
- } else if (name === "edit_file" || name.includes("edit")) {
19679
- if (!filesModified.includes(filepath)) {
19680
- filesModified.push(filepath);
19681
- }
19682
- const abs = path6.resolve(workingDirectory, filepath);
19683
- const link = pathToFileURL4(abs).toString();
19684
- onMessage(`FILE edit: ${filepath} — ${link}`, "info");
19685
- }
19686
- }
19687
- return result;
19688
- }
19689
- getThinkingHistory() {
19690
- return [...this.thinkingHistory];
19691
- }
19692
- getPlan() {
19693
- return [...this.plan];
19694
- }
19695
- }
19696
- function sleep2(ms) {
19697
- return new Promise((resolve6) => setTimeout(resolve6, ms));
19698
- }
19699
- function getEnvInt2(key, defaultValue) {
19700
- const raw = process.env[key];
19701
- if (!raw)
19702
- return defaultValue;
19703
- const parsed = Number.parseInt(raw, 10);
19704
- if (!Number.isFinite(parsed) || parsed < 1)
19705
- return defaultValue;
19706
- return parsed;
19707
- }
19708
- function truncateText2(text, maxChars) {
19709
- if (text.length <= maxChars)
19710
- return text;
19711
- const safe = Math.max(0, maxChars - 1);
19712
- return `${text.slice(0, safe)}…`;
19713
- }
19714
- function collapseWhitespace2(text) {
19715
- return text.replace(/\s+/g, " ").trim();
19716
- }
19717
- function firstNonEmptyLine2(text) {
19718
- const lines = text.split(`
19719
- `);
19720
- for (const line of lines) {
19721
- const trimmed = line.trim();
19722
- if (trimmed.length > 0)
19723
- return trimmed;
19724
- }
19725
- return "";
19726
- }
19727
- function redactSensitiveText2(text) {
19728
- let out = text;
19729
- out = out.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, "[REDACTED:PRIVATE_KEY]");
19730
- out = out.replace(/\bsk-[A-Za-z0-9]{16,}\b/g, "[REDACTED:API_KEY]");
19731
- out = out.replace(/\bAKIA[0-9A-Z]{16}\b/g, "[REDACTED:AWS_ACCESS_KEY_ID]");
19732
- out = out.replace(/\bASIA[0-9A-Z]{16}\b/g, "[REDACTED:AWS_ACCESS_KEY_ID]");
19733
- out = out.replace(/\bghp_[A-Za-z0-9]{20,}\b/g, "[REDACTED:GITHUB_TOKEN]");
19734
- out = out.replace(/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, "[REDACTED:GITHUB_TOKEN]");
19735
- out = out.replace(/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, "[REDACTED:SLACK_TOKEN]");
19736
- out = out.replace(/\bBearer\s+[A-Za-z0-9._-]{10,}\b/g, "Bearer [REDACTED]");
19737
- out = out.replace(/\bBasic\s+[A-Za-z0-9+/=]{10,}\b/g, "Basic [REDACTED]");
19738
- out = out.replace(/(password\s*[:=]\s*)(\S+)/gi, "$1[REDACTED]");
19739
- for (const [key, value] of Object.entries(process.env)) {
19740
- if (!value || value.length < 12)
19741
- continue;
19742
- const upper = key.toUpperCase();
19743
- if (upper.includes("KEY") || upper.includes("TOKEN") || upper.includes("SECRET") || upper.includes("PASSWORD") || upper.includes("AUTH")) {
19744
- out = out.split(value).join(`[REDACTED:${key}]`);
19745
- }
19746
- }
19747
- return out;
19748
- }
19749
-
19750
- // src/sub-agents/opencode-sub-agent.ts
19751
- import { spawn as spawn2 } from "node:child_process";
19752
- import * as path7 from "node:path";
19753
- import { pathToFileURL as pathToFileURL5 } from "node:url";
19754
- import { ModelType as ModelType3 } from "@elizaos/core";
19755
- var OPENCODE_SYSTEM_PROMPT = `You are OpenCode, an expert AI coding agent with LSP integration awareness.
19756
- You help developers write, debug, and refactor code with precision and context-awareness.
19757
-
19758
- ## CAPABILITIES
19759
-
19760
- 1. **LSP-Aware Editing**: Consider type information, imports, and dependencies when making changes
19761
- 2. **Multi-Session Support**: Handle complex tasks by breaking them into logical steps
19762
- 3. **Context Management**: Track relevant files and maintain awareness of the broader codebase
19763
- 4. **Precise Modifications**: Make targeted, minimal changes that preserve existing functionality
19764
-
19765
- ## AVAILABLE TOOLS
19766
-
19767
- 1. TOOL: read_file(filepath="path/to/file")
19768
- - Read the contents of a file
19769
-
19770
- 2. TOOL: list_files(path="directory")
19771
- - List contents of a directory
19772
-
19773
- 3. TOOL: search_files(pattern="text", path="directory", max_matches="50")
19774
- - Search for text patterns in files
19775
-
19776
- 4. TOOL: shell(command="your command")
19777
- - Execute shell commands (use for git, tests, type checking, etc.)
19778
-
19779
- 5. TOOL: edit_file(filepath="file", old_str="find this", new_str="replace with")
19780
- - Make precise search/replace edits to files
19781
-
19782
- 6. TOOL: write_file(filepath="path/to/file")
19783
- CONTENT_START
19784
- <complete file contents>
19785
- CONTENT_END
19786
- - Create or overwrite a file with complete contents
19787
-
19788
- ## METHODOLOGY
19789
-
19790
- ### 1. UNDERSTAND
19791
- - Read relevant files to understand the context
19792
- - Check for type definitions and interfaces
19793
- - Understand the existing code patterns
19794
-
19795
- ### 2. PLAN
19796
- - Identify all files that need modification
19797
- - Consider imports and dependencies
19798
- - Plan changes in the correct order
19799
-
19800
- ### 3. IMPLEMENT
19801
- - Make precise, targeted changes
19802
- - Prefer edit_file for modifications
19803
- - Use write_file only for new files
19804
-
19805
- ### 4. VERIFY
19806
- - Read modified files to confirm changes
19807
- - Consider running type checks or tests
19808
- - Ensure no unintended side effects
19809
-
19810
- ## RULES
19811
-
19812
- 1. **COMPLETE CODE ONLY**: Never truncate or use placeholders
19813
- 2. **MINIMAL CHANGES**: Change only what's necessary
19814
- 3. **TYPE SAFETY**: Respect TypeScript types and interfaces
19815
- 4. **PRESERVE PATTERNS**: Follow existing code conventions
19816
- 5. **ONE TOOL AT A TIME**: Execute tools sequentially, waiting for results
19817
-
19818
- ## OUTPUT FORMAT
19819
-
19820
- When using tools:
19821
- TOOL: command(args...)
19822
-
19823
- For write_file with content:
19824
- TOOL: write_file(filepath="path/to/file")
19825
- CONTENT_START
19826
- <complete file contents here>
19827
- CONTENT_END
19828
-
19829
- When finished:
19830
- DONE: <summary of what was accomplished>
19831
-
19832
- ## WORKING DIRECTORY
19833
-
19834
- {cwd}`;
19835
- function parseOpenCodeOutput(output) {
19836
- const events = [];
19837
- const lines = output.split(`
19838
- `);
19839
- for (const line of lines) {
19840
- const trimmed = line.trim();
19841
- if (!trimmed)
19842
- continue;
19843
- if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
19844
- try {
19845
- const parsed = JSON.parse(trimmed);
19846
- if (parsed.type && typeof parsed.type === "string") {
19847
- events.push({
19848
- type: parsed.type,
19849
- data: parsed
19850
- });
19851
- }
19852
- } catch {
19853
- events.push({
19854
- type: "message",
19855
- data: { content: trimmed }
19856
- });
19857
- }
19858
- } else {
19859
- events.push({
19860
- type: "message",
19861
- data: { content: trimmed }
19862
- });
19863
- }
19864
- }
19865
- return events;
19866
- }
19867
- function parseToolCalls3(response) {
19868
- const calls = [];
19869
- const toolMatches = response.matchAll(/TOOL:\s*([A-Za-z0-9_:/.-]+)\s*\(([^)]*)\)/g);
19870
- for (const match of toolMatches) {
19871
- const name = match[1];
19872
- const argsStr = match[2];
19873
- const args = {};
19874
- const argMatches = argsStr.matchAll(/(\w+)="([^"]*)"/g);
19875
- for (const argMatch of argMatches) {
19876
- args[argMatch[1]] = argMatch[2];
19877
- }
19878
- let content;
19879
- if (name === "write_file") {
19880
- const fullMatch = match[0];
19881
- const afterTool = response.slice(response.indexOf(fullMatch) + fullMatch.length);
19882
- const contentMatch = afterTool.match(/CONTENT_START\s*([\s\S]*?)\s*CONTENT_END/);
19883
- if (contentMatch) {
19884
- content = contentMatch[1];
19885
- }
19886
- }
19887
- calls.push({ name, args, content });
19888
- }
19889
- return calls;
19890
- }
19891
- async function isOpenCodeAvailable() {
19892
- return new Promise((resolve7) => {
19893
- const child = spawn2("opencode", ["--version"], {
19894
- stdio: ["ignore", "pipe", "pipe"]
19895
- });
19896
- let resolved = false;
19897
- const timeout = setTimeout(() => {
19898
- if (!resolved) {
19899
- resolved = true;
19900
- child.kill();
19901
- resolve7(false);
19902
- }
19903
- }, 5000);
19904
- child.on("error", () => {
19905
- if (!resolved) {
19906
- resolved = true;
19907
- clearTimeout(timeout);
19908
- resolve7(false);
19909
- }
19910
- });
19911
- child.on("close", (code) => {
19912
- if (!resolved) {
19913
- resolved = true;
19914
- clearTimeout(timeout);
19915
- resolve7(code === 0);
19916
- }
19917
- });
19918
- });
19919
- }
19920
-
19921
- class OpenCodeSubAgent {
19922
- name = "OpenCode Worker";
19923
- type = "opencode";
19924
- cancelled = false;
19925
- process = null;
19926
- maxIterations;
19927
- debug;
19928
- preferCli;
19929
- constructor(config2) {
19930
- this.maxIterations = config2?.maxIterations ?? getEnvInt3("ELIZA_CODE_OPENCODE_MAX_ITERATIONS", 25);
19931
- this.debug = config2?.debug ?? process.env.ELIZA_CODE_DEBUG === "1";
19932
- this.preferCli = config2?.preferCli ?? process.env.ELIZA_CODE_OPENCODE_PREFER_CLI === "1";
19933
- }
19934
- cancel() {
19935
- this.cancelled = true;
19936
- if (this.process) {
19937
- this.process.kill();
19938
- this.process = null;
19939
- }
19940
- }
19941
- async execute(task, context) {
19942
- this.cancelled = false;
19943
- if (this.preferCli) {
19944
- const cliAvailable = await isOpenCodeAvailable();
19945
- if (cliAvailable) {
19946
- return this.executeWithCli(task, context);
19947
- }
19948
- }
19949
- return this.executeWithPrompt(task, context);
19950
- }
19951
- async executeWithCli(task, context) {
19952
- const { workingDirectory, onMessage, onTrace, isCancelled } = context;
19953
- const filesCreated = [];
19954
- const filesModified = [];
19955
- let finalResponse = "";
19956
- let traceSeq = 0;
19957
- const base = () => {
19958
- traceSeq += 1;
19959
- return { ts: Date.now(), seq: traceSeq };
19960
- };
19961
- return new Promise((resolve7) => {
19962
- const prompt = `${task.name}
19963
-
19964
- ${task.description ?? ""}`.trim();
19965
- this.process = spawn2("opencode", ["--json", "--prompt", prompt], {
19966
- cwd: workingDirectory,
19967
- stdio: ["ignore", "pipe", "pipe"],
19968
- env: { ...process.env, OPENCODE_NONINTERACTIVE: "1" }
19969
- });
19970
- let _stdout = "";
19971
- let stderr = "";
19972
- this.process.stdout?.on("data", (data) => {
19973
- const chunk = data.toString();
19974
- _stdout += chunk;
19975
- if (isCancelled()) {
19976
- this.cancel();
19977
- return;
19978
- }
19979
- const events = parseOpenCodeOutput(chunk);
19980
- for (const event of events) {
19981
- switch (event.type) {
19982
- case "message": {
19983
- const content = event.data.content;
19984
- if (content) {
19985
- finalResponse = content;
19986
- if (this.debug) {
19987
- onMessage(content, "info");
19988
- }
19989
- }
19990
- break;
19991
- }
19992
- case "tool_call": {
19993
- const toolName = event.data.tool;
19994
- const toolArgs = event.data.args;
19995
- onTrace?.({
19996
- kind: "tool_call",
19997
- iteration: traceSeq,
19998
- name: toolName,
19999
- args: toolArgs,
20000
- ...base()
20001
- });
20002
- break;
20003
- }
20004
- case "tool_result": {
20005
- const toolName = event.data.tool;
20006
- const success2 = event.data.success;
20007
- const output = event.data.output;
20008
- onTrace?.({
20009
- kind: "tool_result",
20010
- iteration: traceSeq,
20011
- name: toolName,
20012
- success: success2,
20013
- output: truncateText3(output, 4000),
20014
- outputPreview: truncateText3(output, 180),
20015
- ...base()
20016
- });
20017
- break;
20018
- }
20019
- case "file_change": {
20020
- const filepath = event.data.path;
20021
- const action = event.data.action;
20022
- if (filepath) {
20023
- if (action === "create" || action === "write") {
20024
- if (!filesCreated.includes(filepath)) {
20025
- filesCreated.push(filepath);
20026
- }
20027
- } else {
20028
- if (!filesModified.includes(filepath)) {
20029
- filesModified.push(filepath);
20030
- }
20031
- }
20032
- const abs = path7.resolve(workingDirectory, filepath);
20033
- const link = pathToFileURL5(abs).toString();
20034
- onMessage(`FILE ${action}: ${filepath} — ${link}`, "info");
20035
- }
20036
- break;
20037
- }
20038
- case "done": {
20039
- finalResponse = event.data.summary || finalResponse;
20040
- break;
20041
- }
20042
- case "error": {
20043
- const errorMsg = event.data.message;
20044
- onMessage(`Error: ${errorMsg}`, "error");
20045
- break;
20046
- }
20047
- }
20048
- }
20049
- });
20050
- this.process.stderr?.on("data", (data) => {
20051
- stderr += data.toString();
20052
- });
20053
- this.process.on("error", (error48) => {
20054
- resolve7({
20055
- success: false,
20056
- summary: `OpenCode CLI error: ${error48.message}`,
20057
- filesCreated,
20058
- filesModified,
20059
- error: error48.message
20060
- });
20061
- });
20062
- this.process.on("close", (code) => {
20063
- this.process = null;
20064
- if (this.cancelled || isCancelled()) {
20065
- resolve7({
20066
- success: false,
20067
- summary: "Cancelled",
20068
- filesCreated,
20069
- filesModified,
20070
- error: "Cancelled"
20071
- });
20072
- return;
20073
- }
20074
- const summary = finalResponse.trim().split(`
20075
- `)[0] || `Completed with exit code ${code}`;
20076
- resolve7({
20077
- success: code === 0,
20078
- summary,
20079
- filesCreated,
20080
- filesModified,
20081
- error: code !== 0 ? stderr || `Exit code: ${code}` : undefined
19644
+ ## WORKING DIRECTORY
19645
+
19646
+ {cwd}
19647
+
19648
+ Now, let's solve the task methodically.`;
19649
+ function parseThinkingBlocks(response) {
19650
+ const blocks = [];
19651
+ const regex = /<thinking>([\s\S]*?)<\/thinking>/g;
19652
+ let match;
19653
+ while ((match = regex.exec(response)) !== null) {
19654
+ blocks.push(match[1].trim());
19655
+ }
19656
+ return blocks;
19657
+ }
19658
+ function parsePlan(response) {
19659
+ const steps = [];
19660
+ const planMatch = response.match(/<plan>([\s\S]*?)<\/plan>/);
19661
+ if (planMatch) {
19662
+ const lines = planMatch[1].split(`
19663
+ `);
19664
+ let id = 1;
19665
+ for (const line of lines) {
19666
+ const trimmed = line.trim();
19667
+ const stepMatch = trimmed.match(/^\d+\.\s*\[([ x])\]\s*(.+)$/);
19668
+ if (stepMatch) {
19669
+ steps.push({
19670
+ id: id++,
19671
+ description: stepMatch[2],
19672
+ completed: stepMatch[1] === "x"
20082
19673
  });
20083
- });
20084
- });
19674
+ }
19675
+ }
20085
19676
  }
20086
- async executeWithPrompt(task, context) {
19677
+ return steps;
19678
+ }
19679
+ function parseToolCalls2(response) {
19680
+ const calls = [];
19681
+ const toolMatches = response.matchAll(/TOOL:\s*([A-Za-z0-9_:/.-]+)\s*\(([^)]*)\)/g);
19682
+ for (const match of toolMatches) {
19683
+ const name = match[1];
19684
+ const argsStr = match[2];
19685
+ const args = {};
19686
+ const argMatches = argsStr.matchAll(/(\w+)="([^"]*)"/g);
19687
+ for (const argMatch of argMatches) {
19688
+ args[argMatch[1]] = argMatch[2];
19689
+ }
19690
+ let content;
19691
+ if (name === "write_file") {
19692
+ const fullMatch = match[0];
19693
+ const afterTool = response.slice(response.indexOf(fullMatch) + fullMatch.length);
19694
+ const contentMatch = afterTool.match(/CONTENT_START\s*([\s\S]*?)\s*CONTENT_END/);
19695
+ if (contentMatch) {
19696
+ content = contentMatch[1];
19697
+ }
19698
+ }
19699
+ calls.push({ name, args, content });
19700
+ }
19701
+ return calls;
19702
+ }
19703
+ function generateContext7Docs(mcpTools) {
19704
+ if (!mcpTools || mcpTools.length === 0) {
19705
+ return "";
19706
+ }
19707
+ const context7Tools = mcpTools.filter((t) => t.server === "context7");
19708
+ if (context7Tools.length === 0) {
19709
+ return "";
19710
+ }
19711
+ return `
19712
+ ### Documentation Lookup (Context7 MCP)
19713
+ When you need documentation for a library or API:
19714
+ - Use Context7 tools via MCP, for example:
19715
+ - TOOL: MCP:context7/resolve-library-id(query="...", libraryName="...")
19716
+ - TOOL: MCP:context7/query-docs(libraryId="...", query="...")
19717
+ - This is especially useful for unfamiliar libraries or APIs
19718
+ - Always check documentation when unsure about API usage`;
19719
+ }
19720
+ function generateMcpToolsDocs(mcpTools) {
19721
+ if (!mcpTools || mcpTools.length === 0) {
19722
+ return "";
19723
+ }
19724
+ const toolDocs = mcpTools.map((t) => {
19725
+ const params = Object.entries(t.inputSchema.properties).map(([name, prop]) => `${name}="${prop.description}"`).join(", ");
19726
+ return `- \`MCP:${t.server}/${t.name}(${params})\` - ${t.description}`;
19727
+ }).join(`
19728
+ `);
19729
+ return `
19730
+ ### MCP Tools (External Services)
19731
+ Use these via TOOL calls like:
19732
+ TOOL: MCP:context7/query-docs(libraryId="...", query="...")
19733
+
19734
+ ${toolDocs}`;
19735
+ }
19736
+ function generateGoalsContext(goals) {
19737
+ if (!goals || goals.length === 0) {
19738
+ return "";
19739
+ }
19740
+ const activeGoals = goals.filter((g) => !g.isCompleted);
19741
+ if (activeGoals.length === 0) {
19742
+ return "";
19743
+ }
19744
+ const goalsList = activeGoals.map((g) => `- ${g.name}${g.description ? `: ${g.description}` : ""}`).join(`
19745
+ `);
19746
+ return `
19747
+ ## ACTIVE GOALS
19748
+
19749
+ Consider how this task contributes to your active goals:
19750
+ ${goalsList}`;
19751
+ }
19752
+ function generateTodoInstructions(context) {
19753
+ if (!context.createTodo) {
19754
+ return "";
19755
+ }
19756
+ return `
19757
+ You can create todos to track progress on complex tasks using the createTodo tool.`;
19758
+ }
19759
+
19760
+ class ElizaOSNativeSubAgent {
19761
+ name = "ElizaOS Native Worker";
19762
+ type = "elizaos-native";
19763
+ cancelled = false;
19764
+ plan = [];
19765
+ thinkingHistory = [];
19766
+ maxIterations;
19767
+ debug;
19768
+ enableThinking;
19769
+ constructor(config2) {
19770
+ this.maxIterations = config2?.maxIterations ?? getEnvInt2("ELIZA_CODE_NATIVE_MAX_ITERATIONS", 30);
19771
+ this.debug = config2?.debug ?? process.env.ELIZA_CODE_DEBUG === "1";
19772
+ this.enableThinking = config2?.enableThinking ?? true;
19773
+ }
19774
+ cancel() {
19775
+ this.cancelled = true;
19776
+ }
19777
+ async execute(task, context) {
19778
+ this.cancelled = false;
19779
+ this.plan = [];
19780
+ this.thinkingHistory = [];
20087
19781
  const {
20088
19782
  runtime,
20089
19783
  workingDirectory,
20090
19784
  tools,
20091
- callMcpTool,
19785
+ mcpTools,
19786
+ goals,
20092
19787
  onProgress,
20093
19788
  onMessage,
20094
19789
  onTrace,
19790
+ createTodo,
19791
+ completeTodo,
19792
+ callMcpTool,
20095
19793
  isCancelled,
20096
19794
  isPaused
20097
19795
  } = context;
20098
19796
  const filesCreated = [];
20099
19797
  const filesModified = [];
20100
- const maxTraceResponseChars = getEnvInt3("ELIZA_CODE_TRACE_MAX_RESPONSE_CHARS", this.debug ? 20000 : 4000);
20101
- const maxTraceToolOutputChars = getEnvInt3("ELIZA_CODE_TRACE_MAX_TOOL_OUTPUT_CHARS", 8000);
20102
- const maxUiPreviewChars = getEnvInt3("ELIZA_CODE_TRACE_UI_PREVIEW_CHARS", 180);
19798
+ const createdTodos = [];
19799
+ const maxTraceResponseChars = getEnvInt2("ELIZA_CODE_TRACE_MAX_RESPONSE_CHARS", this.debug ? 20000 : 4000);
19800
+ const maxTracePromptChars = getEnvInt2("ELIZA_CODE_TRACE_MAX_PROMPT_CHARS", 20000);
19801
+ const maxTraceToolOutputChars = getEnvInt2("ELIZA_CODE_TRACE_MAX_TOOL_OUTPUT_CHARS", 8000);
19802
+ const maxUiPreviewChars = getEnvInt2("ELIZA_CODE_TRACE_UI_PREVIEW_CHARS", 180);
20103
19803
  let traceSeq = 0;
20104
19804
  const base = () => {
20105
19805
  traceSeq += 1;
20106
19806
  return { ts: Date.now(), seq: traceSeq };
20107
19807
  };
20108
19808
  onProgress({ taskId: task.id ?? "", progress: 0 });
19809
+ const systemPrompt = ELIZAOS_NATIVE_SYSTEM_PROMPT.replace("{cwd}", workingDirectory).replace("{context7_docs}", generateContext7Docs(mcpTools)).replace("{mcp_tools_docs}", generateMcpToolsDocs(mcpTools)).replace("{goals_context}", generateGoalsContext(goals)).replace("{todo_instructions}", generateTodoInstructions(context));
20109
19810
  const messages = [
20110
19811
  {
20111
19812
  role: "user",
20112
- content: `Execute this task: ${task.name}
19813
+ content: `## TASK
20113
19814
 
20114
- Description: ${task.description ?? "No additional description provided."}
19815
+ **${task.name}**
20115
19816
 
20116
- Start by understanding the requirements, then implement the solution step by step.`
19817
+ ${task.description ?? "No additional description provided."}
19818
+
19819
+ Begin by analyzing the task in a <thinking> block, then explore the codebase to understand what needs to be done.`
20117
19820
  }
20118
19821
  ];
20119
19822
  let iteration = 0;
@@ -20146,7 +19849,7 @@ Start by understanding the requirements, then implement the solution step by ste
20146
19849
  ...base()
20147
19850
  });
20148
19851
  }
20149
- await sleep3(300);
19852
+ await sleep2(300);
20150
19853
  continue;
20151
19854
  }
20152
19855
  if (wasPaused) {
@@ -20164,7 +19867,6 @@ Start by understanding the requirements, then implement the solution step by ste
20164
19867
  taskId: task.id ?? "",
20165
19868
  progress: Math.min(90, Math.round(iteration / this.maxIterations * 80))
20166
19869
  });
20167
- const systemPrompt = OPENCODE_SYSTEM_PROMPT.replace("{cwd}", workingDirectory);
20168
19870
  const history = messages.map((m) => m.role === "user" ? `User: ${m.content}` : `Assistant: ${m.content}`).join(`
20169
19871
 
20170
19872
  `);
@@ -20173,13 +19875,13 @@ Start by understanding the requirements, then implement the solution step by ste
20173
19875
  ${history}
20174
19876
 
20175
19877
  Assistant:`;
20176
- const modelType = runtime.getModel(ModelType3.TEXT_REASONING_LARGE) ? ModelType3.TEXT_REASONING_LARGE : ModelType3.TEXT_LARGE;
19878
+ const modelType = runtime.getModel(ModelType2.TEXT_REASONING_LARGE) ? ModelType2.TEXT_REASONING_LARGE : ModelType2.TEXT_LARGE;
20177
19879
  let response;
20178
19880
  try {
20179
19881
  response = await runtime.useModel(modelType, {
20180
19882
  prompt,
20181
19883
  maxTokens: 4096,
20182
- temperature: 0.2
19884
+ temperature: 0.15
20183
19885
  });
20184
19886
  } catch (error48) {
20185
19887
  const errorMsg = error48 instanceof Error ? error48.message : String(error48);
@@ -20198,17 +19900,42 @@ Assistant:`;
20198
19900
  error: errorMsg
20199
19901
  };
20200
19902
  }
20201
- const responseRedacted = redactSensitiveText3(response);
20202
- const responseStored = truncateText3(responseRedacted, maxTraceResponseChars);
20203
- const responsePreview = truncateText3(collapseWhitespace3(firstNonEmptyLine3(responseStored)), maxUiPreviewChars);
20204
- onTrace?.({
19903
+ const thinkingBlocks = parseThinkingBlocks(response);
19904
+ for (const thinking of thinkingBlocks) {
19905
+ this.thinkingHistory.push(thinking);
19906
+ if (this.debug || this.enableThinking)
19907
+ onMessage(`THINKING: ${truncateText2(thinking, 300)}`, "info");
19908
+ }
19909
+ const parsedPlan = parsePlan(response);
19910
+ if (parsedPlan.length > 0) {
19911
+ this.plan = parsedPlan;
19912
+ if (createTodo && createdTodos.length === 0) {
19913
+ for (const step of this.plan) {
19914
+ const todo = await createTodo(step.description, `Step ${step.id} of task: ${task.name}`);
19915
+ createdTodos.push(todo);
19916
+ }
19917
+ }
19918
+ }
19919
+ const responseRedacted = redactSensitiveText2(response);
19920
+ const responseStored = truncateText2(responseRedacted, maxTraceResponseChars);
19921
+ const responsePreview = truncateText2(collapseWhitespace2(firstNonEmptyLine2(responseStored)), maxUiPreviewChars);
19922
+ const llmTrace = this.debug ? {
20205
19923
  kind: "llm",
20206
19924
  iteration,
20207
19925
  modelType: String(modelType),
20208
19926
  response: responseStored,
20209
19927
  responsePreview,
19928
+ prompt: truncateText2(redactSensitiveText2(prompt), maxTracePromptChars),
20210
19929
  ...base()
20211
- });
19930
+ } : {
19931
+ kind: "llm",
19932
+ iteration,
19933
+ modelType: String(modelType),
19934
+ response: responseStored,
19935
+ responsePreview,
19936
+ ...base()
19937
+ };
19938
+ onTrace?.(llmTrace);
20212
19939
  if (response.includes("DONE:")) {
20213
19940
  const summary2 = response.split("DONE:")[1]?.trim().split(`
20214
19941
  `)[0] ?? "Task completed";
@@ -20219,6 +19946,13 @@ Assistant:`;
20219
19946
  message: `Done: ${summary2}`,
20220
19947
  ...base()
20221
19948
  });
19949
+ if (completeTodo) {
19950
+ for (const todo of createdTodos) {
19951
+ if (!todo.isCompleted) {
19952
+ await completeTodo(todo.id);
19953
+ }
19954
+ }
19955
+ }
20222
19956
  return {
20223
19957
  success: true,
20224
19958
  summary: summary2,
@@ -20226,61 +19960,75 @@ Assistant:`;
20226
19960
  filesModified
20227
19961
  };
20228
19962
  }
20229
- const toolCalls = parseToolCalls3(response);
19963
+ const toolCalls = parseToolCalls2(response);
20230
19964
  if (toolCalls.length === 0) {
20231
19965
  messages.push({ role: "assistant", content: response });
20232
19966
  messages.push({
20233
19967
  role: "user",
20234
- content: "Continue with the task. Use TOOL: to execute commands, or say DONE: when finished."
19968
+ content: `Please continue with the task.
19969
+
19970
+ Remember to:
19971
+ 1. Start with a <thinking> block to reason about your next step
19972
+ 2. Execute ONE tool using the TOOL: syntax
19973
+ 3. Or say DONE: when the task is complete`
20235
19974
  });
20236
19975
  continue;
20237
19976
  }
20238
- const results = [];
20239
- for (const call of toolCalls) {
20240
- onTrace?.({
20241
- kind: "tool_call",
20242
- iteration,
20243
- name: call.name,
20244
- args: call.args,
20245
- ...base()
20246
- });
20247
- const result = (call.name.startsWith("MCP:") || call.name.includes("/")) && callMcpTool ? await (async () => {
20248
- const [server, toolName] = call.name.replace("MCP:", "").split("/");
20249
- if (!server || !toolName) {
20250
- return {
20251
- success: false,
20252
- output: `Invalid MCP tool call name: ${call.name}`
20253
- };
20254
- }
20255
- return await callMcpTool(server, toolName, call.args);
20256
- })() : await this.executeTool(call.name, call.args, call.content, tools, workingDirectory, filesCreated, filesModified, onMessage);
20257
- results.push({ name: call.name, result });
20258
- const outputRedacted = redactSensitiveText3(result.output);
20259
- const outputStored = truncateText3(outputRedacted, maxTraceToolOutputChars);
20260
- const outputPreview = truncateText3(collapseWhitespace3(firstNonEmptyLine3(outputStored)), maxUiPreviewChars);
20261
- onTrace?.({
20262
- kind: "tool_result",
20263
- iteration,
20264
- name: call.name,
20265
- success: result.success,
20266
- output: outputStored,
20267
- outputPreview,
20268
- ...base()
20269
- });
19977
+ const call = toolCalls[0];
19978
+ onTrace?.({
19979
+ kind: "tool_call",
19980
+ iteration,
19981
+ name: call.name,
19982
+ args: call.args,
19983
+ ...base()
19984
+ });
19985
+ if (this.debug)
19986
+ onMessage(`TOOL: ${call.name}(${JSON.stringify(call.args)})`, "info");
19987
+ let result;
19988
+ if (call.name.startsWith("MCP:") || call.name.includes("/")) {
19989
+ if (callMcpTool) {
19990
+ const [server, toolName] = call.name.replace("MCP:", "").split("/");
19991
+ result = await callMcpTool(server, toolName, call.args);
19992
+ } else {
19993
+ result = { success: false, output: "MCP tools not available" };
19994
+ }
19995
+ } else {
19996
+ result = await this.executeTool(call.name, call.args, call.content, tools, workingDirectory, filesCreated, filesModified, onMessage);
19997
+ }
19998
+ const outputRedacted = redactSensitiveText2(result.output);
19999
+ const outputStored = truncateText2(outputRedacted, maxTraceToolOutputChars);
20000
+ const outputPreview = truncateText2(collapseWhitespace2(firstNonEmptyLine2(outputStored)), maxUiPreviewChars);
20001
+ onTrace?.({
20002
+ kind: "tool_result",
20003
+ iteration,
20004
+ name: call.name,
20005
+ success: result.success,
20006
+ output: outputStored,
20007
+ outputPreview,
20008
+ ...base()
20009
+ });
20010
+ const completedSteps = this.plan.filter((s) => s.completed).length;
20011
+ if (completeTodo && completedSteps > createdTodos.filter((t) => t.isCompleted).length) {
20012
+ const todoToComplete = createdTodos.find((t) => !t.isCompleted);
20013
+ if (todoToComplete) {
20014
+ await completeTodo(todoToComplete.id);
20015
+ todoToComplete.isCompleted = true;
20016
+ }
20270
20017
  }
20271
- const resultOutput = results.map((r) => `[${r.name}] ${r.result.success ? "✓" : "✗"} ${truncateText3(r.result.output, 2000)}`).join(`
20272
-
20273
- `);
20274
20018
  messages.push({ role: "assistant", content: response });
20275
20019
  messages.push({
20276
20020
  role: "user",
20277
- content: `Tool results:
20278
- ${resultOutput}
20021
+ content: `**Tool Result:**
20022
+ \`\`\`
20023
+ ${truncateText2(result.output, 8000)}
20024
+ \`\`\`
20279
20025
 
20280
- Continue with the next step.`
20026
+ ${result.success ? "✓ Command executed successfully." : "✗ Command failed."}
20027
+
20028
+ Continue with the next step. Remember to start with a <thinking> block.`
20281
20029
  });
20282
20030
  }
20283
- const summary = `Completed after ${iteration} iterations`;
20031
+ const summary = `Completed after ${iteration} iterations (max reached)`;
20284
20032
  onMessage(`Warning: ${summary}`, "warning");
20285
20033
  onTrace?.({ kind: "note", level: "warning", message: summary, ...base() });
20286
20034
  return {
@@ -20301,9 +20049,11 @@ Continue with the next step.`
20301
20049
  if (!filesCreated.includes(args.filepath)) {
20302
20050
  filesCreated.push(args.filepath);
20303
20051
  }
20304
- const abs = path7.resolve(workingDirectory, args.filepath);
20305
- const link = pathToFileURL5(abs).toString();
20306
- onMessage(`FILE write: ${args.filepath} — ${link}`, "info");
20052
+ const abs = path6.resolve(workingDirectory, args.filepath);
20053
+ const link = pathToFileURL4(abs).toString();
20054
+ const sizeValue = result2.data?.size;
20055
+ const sizeSuffix = typeof sizeValue === "number" ? ` (${sizeValue} chars)` : "";
20056
+ onMessage(`FILE write: ${args.filepath}${sizeSuffix} — ${link}`, "info");
20307
20057
  }
20308
20058
  return result2;
20309
20059
  }
@@ -20318,8 +20068,8 @@ Continue with the next step.`
20318
20068
  if (!filesCreated.includes(filepath)) {
20319
20069
  filesCreated.push(filepath);
20320
20070
  }
20321
- const abs = path7.resolve(workingDirectory, filepath);
20322
- const link = pathToFileURL5(abs).toString();
20071
+ const abs = path6.resolve(workingDirectory, filepath);
20072
+ const link = pathToFileURL4(abs).toString();
20323
20073
  const sizeValue = result.data?.size;
20324
20074
  const sizeSuffix = typeof sizeValue === "number" ? ` (${sizeValue} chars)` : "";
20325
20075
  onMessage(`FILE write: ${filepath}${sizeSuffix} — ${link}`, "info");
@@ -20327,18 +20077,24 @@ Continue with the next step.`
20327
20077
  if (!filesModified.includes(filepath)) {
20328
20078
  filesModified.push(filepath);
20329
20079
  }
20330
- const abs = path7.resolve(workingDirectory, filepath);
20331
- const link = pathToFileURL5(abs).toString();
20080
+ const abs = path6.resolve(workingDirectory, filepath);
20081
+ const link = pathToFileURL4(abs).toString();
20332
20082
  onMessage(`FILE edit: ${filepath} — ${link}`, "info");
20333
20083
  }
20334
20084
  }
20335
20085
  return result;
20336
20086
  }
20087
+ getThinkingHistory() {
20088
+ return [...this.thinkingHistory];
20089
+ }
20090
+ getPlan() {
20091
+ return [...this.plan];
20092
+ }
20337
20093
  }
20338
- function sleep3(ms) {
20339
- return new Promise((resolve7) => setTimeout(resolve7, ms));
20094
+ function sleep2(ms) {
20095
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
20340
20096
  }
20341
- function getEnvInt3(key, defaultValue) {
20097
+ function getEnvInt2(key, defaultValue) {
20342
20098
  const raw = process.env[key];
20343
20099
  if (!raw)
20344
20100
  return defaultValue;
@@ -20347,16 +20103,16 @@ function getEnvInt3(key, defaultValue) {
20347
20103
  return defaultValue;
20348
20104
  return parsed;
20349
20105
  }
20350
- function truncateText3(text, maxChars) {
20106
+ function truncateText2(text, maxChars) {
20351
20107
  if (text.length <= maxChars)
20352
20108
  return text;
20353
20109
  const safe = Math.max(0, maxChars - 1);
20354
20110
  return `${text.slice(0, safe)}…`;
20355
20111
  }
20356
- function collapseWhitespace3(text) {
20112
+ function collapseWhitespace2(text) {
20357
20113
  return text.replace(/\s+/g, " ").trim();
20358
20114
  }
20359
- function firstNonEmptyLine3(text) {
20115
+ function firstNonEmptyLine2(text) {
20360
20116
  const lines = text.split(`
20361
20117
  `);
20362
20118
  for (const line of lines) {
@@ -20366,11 +20122,12 @@ function firstNonEmptyLine3(text) {
20366
20122
  }
20367
20123
  return "";
20368
20124
  }
20369
- function redactSensitiveText3(text) {
20125
+ function redactSensitiveText2(text) {
20370
20126
  let out = text;
20371
20127
  out = out.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, "[REDACTED:PRIVATE_KEY]");
20372
20128
  out = out.replace(/\bsk-[A-Za-z0-9]{16,}\b/g, "[REDACTED:API_KEY]");
20373
20129
  out = out.replace(/\bAKIA[0-9A-Z]{16}\b/g, "[REDACTED:AWS_ACCESS_KEY_ID]");
20130
+ out = out.replace(/\bASIA[0-9A-Z]{16}\b/g, "[REDACTED:AWS_ACCESS_KEY_ID]");
20374
20131
  out = out.replace(/\bghp_[A-Za-z0-9]{20,}\b/g, "[REDACTED:GITHUB_TOKEN]");
20375
20132
  out = out.replace(/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, "[REDACTED:GITHUB_TOKEN]");
20376
20133
  out = out.replace(/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, "[REDACTED:SLACK_TOKEN]");
@@ -20388,393 +20145,653 @@ function redactSensitiveText3(text) {
20388
20145
  return out;
20389
20146
  }
20390
20147
 
20391
- // src/sub-agents/sweagent-sub-agent.ts
20392
- import * as fs3 from "node:fs/promises";
20393
- import * as path8 from "node:path";
20394
- import {
20395
- AbstractModel,
20396
- DefaultAgent,
20397
- TextProblemStatement,
20398
- ToolHandler
20399
- } from "@elizaos/sweagent-root";
20400
- var SUBMISSION_MARKER = "<<SWE_AGENT_SUBMISSION>>";
20401
- function getEnvInt4(key, defaultValue) {
20402
- const raw = process.env[key];
20403
- if (!raw)
20404
- return defaultValue;
20405
- const parsed = Number.parseInt(raw, 10);
20406
- if (!Number.isFinite(parsed) || parsed < 1)
20407
- return defaultValue;
20408
- return parsed;
20409
- }
20410
- function truncate(text, maxChars) {
20411
- if (text.length <= maxChars)
20412
- return text;
20413
- return `${text.slice(0, Math.max(0, maxChars - 1))}…`;
20414
- }
20415
- function redactSensitiveText4(text) {
20416
- let out = text;
20417
- out = out.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, "[REDACTED:PRIVATE_KEY]");
20418
- out = out.replace(/\bsk-[A-Za-z0-9]{16,}\b/g, "[REDACTED:API_KEY]");
20419
- out = out.replace(/\bAKIA[0-9A-Z]{16}\b/g, "[REDACTED:AWS_ACCESS_KEY_ID]");
20420
- out = out.replace(/\bASIA[0-9A-Z]{16}\b/g, "[REDACTED:AWS_ACCESS_KEY_ID]");
20421
- out = out.replace(/\bghp_[A-Za-z0-9]{20,}\b/g, "[REDACTED:GITHUB_TOKEN]");
20422
- out = out.replace(/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, "[REDACTED:GITHUB_TOKEN]");
20423
- out = out.replace(/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, "[REDACTED:SLACK_TOKEN]");
20424
- out = out.replace(/\bBearer\s+[A-Za-z0-9._-]{10,}\b/g, "Bearer [REDACTED]");
20425
- out = out.replace(/\bBasic\s+[A-Za-z0-9+/=]{10,}\b/g, "Basic [REDACTED]");
20426
- out = out.replace(/(password\s*[:=]\s*)(\S+)/gi, "$1[REDACTED]");
20427
- for (const [key, value] of Object.entries(process.env)) {
20428
- if (!value || value.length < 12)
20429
- continue;
20430
- const upper = key.toUpperCase();
20431
- if (upper.includes("KEY") || upper.includes("TOKEN") || upper.includes("SECRET") || upper.includes("PASSWORD") || upper.includes("PASSWD") || upper.includes("AUTH")) {
20432
- out = out.split(value).join(`[REDACTED:${key}]`);
20433
- }
20434
- }
20435
- return out;
20436
- }
20437
- async function ensureDir(dir) {
20438
- if (!dir || dir.trim() === "") {
20439
- throw new Error("Directory path cannot be empty");
20440
- }
20441
- await fs3.mkdir(dir, { recursive: true });
20442
- }
20443
- function findTool(tools, name) {
20444
- const tool2 = tools.find((t) => t.name === name);
20445
- if (!tool2)
20446
- throw new Error(`Required tool not available: ${name}`);
20447
- return tool2;
20448
- }
20449
- function parseGitStatusPorcelain(output) {
20450
- const created = [];
20451
- const modified = [];
20452
- const lines = output.split(`
20453
- `).map((l) => l.trimEnd());
20454
- for (const line of lines) {
20455
- if (!line)
20456
- continue;
20457
- const status = line.slice(0, 2);
20458
- const file2 = line.slice(3).trim();
20459
- if (!file2)
20460
- continue;
20461
- if (status.includes("?") || status.includes("A")) {
20462
- created.push(file2);
20463
- } else {
20464
- modified.push(file2);
20465
- }
20466
- }
20467
- return { created, modified };
20468
- }
20469
- async function isGitRepo(shellTool) {
20470
- const res = await shellTool.execute({
20471
- command: "git rev-parse --is-inside-work-tree"
20472
- });
20473
- return res.success && res.output.includes("true");
20474
- }
20475
- function extractShellStdout(toolOutput) {
20476
- const idx = toolOutput.indexOf(`
20477
- `);
20478
- return idx === -1 ? "" : toolOutput.slice(idx + 1);
20479
- }
20480
- async function getGitStatus(shellTool) {
20481
- const res = await shellTool.execute({ command: "git status --porcelain" });
20482
- if (!res.success)
20483
- throw new Error(`git status failed: ${res.output}`);
20484
- return extractShellStdout(res.output);
20485
- }
20486
- async function buildPatch(shellTool) {
20487
- const unstaged = await shellTool.execute({ command: "git diff" });
20488
- const staged = await shellTool.execute({ command: "git diff --cached" });
20489
- const parts = [];
20490
- if (unstaged.success)
20491
- parts.push(extractShellStdout(unstaged.output));
20492
- if (staged.success)
20493
- parts.push(extractShellStdout(staged.output));
20494
- return parts.join(`
20495
- `).trim();
20496
- }
20148
+ // src/sub-agents/opencode-sub-agent.ts
20149
+ import { spawn as spawn2 } from "node:child_process";
20150
+ import * as path7 from "node:path";
20151
+ import { pathToFileURL as pathToFileURL5 } from "node:url";
20152
+ import { ModelType as ModelType3 } from "@elizaos/core";
20153
+ var OPENCODE_SYSTEM_PROMPT = `You are OpenCode, an expert AI coding agent with LSP integration awareness.
20154
+ You help developers write, debug, and refactor code with precision and context-awareness.
20155
+
20156
+ ## CAPABILITIES
20157
+
20158
+ 1. **LSP-Aware Editing**: Consider type information, imports, and dependencies when making changes
20159
+ 2. **Multi-Session Support**: Handle complex tasks by breaking them into logical steps
20160
+ 3. **Context Management**: Track relevant files and maintain awareness of the broader codebase
20161
+ 4. **Precise Modifications**: Make targeted, minimal changes that preserve existing functionality
20162
+
20163
+ ## AVAILABLE TOOLS
20164
+
20165
+ 1. TOOL: read_file(filepath="path/to/file")
20166
+ - Read the contents of a file
20167
+
20168
+ 2. TOOL: list_files(path="directory")
20169
+ - List contents of a directory
20170
+
20171
+ 3. TOOL: search_files(pattern="text", path="directory", max_matches="50")
20172
+ - Search for text patterns in files
20173
+
20174
+ 4. TOOL: shell(command="your command")
20175
+ - Execute shell commands (use for git, tests, type checking, etc.)
20176
+
20177
+ 5. TOOL: edit_file(filepath="file", old_str="find this", new_str="replace with")
20178
+ - Make precise search/replace edits to files
20179
+
20180
+ 6. TOOL: write_file(filepath="path/to/file")
20181
+ CONTENT_START
20182
+ <complete file contents>
20183
+ CONTENT_END
20184
+ - Create or overwrite a file with complete contents
20185
+
20186
+ ## METHODOLOGY
20187
+
20188
+ ### 1. UNDERSTAND
20189
+ - Read relevant files to understand the context
20190
+ - Check for type definitions and interfaces
20191
+ - Understand the existing code patterns
20192
+
20193
+ ### 2. PLAN
20194
+ - Identify all files that need modification
20195
+ - Consider imports and dependencies
20196
+ - Plan changes in the correct order
20197
+
20198
+ ### 3. IMPLEMENT
20199
+ - Make precise, targeted changes
20200
+ - Prefer edit_file for modifications
20201
+ - Use write_file only for new files
20202
+
20203
+ ### 4. VERIFY
20204
+ - Read modified files to confirm changes
20205
+ - Consider running type checks or tests
20206
+ - Ensure no unintended side effects
20207
+
20208
+ ## RULES
20209
+
20210
+ 1. **COMPLETE CODE ONLY**: Never truncate or use placeholders
20211
+ 2. **MINIMAL CHANGES**: Change only what's necessary
20212
+ 3. **TYPE SAFETY**: Respect TypeScript types and interfaces
20213
+ 4. **PRESERVE PATTERNS**: Follow existing code conventions
20214
+ 5. **ONE TOOL AT A TIME**: Execute tools sequentially, waiting for results
20215
+
20216
+ ## OUTPUT FORMAT
20217
+
20218
+ When using tools:
20219
+ TOOL: command(args...)
20220
+
20221
+ For write_file with content:
20222
+ TOOL: write_file(filepath="path/to/file")
20223
+ CONTENT_START
20224
+ <complete file contents here>
20225
+ CONTENT_END
20226
+
20227
+ When finished:
20228
+ DONE: <summary of what was accomplished>
20497
20229
 
20498
- class RuntimeModel extends AbstractModel {
20499
- runtime;
20500
- modelType;
20501
- stats = { apiCalls: 0, inputTokens: 0, outputTokens: 0 };
20502
- constructor(runtime, config2, tools) {
20503
- super(config2, tools);
20504
- this.runtime = runtime;
20505
- this.modelType = runtime.getModel("TEXT_REASONING_LARGE") ? "TEXT_REASONING_LARGE" : "TEXT_LARGE";
20506
- }
20507
- async query(history) {
20508
- this.stats.apiCalls += 1;
20509
- const prompt = history.map((m) => {
20510
- const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
20511
- return `${m.role.toUpperCase()}: ${content}`;
20512
- }).join(`
20230
+ ## WORKING DIRECTORY
20513
20231
 
20232
+ {cwd}`;
20233
+ function parseOpenCodeOutput(output) {
20234
+ const events = [];
20235
+ const lines = output.split(`
20514
20236
  `);
20515
- const response = await this.runtime.useModel(this.modelType, {
20516
- prompt,
20517
- maxTokens: 4096,
20518
- temperature: 0.1
20519
- });
20520
- return { message: response };
20237
+ for (const line of lines) {
20238
+ const trimmed = line.trim();
20239
+ if (!trimmed)
20240
+ continue;
20241
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
20242
+ try {
20243
+ const parsed = JSON.parse(trimmed);
20244
+ if (parsed.type && typeof parsed.type === "string") {
20245
+ events.push({
20246
+ type: parsed.type,
20247
+ data: parsed
20248
+ });
20249
+ }
20250
+ } catch {
20251
+ events.push({
20252
+ type: "message",
20253
+ data: { content: trimmed }
20254
+ });
20255
+ }
20256
+ } else {
20257
+ events.push({
20258
+ type: "message",
20259
+ data: { content: trimmed }
20260
+ });
20261
+ }
20521
20262
  }
20263
+ return events;
20522
20264
  }
20523
-
20524
- class LocalToolEnvironment {
20525
- workingDirectory;
20526
- shellTool;
20527
- patchPath;
20528
- submitCommand;
20529
- constructor(args) {
20530
- this.workingDirectory = args.workingDirectory;
20531
- this.shellTool = args.shellTool;
20532
- this.patchPath = args.patchPath;
20533
- this.submitCommand = args.submitCommand;
20534
- this.repo = { repoName: path8.basename(this.workingDirectory) };
20535
- this.name = "local";
20536
- }
20537
- repo;
20538
- name;
20539
- getCwd = () => this.workingDirectory;
20540
- async communicate(command) {
20541
- const cmd = command.trim();
20542
- if (cmd === this.submitCommand) {
20543
- const patch = await buildPatch(this.shellTool);
20544
- await ensureDir(path8.dirname(this.patchPath));
20545
- await fs3.writeFile(this.patchPath, patch, "utf-8");
20546
- return SUBMISSION_MARKER;
20265
+ function parseToolCalls3(response) {
20266
+ const calls = [];
20267
+ const toolMatches = response.matchAll(/TOOL:\s*([A-Za-z0-9_:/.-]+)\s*\(([^)]*)\)/g);
20268
+ for (const match of toolMatches) {
20269
+ const name = match[1];
20270
+ const argsStr = match[2];
20271
+ const args = {};
20272
+ const argMatches = argsStr.matchAll(/(\w+)="([^"]*)"/g);
20273
+ for (const argMatch of argMatches) {
20274
+ args[argMatch[1]] = argMatch[2];
20547
20275
  }
20548
- const result = await this.shellTool.execute({ command: cmd });
20549
- return result.output;
20550
- }
20551
- async readFile(p, encoding = "utf-8") {
20552
- const resolved = p === "/root/model.patch" ? this.patchPath : path8.resolve(this.workingDirectory, p);
20553
- return await fs3.readFile(resolved, encoding);
20554
- }
20555
- async writeFile(p, content) {
20556
- const resolved = p === "/root/model.patch" ? this.patchPath : path8.resolve(this.workingDirectory, p);
20557
- await ensureDir(path8.dirname(resolved));
20558
- await fs3.writeFile(resolved, content, "utf-8");
20559
- }
20560
- async setEnvVariables(_vars) {
20561
- return;
20562
- }
20563
- async executeCommand(command) {
20564
- await this.communicate(command);
20565
- }
20566
- async interruptSession() {
20567
- return;
20276
+ let content;
20277
+ if (name === "write_file") {
20278
+ const fullMatch = match[0];
20279
+ const afterTool = response.slice(response.indexOf(fullMatch) + fullMatch.length);
20280
+ const contentMatch = afterTool.match(/CONTENT_START\s*([\s\S]*?)\s*CONTENT_END/);
20281
+ if (contentMatch) {
20282
+ content = contentMatch[1];
20283
+ }
20284
+ }
20285
+ calls.push({ name, args, content });
20568
20286
  }
20287
+ return calls;
20288
+ }
20289
+ async function isOpenCodeAvailable() {
20290
+ return new Promise((resolve7) => {
20291
+ const child = spawn2("opencode", ["--version"], {
20292
+ stdio: ["ignore", "pipe", "pipe"]
20293
+ });
20294
+ let resolved = false;
20295
+ const timeout = setTimeout(() => {
20296
+ if (!resolved) {
20297
+ resolved = true;
20298
+ child.kill();
20299
+ resolve7(false);
20300
+ }
20301
+ }, 5000);
20302
+ child.on("error", () => {
20303
+ if (!resolved) {
20304
+ resolved = true;
20305
+ clearTimeout(timeout);
20306
+ resolve7(false);
20307
+ }
20308
+ });
20309
+ child.on("close", (code) => {
20310
+ if (!resolved) {
20311
+ resolved = true;
20312
+ clearTimeout(timeout);
20313
+ resolve7(code === 0);
20314
+ }
20315
+ });
20316
+ });
20569
20317
  }
20570
- var DEFAULT_TEMPLATES = {
20571
- systemTemplate: `You are SWE-agent. Follow the format strictly.
20572
-
20573
- DISCUSSION
20574
- Explain what you will do.
20575
-
20576
- \`\`\`
20577
- <one shell command>
20578
- \`\`\`
20579
-
20580
- When finished, run:
20581
-
20582
- \`\`\`
20583
- submit
20584
- \`\`\`
20585
- `,
20586
- instanceTemplate: `Task:
20587
- {{problemStatement}}
20588
-
20589
- Repository: {{repo}}
20590
- Working directory: {{workingDir}}
20591
- `,
20592
- nextStepTemplate: "Observation: {{observation}}",
20593
- nextStepTruncatedObservationTemplate: "Observation: {{observation[:max_observation_length]}}<response clipped>",
20594
- maxObservationLength: 50000,
20595
- demonstrations: [],
20596
- putDemosInHistory: false,
20597
- disableImageProcessing: true,
20598
- shellCheckErrorTemplate: `Your command contains syntax errors. Please fix them.
20599
- Error: {{error_message}}
20600
- Hint: {{hint}}`,
20601
- commandCancelledTimeoutTemplate: "Command cancelled after {{timeout}} seconds. The command was: {{command}}",
20602
- nextStepNoOutputTemplate: "Observation: (no output)",
20603
- strategyTemplate: undefined,
20604
- demonstrationTemplate: undefined
20605
- };
20606
20318
 
20607
- class SweAgentSubAgent {
20608
- name = "SWE-agent Worker";
20609
- type = "sweagent";
20319
+ class OpenCodeSubAgent {
20320
+ name = "OpenCode Worker";
20321
+ type = "opencode";
20610
20322
  cancelled = false;
20323
+ process = null;
20611
20324
  maxIterations;
20612
20325
  debug;
20326
+ preferCli;
20613
20327
  constructor(config2) {
20614
- this.maxIterations = config2?.maxIterations ?? getEnvInt4("ELIZA_CODE_SWEAGENT_MAX_ITERATIONS", 30);
20328
+ this.maxIterations = config2?.maxIterations ?? getEnvInt3("ELIZA_CODE_OPENCODE_MAX_ITERATIONS", 25);
20615
20329
  this.debug = config2?.debug ?? process.env.ELIZA_CODE_DEBUG === "1";
20330
+ this.preferCli = config2?.preferCli ?? process.env.ELIZA_CODE_OPENCODE_PREFER_CLI === "1";
20616
20331
  }
20617
20332
  cancel() {
20618
20333
  this.cancelled = true;
20334
+ if (this.process) {
20335
+ this.process.kill();
20336
+ this.process = null;
20337
+ }
20338
+ }
20339
+ async execute(task, context) {
20340
+ this.cancelled = false;
20341
+ if (this.preferCli) {
20342
+ const cliAvailable = await isOpenCodeAvailable();
20343
+ if (cliAvailable) {
20344
+ return this.executeWithCli(task, context);
20345
+ }
20346
+ }
20347
+ return this.executeWithPrompt(task, context);
20348
+ }
20349
+ async executeWithCli(task, context) {
20350
+ const { workingDirectory, onMessage, onTrace, isCancelled } = context;
20351
+ const filesCreated = [];
20352
+ const filesModified = [];
20353
+ let finalResponse = "";
20354
+ let traceSeq = 0;
20355
+ const base = () => {
20356
+ traceSeq += 1;
20357
+ return { ts: Date.now(), seq: traceSeq };
20358
+ };
20359
+ return new Promise((resolve7) => {
20360
+ const prompt = `${task.name}
20361
+
20362
+ ${task.description ?? ""}`.trim();
20363
+ this.process = spawn2("opencode", ["--json", "--prompt", prompt], {
20364
+ cwd: workingDirectory,
20365
+ stdio: ["ignore", "pipe", "pipe"],
20366
+ env: { ...process.env, OPENCODE_NONINTERACTIVE: "1" }
20367
+ });
20368
+ let _stdout = "";
20369
+ let stderr = "";
20370
+ this.process.stdout?.on("data", (data) => {
20371
+ const chunk = data.toString();
20372
+ _stdout += chunk;
20373
+ if (isCancelled()) {
20374
+ this.cancel();
20375
+ return;
20376
+ }
20377
+ const events = parseOpenCodeOutput(chunk);
20378
+ for (const event of events) {
20379
+ switch (event.type) {
20380
+ case "message": {
20381
+ const content = event.data.content;
20382
+ if (content) {
20383
+ finalResponse = content;
20384
+ if (this.debug) {
20385
+ onMessage(content, "info");
20386
+ }
20387
+ }
20388
+ break;
20389
+ }
20390
+ case "tool_call": {
20391
+ const toolName = event.data.tool;
20392
+ const toolArgs = event.data.args;
20393
+ onTrace?.({
20394
+ kind: "tool_call",
20395
+ iteration: traceSeq,
20396
+ name: toolName,
20397
+ args: toolArgs,
20398
+ ...base()
20399
+ });
20400
+ break;
20401
+ }
20402
+ case "tool_result": {
20403
+ const toolName = event.data.tool;
20404
+ const success2 = event.data.success;
20405
+ const output = event.data.output;
20406
+ onTrace?.({
20407
+ kind: "tool_result",
20408
+ iteration: traceSeq,
20409
+ name: toolName,
20410
+ success: success2,
20411
+ output: truncateText3(output, 4000),
20412
+ outputPreview: truncateText3(output, 180),
20413
+ ...base()
20414
+ });
20415
+ break;
20416
+ }
20417
+ case "file_change": {
20418
+ const filepath = event.data.path;
20419
+ const action = event.data.action;
20420
+ if (filepath) {
20421
+ if (action === "create" || action === "write") {
20422
+ if (!filesCreated.includes(filepath)) {
20423
+ filesCreated.push(filepath);
20424
+ }
20425
+ } else {
20426
+ if (!filesModified.includes(filepath)) {
20427
+ filesModified.push(filepath);
20428
+ }
20429
+ }
20430
+ const abs = path7.resolve(workingDirectory, filepath);
20431
+ const link = pathToFileURL5(abs).toString();
20432
+ onMessage(`FILE ${action}: ${filepath} — ${link}`, "info");
20433
+ }
20434
+ break;
20435
+ }
20436
+ case "done": {
20437
+ finalResponse = event.data.summary || finalResponse;
20438
+ break;
20439
+ }
20440
+ case "error": {
20441
+ const errorMsg = event.data.message;
20442
+ onMessage(`Error: ${errorMsg}`, "error");
20443
+ break;
20444
+ }
20445
+ }
20446
+ }
20447
+ });
20448
+ this.process.stderr?.on("data", (data) => {
20449
+ stderr += data.toString();
20450
+ });
20451
+ this.process.on("error", (error48) => {
20452
+ resolve7({
20453
+ success: false,
20454
+ summary: `OpenCode CLI error: ${error48.message}`,
20455
+ filesCreated,
20456
+ filesModified,
20457
+ error: error48.message
20458
+ });
20459
+ });
20460
+ this.process.on("close", (code) => {
20461
+ this.process = null;
20462
+ if (this.cancelled || isCancelled()) {
20463
+ resolve7({
20464
+ success: false,
20465
+ summary: "Cancelled",
20466
+ filesCreated,
20467
+ filesModified,
20468
+ error: "Cancelled"
20469
+ });
20470
+ return;
20471
+ }
20472
+ const summary = finalResponse.trim().split(`
20473
+ `)[0] || `Completed with exit code ${code}`;
20474
+ resolve7({
20475
+ success: code === 0,
20476
+ summary,
20477
+ filesCreated,
20478
+ filesModified,
20479
+ error: code !== 0 ? stderr || `Exit code: ${code}` : undefined
20480
+ });
20481
+ });
20482
+ });
20619
20483
  }
20620
- async execute(task, context) {
20621
- this.cancelled = false;
20484
+ async executeWithPrompt(task, context) {
20622
20485
  const {
20623
20486
  runtime,
20624
20487
  workingDirectory,
20625
20488
  tools,
20489
+ callMcpTool,
20626
20490
  onProgress,
20627
20491
  onMessage,
20628
20492
  onTrace,
20629
20493
  isCancelled,
20630
20494
  isPaused
20631
20495
  } = context;
20632
- const shellTool = findTool(tools, "shell");
20633
- if (!await isGitRepo(shellTool)) {
20634
- return {
20635
- success: false,
20636
- summary: "SWE-agent requires a git repository",
20637
- filesCreated: [],
20638
- filesModified: [],
20639
- error: "Not a git repository (git rev-parse --is-inside-work-tree returned false)"
20640
- };
20641
- }
20642
- const beforeStatus = await getGitStatus(shellTool);
20643
- const patchPath = path8.resolve(workingDirectory, ".eliza/sweagent/model.patch");
20644
- const env = new LocalToolEnvironment({
20645
- workingDirectory,
20646
- shellTool,
20647
- patchPath,
20648
- submitCommand: "submit"
20649
- });
20650
- const toolConfig = {
20651
- commands: [],
20652
- parseFunction: "thought_action",
20653
- executionTimeout: 55,
20654
- maxConsecutiveExecutionTimeouts: 2,
20655
- totalExecutionTimeout: 60 * 60,
20656
- submitCommand: "submit",
20657
- useFunctionCalling: false,
20658
- formatErrorTemplate: "Your output was not formatted correctly. Use DISCUSSION then one command in a code block.",
20659
- filter: {
20660
- blocklistErrorTemplate: "That command is not allowed. Choose a safer alternative.",
20661
- blocklist: ["rm -rf", "sudo rm", "mkfs", "dd "],
20662
- blocklistStandalone: ["shutdown", "reboot"]
20663
- },
20664
- envVariables: {}
20665
- };
20666
- const modelConfig = {
20667
- name: "runtime",
20668
- perInstanceCostLimit: 0,
20669
- totalCostLimit: 0,
20670
- perInstanceCallLimit: 0,
20671
- temperature: 0.1,
20672
- topP: 1,
20673
- apiBase: null,
20674
- apiVersion: null,
20675
- apiKey: null,
20676
- stop: [],
20677
- completionKwargs: {},
20678
- convertSystemToUser: false,
20679
- retry: { retries: 0, minWait: 0, maxWait: 0 },
20680
- delay: 0,
20681
- fallbacks: [],
20682
- chooseApiKeyByThread: false,
20683
- maxInputTokens: null,
20684
- maxOutputTokens: null,
20685
- litellmModelRegistry: null,
20686
- customTokenizer: null
20496
+ const filesCreated = [];
20497
+ const filesModified = [];
20498
+ const maxTraceResponseChars = getEnvInt3("ELIZA_CODE_TRACE_MAX_RESPONSE_CHARS", this.debug ? 20000 : 4000);
20499
+ const maxTraceToolOutputChars = getEnvInt3("ELIZA_CODE_TRACE_MAX_TOOL_OUTPUT_CHARS", 8000);
20500
+ const maxUiPreviewChars = getEnvInt3("ELIZA_CODE_TRACE_UI_PREVIEW_CHARS", 180);
20501
+ let traceSeq = 0;
20502
+ const base = () => {
20503
+ traceSeq += 1;
20504
+ return { ts: Date.now(), seq: traceSeq };
20687
20505
  };
20688
- const model = new RuntimeModel(runtime, modelConfig, toolConfig);
20689
- const agent = new DefaultAgent({
20690
- templates: DEFAULT_TEMPLATES,
20691
- tools: new ToolHandler(toolConfig),
20692
- historyProcessors: [],
20693
- model,
20694
- maxRequeries: 3,
20695
- name: "sweagent"
20696
- });
20697
- const outputDir = path8.resolve(workingDirectory, ".eliza/sweagent/runs");
20698
- await ensureDir(outputDir);
20699
- const ps = new TextProblemStatement({
20700
- text: `${task.name}
20506
+ onProgress({ taskId: task.id ?? "", progress: 0 });
20507
+ const messages = [
20508
+ {
20509
+ role: "user",
20510
+ content: `Execute this task: ${task.name}
20701
20511
 
20702
- ${task.description ?? ""}`.trim(),
20703
- id: task.id ?? "task"
20704
- });
20705
- await agent.setup(env, ps, outputDir);
20512
+ Description: ${task.description ?? "No additional description provided."}
20513
+
20514
+ Start by understanding the requirements, then implement the solution step by step.`
20515
+ }
20516
+ ];
20706
20517
  let iteration = 0;
20707
- while (!this.cancelled) {
20518
+ let wasPaused = false;
20519
+ while (iteration < this.maxIterations && !this.cancelled) {
20708
20520
  if (isCancelled()) {
20521
+ onMessage("Task cancelled", "warning");
20522
+ onTrace?.({
20523
+ kind: "status",
20524
+ status: "cancelled",
20525
+ message: "Task cancelled",
20526
+ ...base()
20527
+ });
20528
+ return {
20529
+ success: false,
20530
+ summary: "Task was cancelled",
20531
+ filesCreated,
20532
+ filesModified,
20533
+ error: "Cancelled by user"
20534
+ };
20535
+ }
20536
+ if (isPaused?.()) {
20537
+ if (!wasPaused) {
20538
+ wasPaused = true;
20539
+ onMessage("Task paused", "warning");
20540
+ onTrace?.({
20541
+ kind: "status",
20542
+ status: "paused",
20543
+ message: "Task paused",
20544
+ ...base()
20545
+ });
20546
+ }
20547
+ await sleep3(300);
20548
+ continue;
20549
+ }
20550
+ if (wasPaused) {
20551
+ wasPaused = false;
20552
+ onMessage("Task resumed", "info");
20553
+ onTrace?.({
20554
+ kind: "status",
20555
+ status: "resumed",
20556
+ message: "Task resumed",
20557
+ ...base()
20558
+ });
20559
+ }
20560
+ iteration++;
20561
+ onProgress({
20562
+ taskId: task.id ?? "",
20563
+ progress: Math.min(90, Math.round(iteration / this.maxIterations * 80))
20564
+ });
20565
+ const systemPrompt = OPENCODE_SYSTEM_PROMPT.replace("{cwd}", workingDirectory);
20566
+ const history = messages.map((m) => m.role === "user" ? `User: ${m.content}` : `Assistant: ${m.content}`).join(`
20567
+
20568
+ `);
20569
+ const prompt = `${systemPrompt}
20570
+
20571
+ ${history}
20572
+
20573
+ Assistant:`;
20574
+ const modelType = runtime.getModel(ModelType3.TEXT_REASONING_LARGE) ? ModelType3.TEXT_REASONING_LARGE : ModelType3.TEXT_LARGE;
20575
+ let response;
20576
+ try {
20577
+ response = await runtime.useModel(modelType, {
20578
+ prompt,
20579
+ maxTokens: 4096,
20580
+ temperature: 0.2
20581
+ });
20582
+ } catch (error48) {
20583
+ const errorMsg = error48 instanceof Error ? error48.message : String(error48);
20584
+ onMessage(`LLM error: ${errorMsg}`, "error");
20585
+ onTrace?.({
20586
+ kind: "note",
20587
+ level: "error",
20588
+ message: errorMsg,
20589
+ ...base()
20590
+ });
20591
+ return {
20592
+ success: false,
20593
+ summary: `Failed: ${errorMsg}`,
20594
+ filesCreated,
20595
+ filesModified,
20596
+ error: errorMsg
20597
+ };
20598
+ }
20599
+ const responseRedacted = redactSensitiveText3(response);
20600
+ const responseStored = truncateText3(responseRedacted, maxTraceResponseChars);
20601
+ const responsePreview = truncateText3(collapseWhitespace3(firstNonEmptyLine3(responseStored)), maxUiPreviewChars);
20602
+ onTrace?.({
20603
+ kind: "llm",
20604
+ iteration,
20605
+ modelType: String(modelType),
20606
+ response: responseStored,
20607
+ responsePreview,
20608
+ ...base()
20609
+ });
20610
+ if (response.includes("DONE:")) {
20611
+ const summary2 = response.split("DONE:")[1]?.trim().split(`
20612
+ `)[0] ?? "Task completed";
20613
+ onMessage(`Done: ${summary2}`, "info");
20614
+ onTrace?.({
20615
+ kind: "note",
20616
+ level: "info",
20617
+ message: `Done: ${summary2}`,
20618
+ ...base()
20619
+ });
20709
20620
  return {
20710
- success: false,
20711
- summary: "Cancelled",
20712
- filesCreated: [],
20713
- filesModified: [],
20714
- error: "Cancelled by user"
20621
+ success: true,
20622
+ summary: summary2,
20623
+ filesCreated,
20624
+ filesModified
20715
20625
  };
20716
20626
  }
20717
- if (isPaused?.()) {
20718
- await new Promise((r) => setTimeout(r, 250));
20627
+ const toolCalls = parseToolCalls3(response);
20628
+ if (toolCalls.length === 0) {
20629
+ messages.push({ role: "assistant", content: response });
20630
+ messages.push({
20631
+ role: "user",
20632
+ content: "Continue with the task. Use TOOL: to execute commands, or say DONE: when finished."
20633
+ });
20719
20634
  continue;
20720
20635
  }
20721
- iteration += 1;
20722
- onProgress({
20723
- taskId: task.id ?? "",
20724
- progress: Math.min(90, Math.round(iteration / this.maxIterations * 80))
20725
- });
20726
- const step = await agent.step();
20727
- const thoughtPreview = truncate(step.thought ?? "", 220);
20728
- const actionPreview = truncate(step.action ?? "", 220);
20729
- if (this.debug) {
20730
- onMessage(`DISCUSSION: ${thoughtPreview}`, "info");
20731
- onMessage(`COMMAND: ${actionPreview}`, "info");
20636
+ const results = [];
20637
+ for (const call of toolCalls) {
20638
+ onTrace?.({
20639
+ kind: "tool_call",
20640
+ iteration,
20641
+ name: call.name,
20642
+ args: call.args,
20643
+ ...base()
20644
+ });
20645
+ const result = (call.name.startsWith("MCP:") || call.name.includes("/")) && callMcpTool ? await (async () => {
20646
+ const [server, toolName] = call.name.replace("MCP:", "").split("/");
20647
+ if (!server || !toolName) {
20648
+ return {
20649
+ success: false,
20650
+ output: `Invalid MCP tool call name: ${call.name}`
20651
+ };
20652
+ }
20653
+ return await callMcpTool(server, toolName, call.args);
20654
+ })() : await this.executeTool(call.name, call.args, call.content, tools, workingDirectory, filesCreated, filesModified, onMessage);
20655
+ results.push({ name: call.name, result });
20656
+ const outputRedacted = redactSensitiveText3(result.output);
20657
+ const outputStored = truncateText3(outputRedacted, maxTraceToolOutputChars);
20658
+ const outputPreview = truncateText3(collapseWhitespace3(firstNonEmptyLine3(outputStored)), maxUiPreviewChars);
20659
+ onTrace?.({
20660
+ kind: "tool_result",
20661
+ iteration,
20662
+ name: call.name,
20663
+ success: result.success,
20664
+ output: outputStored,
20665
+ outputPreview,
20666
+ ...base()
20667
+ });
20732
20668
  }
20733
- onTrace?.({
20734
- kind: "note",
20735
- level: "info",
20736
- message: `step ${iteration}: ${truncate(redactSensitiveText4(thoughtPreview), 160)}`,
20737
- ts: Date.now(),
20738
- seq: iteration
20669
+ const resultOutput = results.map((r) => `[${r.name}] ${r.result.success ? "✓" : "✗"} ${truncateText3(r.result.output, 2000)}`).join(`
20670
+
20671
+ `);
20672
+ messages.push({ role: "assistant", content: response });
20673
+ messages.push({
20674
+ role: "user",
20675
+ content: `Tool results:
20676
+ ${resultOutput}
20677
+
20678
+ Continue with the next step.`
20739
20679
  });
20740
- if (step.done)
20741
- break;
20742
- if (iteration >= this.maxIterations)
20743
- break;
20744
- }
20745
- const afterStatus = await getGitStatus(shellTool);
20746
- const delta = parseGitStatusPorcelain(afterStatus);
20747
- let patchExists = false;
20748
- try {
20749
- await fs3.stat(patchPath);
20750
- patchExists = true;
20751
- } catch {
20752
- patchExists = false;
20753
- }
20754
- const success2 = patchExists || delta.created.length + delta.modified.length > 0;
20755
- if (!success2) {
20756
- return {
20757
- success: false,
20758
- summary: "No patch produced",
20759
- filesCreated: delta.created,
20760
- filesModified: delta.modified,
20761
- error: `No submission patch produced.
20762
- Before status:
20763
- ${beforeStatus}
20764
- After status:
20765
- ${afterStatus}`
20766
- };
20767
20680
  }
20681
+ const summary = `Completed after ${iteration} iterations`;
20682
+ onMessage(`Warning: ${summary}`, "warning");
20683
+ onTrace?.({ kind: "note", level: "warning", message: summary, ...base() });
20768
20684
  return {
20769
20685
  success: true,
20770
- summary: "Submitted patch",
20771
- filesCreated: delta.created,
20772
- filesModified: delta.modified
20686
+ summary,
20687
+ filesCreated,
20688
+ filesModified
20773
20689
  };
20774
20690
  }
20691
+ async executeTool(name, args, content, tools, workingDirectory, filesCreated, filesModified, onMessage) {
20692
+ if (name === "write_file" && content !== undefined) {
20693
+ const tool3 = tools.find((t) => t.name === "write_file");
20694
+ if (!tool3) {
20695
+ return { success: false, output: "write_file tool not available" };
20696
+ }
20697
+ const result2 = await tool3.execute({ ...args, content });
20698
+ if (result2.success && args.filepath) {
20699
+ if (!filesCreated.includes(args.filepath)) {
20700
+ filesCreated.push(args.filepath);
20701
+ }
20702
+ const abs = path7.resolve(workingDirectory, args.filepath);
20703
+ const link = pathToFileURL5(abs).toString();
20704
+ onMessage(`FILE write: ${args.filepath} — ${link}`, "info");
20705
+ }
20706
+ return result2;
20707
+ }
20708
+ const tool2 = tools.find((t) => t.name === name || t.name === name.toLowerCase());
20709
+ if (!tool2) {
20710
+ return { success: false, output: `Unknown tool: ${name}` };
20711
+ }
20712
+ const result = await tool2.execute(args);
20713
+ const filepath = result.data?.filepath;
20714
+ if (result.success && typeof filepath === "string") {
20715
+ if (name === "write_file" || name.includes("write")) {
20716
+ if (!filesCreated.includes(filepath)) {
20717
+ filesCreated.push(filepath);
20718
+ }
20719
+ const abs = path7.resolve(workingDirectory, filepath);
20720
+ const link = pathToFileURL5(abs).toString();
20721
+ const sizeValue = result.data?.size;
20722
+ const sizeSuffix = typeof sizeValue === "number" ? ` (${sizeValue} chars)` : "";
20723
+ onMessage(`FILE write: ${filepath}${sizeSuffix} — ${link}`, "info");
20724
+ } else if (name === "edit_file" || name.includes("edit")) {
20725
+ if (!filesModified.includes(filepath)) {
20726
+ filesModified.push(filepath);
20727
+ }
20728
+ const abs = path7.resolve(workingDirectory, filepath);
20729
+ const link = pathToFileURL5(abs).toString();
20730
+ onMessage(`FILE edit: ${filepath} — ${link}`, "info");
20731
+ }
20732
+ }
20733
+ return result;
20734
+ }
20735
+ }
20736
+ function sleep3(ms) {
20737
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
20738
+ }
20739
+ function getEnvInt3(key, defaultValue) {
20740
+ const raw = process.env[key];
20741
+ if (!raw)
20742
+ return defaultValue;
20743
+ const parsed = Number.parseInt(raw, 10);
20744
+ if (!Number.isFinite(parsed) || parsed < 1)
20745
+ return defaultValue;
20746
+ return parsed;
20747
+ }
20748
+ function truncateText3(text, maxChars) {
20749
+ if (text.length <= maxChars)
20750
+ return text;
20751
+ const safe = Math.max(0, maxChars - 1);
20752
+ return `${text.slice(0, safe)}…`;
20753
+ }
20754
+ function collapseWhitespace3(text) {
20755
+ return text.replace(/\s+/g, " ").trim();
20756
+ }
20757
+ function firstNonEmptyLine3(text) {
20758
+ const lines = text.split(`
20759
+ `);
20760
+ for (const line of lines) {
20761
+ const trimmed = line.trim();
20762
+ if (trimmed.length > 0)
20763
+ return trimmed;
20764
+ }
20765
+ return "";
20766
+ }
20767
+ function redactSensitiveText3(text) {
20768
+ let out = text;
20769
+ out = out.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, "[REDACTED:PRIVATE_KEY]");
20770
+ out = out.replace(/\bsk-[A-Za-z0-9]{16,}\b/g, "[REDACTED:API_KEY]");
20771
+ out = out.replace(/\bAKIA[0-9A-Z]{16}\b/g, "[REDACTED:AWS_ACCESS_KEY_ID]");
20772
+ out = out.replace(/\bghp_[A-Za-z0-9]{20,}\b/g, "[REDACTED:GITHUB_TOKEN]");
20773
+ out = out.replace(/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, "[REDACTED:GITHUB_TOKEN]");
20774
+ out = out.replace(/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, "[REDACTED:SLACK_TOKEN]");
20775
+ out = out.replace(/\bBearer\s+[A-Za-z0-9._-]{10,}\b/g, "Bearer [REDACTED]");
20776
+ out = out.replace(/\bBasic\s+[A-Za-z0-9+/=]{10,}\b/g, "Basic [REDACTED]");
20777
+ out = out.replace(/(password\s*[:=]\s*)(\S+)/gi, "$1[REDACTED]");
20778
+ for (const [key, value] of Object.entries(process.env)) {
20779
+ if (!value || value.length < 12)
20780
+ continue;
20781
+ const upper = key.toUpperCase();
20782
+ if (upper.includes("KEY") || upper.includes("TOKEN") || upper.includes("SECRET") || upper.includes("PASSWORD") || upper.includes("AUTH")) {
20783
+ out = out.split(value).join(`[REDACTED:${key}]`);
20784
+ }
20785
+ }
20786
+ return out;
20775
20787
  }
20776
20788
 
20777
20789
  // src/sub-agents/registry.ts
20790
+ var SweAgentSubAgent2 = null;
20791
+ try {
20792
+ const sweagentModule = await Promise.resolve().then(() => (init_sweagent_sub_agent(), exports_sweagent_sub_agent));
20793
+ SweAgentSubAgent2 = sweagentModule.SweAgentSubAgent;
20794
+ } catch {}
20778
20795
  var CLAUDE_CODE_PROMPT_TEMPLATE = `You are a Claude Code–style coding worker. Execute tasks using these tools:
20779
20796
 
20780
20797
  AVAILABLE TOOLS:
@@ -20841,7 +20858,10 @@ function createSubAgent(type) {
20841
20858
  case "opencode":
20842
20859
  return new OpenCodeSubAgent;
20843
20860
  case "sweagent":
20844
- return new SweAgentSubAgent;
20861
+ if (!SweAgentSubAgent2) {
20862
+ throw new Error("SweAgent is not available - @elizaos/sweagent-root package not installed");
20863
+ }
20864
+ return new SweAgentSubAgent2;
20845
20865
  case "elizaos-native":
20846
20866
  return new ElizaOSNativeSubAgent;
20847
20867
  default:
@@ -20886,15 +20906,15 @@ function toCodeTask(task) {
20886
20906
  class SubAgentProvider {
20887
20907
  id;
20888
20908
  label;
20889
- description;
20890
20909
  subAgentType;
20910
+ description;
20891
20911
  constructor(id, label, subAgentType, description) {
20892
20912
  this.id = id;
20893
20913
  this.label = label;
20894
20914
  this.subAgentType = subAgentType;
20895
20915
  this.description = description;
20896
20916
  }
20897
- async executeTask(task, ctx) {
20917
+ async executeTask(_task, _ctx) {
20898
20918
  throw new Error("SubAgentProvider needs IAgentRuntime to execute. This should be handled by the factory/service.");
20899
20919
  }
20900
20920
  }
@@ -20914,7 +20934,7 @@ var createSubAgentProvider = (runtime, id, type, label) => {
20914
20934
  if (u.message)
20915
20935
  ctx.appendOutput(u.message);
20916
20936
  },
20917
- onMessage: (msg, priority) => {
20937
+ onMessage: (msg, _priority) => {
20918
20938
  ctx.appendOutput(msg);
20919
20939
  },
20920
20940
  isCancelled: ctx.isCancelled,
@@ -20923,12 +20943,44 @@ var createSubAgentProvider = (runtime, id, type, label) => {
20923
20943
  throw new Error("Todos not supported in adapter yet");
20924
20944
  },
20925
20945
  completeTodo: async () => {},
20926
- onTrace: (e) => {}
20946
+ onTrace: (_e) => {}
20927
20947
  });
20928
20948
  }
20929
20949
  };
20930
20950
  };
20951
+ // src/types/messaging.ts
20952
+ var MessagingEventType = {
20953
+ SEND_REQUESTED: "MESSAGING_SEND_REQUESTED",
20954
+ SENT: "MESSAGING_SENT",
20955
+ SEND_FAILED: "MESSAGING_SEND_FAILED",
20956
+ DELIVERED: "MESSAGING_DELIVERED",
20957
+ READ: "MESSAGING_READ"
20958
+ };
20959
+ // src/types/sandbox.ts
20960
+ var SandboxEventType = {
20961
+ CREATED: "SANDBOX_CREATED",
20962
+ DESTROYED: "SANDBOX_DESTROYED",
20963
+ COMMAND_STARTED: "SANDBOX_COMMAND_STARTED",
20964
+ COMMAND_COMPLETED: "SANDBOX_COMMAND_COMPLETED",
20965
+ COMMAND_FAILED: "SANDBOX_COMMAND_FAILED",
20966
+ BROWSER_STARTED: "SANDBOX_BROWSER_STARTED",
20967
+ BROWSER_STOPPED: "SANDBOX_BROWSER_STOPPED"
20968
+ };
20969
+ // src/types/subagent.ts
20970
+ var SubagentEventType = {
20971
+ SPAWN_REQUESTED: "SUBAGENT_SPAWN_REQUESTED",
20972
+ RUN_STARTED: "SUBAGENT_RUN_STARTED",
20973
+ RUN_COMPLETED: "SUBAGENT_RUN_COMPLETED",
20974
+ RUN_FAILED: "SUBAGENT_RUN_FAILED",
20975
+ RUN_TIMEOUT: "SUBAGENT_RUN_TIMEOUT",
20976
+ ANNOUNCE_SENT: "SUBAGENT_ANNOUNCE_SENT",
20977
+ A2A_MESSAGE_SENT: "A2A_MESSAGE_SENT",
20978
+ A2A_MESSAGE_RECEIVED: "A2A_MESSAGE_RECEIVED"
20979
+ };
20931
20980
  // index.ts
20981
+ function getSessionProviders2() {
20982
+ return [];
20983
+ }
20932
20984
  var sessionProviders = getSessionProviders2();
20933
20985
  var agentOrchestratorPlugin = {
20934
20986
  name: "agent-orchestrator",
@@ -20999,8 +21051,8 @@ export {
20999
21051
  normalizeSessionKey,
21000
21052
  normalizeMainKey,
21001
21053
  normalizeDeliveryContext,
21002
- normalizeAgentId as normalizeCoreAgentId,
21003
- normalizeAgentId2 as normalizeAgentId,
21054
+ normalizeCoreAgentId,
21055
+ normalizeAgentId,
21004
21056
  normalizeAccountId,
21005
21057
  mergeSessionEntry,
21006
21058
  mergeDeliveryContext,
@@ -21010,8 +21062,8 @@ export {
21010
21062
  listSessionKeys,
21011
21063
  listMessagingChannelsAction,
21012
21064
  isValidSessionEntry,
21013
- isSubagentSessionKey2 as isSubagentSessionKey,
21014
- isSubagentSessionKey as isCoreSubagentSessionKey,
21065
+ isSubagentSessionKey,
21066
+ isCoreSubagentSessionKey,
21015
21067
  isAcpSessionKey,
21016
21068
  hashToUUID,
21017
21069
  getSubagentStatusAction,
@@ -21055,4 +21107,4 @@ export {
21055
21107
  AgentOrchestratorService
21056
21108
  };
21057
21109
 
21058
- //# debugId=15B5D85268F84FD764756E2164756E21
21110
+ //# debugId=50986580F51FCE4464756E2164756E21