zidane 1.3.1 → 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/dist/{agent-DxIUxou4.d.ts → agent-B4wguzkU.d.ts} +26 -80
- package/dist/chunk-PRNQ7DXE.js +430 -0
- package/dist/chunk-QPYZR2QM.js +21 -0
- package/dist/{chunk-SWS5624X.js → chunk-YCH7G7YC.js} +272 -251
- package/dist/harnesses.d.ts +2 -1
- package/dist/harnesses.js +8 -4
- package/dist/index.d.ts +5 -3
- package/dist/index.js +33 -5
- package/dist/mcp.d.ts +2 -1
- package/dist/providers.d.ts +19 -4
- package/dist/providers.js +26 -24
- package/dist/skills.d.ts +124 -0
- package/dist/skills.js +31 -0
- package/dist/{spawn-bEqlGUVT.d.ts → spawn-vZAQfDkd.d.ts} +9 -9
- package/dist/tools.d.ts +3 -2
- package/dist/tools.js +4 -1
- package/dist/types-D8fzooXc.d.ts +141 -0
- package/package.json +5 -1
- package/dist/chunk-N523NBO2.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 ?? [];
|
|
@@ -288,7 +431,7 @@ var init_validation = __esm({
|
|
|
288
431
|
|
|
289
432
|
// src/loop.ts
|
|
290
433
|
function turnsToMessages(turns) {
|
|
291
|
-
return turns.map((t) => ({ role: t.role, content: t.content }));
|
|
434
|
+
return turns.filter((t) => t.role !== "system").map((t) => ({ role: t.role, content: t.content }));
|
|
292
435
|
}
|
|
293
436
|
async function runLoop(ctx) {
|
|
294
437
|
let totalIn = 0;
|
|
@@ -356,7 +499,7 @@ async function executeTurn(ctx, turn) {
|
|
|
356
499
|
await ctx.hooks.callHook("context:transform", { messages });
|
|
357
500
|
await ctx.hooks.callHook("turn:before", { turn, turnId, options: streamOptions });
|
|
358
501
|
let currentText = "";
|
|
359
|
-
|
|
502
|
+
let blockIndex = 0;
|
|
360
503
|
const result = await ctx.provider.stream(
|
|
361
504
|
streamOptions,
|
|
362
505
|
{
|
|
@@ -368,6 +511,7 @@ async function executeTurn(ctx, turn) {
|
|
|
368
511
|
);
|
|
369
512
|
if (currentText) {
|
|
370
513
|
await ctx.hooks.callHook("stream:end", { text: currentText, turnId, blockIndex });
|
|
514
|
+
blockIndex++;
|
|
371
515
|
}
|
|
372
516
|
await ctx.hooks.callHook("turn:after", { turn, turnId, usage: result.usage });
|
|
373
517
|
if (result.done) {
|
|
@@ -484,8 +628,9 @@ var init_loop = __esm({
|
|
|
484
628
|
|
|
485
629
|
// src/agent.ts
|
|
486
630
|
import { createHooks } from "hookable";
|
|
487
|
-
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 }) {
|
|
488
632
|
const hooks = createHooks();
|
|
633
|
+
const harness = harnessOption ?? noTools;
|
|
489
634
|
const executionContext = execution ?? createProcessContext();
|
|
490
635
|
let abortController;
|
|
491
636
|
let running = false;
|
|
@@ -498,6 +643,11 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
498
643
|
const followUpQueue = [];
|
|
499
644
|
let conversationTurns = session?.turns.slice() ?? [];
|
|
500
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;
|
|
501
651
|
async function run(options) {
|
|
502
652
|
if (running) {
|
|
503
653
|
throw new Error("Agent is already running. Use steer() or followUp() to queue messages, or waitForIdle().");
|
|
@@ -518,8 +668,8 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
518
668
|
options.signal.addEventListener("abort", onExternalAbort, { once: true });
|
|
519
669
|
}
|
|
520
670
|
}
|
|
521
|
-
idlePromise = new Promise((
|
|
522
|
-
idleResolve =
|
|
671
|
+
idlePromise = new Promise((resolve2) => {
|
|
672
|
+
idleResolve = resolve2;
|
|
523
673
|
});
|
|
524
674
|
const childrenStats = [];
|
|
525
675
|
const unregisterSpawnHook = hooks.hook("spawn:complete", (ctx) => {
|
|
@@ -535,10 +685,52 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
535
685
|
mcpConnection = await connectMcpServers(allMcpServers, void 0, hooks);
|
|
536
686
|
}
|
|
537
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
|
+
}
|
|
538
721
|
const thinking = options.thinking ?? "off";
|
|
539
722
|
const model = options.model ?? provider.meta.defaultModel;
|
|
540
|
-
|
|
541
|
-
|
|
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
|
+
}
|
|
542
734
|
const toolSpecs = Object.values(tools).map(
|
|
543
735
|
(t) => ({
|
|
544
736
|
name: t.spec.name,
|
|
@@ -546,7 +738,7 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
546
738
|
input_schema: t.spec.input_schema
|
|
547
739
|
})
|
|
548
740
|
);
|
|
549
|
-
const formattedTools = provider.formatTools(toolSpecs);
|
|
741
|
+
const formattedTools = enableTools ? provider.formatTools(toolSpecs) : [];
|
|
550
742
|
const turns = [];
|
|
551
743
|
const isResume = session && session.turns.length > 0 && session.runs.length > 0;
|
|
552
744
|
if (isResume) {
|
|
@@ -751,8 +943,12 @@ var init_agent = __esm({
|
|
|
751
943
|
"src/agent.ts"() {
|
|
752
944
|
"use strict";
|
|
753
945
|
init_contexts();
|
|
946
|
+
init_harnesses();
|
|
754
947
|
init_loop();
|
|
755
948
|
init_mcp();
|
|
949
|
+
init_catalog();
|
|
950
|
+
init_interpolate();
|
|
951
|
+
init_resolve();
|
|
756
952
|
}
|
|
757
953
|
});
|
|
758
954
|
|
|
@@ -762,6 +958,17 @@ __export(spawn_exports, {
|
|
|
762
958
|
createSpawnTool: () => createSpawnTool,
|
|
763
959
|
spawn: () => spawn
|
|
764
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
|
+
}
|
|
765
972
|
function createSpawnTool(options = {}) {
|
|
766
973
|
const localChildren = /* @__PURE__ */ new Map();
|
|
767
974
|
let localCounter = 0;
|
|
@@ -851,257 +1058,71 @@ function createSpawnTool(options = {}) {
|
|
|
851
1058
|
}
|
|
852
1059
|
};
|
|
853
1060
|
}
|
|
854
|
-
|
|
855
|
-
if (!message || typeof message !== "object")
|
|
856
|
-
return "";
|
|
857
|
-
const msg = message;
|
|
858
|
-
if (typeof msg.content === "string")
|
|
859
|
-
return msg.content;
|
|
860
|
-
if (Array.isArray(msg.content)) {
|
|
861
|
-
return msg.content.filter((block) => block.type === "text").map((block) => block.text).join("\n");
|
|
862
|
-
}
|
|
863
|
-
return "";
|
|
864
|
-
}
|
|
865
|
-
var children, childCounter, activeCount, MAX_CONCURRENT, _totalChildStats, spawn;
|
|
1061
|
+
var spawn;
|
|
866
1062
|
var init_spawn = __esm({
|
|
867
1063
|
"src/tools/spawn.ts"() {
|
|
868
1064
|
"use strict";
|
|
869
1065
|
init_agent();
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
spawn = {
|
|
881
|
-
get children() {
|
|
882
|
-
return children;
|
|
883
|
-
},
|
|
884
|
-
get totalChildStats() {
|
|
885
|
-
return { ..._totalChildStats };
|
|
886
|
-
},
|
|
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 = {
|
|
887
1076
|
spec: {
|
|
888
|
-
name: "
|
|
889
|
-
description: "
|
|
1077
|
+
name: "write_file",
|
|
1078
|
+
description: "Write content to a file. Creates parent directories if needed.",
|
|
890
1079
|
input_schema: {
|
|
891
1080
|
type: "object",
|
|
892
1081
|
properties: {
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
description: "The task prompt for the sub-agent. Be specific about what you want it to accomplish."
|
|
896
|
-
},
|
|
897
|
-
system: {
|
|
898
|
-
type: "string",
|
|
899
|
-
description: "Optional system prompt override for this specific sub-agent."
|
|
900
|
-
}
|
|
1082
|
+
path: { type: "string", description: "Relative file path" },
|
|
1083
|
+
content: { type: "string", description: "File content to write" }
|
|
901
1084
|
},
|
|
902
|
-
required: ["
|
|
1085
|
+
required: ["path", "content"]
|
|
903
1086
|
}
|
|
904
1087
|
},
|
|
905
|
-
async execute(
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
if (activeCount >= MAX_CONCURRENT) {
|
|
909
|
-
return `Cannot spawn: ${activeCount}/${MAX_CONCURRENT} sub-agents already running. Wait for one to complete.`;
|
|
910
|
-
}
|
|
911
|
-
const id = `child-${++childCounter}`;
|
|
912
|
-
const child = { id, task, startedAt: Date.now() };
|
|
913
|
-
const agent = createAgent({
|
|
914
|
-
harness: ctx.harness,
|
|
915
|
-
provider: ctx.provider,
|
|
916
|
-
execution: ctx.execution
|
|
917
|
-
});
|
|
918
|
-
children.set(id, child);
|
|
919
|
-
activeCount++;
|
|
920
|
-
await ctx.hooks.callHook("spawn:before", { id, task });
|
|
921
|
-
try {
|
|
922
|
-
const stats = await agent.run({
|
|
923
|
-
prompt: task,
|
|
924
|
-
system: systemOverride,
|
|
925
|
-
signal: ctx.signal
|
|
926
|
-
});
|
|
927
|
-
_totalChildStats.totalIn += stats.totalIn;
|
|
928
|
-
_totalChildStats.totalOut += stats.totalOut;
|
|
929
|
-
_totalChildStats.turns += stats.turns;
|
|
930
|
-
_totalChildStats.elapsed += stats.elapsed;
|
|
931
|
-
await ctx.hooks.callHook("spawn:complete", {
|
|
932
|
-
id,
|
|
933
|
-
task,
|
|
934
|
-
stats
|
|
935
|
-
});
|
|
936
|
-
const response = extractText(agent.turns.at(-1));
|
|
937
|
-
return [
|
|
938
|
-
`[sub-agent ${id}] Completed in ${stats.turns} turns (${stats.elapsed}ms)`,
|
|
939
|
-
`Tokens: ${stats.totalIn} in / ${stats.totalOut} out`,
|
|
940
|
-
"",
|
|
941
|
-
response || "(no text response)"
|
|
942
|
-
].join("\n");
|
|
943
|
-
} catch (err) {
|
|
944
|
-
await ctx.hooks.callHook("spawn:error", { id, task, error: err });
|
|
945
|
-
return `[sub-agent ${id}] Error: ${err.message}`;
|
|
946
|
-
} finally {
|
|
947
|
-
activeCount--;
|
|
948
|
-
await agent.destroy();
|
|
949
|
-
children.delete(id);
|
|
950
|
-
}
|
|
1088
|
+
async execute({ path, content }, ctx) {
|
|
1089
|
+
await ctx.execution.writeFile(ctx.handle, path, content);
|
|
1090
|
+
return `Wrote ${content.length} bytes to ${path}`;
|
|
951
1091
|
}
|
|
952
1092
|
};
|
|
953
1093
|
}
|
|
954
1094
|
});
|
|
955
1095
|
|
|
956
|
-
// src/tools/list-files.ts
|
|
957
|
-
import { existsSync, readdirSync, statSync } from "fs";
|
|
958
|
-
import { resolve } from "path";
|
|
959
|
-
var cwd = process.cwd();
|
|
960
|
-
function safePath(p) {
|
|
961
|
-
const resolved = resolve(cwd, p);
|
|
962
|
-
if (!resolved.startsWith(cwd))
|
|
963
|
-
throw new Error(`Path escapes working directory: ${p}`);
|
|
964
|
-
return resolved;
|
|
965
|
-
}
|
|
966
|
-
var listFiles = {
|
|
967
|
-
spec: {
|
|
968
|
-
name: "list_files",
|
|
969
|
-
description: "List files and directories at the given path (relative to project root).",
|
|
970
|
-
input_schema: {
|
|
971
|
-
type: "object",
|
|
972
|
-
properties: {
|
|
973
|
-
path: { type: "string", description: 'Relative directory path (default: ".")' }
|
|
974
|
-
},
|
|
975
|
-
required: []
|
|
976
|
-
}
|
|
977
|
-
},
|
|
978
|
-
async execute({ path }, _ctx) {
|
|
979
|
-
const target = safePath(path || ".");
|
|
980
|
-
if (!existsSync(target))
|
|
981
|
-
return `Directory not found: ${path}`;
|
|
982
|
-
const entries = readdirSync(target);
|
|
983
|
-
return entries.map((name) => {
|
|
984
|
-
const full = resolve(target, name);
|
|
985
|
-
const isDir = statSync(full).isDirectory();
|
|
986
|
-
return `${isDir ? "\u{1F4C1}" : "\u{1F4C4}"} ${name}`;
|
|
987
|
-
}).join("\n");
|
|
988
|
-
}
|
|
989
|
-
};
|
|
990
|
-
|
|
991
|
-
// src/tools/read-file.ts
|
|
992
|
-
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
993
|
-
import { resolve as resolve2 } from "path";
|
|
994
|
-
var cwd2 = process.cwd();
|
|
995
|
-
function safePath2(p) {
|
|
996
|
-
const resolved = resolve2(cwd2, p);
|
|
997
|
-
if (!resolved.startsWith(cwd2))
|
|
998
|
-
throw new Error(`Path escapes working directory: ${p}`);
|
|
999
|
-
return resolved;
|
|
1000
|
-
}
|
|
1001
|
-
var readFile = {
|
|
1002
|
-
spec: {
|
|
1003
|
-
name: "read_file",
|
|
1004
|
-
description: "Read the contents of a file at the given path (relative to project root).",
|
|
1005
|
-
input_schema: {
|
|
1006
|
-
type: "object",
|
|
1007
|
-
properties: {
|
|
1008
|
-
path: { type: "string", description: "Relative file path" }
|
|
1009
|
-
},
|
|
1010
|
-
required: ["path"]
|
|
1011
|
-
}
|
|
1012
|
-
},
|
|
1013
|
-
async execute({ path }, _ctx) {
|
|
1014
|
-
const target = safePath2(path);
|
|
1015
|
-
if (!existsSync2(target))
|
|
1016
|
-
return `File not found: ${path}`;
|
|
1017
|
-
return readFileSync(target, "utf-8");
|
|
1018
|
-
}
|
|
1019
|
-
};
|
|
1020
|
-
|
|
1021
|
-
// src/tools/shell.ts
|
|
1022
|
-
import { execSync } from "child_process";
|
|
1023
|
-
var cwd3 = process.cwd();
|
|
1024
|
-
var shell = {
|
|
1025
|
-
spec: {
|
|
1026
|
-
name: "shell",
|
|
1027
|
-
description: "Execute a shell command and return stdout+stderr. Runs in the project root.",
|
|
1028
|
-
input_schema: {
|
|
1029
|
-
type: "object",
|
|
1030
|
-
properties: {
|
|
1031
|
-
command: { type: "string", description: "The shell command to run" }
|
|
1032
|
-
},
|
|
1033
|
-
required: ["command"]
|
|
1034
|
-
}
|
|
1035
|
-
},
|
|
1036
|
-
async execute({ command }, _ctx) {
|
|
1037
|
-
try {
|
|
1038
|
-
const out = execSync(command, {
|
|
1039
|
-
cwd: cwd3,
|
|
1040
|
-
encoding: "utf-8",
|
|
1041
|
-
timeout: 3e4,
|
|
1042
|
-
maxBuffer: 1024 * 1024,
|
|
1043
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
1044
|
-
});
|
|
1045
|
-
return out || "(no output)";
|
|
1046
|
-
} catch (err) {
|
|
1047
|
-
const stderr = err.stderr?.toString() ?? "";
|
|
1048
|
-
const stdout = err.stdout?.toString() ?? "";
|
|
1049
|
-
return `Exit code ${err.status ?? 1}
|
|
1050
|
-
${stdout}
|
|
1051
|
-
${stderr}`.trim();
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
};
|
|
1055
|
-
|
|
1056
1096
|
// src/tools/index.ts
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
const resolved = resolve4(cwd4, p);
|
|
1066
|
-
if (!resolved.startsWith(cwd4))
|
|
1067
|
-
throw new Error(`Path escapes working directory: ${p}`);
|
|
1068
|
-
return resolved;
|
|
1069
|
-
}
|
|
1070
|
-
var writeFile2 = {
|
|
1071
|
-
spec: {
|
|
1072
|
-
name: "write_file",
|
|
1073
|
-
description: "Write content to a file. Creates parent directories if needed.",
|
|
1074
|
-
input_schema: {
|
|
1075
|
-
type: "object",
|
|
1076
|
-
properties: {
|
|
1077
|
-
path: { type: "string", description: "Relative file path" },
|
|
1078
|
-
content: { type: "string", description: "File content to write" }
|
|
1079
|
-
},
|
|
1080
|
-
required: ["path", "content"]
|
|
1081
|
-
}
|
|
1082
|
-
},
|
|
1083
|
-
async execute({ path, content }, _ctx) {
|
|
1084
|
-
const target = safePath3(path);
|
|
1085
|
-
mkdirSync(dirname2(target), { recursive: true });
|
|
1086
|
-
writeFileSync(target, content);
|
|
1087
|
-
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();
|
|
1088
1105
|
}
|
|
1089
|
-
};
|
|
1106
|
+
});
|
|
1090
1107
|
|
|
1091
1108
|
export {
|
|
1092
1109
|
createDockerContext,
|
|
1093
1110
|
createProcessContext,
|
|
1094
1111
|
createSandboxContext,
|
|
1095
1112
|
init_contexts,
|
|
1096
|
-
validateToolArgs,
|
|
1097
|
-
createAgent,
|
|
1098
|
-
init_agent,
|
|
1099
1113
|
listFiles,
|
|
1100
1114
|
readFile,
|
|
1101
1115
|
shell,
|
|
1102
|
-
spawn,
|
|
1103
1116
|
createSpawnTool,
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
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
|
|
1107
1128
|
};
|