zidane 1.2.0 → 1.4.0
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/README.md +71 -9
- package/dist/{agent-DvZm8U14.d.ts → agent-B4wguzkU.d.ts} +36 -84
- package/dist/{chunk-LMSOIIAT.js → chunk-IC2WAUBZ.js} +153 -11
- package/dist/chunk-PRNQ7DXE.js +430 -0
- package/dist/chunk-QPYZR2QM.js +21 -0
- package/dist/{chunk-27EP7HB3.js → chunk-YCH7G7YC.js} +406 -283
- package/dist/harnesses.d.ts +3 -2
- package/dist/harnesses.js +8 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +34 -6
- package/dist/mcp.d.ts +3 -2
- package/dist/providers.d.ts +20 -5
- package/dist/providers.js +26 -24
- package/dist/session.d.ts +46 -20
- package/dist/session.js +1 -1
- package/dist/skills.d.ts +124 -0
- package/dist/skills.js +31 -0
- package/dist/{spawn-pP2grsVp.d.ts → spawn-vZAQfDkd.d.ts} +10 -10
- package/dist/tools.d.ts +4 -3
- package/dist/tools.js +4 -1
- package/dist/{types-4CFQ-6Qu.d.ts → types-CLRMCak3.d.ts} +11 -1
- package/dist/types-D8fzooXc.d.ts +141 -0
- package/package.json +5 -1
- package/dist/chunk-34KXKPNN.js +0 -45
|
@@ -2,11 +2,108 @@ import {
|
|
|
2
2
|
connectMcpServers,
|
|
3
3
|
init_mcp
|
|
4
4
|
} from "./chunk-26LIQARN.js";
|
|
5
|
+
import {
|
|
6
|
+
buildCatalog,
|
|
7
|
+
init_catalog,
|
|
8
|
+
init_interpolate,
|
|
9
|
+
init_resolve,
|
|
10
|
+
interpolateShellCommands,
|
|
11
|
+
mergeSkillsConfig,
|
|
12
|
+
resolveSkills
|
|
13
|
+
} from "./chunk-PRNQ7DXE.js";
|
|
5
14
|
import {
|
|
6
15
|
__esm,
|
|
7
|
-
__export
|
|
16
|
+
__export,
|
|
17
|
+
__toCommonJS
|
|
8
18
|
} from "./chunk-PNKVD2UK.js";
|
|
9
19
|
|
|
20
|
+
// src/tools/list-files.ts
|
|
21
|
+
var listFiles;
|
|
22
|
+
var init_list_files = __esm({
|
|
23
|
+
"src/tools/list-files.ts"() {
|
|
24
|
+
"use strict";
|
|
25
|
+
listFiles = {
|
|
26
|
+
spec: {
|
|
27
|
+
name: "list_files",
|
|
28
|
+
description: "List files and directories at the given path (relative to project root).",
|
|
29
|
+
input_schema: {
|
|
30
|
+
type: "object",
|
|
31
|
+
properties: {
|
|
32
|
+
path: { type: "string", description: 'Relative directory path (default: ".")' }
|
|
33
|
+
},
|
|
34
|
+
required: []
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
async execute({ path }, ctx) {
|
|
38
|
+
try {
|
|
39
|
+
const entries = await ctx.execution.listFiles(ctx.handle, path || ".");
|
|
40
|
+
return entries.join("\n") || "(empty directory)";
|
|
41
|
+
} catch {
|
|
42
|
+
return `Directory not found: ${path}`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// src/tools/read-file.ts
|
|
50
|
+
var readFile;
|
|
51
|
+
var init_read_file = __esm({
|
|
52
|
+
"src/tools/read-file.ts"() {
|
|
53
|
+
"use strict";
|
|
54
|
+
readFile = {
|
|
55
|
+
spec: {
|
|
56
|
+
name: "read_file",
|
|
57
|
+
description: "Read the contents of a file at the given path (relative to project root).",
|
|
58
|
+
input_schema: {
|
|
59
|
+
type: "object",
|
|
60
|
+
properties: {
|
|
61
|
+
path: { type: "string", description: "Relative file path" }
|
|
62
|
+
},
|
|
63
|
+
required: ["path"]
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
async execute({ path }, ctx) {
|
|
67
|
+
try {
|
|
68
|
+
return await ctx.execution.readFile(ctx.handle, path);
|
|
69
|
+
} catch {
|
|
70
|
+
return `File not found: ${path}`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// src/tools/shell.ts
|
|
78
|
+
var shell;
|
|
79
|
+
var init_shell = __esm({
|
|
80
|
+
"src/tools/shell.ts"() {
|
|
81
|
+
"use strict";
|
|
82
|
+
shell = {
|
|
83
|
+
spec: {
|
|
84
|
+
name: "shell",
|
|
85
|
+
description: "Execute a shell command and return stdout+stderr. Runs in the project root.",
|
|
86
|
+
input_schema: {
|
|
87
|
+
type: "object",
|
|
88
|
+
properties: {
|
|
89
|
+
command: { type: "string", description: "The shell command to run" }
|
|
90
|
+
},
|
|
91
|
+
required: ["command"]
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
async execute({ command }, ctx) {
|
|
95
|
+
const result = await ctx.execution.exec(ctx.handle, command);
|
|
96
|
+
if (result.exitCode === 0) {
|
|
97
|
+
return result.stdout || "(no output)";
|
|
98
|
+
}
|
|
99
|
+
return `Exit code ${result.exitCode}
|
|
100
|
+
${result.stdout}
|
|
101
|
+
${result.stderr}`.trim();
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
10
107
|
// src/contexts/docker.ts
|
|
11
108
|
function createDockerContext(config) {
|
|
12
109
|
let counter = 0;
|
|
@@ -35,16 +132,16 @@ function createDockerContext(config) {
|
|
|
35
132
|
const docker = await getDockerode();
|
|
36
133
|
const id = `docker-${++counter}`;
|
|
37
134
|
const image = overrides?.image ?? defaultImage;
|
|
38
|
-
const
|
|
135
|
+
const cwd = overrides?.cwd ?? defaultCwd;
|
|
39
136
|
try {
|
|
40
137
|
await docker.getImage(image).inspect();
|
|
41
138
|
} catch {
|
|
42
|
-
await new Promise((
|
|
139
|
+
await new Promise((resolve2, reject) => {
|
|
43
140
|
docker.pull(image, (err, stream) => {
|
|
44
141
|
if (err)
|
|
45
142
|
return reject(err);
|
|
46
143
|
docker.modem.followProgress(stream, (err2) => {
|
|
47
|
-
err2 ? reject(err2) :
|
|
144
|
+
err2 ? reject(err2) : resolve2();
|
|
48
145
|
});
|
|
49
146
|
});
|
|
50
147
|
});
|
|
@@ -61,12 +158,12 @@ function createDockerContext(config) {
|
|
|
61
158
|
const container = await docker.createContainer({
|
|
62
159
|
Image: image,
|
|
63
160
|
Cmd: ["sleep", "infinity"],
|
|
64
|
-
WorkingDir:
|
|
161
|
+
WorkingDir: cwd,
|
|
65
162
|
Env: Object.entries(env).map(([k, v]) => `${k}=${v}`),
|
|
66
163
|
HostConfig: hostConfig
|
|
67
164
|
});
|
|
68
165
|
await container.start();
|
|
69
|
-
const handle = { id, type: "docker", cwd
|
|
166
|
+
const handle = { id, type: "docker", cwd };
|
|
70
167
|
containers.set(id, { handle, container, docker });
|
|
71
168
|
return handle;
|
|
72
169
|
},
|
|
@@ -84,12 +181,12 @@ function createDockerContext(config) {
|
|
|
84
181
|
AttachStderr: true
|
|
85
182
|
});
|
|
86
183
|
const stream = await exec.start({ Detach: false });
|
|
87
|
-
return new Promise((
|
|
184
|
+
return new Promise((resolve2) => {
|
|
88
185
|
let stdout = "";
|
|
89
186
|
const stderr = "";
|
|
90
187
|
const timeout = options?.timeout ?? defaultLimits?.timeout ?? 30;
|
|
91
188
|
const timer = setTimeout(() => {
|
|
92
|
-
|
|
189
|
+
resolve2({ stdout, stderr: `${stderr}
|
|
93
190
|
[timeout]`, exitCode: 124 });
|
|
94
191
|
}, timeout * 1e3);
|
|
95
192
|
stream.on("data", (chunk) => {
|
|
@@ -98,7 +195,7 @@ function createDockerContext(config) {
|
|
|
98
195
|
stream.on("end", async () => {
|
|
99
196
|
clearTimeout(timer);
|
|
100
197
|
const inspect = await exec.inspect();
|
|
101
|
-
|
|
198
|
+
resolve2({ stdout, stderr, exitCode: inspect.ExitCode ?? 0 });
|
|
102
199
|
});
|
|
103
200
|
});
|
|
104
201
|
},
|
|
@@ -145,7 +242,7 @@ var init_docker = __esm({
|
|
|
145
242
|
// src/contexts/process.ts
|
|
146
243
|
import { exec as execCb } from "child_process";
|
|
147
244
|
import { mkdir, readdir, readFile as readFile2, writeFile } from "fs/promises";
|
|
148
|
-
import { dirname, resolve
|
|
245
|
+
import { dirname, resolve } from "path";
|
|
149
246
|
import { promisify } from "util";
|
|
150
247
|
function createProcessContext(config) {
|
|
151
248
|
let counter = 0;
|
|
@@ -162,17 +259,17 @@ function createProcessContext(config) {
|
|
|
162
259
|
},
|
|
163
260
|
async spawn(overrides) {
|
|
164
261
|
const id = `process-${++counter}`;
|
|
165
|
-
const
|
|
166
|
-
await mkdir(
|
|
167
|
-
const handle = { id, type: "process", cwd
|
|
262
|
+
const cwd = overrides?.cwd ?? defaultCwd;
|
|
263
|
+
await mkdir(cwd, { recursive: true });
|
|
264
|
+
const handle = { id, type: "process", cwd };
|
|
168
265
|
handles.set(id, handle);
|
|
169
266
|
return handle;
|
|
170
267
|
},
|
|
171
268
|
async exec(handle, command, options) {
|
|
172
|
-
const
|
|
269
|
+
const cwd = options?.cwd ? resolve(handle.cwd, options.cwd) : handle.cwd;
|
|
173
270
|
try {
|
|
174
271
|
const { stdout, stderr } = await execAsync(command, {
|
|
175
|
-
cwd
|
|
272
|
+
cwd,
|
|
176
273
|
env: { ...process.env, ...defaultEnv, ...options?.env },
|
|
177
274
|
timeout: (options?.timeout ?? config?.limits?.timeout ?? 30) * 1e3,
|
|
178
275
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -187,15 +284,15 @@ function createProcessContext(config) {
|
|
|
187
284
|
}
|
|
188
285
|
},
|
|
189
286
|
async readFile(handle, path) {
|
|
190
|
-
return readFile2(
|
|
287
|
+
return readFile2(resolve(handle.cwd, path), "utf-8");
|
|
191
288
|
},
|
|
192
289
|
async writeFile(handle, path, content) {
|
|
193
|
-
const fullPath =
|
|
290
|
+
const fullPath = resolve(handle.cwd, path);
|
|
194
291
|
await mkdir(dirname(fullPath), { recursive: true });
|
|
195
292
|
await writeFile(fullPath, content, "utf-8");
|
|
196
293
|
},
|
|
197
294
|
async listFiles(handle, path) {
|
|
198
|
-
return readdir(
|
|
295
|
+
return readdir(resolve(handle.cwd, path));
|
|
199
296
|
},
|
|
200
297
|
async destroy(handle) {
|
|
201
298
|
handles.delete(handle.id);
|
|
@@ -270,6 +367,52 @@ var init_contexts = __esm({
|
|
|
270
367
|
}
|
|
271
368
|
});
|
|
272
369
|
|
|
370
|
+
// src/harnesses/basic.ts
|
|
371
|
+
function getSpawn() {
|
|
372
|
+
if (!_spawn) {
|
|
373
|
+
_spawn = (init_spawn(), __toCommonJS(spawn_exports)).spawn;
|
|
374
|
+
}
|
|
375
|
+
return _spawn;
|
|
376
|
+
}
|
|
377
|
+
var basicTools, _spawn, spawnProxy, basic_default;
|
|
378
|
+
var init_basic = __esm({
|
|
379
|
+
"src/harnesses/basic.ts"() {
|
|
380
|
+
"use strict";
|
|
381
|
+
init_harnesses();
|
|
382
|
+
init_tools();
|
|
383
|
+
basicTools = { shell, readFile, writeFile: writeFile2, listFiles };
|
|
384
|
+
spawnProxy = {
|
|
385
|
+
get spec() {
|
|
386
|
+
return getSpawn().spec;
|
|
387
|
+
},
|
|
388
|
+
execute(input, ctx) {
|
|
389
|
+
return getSpawn().execute(input, ctx);
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
basic_default = defineHarness({
|
|
393
|
+
name: "basic",
|
|
394
|
+
system: "You are a helpful assistant with access to shell, file reading, file writing, directory listing, and sub-agent spawning tools. Use them to accomplish tasks in the project directory.",
|
|
395
|
+
tools: { ...basicTools, spawn: spawnProxy }
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
// src/harnesses/index.ts
|
|
401
|
+
function defineHarness(config) {
|
|
402
|
+
return config;
|
|
403
|
+
}
|
|
404
|
+
var noTools;
|
|
405
|
+
var init_harnesses = __esm({
|
|
406
|
+
"src/harnesses/index.ts"() {
|
|
407
|
+
init_basic();
|
|
408
|
+
noTools = defineHarness({
|
|
409
|
+
name: "none",
|
|
410
|
+
system: "You are a helpful assistant.",
|
|
411
|
+
tools: {}
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
273
416
|
// src/tools/validation.ts
|
|
274
417
|
function validateToolArgs(input, schema) {
|
|
275
418
|
const required = schema.required ?? [];
|
|
@@ -287,6 +430,9 @@ var init_validation = __esm({
|
|
|
287
430
|
});
|
|
288
431
|
|
|
289
432
|
// src/loop.ts
|
|
433
|
+
function turnsToMessages(turns) {
|
|
434
|
+
return turns.filter((t) => t.role !== "system").map((t) => ({ role: t.role, content: t.content }));
|
|
435
|
+
}
|
|
290
436
|
async function runLoop(ctx) {
|
|
291
437
|
let totalIn = 0;
|
|
292
438
|
let totalOut = 0;
|
|
@@ -309,14 +455,26 @@ async function runLoop(ctx) {
|
|
|
309
455
|
if (ctx.steeringQueue.length > 0) {
|
|
310
456
|
const steerMsg = ctx.steeringQueue.shift();
|
|
311
457
|
await ctx.hooks.callHook("steer:inject", { message: steerMsg });
|
|
312
|
-
ctx.
|
|
458
|
+
const steerUserMsg = ctx.provider.userMessage(steerMsg);
|
|
459
|
+
ctx.turns.push({
|
|
460
|
+
id: await ctx.generateTurnId(),
|
|
461
|
+
role: steerUserMsg.role,
|
|
462
|
+
content: steerUserMsg.content,
|
|
463
|
+
createdAt: Date.now()
|
|
464
|
+
});
|
|
313
465
|
continue;
|
|
314
466
|
}
|
|
315
467
|
if (result.ended) {
|
|
316
468
|
if (ctx.followUpQueue.length > 0) {
|
|
317
469
|
const followUp = ctx.followUpQueue.shift();
|
|
318
470
|
await ctx.hooks.callHook("steer:inject", { message: followUp });
|
|
319
|
-
ctx.
|
|
471
|
+
const followUpMsg = ctx.provider.userMessage(followUp);
|
|
472
|
+
ctx.turns.push({
|
|
473
|
+
id: await ctx.generateTurnId(),
|
|
474
|
+
role: followUpMsg.role,
|
|
475
|
+
content: followUpMsg.content,
|
|
476
|
+
createdAt: Date.now()
|
|
477
|
+
});
|
|
320
478
|
continue;
|
|
321
479
|
}
|
|
322
480
|
return { totalIn, totalOut, turns: turn + 1, elapsed: Date.now() - startTime, turnUsage: turnUsages };
|
|
@@ -327,37 +485,60 @@ async function runLoop(ctx) {
|
|
|
327
485
|
return stats;
|
|
328
486
|
}
|
|
329
487
|
async function executeTurn(ctx, turn) {
|
|
488
|
+
const turnId = await ctx.generateTurnId();
|
|
489
|
+
const messages = turnsToMessages(ctx.turns);
|
|
330
490
|
const streamOptions = {
|
|
331
491
|
model: ctx.model,
|
|
332
492
|
system: ctx.system,
|
|
333
493
|
tools: ctx.formattedTools,
|
|
334
|
-
messages
|
|
494
|
+
messages,
|
|
335
495
|
maxTokens: 16384,
|
|
336
496
|
thinking: ctx.thinking,
|
|
337
497
|
signal: ctx.signal
|
|
338
498
|
};
|
|
339
|
-
await ctx.hooks.callHook("context:transform", { messages
|
|
340
|
-
await ctx.hooks.callHook("turn:before", { turn, options: streamOptions });
|
|
499
|
+
await ctx.hooks.callHook("context:transform", { messages });
|
|
500
|
+
await ctx.hooks.callHook("turn:before", { turn, turnId, options: streamOptions });
|
|
341
501
|
let currentText = "";
|
|
502
|
+
let blockIndex = 0;
|
|
342
503
|
const result = await ctx.provider.stream(
|
|
343
504
|
streamOptions,
|
|
344
505
|
{
|
|
345
506
|
onText(delta) {
|
|
346
507
|
currentText += delta;
|
|
347
|
-
ctx.hooks.callHook("stream:text", { delta, text: currentText });
|
|
508
|
+
ctx.hooks.callHook("stream:text", { delta, text: currentText, turnId, blockIndex });
|
|
348
509
|
}
|
|
349
510
|
}
|
|
350
511
|
);
|
|
351
512
|
if (currentText) {
|
|
352
|
-
await ctx.hooks.callHook("stream:end", { text: currentText });
|
|
513
|
+
await ctx.hooks.callHook("stream:end", { text: currentText, turnId, blockIndex });
|
|
514
|
+
blockIndex++;
|
|
353
515
|
}
|
|
354
|
-
await ctx.hooks.callHook("turn:after", { turn, usage: result.usage });
|
|
516
|
+
await ctx.hooks.callHook("turn:after", { turn, turnId, usage: result.usage });
|
|
355
517
|
if (result.done) {
|
|
518
|
+
ctx.turns.push({
|
|
519
|
+
id: turnId,
|
|
520
|
+
role: "assistant",
|
|
521
|
+
content: result.assistantMessage?.content ?? [{ type: "text", text: currentText }],
|
|
522
|
+
usage: result.usage,
|
|
523
|
+
createdAt: Date.now()
|
|
524
|
+
});
|
|
356
525
|
return { ended: true, usage: result.usage };
|
|
357
526
|
}
|
|
358
|
-
ctx.
|
|
527
|
+
ctx.turns.push({
|
|
528
|
+
id: turnId,
|
|
529
|
+
role: "assistant",
|
|
530
|
+
content: result.assistantMessage.content,
|
|
531
|
+
usage: result.usage,
|
|
532
|
+
createdAt: Date.now()
|
|
533
|
+
});
|
|
359
534
|
const toolResults = ctx.toolExecution === "parallel" ? await executeToolsParallel(ctx, result.toolCalls) : await executeToolsSequential(ctx, result.toolCalls);
|
|
360
|
-
ctx.
|
|
535
|
+
const toolResultMsg = ctx.provider.toolResultsMessage(toolResults);
|
|
536
|
+
ctx.turns.push({
|
|
537
|
+
id: await ctx.generateTurnId(),
|
|
538
|
+
role: toolResultMsg.role,
|
|
539
|
+
content: toolResultMsg.content,
|
|
540
|
+
createdAt: Date.now()
|
|
541
|
+
});
|
|
361
542
|
return { ended: false, usage: result.usage };
|
|
362
543
|
}
|
|
363
544
|
async function executeSingleTool(ctx, call) {
|
|
@@ -412,8 +593,20 @@ async function executeToolsSequential(ctx, toolCalls) {
|
|
|
412
593
|
for (const skipped of toolCalls.slice(toolCalls.indexOf(call))) {
|
|
413
594
|
results.push({ id: skipped.id, content: "Skipped: steering message received" });
|
|
414
595
|
}
|
|
415
|
-
ctx.
|
|
416
|
-
ctx.
|
|
596
|
+
const toolResultMsg = ctx.provider.toolResultsMessage(results);
|
|
597
|
+
ctx.turns.push({
|
|
598
|
+
id: await ctx.generateTurnId(),
|
|
599
|
+
role: toolResultMsg.role,
|
|
600
|
+
content: toolResultMsg.content,
|
|
601
|
+
createdAt: Date.now()
|
|
602
|
+
});
|
|
603
|
+
const steerUserMsg = ctx.provider.userMessage(steerMsg);
|
|
604
|
+
ctx.turns.push({
|
|
605
|
+
id: await ctx.generateTurnId(),
|
|
606
|
+
role: steerUserMsg.role,
|
|
607
|
+
content: steerUserMsg.content,
|
|
608
|
+
createdAt: Date.now()
|
|
609
|
+
});
|
|
417
610
|
return [];
|
|
418
611
|
}
|
|
419
612
|
const { result } = await executeSingleTool(ctx, call);
|
|
@@ -435,8 +628,9 @@ var init_loop = __esm({
|
|
|
435
628
|
|
|
436
629
|
// src/agent.ts
|
|
437
630
|
import { createHooks } from "hookable";
|
|
438
|
-
function createAgent({ harness, provider, toolExecution = "sequential", execution, mcpServers, session, _mcpConnector }) {
|
|
631
|
+
function createAgent({ harness: harnessOption, provider, toolExecution = "sequential", enableTools = true, execution, mcpServers, session, skills: agentSkills, _mcpConnector }) {
|
|
439
632
|
const hooks = createHooks();
|
|
633
|
+
const harness = harnessOption ?? noTools;
|
|
440
634
|
const executionContext = execution ?? createProcessContext();
|
|
441
635
|
let abortController;
|
|
442
636
|
let running = false;
|
|
@@ -447,8 +641,13 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
447
641
|
const allMcpServers = [...harness.mcpServers ?? [], ...mcpServers ?? []];
|
|
448
642
|
const steeringQueue = [];
|
|
449
643
|
const followUpQueue = [];
|
|
450
|
-
let
|
|
451
|
-
let runCounter = 0;
|
|
644
|
+
let conversationTurns = session?.turns.slice() ?? [];
|
|
645
|
+
let runCounter = session?.runs.length ?? 0;
|
|
646
|
+
const mergedSkillsConfig = mergeSkillsConfig(harness.skills, agentSkills);
|
|
647
|
+
const skillsEnabledValue = mergedSkillsConfig?.enabled;
|
|
648
|
+
const skillsDisabled = skillsEnabledValue === false || Array.isArray(skillsEnabledValue) && skillsEnabledValue.length === 0;
|
|
649
|
+
let resolvedSkills = null;
|
|
650
|
+
let skillsCatalog = null;
|
|
452
651
|
async function run(options) {
|
|
453
652
|
if (running) {
|
|
454
653
|
throw new Error("Agent is already running. Use steer() or followUp() to queue messages, or waitForIdle().");
|
|
@@ -457,8 +656,10 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
457
656
|
abortController = new AbortController();
|
|
458
657
|
const runId = `run_${++runCounter}`;
|
|
459
658
|
session?.startRun(runId, options.prompt);
|
|
460
|
-
if (session)
|
|
659
|
+
if (session) {
|
|
660
|
+
await session.updateStatus("running");
|
|
461
661
|
await hooks.callHook("session:start", { sessionId: session.id, runId, prompt: options.prompt });
|
|
662
|
+
}
|
|
462
663
|
if (options.signal) {
|
|
463
664
|
if (options.signal.aborted) {
|
|
464
665
|
abortController.abort();
|
|
@@ -467,8 +668,8 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
467
668
|
options.signal.addEventListener("abort", onExternalAbort, { once: true });
|
|
468
669
|
}
|
|
469
670
|
}
|
|
470
|
-
idlePromise = new Promise((
|
|
471
|
-
idleResolve =
|
|
671
|
+
idlePromise = new Promise((resolve2) => {
|
|
672
|
+
idleResolve = resolve2;
|
|
472
673
|
});
|
|
473
674
|
const childrenStats = [];
|
|
474
675
|
const unregisterSpawnHook = hooks.hook("spawn:complete", (ctx) => {
|
|
@@ -484,10 +685,52 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
484
685
|
mcpConnection = await connectMcpServers(allMcpServers, void 0, hooks);
|
|
485
686
|
}
|
|
486
687
|
}
|
|
688
|
+
if (!skillsDisabled && mergedSkillsConfig && !resolvedSkills) {
|
|
689
|
+
resolvedSkills = await resolveSkills(mergedSkillsConfig);
|
|
690
|
+
await hooks.callHook("skills:resolve", { skills: resolvedSkills });
|
|
691
|
+
if (executionHandle) {
|
|
692
|
+
for (const skill of resolvedSkills) {
|
|
693
|
+
if (skill.instructions.includes("!`")) {
|
|
694
|
+
skill.instructions = await interpolateShellCommands(
|
|
695
|
+
skill.instructions,
|
|
696
|
+
executionContext,
|
|
697
|
+
executionHandle
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
const readToolName = mergedSkillsConfig.readToolName ?? "read_file";
|
|
703
|
+
const catalogCtx = { catalog: buildCatalog(resolvedSkills, readToolName), skills: resolvedSkills };
|
|
704
|
+
await hooks.callHook("skills:catalog", catalogCtx);
|
|
705
|
+
skillsCatalog = catalogCtx.catalog;
|
|
706
|
+
const fsSkills = resolvedSkills.filter((s) => s.location);
|
|
707
|
+
if (fsSkills.length > 0) {
|
|
708
|
+
const skillByLocation = new Map(fsSkills.map((s) => [s.location, s]));
|
|
709
|
+
hooks.hook("tool:after", (ctx) => {
|
|
710
|
+
if (ctx.name !== readToolName)
|
|
711
|
+
return;
|
|
712
|
+
const path = ctx.input.path;
|
|
713
|
+
if (!path)
|
|
714
|
+
return;
|
|
715
|
+
const matched = skillByLocation.get(path) ?? fsSkills.find((s) => s.location.endsWith(path));
|
|
716
|
+
if (matched)
|
|
717
|
+
hooks.callHook("skills:activate", { skill: matched });
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
}
|
|
487
721
|
const thinking = options.thinking ?? "off";
|
|
488
722
|
const model = options.model ?? provider.meta.defaultModel;
|
|
489
|
-
|
|
490
|
-
|
|
723
|
+
let system = options.system || harness.system || "You are a helpful assistant.";
|
|
724
|
+
if (skillsCatalog) {
|
|
725
|
+
system = `${system}
|
|
726
|
+
|
|
727
|
+
${skillsCatalog}`;
|
|
728
|
+
}
|
|
729
|
+
const harnessTools = enableTools ? mcpConnection ? { ...harness.tools, ...mcpConnection.tools } : harness.tools : {};
|
|
730
|
+
const tools = {};
|
|
731
|
+
for (const tool of Object.values(harnessTools)) {
|
|
732
|
+
tools[tool.spec.name] = tool;
|
|
733
|
+
}
|
|
491
734
|
const toolSpecs = Object.values(tools).map(
|
|
492
735
|
(t) => ({
|
|
493
736
|
name: t.spec.name,
|
|
@@ -495,19 +738,45 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
495
738
|
input_schema: t.spec.input_schema
|
|
496
739
|
})
|
|
497
740
|
);
|
|
498
|
-
const formattedTools = provider.formatTools(toolSpecs);
|
|
499
|
-
const
|
|
741
|
+
const formattedTools = enableTools ? provider.formatTools(toolSpecs) : [];
|
|
742
|
+
const turns = [];
|
|
743
|
+
const isResume = session && session.turns.length > 0 && session.runs.length > 0;
|
|
744
|
+
if (isResume) {
|
|
745
|
+
turns.push(...session.turns);
|
|
746
|
+
}
|
|
500
747
|
if (options.system) {
|
|
501
748
|
await hooks.callHook("system:before", { system: options.system });
|
|
502
|
-
|
|
503
|
-
|
|
749
|
+
const systemUserMsg = provider.userMessage(options.system);
|
|
750
|
+
turns.push({
|
|
751
|
+
id: crypto.randomUUID(),
|
|
752
|
+
role: systemUserMsg.role,
|
|
753
|
+
content: systemUserMsg.content,
|
|
754
|
+
createdAt: Date.now()
|
|
755
|
+
});
|
|
756
|
+
const systemAckMsg = provider.assistantMessage("Understood. I will proceed with these instructions above the rest of my system prompt.");
|
|
757
|
+
turns.push({
|
|
758
|
+
id: crypto.randomUUID(),
|
|
759
|
+
role: systemAckMsg.role,
|
|
760
|
+
content: systemAckMsg.content,
|
|
761
|
+
createdAt: Date.now()
|
|
762
|
+
});
|
|
504
763
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
764
|
+
const promptMsg = provider.userMessage(options.prompt, options.images);
|
|
765
|
+
turns.push({
|
|
766
|
+
id: crypto.randomUUID(),
|
|
767
|
+
role: promptMsg.role,
|
|
768
|
+
content: promptMsg.content,
|
|
769
|
+
createdAt: Date.now()
|
|
770
|
+
});
|
|
771
|
+
conversationTurns = turns;
|
|
772
|
+
let lastPersistedTurnCount = isResume ? session.turns.length : 0;
|
|
773
|
+
const unregisterSessionSync = session ? hooks.hook("turn:after", async () => {
|
|
774
|
+
const newTurns = turns.slice(lastPersistedTurnCount);
|
|
775
|
+
if (newTurns.length > 0) {
|
|
776
|
+
await session.appendTurns(newTurns);
|
|
777
|
+
lastPersistedTurnCount = turns.length;
|
|
778
|
+
hooks.callHook("session:turns", { sessionId: session.id, count: turns.length });
|
|
779
|
+
}
|
|
511
780
|
}) : void 0;
|
|
512
781
|
try {
|
|
513
782
|
const stats = await runLoop({
|
|
@@ -526,7 +795,8 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
526
795
|
handle: executionHandle,
|
|
527
796
|
steeringQueue,
|
|
528
797
|
followUpQueue,
|
|
529
|
-
|
|
798
|
+
turns,
|
|
799
|
+
generateTurnId: () => session?.generateTurnId() ?? crypto.randomUUID()
|
|
530
800
|
});
|
|
531
801
|
const finalStats = {
|
|
532
802
|
...stats,
|
|
@@ -534,15 +804,24 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
534
804
|
};
|
|
535
805
|
if (abortController.signal.aborted) {
|
|
536
806
|
session?.abortRun(runId);
|
|
537
|
-
if (session)
|
|
807
|
+
if (session) {
|
|
808
|
+
const run2 = session.runs.find((r) => r.id === runId);
|
|
809
|
+
if (run2)
|
|
810
|
+
await session.updateRun(run2);
|
|
811
|
+
await session.updateStatus("idle");
|
|
538
812
|
await hooks.callHook("session:end", { sessionId: session.id, runId, status: "aborted" });
|
|
813
|
+
}
|
|
539
814
|
await hooks.callHook("agent:done", finalStats);
|
|
540
815
|
return finalStats;
|
|
541
816
|
}
|
|
542
817
|
const totalCost = finalStats.turnUsage?.reduce((sum, t) => sum + (t.cost ?? 0), 0) || void 0;
|
|
543
818
|
if (totalCost)
|
|
544
819
|
finalStats.cost = totalCost;
|
|
545
|
-
|
|
820
|
+
const finalNewTurns = turns.slice(lastPersistedTurnCount);
|
|
821
|
+
if (session && finalNewTurns.length > 0) {
|
|
822
|
+
await session.appendTurns(finalNewTurns);
|
|
823
|
+
lastPersistedTurnCount = turns.length;
|
|
824
|
+
}
|
|
546
825
|
session?.completeRun(runId, {
|
|
547
826
|
turns: finalStats.turns,
|
|
548
827
|
tokensIn: finalStats.totalIn,
|
|
@@ -550,22 +829,37 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
550
829
|
turnUsage: finalStats.turnUsage,
|
|
551
830
|
cost: totalCost
|
|
552
831
|
});
|
|
553
|
-
if (session)
|
|
832
|
+
if (session) {
|
|
833
|
+
const run2 = session.runs.find((r) => r.id === runId);
|
|
834
|
+
if (run2)
|
|
835
|
+
await session.updateRun(run2);
|
|
836
|
+
await session.updateStatus("completed");
|
|
554
837
|
await hooks.callHook("session:end", { sessionId: session.id, runId, status: "completed" });
|
|
838
|
+
}
|
|
555
839
|
await hooks.callHook("agent:done", finalStats);
|
|
556
840
|
return finalStats;
|
|
557
841
|
} catch (err) {
|
|
558
842
|
if (abortController.signal.aborted) {
|
|
559
843
|
session?.abortRun(runId);
|
|
560
|
-
if (session)
|
|
844
|
+
if (session) {
|
|
845
|
+
const run2 = session.runs.find((r) => r.id === runId);
|
|
846
|
+
if (run2)
|
|
847
|
+
await session.updateRun(run2);
|
|
848
|
+
await session.updateStatus("idle");
|
|
561
849
|
await hooks.callHook("session:end", { sessionId: session.id, runId, status: "aborted" });
|
|
850
|
+
}
|
|
562
851
|
const stats = { totalIn: 0, totalOut: 0, turns: 0, elapsed: 0 };
|
|
563
852
|
await hooks.callHook("agent:done", stats);
|
|
564
853
|
return stats;
|
|
565
854
|
}
|
|
566
855
|
session?.errorRun(runId, err.message);
|
|
567
|
-
if (session)
|
|
856
|
+
if (session) {
|
|
857
|
+
const run2 = session.runs.find((r) => r.id === runId);
|
|
858
|
+
if (run2)
|
|
859
|
+
await session.updateRun(run2);
|
|
860
|
+
await session.updateStatus("error");
|
|
568
861
|
await hooks.callHook("session:end", { sessionId: session.id, runId, status: "error" });
|
|
862
|
+
}
|
|
569
863
|
throw err;
|
|
570
864
|
} finally {
|
|
571
865
|
unregisterSpawnHook();
|
|
@@ -592,7 +886,7 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
592
886
|
return idlePromise ?? Promise.resolve();
|
|
593
887
|
}
|
|
594
888
|
function reset() {
|
|
595
|
-
|
|
889
|
+
conversationTurns = [];
|
|
596
890
|
steeringQueue.length = 0;
|
|
597
891
|
followUpQueue.length = 0;
|
|
598
892
|
}
|
|
@@ -630,8 +924,8 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
630
924
|
get isRunning() {
|
|
631
925
|
return running;
|
|
632
926
|
},
|
|
633
|
-
get
|
|
634
|
-
return
|
|
927
|
+
get turns() {
|
|
928
|
+
return conversationTurns;
|
|
635
929
|
},
|
|
636
930
|
get execution() {
|
|
637
931
|
return executionContext;
|
|
@@ -649,8 +943,12 @@ var init_agent = __esm({
|
|
|
649
943
|
"src/agent.ts"() {
|
|
650
944
|
"use strict";
|
|
651
945
|
init_contexts();
|
|
946
|
+
init_harnesses();
|
|
652
947
|
init_loop();
|
|
653
948
|
init_mcp();
|
|
949
|
+
init_catalog();
|
|
950
|
+
init_interpolate();
|
|
951
|
+
init_resolve();
|
|
654
952
|
}
|
|
655
953
|
});
|
|
656
954
|
|
|
@@ -660,6 +958,17 @@ __export(spawn_exports, {
|
|
|
660
958
|
createSpawnTool: () => createSpawnTool,
|
|
661
959
|
spawn: () => spawn
|
|
662
960
|
});
|
|
961
|
+
function extractText(message) {
|
|
962
|
+
if (!message || typeof message !== "object")
|
|
963
|
+
return "";
|
|
964
|
+
const msg = message;
|
|
965
|
+
if (typeof msg.content === "string")
|
|
966
|
+
return msg.content;
|
|
967
|
+
if (Array.isArray(msg.content)) {
|
|
968
|
+
return msg.content.filter((block) => block.type === "text").map((block) => block.text).join("\n");
|
|
969
|
+
}
|
|
970
|
+
return "";
|
|
971
|
+
}
|
|
663
972
|
function createSpawnTool(options = {}) {
|
|
664
973
|
const localChildren = /* @__PURE__ */ new Map();
|
|
665
974
|
let localCounter = 0;
|
|
@@ -731,7 +1040,7 @@ function createSpawnTool(options = {}) {
|
|
|
731
1040
|
task,
|
|
732
1041
|
stats
|
|
733
1042
|
});
|
|
734
|
-
const response = extractText(agent.
|
|
1043
|
+
const response = extractText(agent.turns.at(-1));
|
|
735
1044
|
return [
|
|
736
1045
|
`[sub-agent ${id}] Completed in ${stats.turns} turns (${stats.elapsed}ms)`,
|
|
737
1046
|
`Tokens: ${stats.totalIn} in / ${stats.totalOut} out`,
|
|
@@ -749,257 +1058,71 @@ function createSpawnTool(options = {}) {
|
|
|
749
1058
|
}
|
|
750
1059
|
};
|
|
751
1060
|
}
|
|
752
|
-
|
|
753
|
-
if (!message || typeof message !== "object")
|
|
754
|
-
return "";
|
|
755
|
-
const msg = message;
|
|
756
|
-
if (typeof msg.content === "string")
|
|
757
|
-
return msg.content;
|
|
758
|
-
if (Array.isArray(msg.content)) {
|
|
759
|
-
return msg.content.filter((block) => block.type === "text").map((block) => block.text).join("\n");
|
|
760
|
-
}
|
|
761
|
-
return "";
|
|
762
|
-
}
|
|
763
|
-
var children, childCounter, activeCount, MAX_CONCURRENT, _totalChildStats, spawn;
|
|
1061
|
+
var spawn;
|
|
764
1062
|
var init_spawn = __esm({
|
|
765
1063
|
"src/tools/spawn.ts"() {
|
|
766
1064
|
"use strict";
|
|
767
1065
|
init_agent();
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
spawn = {
|
|
779
|
-
get children() {
|
|
780
|
-
return children;
|
|
781
|
-
},
|
|
782
|
-
get totalChildStats() {
|
|
783
|
-
return { ..._totalChildStats };
|
|
784
|
-
},
|
|
1066
|
+
spawn = createSpawnTool();
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
// src/tools/write-file.ts
|
|
1071
|
+
var writeFile2;
|
|
1072
|
+
var init_write_file = __esm({
|
|
1073
|
+
"src/tools/write-file.ts"() {
|
|
1074
|
+
"use strict";
|
|
1075
|
+
writeFile2 = {
|
|
785
1076
|
spec: {
|
|
786
|
-
name: "
|
|
787
|
-
description: "
|
|
1077
|
+
name: "write_file",
|
|
1078
|
+
description: "Write content to a file. Creates parent directories if needed.",
|
|
788
1079
|
input_schema: {
|
|
789
1080
|
type: "object",
|
|
790
1081
|
properties: {
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
description: "The task prompt for the sub-agent. Be specific about what you want it to accomplish."
|
|
794
|
-
},
|
|
795
|
-
system: {
|
|
796
|
-
type: "string",
|
|
797
|
-
description: "Optional system prompt override for this specific sub-agent."
|
|
798
|
-
}
|
|
1082
|
+
path: { type: "string", description: "Relative file path" },
|
|
1083
|
+
content: { type: "string", description: "File content to write" }
|
|
799
1084
|
},
|
|
800
|
-
required: ["
|
|
1085
|
+
required: ["path", "content"]
|
|
801
1086
|
}
|
|
802
1087
|
},
|
|
803
|
-
async execute(
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
if (activeCount >= MAX_CONCURRENT) {
|
|
807
|
-
return `Cannot spawn: ${activeCount}/${MAX_CONCURRENT} sub-agents already running. Wait for one to complete.`;
|
|
808
|
-
}
|
|
809
|
-
const id = `child-${++childCounter}`;
|
|
810
|
-
const child = { id, task, startedAt: Date.now() };
|
|
811
|
-
const agent = createAgent({
|
|
812
|
-
harness: ctx.harness,
|
|
813
|
-
provider: ctx.provider,
|
|
814
|
-
execution: ctx.execution
|
|
815
|
-
});
|
|
816
|
-
children.set(id, child);
|
|
817
|
-
activeCount++;
|
|
818
|
-
await ctx.hooks.callHook("spawn:before", { id, task });
|
|
819
|
-
try {
|
|
820
|
-
const stats = await agent.run({
|
|
821
|
-
prompt: task,
|
|
822
|
-
system: systemOverride,
|
|
823
|
-
signal: ctx.signal
|
|
824
|
-
});
|
|
825
|
-
_totalChildStats.totalIn += stats.totalIn;
|
|
826
|
-
_totalChildStats.totalOut += stats.totalOut;
|
|
827
|
-
_totalChildStats.turns += stats.turns;
|
|
828
|
-
_totalChildStats.elapsed += stats.elapsed;
|
|
829
|
-
await ctx.hooks.callHook("spawn:complete", {
|
|
830
|
-
id,
|
|
831
|
-
task,
|
|
832
|
-
stats
|
|
833
|
-
});
|
|
834
|
-
const response = extractText(agent.messages.at(-1));
|
|
835
|
-
return [
|
|
836
|
-
`[sub-agent ${id}] Completed in ${stats.turns} turns (${stats.elapsed}ms)`,
|
|
837
|
-
`Tokens: ${stats.totalIn} in / ${stats.totalOut} out`,
|
|
838
|
-
"",
|
|
839
|
-
response || "(no text response)"
|
|
840
|
-
].join("\n");
|
|
841
|
-
} catch (err) {
|
|
842
|
-
await ctx.hooks.callHook("spawn:error", { id, task, error: err });
|
|
843
|
-
return `[sub-agent ${id}] Error: ${err.message}`;
|
|
844
|
-
} finally {
|
|
845
|
-
activeCount--;
|
|
846
|
-
await agent.destroy();
|
|
847
|
-
children.delete(id);
|
|
848
|
-
}
|
|
1088
|
+
async execute({ path, content }, ctx) {
|
|
1089
|
+
await ctx.execution.writeFile(ctx.handle, path, content);
|
|
1090
|
+
return `Wrote ${content.length} bytes to ${path}`;
|
|
849
1091
|
}
|
|
850
1092
|
};
|
|
851
1093
|
}
|
|
852
1094
|
});
|
|
853
1095
|
|
|
854
|
-
// src/tools/list-files.ts
|
|
855
|
-
import { existsSync, readdirSync, statSync } from "fs";
|
|
856
|
-
import { resolve } from "path";
|
|
857
|
-
var cwd = process.cwd();
|
|
858
|
-
function safePath(p) {
|
|
859
|
-
const resolved = resolve(cwd, p);
|
|
860
|
-
if (!resolved.startsWith(cwd))
|
|
861
|
-
throw new Error(`Path escapes working directory: ${p}`);
|
|
862
|
-
return resolved;
|
|
863
|
-
}
|
|
864
|
-
var listFiles = {
|
|
865
|
-
spec: {
|
|
866
|
-
name: "list_files",
|
|
867
|
-
description: "List files and directories at the given path (relative to project root).",
|
|
868
|
-
input_schema: {
|
|
869
|
-
type: "object",
|
|
870
|
-
properties: {
|
|
871
|
-
path: { type: "string", description: 'Relative directory path (default: ".")' }
|
|
872
|
-
},
|
|
873
|
-
required: []
|
|
874
|
-
}
|
|
875
|
-
},
|
|
876
|
-
async execute({ path }, _ctx) {
|
|
877
|
-
const target = safePath(path || ".");
|
|
878
|
-
if (!existsSync(target))
|
|
879
|
-
return `Directory not found: ${path}`;
|
|
880
|
-
const entries = readdirSync(target);
|
|
881
|
-
return entries.map((name) => {
|
|
882
|
-
const full = resolve(target, name);
|
|
883
|
-
const isDir = statSync(full).isDirectory();
|
|
884
|
-
return `${isDir ? "\u{1F4C1}" : "\u{1F4C4}"} ${name}`;
|
|
885
|
-
}).join("\n");
|
|
886
|
-
}
|
|
887
|
-
};
|
|
888
|
-
|
|
889
|
-
// src/tools/read-file.ts
|
|
890
|
-
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
891
|
-
import { resolve as resolve2 } from "path";
|
|
892
|
-
var cwd2 = process.cwd();
|
|
893
|
-
function safePath2(p) {
|
|
894
|
-
const resolved = resolve2(cwd2, p);
|
|
895
|
-
if (!resolved.startsWith(cwd2))
|
|
896
|
-
throw new Error(`Path escapes working directory: ${p}`);
|
|
897
|
-
return resolved;
|
|
898
|
-
}
|
|
899
|
-
var readFile = {
|
|
900
|
-
spec: {
|
|
901
|
-
name: "read_file",
|
|
902
|
-
description: "Read the contents of a file at the given path (relative to project root).",
|
|
903
|
-
input_schema: {
|
|
904
|
-
type: "object",
|
|
905
|
-
properties: {
|
|
906
|
-
path: { type: "string", description: "Relative file path" }
|
|
907
|
-
},
|
|
908
|
-
required: ["path"]
|
|
909
|
-
}
|
|
910
|
-
},
|
|
911
|
-
async execute({ path }, _ctx) {
|
|
912
|
-
const target = safePath2(path);
|
|
913
|
-
if (!existsSync2(target))
|
|
914
|
-
return `File not found: ${path}`;
|
|
915
|
-
return readFileSync(target, "utf-8");
|
|
916
|
-
}
|
|
917
|
-
};
|
|
918
|
-
|
|
919
|
-
// src/tools/shell.ts
|
|
920
|
-
import { execSync } from "child_process";
|
|
921
|
-
var cwd3 = process.cwd();
|
|
922
|
-
var shell = {
|
|
923
|
-
spec: {
|
|
924
|
-
name: "shell",
|
|
925
|
-
description: "Execute a shell command and return stdout+stderr. Runs in the project root.",
|
|
926
|
-
input_schema: {
|
|
927
|
-
type: "object",
|
|
928
|
-
properties: {
|
|
929
|
-
command: { type: "string", description: "The shell command to run" }
|
|
930
|
-
},
|
|
931
|
-
required: ["command"]
|
|
932
|
-
}
|
|
933
|
-
},
|
|
934
|
-
async execute({ command }, _ctx) {
|
|
935
|
-
try {
|
|
936
|
-
const out = execSync(command, {
|
|
937
|
-
cwd: cwd3,
|
|
938
|
-
encoding: "utf-8",
|
|
939
|
-
timeout: 3e4,
|
|
940
|
-
maxBuffer: 1024 * 1024,
|
|
941
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
942
|
-
});
|
|
943
|
-
return out || "(no output)";
|
|
944
|
-
} catch (err) {
|
|
945
|
-
const stderr = err.stderr?.toString() ?? "";
|
|
946
|
-
const stdout = err.stdout?.toString() ?? "";
|
|
947
|
-
return `Exit code ${err.status ?? 1}
|
|
948
|
-
${stdout}
|
|
949
|
-
${stderr}`.trim();
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
};
|
|
953
|
-
|
|
954
1096
|
// src/tools/index.ts
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
const resolved = resolve4(cwd4, p);
|
|
964
|
-
if (!resolved.startsWith(cwd4))
|
|
965
|
-
throw new Error(`Path escapes working directory: ${p}`);
|
|
966
|
-
return resolved;
|
|
967
|
-
}
|
|
968
|
-
var writeFile2 = {
|
|
969
|
-
spec: {
|
|
970
|
-
name: "write_file",
|
|
971
|
-
description: "Write content to a file. Creates parent directories if needed.",
|
|
972
|
-
input_schema: {
|
|
973
|
-
type: "object",
|
|
974
|
-
properties: {
|
|
975
|
-
path: { type: "string", description: "Relative file path" },
|
|
976
|
-
content: { type: "string", description: "File content to write" }
|
|
977
|
-
},
|
|
978
|
-
required: ["path", "content"]
|
|
979
|
-
}
|
|
980
|
-
},
|
|
981
|
-
async execute({ path, content }, _ctx) {
|
|
982
|
-
const target = safePath3(path);
|
|
983
|
-
mkdirSync(dirname2(target), { recursive: true });
|
|
984
|
-
writeFileSync(target, content);
|
|
985
|
-
return `Wrote ${content.length} bytes to ${path}`;
|
|
1097
|
+
var init_tools = __esm({
|
|
1098
|
+
"src/tools/index.ts"() {
|
|
1099
|
+
init_list_files();
|
|
1100
|
+
init_read_file();
|
|
1101
|
+
init_shell();
|
|
1102
|
+
init_spawn();
|
|
1103
|
+
init_validation();
|
|
1104
|
+
init_write_file();
|
|
986
1105
|
}
|
|
987
|
-
};
|
|
1106
|
+
});
|
|
988
1107
|
|
|
989
1108
|
export {
|
|
990
1109
|
createDockerContext,
|
|
991
1110
|
createProcessContext,
|
|
992
1111
|
createSandboxContext,
|
|
993
1112
|
init_contexts,
|
|
994
|
-
validateToolArgs,
|
|
995
|
-
createAgent,
|
|
996
|
-
init_agent,
|
|
997
1113
|
listFiles,
|
|
998
1114
|
readFile,
|
|
999
1115
|
shell,
|
|
1000
|
-
spawn,
|
|
1001
1116
|
createSpawnTool,
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
writeFile2 as writeFile
|
|
1117
|
+
spawn,
|
|
1118
|
+
validateToolArgs,
|
|
1119
|
+
writeFile2 as writeFile,
|
|
1120
|
+
init_tools,
|
|
1121
|
+
basicTools,
|
|
1122
|
+
basic_default,
|
|
1123
|
+
defineHarness,
|
|
1124
|
+
noTools,
|
|
1125
|
+
init_harnesses,
|
|
1126
|
+
createAgent,
|
|
1127
|
+
init_agent
|
|
1005
1128
|
};
|