@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.
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1587 -1535
- package/dist/index.js.map +28 -28
- package/dist/src/actions/messaging.d.ts.map +1 -1
- package/dist/src/actions/peek-subagent.d.ts.map +1 -1
- package/dist/src/actions/subagent-management.d.ts.map +1 -1
- package/dist/src/actions/task-management.d.ts.map +1 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/providers/orchestrator-config.d.ts.map +1 -1
- package/dist/src/providers/task-context.d.ts.map +1 -1
- package/dist/src/services/agent-orchestrator-service.d.ts.map +1 -1
- package/dist/src/services/messaging-service.d.ts.map +1 -1
- package/dist/src/services/sandbox-service.d.ts.map +1 -1
- package/dist/src/services/subagent-service.d.ts.map +1 -1
- package/dist/src/sub-agents/adapter.d.ts +5 -5
- package/dist/src/sub-agents/adapter.d.ts.map +1 -1
- package/dist/src/sub-agents/claude-agent-sdk-sub-agent.d.ts +1 -2
- package/dist/src/sub-agents/claude-agent-sdk-sub-agent.d.ts.map +1 -1
- package/dist/src/sub-agents/codex-sdk-sub-agent.d.ts +1 -2
- package/dist/src/sub-agents/codex-sdk-sub-agent.d.ts.map +1 -1
- package/dist/src/sub-agents/eliza-sub-agent.d.ts +1 -2
- package/dist/src/sub-agents/eliza-sub-agent.d.ts.map +1 -1
- package/dist/src/sub-agents/elizaos-native-sub-agent.d.ts +1 -2
- package/dist/src/sub-agents/elizaos-native-sub-agent.d.ts.map +1 -1
- package/dist/src/sub-agents/opencode-sub-agent.d.ts +1 -2
- package/dist/src/sub-agents/opencode-sub-agent.d.ts.map +1 -1
- package/dist/src/sub-agents/registry.d.ts.map +1 -1
- package/dist/src/sub-agents/sweagent-sub-agent.d.ts +1 -2
- package/dist/src/sub-agents/sweagent-sub-agent.d.ts.map +1 -1
- package/dist/src/sub-agents/tools.d.ts.map +1 -1
- package/dist/src/sub-agents/types.d.ts +11 -11
- package/dist/src/sub-agents/types.d.ts.map +1 -1
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/messaging.d.ts.map +1 -1
- package/dist/src/types/sandbox.d.ts.map +1 -1
- package/dist/src/types/subagent.d.ts.map +1 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/session.d.ts +79 -1
- package/dist/src/utils/session.d.ts.map +1 -1
- 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
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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 {
|
|
110
|
+
return { created, modified };
|
|
62
111
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
108
|
-
const
|
|
109
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
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 =
|
|
1194
|
+
const normalizedAgentId = normalizeAgentId(agentId);
|
|
781
1195
|
return `agent:${normalizedAgentId}:${keyType}:${identifier}`;
|
|
782
1196
|
}
|
|
783
|
-
function
|
|
1197
|
+
function normalizeAgentId(agentId) {
|
|
784
1198
|
return agentId.trim().toLowerCase();
|
|
785
1199
|
}
|
|
786
|
-
function
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 = [
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
3712
|
-
const targetNorm =
|
|
4132
|
+
const sourceNorm = normalizeAgentId(sourceAgentId);
|
|
4133
|
+
const targetNorm = normalizeAgentId(targetAgentId);
|
|
3713
4134
|
for (const rule of allowRules) {
|
|
3714
|
-
const sourceMatch = rule.source === "*" ||
|
|
3715
|
-
const targetMatch = rule.target === "*" ||
|
|
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 &&
|
|
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 ?
|
|
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) =>
|
|
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 ?
|
|
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 (
|
|
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 (
|
|
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 = {
|
|
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 = {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
20101
|
-
const
|
|
20102
|
-
const
|
|
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:
|
|
19813
|
+
content: `## TASK
|
|
20113
19814
|
|
|
20114
|
-
|
|
19815
|
+
**${task.name}**
|
|
20115
19816
|
|
|
20116
|
-
|
|
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
|
|
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(
|
|
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.
|
|
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
|
|
20202
|
-
const
|
|
20203
|
-
|
|
20204
|
-
|
|
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 =
|
|
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:
|
|
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
|
|
20239
|
-
|
|
20240
|
-
|
|
20241
|
-
|
|
20242
|
-
|
|
20243
|
-
|
|
20244
|
-
|
|
20245
|
-
|
|
20246
|
-
|
|
20247
|
-
|
|
20248
|
-
|
|
20249
|
-
|
|
20250
|
-
|
|
20251
|
-
|
|
20252
|
-
|
|
20253
|
-
|
|
20254
|
-
}
|
|
20255
|
-
|
|
20256
|
-
|
|
20257
|
-
|
|
20258
|
-
|
|
20259
|
-
|
|
20260
|
-
|
|
20261
|
-
|
|
20262
|
-
|
|
20263
|
-
|
|
20264
|
-
|
|
20265
|
-
|
|
20266
|
-
|
|
20267
|
-
|
|
20268
|
-
|
|
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:
|
|
20278
|
-
|
|
20021
|
+
content: `**Tool Result:**
|
|
20022
|
+
\`\`\`
|
|
20023
|
+
${truncateText2(result.output, 8000)}
|
|
20024
|
+
\`\`\`
|
|
20279
20025
|
|
|
20280
|
-
|
|
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 =
|
|
20305
|
-
const link =
|
|
20306
|
-
|
|
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 =
|
|
20322
|
-
const link =
|
|
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 =
|
|
20331
|
-
const link =
|
|
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
|
|
20339
|
-
return new Promise((
|
|
20094
|
+
function sleep2(ms) {
|
|
20095
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
20340
20096
|
}
|
|
20341
|
-
function
|
|
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
|
|
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
|
|
20112
|
+
function collapseWhitespace2(text) {
|
|
20357
20113
|
return text.replace(/\s+/g, " ").trim();
|
|
20358
20114
|
}
|
|
20359
|
-
function
|
|
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
|
|
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/
|
|
20392
|
-
import
|
|
20393
|
-
import * as
|
|
20394
|
-
import {
|
|
20395
|
-
|
|
20396
|
-
|
|
20397
|
-
|
|
20398
|
-
|
|
20399
|
-
|
|
20400
|
-
|
|
20401
|
-
|
|
20402
|
-
|
|
20403
|
-
|
|
20404
|
-
|
|
20405
|
-
|
|
20406
|
-
|
|
20407
|
-
|
|
20408
|
-
|
|
20409
|
-
|
|
20410
|
-
|
|
20411
|
-
|
|
20412
|
-
|
|
20413
|
-
|
|
20414
|
-
|
|
20415
|
-
|
|
20416
|
-
|
|
20417
|
-
|
|
20418
|
-
|
|
20419
|
-
|
|
20420
|
-
|
|
20421
|
-
|
|
20422
|
-
|
|
20423
|
-
|
|
20424
|
-
|
|
20425
|
-
|
|
20426
|
-
|
|
20427
|
-
|
|
20428
|
-
|
|
20429
|
-
|
|
20430
|
-
|
|
20431
|
-
|
|
20432
|
-
|
|
20433
|
-
|
|
20434
|
-
|
|
20435
|
-
|
|
20436
|
-
|
|
20437
|
-
|
|
20438
|
-
|
|
20439
|
-
|
|
20440
|
-
|
|
20441
|
-
|
|
20442
|
-
|
|
20443
|
-
|
|
20444
|
-
|
|
20445
|
-
|
|
20446
|
-
|
|
20447
|
-
|
|
20448
|
-
|
|
20449
|
-
|
|
20450
|
-
|
|
20451
|
-
|
|
20452
|
-
|
|
20453
|
-
|
|
20454
|
-
|
|
20455
|
-
|
|
20456
|
-
|
|
20457
|
-
|
|
20458
|
-
|
|
20459
|
-
|
|
20460
|
-
|
|
20461
|
-
|
|
20462
|
-
|
|
20463
|
-
|
|
20464
|
-
|
|
20465
|
-
|
|
20466
|
-
|
|
20467
|
-
|
|
20468
|
-
|
|
20469
|
-
|
|
20470
|
-
|
|
20471
|
-
|
|
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
|
-
|
|
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
|
-
|
|
20516
|
-
|
|
20517
|
-
|
|
20518
|
-
|
|
20519
|
-
})
|
|
20520
|
-
|
|
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
|
-
|
|
20525
|
-
|
|
20526
|
-
|
|
20527
|
-
|
|
20528
|
-
|
|
20529
|
-
|
|
20530
|
-
|
|
20531
|
-
|
|
20532
|
-
|
|
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
|
-
|
|
20549
|
-
|
|
20550
|
-
|
|
20551
|
-
|
|
20552
|
-
|
|
20553
|
-
|
|
20554
|
-
|
|
20555
|
-
|
|
20556
|
-
|
|
20557
|
-
|
|
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
|
|
20608
|
-
name = "
|
|
20609
|
-
type = "
|
|
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 ??
|
|
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
|
|
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
|
|
20633
|
-
|
|
20634
|
-
|
|
20635
|
-
|
|
20636
|
-
|
|
20637
|
-
|
|
20638
|
-
|
|
20639
|
-
|
|
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
|
-
|
|
20689
|
-
const
|
|
20690
|
-
|
|
20691
|
-
|
|
20692
|
-
|
|
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 ?? ""}
|
|
20703
|
-
|
|
20704
|
-
|
|
20705
|
-
|
|
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
|
-
|
|
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:
|
|
20711
|
-
summary:
|
|
20712
|
-
filesCreated
|
|
20713
|
-
filesModified
|
|
20714
|
-
error: "Cancelled by user"
|
|
20621
|
+
success: true,
|
|
20622
|
+
summary: summary2,
|
|
20623
|
+
filesCreated,
|
|
20624
|
+
filesModified
|
|
20715
20625
|
};
|
|
20716
20626
|
}
|
|
20717
|
-
|
|
20718
|
-
|
|
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
|
-
|
|
20722
|
-
|
|
20723
|
-
|
|
20724
|
-
|
|
20725
|
-
|
|
20726
|
-
|
|
20727
|
-
|
|
20728
|
-
|
|
20729
|
-
|
|
20730
|
-
|
|
20731
|
-
|
|
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
|
-
|
|
20734
|
-
|
|
20735
|
-
|
|
20736
|
-
|
|
20737
|
-
|
|
20738
|
-
|
|
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
|
|
20771
|
-
filesCreated
|
|
20772
|
-
filesModified
|
|
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
|
-
|
|
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(
|
|
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,
|
|
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: (
|
|
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
|
-
|
|
21003
|
-
|
|
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
|
-
|
|
21014
|
-
|
|
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=
|
|
21110
|
+
//# debugId=50986580F51FCE4464756E2164756E21
|