stitchkit 0.70.6 → 0.72.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 +1 -1
- package/dist/agent-runtime/coding-tool-contract.d.ts +11 -1
- package/dist/agent-runtime/coding-tool-contract.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-files.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-listing.d.ts +15 -0
- package/dist/agent-runtime/coding-tool-listing.d.ts.map +1 -0
- package/dist/agent-runtime/coding-tool-paths.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-refusals.d.ts +59 -0
- package/dist/agent-runtime/coding-tool-refusals.d.ts.map +1 -0
- package/dist/agent-runtime/coding-tool-search-patch.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tools.d.ts +3 -1
- package/dist/agent-runtime/coding-tools.d.ts.map +1 -1
- package/dist/agent-runtime/compaction.d.ts +35 -0
- package/dist/agent-runtime/compaction.d.ts.map +1 -1
- package/dist/agent-runtime/contained-files.d.ts +21 -2
- package/dist/agent-runtime/contained-files.d.ts.map +1 -1
- package/dist/agent-runtime/provider-failure.d.ts +66 -0
- package/dist/agent-runtime/provider-failure.d.ts.map +1 -0
- package/dist/agent-runtime/run-execution.d.ts.map +1 -1
- package/dist/agent-runtime/runtime.d.ts +31 -1
- package/dist/agent-runtime/runtime.d.ts.map +1 -1
- package/dist/agent-runtime/schemas.d.ts +1 -0
- package/dist/agent-runtime/schemas.d.ts.map +1 -1
- package/dist/agent-runtime-coding-tools.js +438 -124
- package/dist/agent-runtime-harness.js +4 -4
- package/dist/agent-runtime-openrouter.d.ts +19 -0
- package/dist/agent-runtime-openrouter.d.ts.map +1 -1
- package/dist/agent-runtime-openrouter.js +2 -1
- package/dist/agent-runtime.d.ts +3 -2
- package/dist/agent-runtime.d.ts.map +1 -1
- package/dist/agent-runtime.js +118 -14
- package/dist/application/admission.d.ts +22 -2
- package/dist/application/admission.d.ts.map +1 -1
- package/dist/application/channel.d.ts +28 -0
- package/dist/application/channel.d.ts.map +1 -1
- package/dist/application/diagnostic-journal-contract.d.ts +20 -0
- package/dist/application/diagnostic-journal-contract.d.ts.map +1 -1
- package/dist/application/diagnostic-journal-lock.d.ts +17 -0
- package/dist/application/diagnostic-journal-lock.d.ts.map +1 -0
- package/dist/application/diagnostic-journal-manager.d.ts +2 -1
- package/dist/application/diagnostic-journal-manager.d.ts.map +1 -1
- package/dist/application/diagnostic-journal-storage.d.ts +4 -1
- package/dist/application/diagnostic-journal-storage.d.ts.map +1 -1
- package/dist/application/diagnostic-journal.d.ts +4 -2
- package/dist/application/diagnostic-journal.d.ts.map +1 -1
- package/dist/application-opentelemetry.js +1 -1
- package/dist/application.d.ts +3 -3
- package/dist/application.d.ts.map +1 -1
- package/dist/application.js +134 -21
- package/dist/browser/resumable.d.ts +56 -0
- package/dist/browser/resumable.d.ts.map +1 -0
- package/dist/cli.js +5 -5
- package/dist/{index-cx84zg25.js → index-118v0z41.js} +1 -1
- package/dist/{index-zpyj7hsv.js → index-3cwck0rm.js} +98 -33
- package/dist/{index-ejv31h14.js → index-7qy2ex0m.js} +1 -1
- package/dist/{index-trrf7nch.js → index-ezmn6ac6.js} +3 -3
- package/dist/{index-ekkt4gy9.js → index-jqtsc9mj.js} +2 -2
- package/dist/{index-hxtm2xr2.js → index-k2zczx1g.js} +1 -1
- package/dist/{index-by57nwhc.js → index-m668wzyc.js} +10 -2
- package/dist/{index-w9m1wznn.js → index-nemjkxjp.js} +118 -1
- package/dist/{index-tnazr5tc.js → index-pz7ytdga.js} +3 -3
- package/dist/{index-1z5xxfst.js → index-rqpdar1e.js} +102 -5
- package/dist/{index-qm87g51s.js → index-s4c8wy8m.js} +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +103 -14
- package/dist/node.js +2 -2
- package/dist/observability/index.js +1 -1
- package/dist/primitives/audit.d.ts +52 -0
- package/dist/primitives/audit.d.ts.map +1 -0
- package/dist/primitives/deadline.d.ts +39 -0
- package/dist/primitives/deadline.d.ts.map +1 -0
- package/dist/primitives/decimal.d.ts +10 -0
- package/dist/primitives/decimal.d.ts.map +1 -0
- package/dist/primitives/delivery.d.ts +96 -0
- package/dist/primitives/delivery.d.ts.map +1 -0
- package/dist/primitives/event.d.ts +42 -0
- package/dist/primitives/event.d.ts.map +1 -0
- package/dist/primitives/export-operation.d.ts +89 -0
- package/dist/primitives/export-operation.d.ts.map +1 -0
- package/dist/primitives/index.d.ts +12 -0
- package/dist/primitives/index.d.ts.map +1 -0
- package/dist/primitives/lifecycle.d.ts +90 -0
- package/dist/primitives/lifecycle.d.ts.map +1 -0
- package/dist/primitives/migration-checks.d.ts +15 -0
- package/dist/primitives/migration-checks.d.ts.map +1 -0
- package/dist/primitives/money.d.ts +43 -0
- package/dist/primitives/money.d.ts.map +1 -0
- package/dist/primitives/owner-scope.d.ts +30 -0
- package/dist/primitives/owner-scope.d.ts.map +1 -0
- package/dist/primitives/permission.d.ts +28 -0
- package/dist/primitives/permission.d.ts.map +1 -0
- package/dist/primitives/quantity.d.ts +57 -0
- package/dist/primitives/quantity.d.ts.map +1 -0
- package/dist/primitives.d.ts +3 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +750 -0
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +4 -2
- package/dist/server/request.d.ts +19 -0
- package/dist/server/request.d.ts.map +1 -1
- package/dist/telegram/init-data.d.ts +134 -0
- package/dist/telegram/init-data.d.ts.map +1 -0
- package/dist/telegram/send-failure.d.ts +73 -0
- package/dist/telegram/send-failure.d.ts.map +1 -0
- package/dist/telegram.d.ts +3 -0
- package/dist/telegram.d.ts.map +1 -0
- package/dist/telegram.js +224 -0
- package/dist/tool-invoker.js +4 -4
- package/dist/tools.js +7 -7
- package/llms-full.txt +510 -10
- package/llms.txt +1 -0
- package/native/darwin-arm64.node +0 -0
- package/native/darwin-x64.node +0 -0
- package/package.json +11 -3
|
@@ -2,13 +2,15 @@ import {
|
|
|
2
2
|
assertContainedFileCurrent,
|
|
3
3
|
assertContainedParentCurrent,
|
|
4
4
|
containedEntryMetadata,
|
|
5
|
+
listContainedDirectory,
|
|
6
|
+
missingContainedDirectories,
|
|
5
7
|
openContainedFile,
|
|
6
8
|
openContainedParent,
|
|
7
9
|
openContainedParentFile,
|
|
8
10
|
readContainedUtf8Handle,
|
|
9
11
|
scanContainedFiles,
|
|
10
12
|
writeContainedFile
|
|
11
|
-
} from "./index-
|
|
13
|
+
} from "./index-rqpdar1e.js";
|
|
12
14
|
import {
|
|
13
15
|
defineRuntimeTool
|
|
14
16
|
} from "./index-wwst0td5.js";
|
|
@@ -16,6 +18,7 @@ import"./index-22by16v6.js";
|
|
|
16
18
|
import"./index-cby4ar3v.js";
|
|
17
19
|
import"./index-vj3vvpaa.js";
|
|
18
20
|
import {
|
|
21
|
+
AppError,
|
|
19
22
|
conflict,
|
|
20
23
|
forbidden
|
|
21
24
|
} from "./index-0w9abg87.js";
|
|
@@ -23,8 +26,8 @@ import"./index-qyrqwr4c.js";
|
|
|
23
26
|
import"./index-6k1937bx.js";
|
|
24
27
|
|
|
25
28
|
// src/agent-runtime/coding-tools.ts
|
|
26
|
-
import
|
|
27
|
-
import { z as
|
|
29
|
+
import path4 from "node:path";
|
|
30
|
+
import { z as z4 } from "zod";
|
|
28
31
|
|
|
29
32
|
// src/agent-runtime/coding-tool-contract.ts
|
|
30
33
|
import { z } from "zod";
|
|
@@ -36,6 +39,7 @@ var AgentCodingToolLimitsSchema = z.object({
|
|
|
36
39
|
maxShellArgumentBytes: z.int().positive(),
|
|
37
40
|
maxShellOutputBytes: z.int().positive(),
|
|
38
41
|
maxArtifactBytes: z.int().positive(),
|
|
42
|
+
maxListEntries: z.int().positive(),
|
|
39
43
|
maxSearchResults: z.int().positive(),
|
|
40
44
|
maxSearchFiles: z.int().positive(),
|
|
41
45
|
maxSearchDepth: z.int().nonnegative(),
|
|
@@ -48,7 +52,8 @@ var AgentCodingToolAuthorizationSchema = z.discriminatedUnion("operation", [
|
|
|
48
52
|
operation: z.literal("write"),
|
|
49
53
|
path: z.string().min(1),
|
|
50
54
|
bytes: z.int().nonnegative(),
|
|
51
|
-
overwrite: z.boolean()
|
|
55
|
+
overwrite: z.boolean(),
|
|
56
|
+
createsDirectories: z.array(z.string().min(1))
|
|
52
57
|
}).strict(),
|
|
53
58
|
z.object({
|
|
54
59
|
operation: z.literal("search"),
|
|
@@ -56,7 +61,7 @@ var AgentCodingToolAuthorizationSchema = z.discriminatedUnion("operation", [
|
|
|
56
61
|
mode: z.enum(["path", "content"])
|
|
57
62
|
}).strict(),
|
|
58
63
|
z.object({
|
|
59
|
-
operation: z.literal("
|
|
64
|
+
operation: z.literal("edit"),
|
|
60
65
|
path: z.string().min(1),
|
|
61
66
|
baseSha256: z.string().length(64),
|
|
62
67
|
resultSha256: z.string().length(64),
|
|
@@ -64,6 +69,12 @@ var AgentCodingToolAuthorizationSchema = z.discriminatedUnion("operation", [
|
|
|
64
69
|
replacements: z.int().positive(),
|
|
65
70
|
dryRun: z.boolean()
|
|
66
71
|
}).strict(),
|
|
72
|
+
z.object({ operation: z.literal("list"), path: z.string().min(1) }).strict(),
|
|
73
|
+
z.object({
|
|
74
|
+
operation: z.literal("glob"),
|
|
75
|
+
pattern: z.string().min(1),
|
|
76
|
+
path: z.string().min(1)
|
|
77
|
+
}).strict(),
|
|
67
78
|
z.object({
|
|
68
79
|
operation: z.literal("artifact-read"),
|
|
69
80
|
reference: z.string().min(1),
|
|
@@ -95,7 +106,11 @@ var FileWriteInputSchema = z.object({
|
|
|
95
106
|
content: z.string(),
|
|
96
107
|
overwrite: z.boolean().default(false)
|
|
97
108
|
}).strict();
|
|
98
|
-
var FileWriteOutputSchema = z.object({
|
|
109
|
+
var FileWriteOutputSchema = z.object({
|
|
110
|
+
path: z.string().min(1),
|
|
111
|
+
bytes: z.int().nonnegative(),
|
|
112
|
+
createdDirectories: z.array(z.string().min(1))
|
|
113
|
+
}).strict();
|
|
99
114
|
function createShellInputSchema(executableNames) {
|
|
100
115
|
if (executableNames.length === 0) {
|
|
101
116
|
throw new Error("A command tool requires at least one executable alias");
|
|
@@ -132,6 +147,7 @@ var DEFAULT_LIMITS = {
|
|
|
132
147
|
maxShellArgumentBytes: 65536,
|
|
133
148
|
maxShellOutputBytes: 262144,
|
|
134
149
|
maxArtifactBytes: 4194304,
|
|
150
|
+
maxListEntries: 500,
|
|
135
151
|
maxSearchResults: 100,
|
|
136
152
|
maxSearchFiles: 1e4,
|
|
137
153
|
maxSearchDepth: 32,
|
|
@@ -149,23 +165,89 @@ import { realpath as realpath2 } from "node:fs/promises";
|
|
|
149
165
|
// src/agent-runtime/coding-tool-paths.ts
|
|
150
166
|
import { lstat, realpath } from "node:fs/promises";
|
|
151
167
|
import path from "node:path";
|
|
168
|
+
|
|
169
|
+
// src/agent-runtime/coding-tool-refusals.ts
|
|
170
|
+
var REFUSAL_STATUS = {
|
|
171
|
+
BAD_REQUEST: 400,
|
|
172
|
+
FORBIDDEN: 403,
|
|
173
|
+
NOT_FOUND: 404,
|
|
174
|
+
CONFLICT: 409
|
|
175
|
+
};
|
|
176
|
+
function codingRefusal(code, message, options = {}) {
|
|
177
|
+
throw new AppError(code, message, REFUSAL_STATUS[code], { message, ...options.details }, options.hint);
|
|
178
|
+
}
|
|
179
|
+
function codingPathRefusal(code, message, path, options = {}) {
|
|
180
|
+
codingRefusal(code, message, {
|
|
181
|
+
details: { path, ...options.details },
|
|
182
|
+
...options.hint && { hint: options.hint }
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function refuseMissingCodingPath(error, relative) {
|
|
186
|
+
const code = error?.code;
|
|
187
|
+
if (error instanceof Error && error.message.includes("is not a regular file")) {
|
|
188
|
+
codingPathRefusal("BAD_REQUEST", "This path is not a regular file", relative, {
|
|
189
|
+
hint: "Use list_directory to see what is here."
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
if (code === "ENOENT") {
|
|
193
|
+
codingPathRefusal("NOT_FOUND", "This path does not exist", relative, {
|
|
194
|
+
hint: "Use list_directory or glob to find the right path."
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
if (code === "ENOTDIR") {
|
|
198
|
+
codingPathRefusal("BAD_REQUEST", "A segment of this path is not a directory", relative, {
|
|
199
|
+
hint: "Check the path with list_directory."
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (code === "ELOOP") {
|
|
203
|
+
codingPathRefusal("FORBIDDEN", "This path is a symlink, which is not followed", relative, {
|
|
204
|
+
hint: "Read or write the target directly, by its own workspace-relative path."
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
if (code === "EISDIR") {
|
|
208
|
+
codingPathRefusal("BAD_REQUEST", "This path is not a regular file", relative, {
|
|
209
|
+
hint: "Use list_directory to see what is here."
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// src/agent-runtime/coding-tool-paths.ts
|
|
152
216
|
function within(root, target) {
|
|
153
217
|
const relative = path.relative(root, target);
|
|
154
218
|
return relative === "" || !relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative);
|
|
155
219
|
}
|
|
156
220
|
function inputPath(root, requested, maxPathBytes) {
|
|
157
221
|
if (new TextEncoder().encode(requested).byteLength > maxPathBytes) {
|
|
158
|
-
|
|
222
|
+
codingRefusal("BAD_REQUEST", `Path exceeds the ${maxPathBytes}-byte limit`, {
|
|
223
|
+
details: { maxPathBytes },
|
|
224
|
+
hint: "Use a shorter workspace-relative path."
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
if (path.isAbsolute(requested)) {
|
|
228
|
+
codingRefusal("BAD_REQUEST", "Paths must be relative to the workspace root", {
|
|
229
|
+
details: { path: requested },
|
|
230
|
+
hint: "Drop the leading slash and pass a path relative to the workspace root."
|
|
231
|
+
});
|
|
159
232
|
}
|
|
160
|
-
if (path.isAbsolute(requested))
|
|
161
|
-
throw new Error("Coding tool paths must be relative");
|
|
162
233
|
const resolved = path.resolve(root, requested);
|
|
163
|
-
if (!within(root, resolved))
|
|
164
|
-
|
|
234
|
+
if (!within(root, resolved)) {
|
|
235
|
+
codingRefusal("FORBIDDEN", "Path escapes the workspace root", {
|
|
236
|
+
details: { path: requested },
|
|
237
|
+
hint: "Stay inside the workspace; `..` segments that leave the root are refused."
|
|
238
|
+
});
|
|
239
|
+
}
|
|
165
240
|
return resolved;
|
|
166
241
|
}
|
|
167
242
|
function boundedCodingRelativePath(requested, maxPathBytes) {
|
|
168
243
|
inputPath(path.parse(process.cwd()).root, requested, maxPathBytes);
|
|
244
|
+
const segments = requested.split(/[\\/]/u);
|
|
245
|
+
if (segments.some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
246
|
+
codingRefusal("FORBIDDEN", "Path segments must name real entries under the root", {
|
|
247
|
+
details: { path: requested },
|
|
248
|
+
hint: "Pass a plain workspace-relative path — `.`, `..` and empty segments are refused."
|
|
249
|
+
});
|
|
250
|
+
}
|
|
169
251
|
return requested;
|
|
170
252
|
}
|
|
171
253
|
async function existingCodingPath(root, requested, maxPathBytes) {
|
|
@@ -237,7 +319,7 @@ function createFileCodingTools(config, limits) {
|
|
|
237
319
|
handler: async ({ input }) => {
|
|
238
320
|
const root = await realpath2(config.root);
|
|
239
321
|
const relative = boundedCodingRelativePath(input.path, limits.maxPathBytes);
|
|
240
|
-
const handle = await openContainedFile(root, relative);
|
|
322
|
+
const handle = await openContainedFile(root, relative).catch((error) => refuseMissingCodingPath(error, relative));
|
|
241
323
|
const maximum = Math.min(input.maxBytes ?? limits.maxReadBytes, limits.maxReadBytes);
|
|
242
324
|
let selected;
|
|
243
325
|
let size;
|
|
@@ -246,8 +328,11 @@ function createFileCodingTools(config, limits) {
|
|
|
246
328
|
await authorizeCodingTool(config, { operation: "read", path: relative });
|
|
247
329
|
await assertContainedFileCurrent(root, relative, handle);
|
|
248
330
|
const metadata = await handle.stat();
|
|
249
|
-
if (!metadata.isFile())
|
|
250
|
-
|
|
331
|
+
if (!metadata.isFile()) {
|
|
332
|
+
codingPathRefusal("BAD_REQUEST", "This path is not a regular file", relative, {
|
|
333
|
+
hint: "Use list_directory to see what is here."
|
|
334
|
+
});
|
|
335
|
+
}
|
|
251
336
|
size = metadata.size;
|
|
252
337
|
const length = Math.min(maximum, Math.max(0, size - input.offset));
|
|
253
338
|
selected = Buffer.alloc(length);
|
|
@@ -281,21 +366,46 @@ function createFileCodingTools(config, limits) {
|
|
|
281
366
|
const root = await realpath2(config.root);
|
|
282
367
|
const relative = boundedCodingRelativePath(input.path, limits.maxPathBytes);
|
|
283
368
|
const bytes = Buffer.byteLength(input.content);
|
|
284
|
-
if (bytes > limits.maxWriteBytes)
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
await authorizeCodingTool(config, {
|
|
289
|
-
operation: "write",
|
|
290
|
-
path: relative,
|
|
291
|
-
bytes,
|
|
292
|
-
overwrite: input.overwrite
|
|
369
|
+
if (bytes > limits.maxWriteBytes) {
|
|
370
|
+
codingPathRefusal("BAD_REQUEST", `The content is ${bytes} bytes, over the ${limits.maxWriteBytes}-byte limit`, relative, {
|
|
371
|
+
details: { bytes, maxWriteBytes: limits.maxWriteBytes },
|
|
372
|
+
hint: "Write a smaller file, or split it."
|
|
293
373
|
});
|
|
374
|
+
}
|
|
375
|
+
const createsDirectories = await missingContainedDirectories(root, relative).catch((error) => {
|
|
376
|
+
if (error.code === "ENOTDIR") {
|
|
377
|
+
codingPathRefusal("CONFLICT", "A segment of this path is not a directory", relative, {
|
|
378
|
+
hint: "Write under a different path, or remove the file blocking it."
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
throw error;
|
|
382
|
+
});
|
|
383
|
+
await authorizeCodingTool(config, {
|
|
384
|
+
operation: "write",
|
|
385
|
+
path: relative,
|
|
386
|
+
bytes,
|
|
387
|
+
overwrite: input.overwrite,
|
|
388
|
+
createsDirectories
|
|
389
|
+
});
|
|
390
|
+
const parent = await openContainedParent(root, relative, { create: true }).catch((error) => {
|
|
391
|
+
const code = error.code;
|
|
392
|
+
if (code === "ENOTDIR" || error instanceof Error && error.message.includes("ancestor is not a directory")) {
|
|
393
|
+
codingPathRefusal("CONFLICT", "A segment of this path is not a directory", relative, {
|
|
394
|
+
details: { createsDirectories },
|
|
395
|
+
hint: "Write under a different path, or remove the file blocking it."
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
throw error;
|
|
399
|
+
});
|
|
400
|
+
try {
|
|
294
401
|
await assertContainedParentCurrent(root, relative, parent.handle);
|
|
402
|
+
const current = await containedEntryMetadata(parent);
|
|
295
403
|
if (input.overwrite) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
404
|
+
if (current?.isSymbolicLink()) {
|
|
405
|
+
codingPathRefusal("FORBIDDEN", "This path is a symlink", relative, {
|
|
406
|
+
hint: "Coding tools never write through symlinks; write to the target directly."
|
|
407
|
+
});
|
|
408
|
+
}
|
|
299
409
|
await writeContainedFile({
|
|
300
410
|
parent,
|
|
301
411
|
content: input.content,
|
|
@@ -303,19 +413,23 @@ function createFileCodingTools(config, limits) {
|
|
|
303
413
|
...current && { mode: current.mode }
|
|
304
414
|
});
|
|
305
415
|
} else {
|
|
416
|
+
if (current) {
|
|
417
|
+
codingPathRefusal("CONFLICT", "This file already exists", relative, {
|
|
418
|
+
hint: "Pass overwrite: true to replace it, or edit_file to change part of it."
|
|
419
|
+
});
|
|
420
|
+
}
|
|
306
421
|
await writeContainedFile({ parent, content: input.content, replace: false });
|
|
307
422
|
}
|
|
308
423
|
} finally {
|
|
309
424
|
await parent.handle.close();
|
|
310
425
|
}
|
|
311
|
-
return { path: relative, bytes };
|
|
426
|
+
return { path: relative, bytes, createdDirectories: createsDirectories };
|
|
312
427
|
}
|
|
313
428
|
});
|
|
314
429
|
return [read, write];
|
|
315
430
|
}
|
|
316
431
|
|
|
317
|
-
// src/agent-runtime/coding-tool-
|
|
318
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
432
|
+
// src/agent-runtime/coding-tool-listing.ts
|
|
319
433
|
import { realpath as realpath3 } from "node:fs/promises";
|
|
320
434
|
import path2 from "node:path";
|
|
321
435
|
import { z as z2 } from "zod";
|
|
@@ -328,29 +442,190 @@ var DEFAULT_EXCLUDED_DIRECTORIES = [
|
|
|
328
442
|
"dist",
|
|
329
443
|
"node_modules"
|
|
330
444
|
];
|
|
331
|
-
var
|
|
332
|
-
var
|
|
333
|
-
|
|
445
|
+
var ListInputSchema = z2.object({ path: z2.string().min(1).default(".") }).strict();
|
|
446
|
+
var ListOutputSchema = z2.object({
|
|
447
|
+
path: z2.string().min(1),
|
|
448
|
+
entries: z2.array(z2.object({
|
|
449
|
+
name: z2.string().min(1),
|
|
450
|
+
kind: z2.enum(["file", "directory", "symlink", "other"]),
|
|
451
|
+
bytes: z2.int().nonnegative().optional(),
|
|
452
|
+
excluded: z2.boolean().optional()
|
|
453
|
+
}).strict()),
|
|
454
|
+
truncated: z2.boolean()
|
|
455
|
+
}).strict();
|
|
456
|
+
var GlobInputSchema = z2.object({ pattern: z2.string().min(1), path: z2.string().min(1).default(".") }).strict();
|
|
457
|
+
var GlobOutputSchema = z2.object({
|
|
458
|
+
paths: z2.array(z2.string().min(1)),
|
|
334
459
|
truncated: z2.boolean(),
|
|
335
|
-
|
|
460
|
+
resultTruncated: z2.boolean(),
|
|
336
461
|
skippedDirectories: z2.int().nonnegative(),
|
|
337
|
-
|
|
462
|
+
scannedFiles: z2.int().nonnegative()
|
|
338
463
|
}).strict();
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
464
|
+
function compileWorkspaceGlob(pattern) {
|
|
465
|
+
let source = "";
|
|
466
|
+
for (let index = 0;index < pattern.length; index += 1) {
|
|
467
|
+
const character = pattern[index];
|
|
468
|
+
if (character === "*") {
|
|
469
|
+
if (pattern[index + 1] === "*") {
|
|
470
|
+
if (pattern[index + 2] === "/") {
|
|
471
|
+
source += "(?:[^/]+/)*";
|
|
472
|
+
index += 2;
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
source += ".*";
|
|
476
|
+
index += 1;
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
source += "[^/]*";
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
if (character === "?") {
|
|
483
|
+
source += "[^/]";
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
source += character?.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") ?? "";
|
|
487
|
+
}
|
|
488
|
+
return new RegExp(`^${source}$`);
|
|
489
|
+
}
|
|
490
|
+
function createListingCodingTools(config, limits) {
|
|
491
|
+
const excluded = new Set(config.search?.excludeDirectories ?? DEFAULT_EXCLUDED_DIRECTORIES);
|
|
492
|
+
const list = defineRuntimeTool({
|
|
493
|
+
name: "list_directory",
|
|
494
|
+
description: "List the direct entries of one workspace directory.",
|
|
495
|
+
identity: { serviceName: "coding", action: "list-directory", method: "POST" },
|
|
496
|
+
input: ListInputSchema,
|
|
497
|
+
output: ListOutputSchema,
|
|
498
|
+
transports: ["AGENT"],
|
|
499
|
+
handler: async ({ input }) => {
|
|
500
|
+
const root = await realpath3(config.root);
|
|
501
|
+
const relative = input.path === "." ? "." : boundedCodingRelativePath(input.path, limits.maxPathBytes);
|
|
502
|
+
await authorizeCodingTool(config, { operation: "list", path: relative });
|
|
503
|
+
const listing = await listContainedDirectory(root, relative, limits.maxListEntries).catch((error) => {
|
|
504
|
+
if (error instanceof Error && error.message.includes("ancestor is not a directory")) {
|
|
505
|
+
codingPathRefusal("BAD_REQUEST", "This path is not a directory", relative, {
|
|
506
|
+
hint: "Pass a directory; use read_file for a file."
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
if (error.code === "ENOENT") {
|
|
510
|
+
codingPathRefusal("NOT_FOUND", "This directory does not exist", relative, {
|
|
511
|
+
hint: "List a parent directory to see what is there."
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
return refuseMissingCodingPath(error, relative);
|
|
515
|
+
});
|
|
516
|
+
return {
|
|
517
|
+
path: relative,
|
|
518
|
+
entries: listing.entries.map((entry) => ({
|
|
519
|
+
...entry,
|
|
520
|
+
...entry.kind === "directory" && excluded.has(entry.name) && { excluded: true }
|
|
521
|
+
})),
|
|
522
|
+
truncated: listing.truncated
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
const glob = defineRuntimeTool({
|
|
527
|
+
name: "glob",
|
|
528
|
+
description: "List workspace files matching a `**`/`*`/`?` pattern.",
|
|
529
|
+
identity: { serviceName: "coding", action: "glob", method: "POST" },
|
|
530
|
+
input: GlobInputSchema,
|
|
531
|
+
output: GlobOutputSchema,
|
|
532
|
+
transports: ["AGENT"],
|
|
533
|
+
handler: async ({ input }) => {
|
|
534
|
+
const relative = input.path === "." ? "." : boundedCodingRelativePath(input.path, limits.maxPathBytes);
|
|
535
|
+
await authorizeCodingTool(config, {
|
|
536
|
+
operation: "glob",
|
|
537
|
+
pattern: input.pattern,
|
|
538
|
+
path: relative
|
|
539
|
+
});
|
|
540
|
+
let matcher;
|
|
541
|
+
try {
|
|
542
|
+
matcher = compileWorkspaceGlob(input.pattern);
|
|
543
|
+
} catch {
|
|
544
|
+
codingRefusal("BAD_REQUEST", "This glob pattern could not be compiled", {
|
|
545
|
+
details: { pattern: input.pattern },
|
|
546
|
+
hint: "Use only `**`, `*` and `?`."
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
const root = await realpath3(config.root);
|
|
550
|
+
const scan = await scanContainedFiles({
|
|
551
|
+
root,
|
|
552
|
+
maxDepth: limits.maxSearchDepth,
|
|
553
|
+
maxFiles: limits.maxSearchFiles,
|
|
554
|
+
symlinks: "skip",
|
|
555
|
+
excludeDirectory: (directory) => directory.split(path2.sep).some((segment) => excluded.has(segment))
|
|
556
|
+
});
|
|
557
|
+
const prefix = relative === "." ? "" : `${relative}${path2.sep}`;
|
|
558
|
+
const matched = scan.files.filter((file) => file.relative.startsWith(prefix)).map((file) => file.relative).filter((candidate) => matcher.test(candidate.slice(prefix.length))).sort();
|
|
559
|
+
const paths = matched.slice(0, limits.maxSearchResults);
|
|
560
|
+
return {
|
|
561
|
+
paths,
|
|
562
|
+
truncated: scan.truncated,
|
|
563
|
+
resultTruncated: matched.length > paths.length,
|
|
564
|
+
skippedDirectories: scan.skippedDirectories,
|
|
565
|
+
scannedFiles: scan.files.length
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
return [list, glob];
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// src/agent-runtime/coding-tool-search-patch.ts
|
|
573
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
574
|
+
import { realpath as realpath4 } from "node:fs/promises";
|
|
575
|
+
import path3 from "node:path";
|
|
576
|
+
import { z as z3 } from "zod";
|
|
577
|
+
var SearchInputSchema = z3.object({
|
|
578
|
+
query: z3.string().min(1),
|
|
579
|
+
mode: z3.enum(["path", "content"]).default("content"),
|
|
580
|
+
regex: z3.boolean().default(false),
|
|
581
|
+
context: z3.int().nonnegative().max(10).default(0),
|
|
582
|
+
include: z3.string().min(1).optional()
|
|
346
583
|
}).strict();
|
|
347
|
-
var
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
584
|
+
var SearchOutputSchema = z3.object({
|
|
585
|
+
matches: z3.array(z3.object({
|
|
586
|
+
path: z3.string().min(1),
|
|
587
|
+
line: z3.int().positive().optional(),
|
|
588
|
+
text: z3.string().optional(),
|
|
589
|
+
before: z3.array(z3.string()).optional(),
|
|
590
|
+
after: z3.array(z3.string()).optional()
|
|
591
|
+
}).strict()),
|
|
592
|
+
truncated: z3.boolean(),
|
|
593
|
+
scannedFiles: z3.int().nonnegative(),
|
|
594
|
+
skippedDirectories: z3.int().nonnegative(),
|
|
595
|
+
skippedSymlinks: z3.int().nonnegative()
|
|
596
|
+
}).strict();
|
|
597
|
+
function compileSearchRegex(pattern) {
|
|
598
|
+
if (/\\[1-9]/.test(pattern) || /\(\?<?[=!]/.test(pattern)) {
|
|
599
|
+
codingRefusal("BAD_REQUEST", "This pattern uses a construct search does not allow", {
|
|
600
|
+
details: { pattern },
|
|
601
|
+
hint: "Backreferences and lookaround are refused because they cannot be bounded. Rewrite without them."
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
try {
|
|
605
|
+
return new RegExp(pattern);
|
|
606
|
+
} catch (error) {
|
|
607
|
+
codingRefusal("BAD_REQUEST", "This pattern is not a valid regular expression", {
|
|
608
|
+
details: { pattern, reason: error instanceof Error ? error.message : "unknown" },
|
|
609
|
+
hint: "Fix the expression, or pass regex: false to search for it literally."
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
var MAX_SEARCHED_LINE_BYTES = 8192;
|
|
614
|
+
var EditInputSchema = z3.object({
|
|
615
|
+
path: z3.string().min(1),
|
|
616
|
+
oldText: z3.string().min(1),
|
|
617
|
+
newText: z3.string(),
|
|
618
|
+
replaceAll: z3.boolean().default(false),
|
|
619
|
+
expectedSha256: z3.string().length(64).optional(),
|
|
620
|
+
dryRun: z3.boolean().default(false)
|
|
621
|
+
}).strict();
|
|
622
|
+
var EditOutputSchema = z3.object({
|
|
623
|
+
path: z3.string().min(1),
|
|
624
|
+
baseSha256: z3.string().length(64),
|
|
625
|
+
sha256: z3.string().length(64),
|
|
626
|
+
replacements: z3.int().positive(),
|
|
627
|
+
bytes: z3.int().nonnegative(),
|
|
628
|
+
applied: z3.boolean()
|
|
354
629
|
}).strict();
|
|
355
630
|
function sha256(value) {
|
|
356
631
|
return createHash2("sha256").update(value).digest("hex");
|
|
@@ -369,7 +644,7 @@ function createSearchAndPatchCodingTools(config, limits) {
|
|
|
369
644
|
query: input.query,
|
|
370
645
|
mode: input.mode
|
|
371
646
|
});
|
|
372
|
-
const root = await
|
|
647
|
+
const root = await realpath4(config.root);
|
|
373
648
|
const excluded = new Set(config.search?.excludeDirectories ?? DEFAULT_EXCLUDED_DIRECTORIES);
|
|
374
649
|
const scan = await scanContainedFiles({
|
|
375
650
|
root,
|
|
@@ -380,13 +655,26 @@ function createSearchAndPatchCodingTools(config, limits) {
|
|
|
380
655
|
readMaxBytes: limits.maxReadBytes,
|
|
381
656
|
skipUnreadable: true
|
|
382
657
|
},
|
|
383
|
-
excludeDirectory: (relative) => relative.split(
|
|
658
|
+
excludeDirectory: (relative) => relative.split(path3.sep).some((segment) => excluded.has(segment))
|
|
384
659
|
});
|
|
660
|
+
const matcher = input.regex ? compileSearchRegex(input.query) : null;
|
|
661
|
+
const included = input.include ? compileWorkspaceGlob(input.include) : null;
|
|
662
|
+
const hit = (line) => {
|
|
663
|
+
if (line.length > MAX_SEARCHED_LINE_BYTES)
|
|
664
|
+
return false;
|
|
665
|
+
if (matcher) {
|
|
666
|
+
matcher.lastIndex = 0;
|
|
667
|
+
return matcher.test(line);
|
|
668
|
+
}
|
|
669
|
+
return line.includes(input.query);
|
|
670
|
+
};
|
|
385
671
|
const matches = [];
|
|
386
672
|
let truncated = false;
|
|
387
673
|
for (const file of scan.files) {
|
|
674
|
+
if (included && !included.test(file.relative))
|
|
675
|
+
continue;
|
|
388
676
|
if (input.mode === "path") {
|
|
389
|
-
if (file.relative
|
|
677
|
+
if (hit(file.relative))
|
|
390
678
|
matches.push({ path: file.relative });
|
|
391
679
|
} else {
|
|
392
680
|
const text = file.content?.text;
|
|
@@ -395,11 +683,20 @@ function createSearchAndPatchCodingTools(config, limits) {
|
|
|
395
683
|
const lines = text.split(`
|
|
396
684
|
`);
|
|
397
685
|
for (let index = 0;index < lines.length; index += 1) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
686
|
+
const line = lines[index];
|
|
687
|
+
if (line === undefined || !hit(line))
|
|
688
|
+
continue;
|
|
689
|
+
matches.push({
|
|
690
|
+
path: file.relative,
|
|
691
|
+
line: index + 1,
|
|
692
|
+
text: line,
|
|
693
|
+
...input.context > 0 && {
|
|
694
|
+
before: lines.slice(Math.max(0, index - input.context), index),
|
|
695
|
+
after: lines.slice(index + 1, index + 1 + input.context)
|
|
696
|
+
}
|
|
697
|
+
});
|
|
698
|
+
if (matches.length >= limits.maxSearchResults)
|
|
699
|
+
break;
|
|
403
700
|
}
|
|
404
701
|
}
|
|
405
702
|
if (matches.length >= limits.maxSearchResults) {
|
|
@@ -416,78 +713,92 @@ function createSearchAndPatchCodingTools(config, limits) {
|
|
|
416
713
|
};
|
|
417
714
|
}
|
|
418
715
|
});
|
|
419
|
-
const
|
|
420
|
-
name: "
|
|
421
|
-
description: "
|
|
422
|
-
identity: { serviceName: "coding", action: "
|
|
423
|
-
input:
|
|
424
|
-
output:
|
|
716
|
+
const edit = defineRuntimeTool({
|
|
717
|
+
name: "edit_file",
|
|
718
|
+
description: "Replace an exact snippet in one workspace file.",
|
|
719
|
+
identity: { serviceName: "coding", action: "edit-file", method: "POST" },
|
|
720
|
+
input: EditInputSchema,
|
|
721
|
+
output: EditOutputSchema,
|
|
425
722
|
transports: ["AGENT"],
|
|
426
723
|
handler: async ({ input }) => {
|
|
427
|
-
const root = await
|
|
724
|
+
const root = await realpath4(config.root);
|
|
428
725
|
const relative = boundedCodingRelativePath(input.path, limits.maxPathBytes);
|
|
429
|
-
const parent = await openContainedParent(root, relative);
|
|
726
|
+
const parent = await openContainedParent(root, relative).catch((error) => refuseMissingCodingPath(error, relative));
|
|
430
727
|
try {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
728
|
+
return await withCodingPathLock(`${root}:${relative}`, async () => {
|
|
729
|
+
const handle = await openContainedParentFile(parent).catch((error) => refuseMissingCodingPath(error, relative));
|
|
730
|
+
const read = await readContainedUtf8Handle(handle, limits.maxWriteBytes).finally(() => handle.close());
|
|
731
|
+
const source = read.text;
|
|
732
|
+
const baseSha256 = sha256(source);
|
|
733
|
+
if (input.expectedSha256 !== undefined && baseSha256 !== input.expectedSha256) {
|
|
734
|
+
conflict("The file changed since it was read", {
|
|
735
|
+
message: "The file changed since it was read",
|
|
736
|
+
path: relative,
|
|
737
|
+
expectedSha256: input.expectedSha256,
|
|
738
|
+
actualSha256: baseSha256
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
const count = textOccurrences(source, input.oldText);
|
|
742
|
+
if (count === 0) {
|
|
743
|
+
codingPathRefusal("NOT_FOUND", "oldText does not appear in this file", relative, {
|
|
744
|
+
details: { occurrences: 0 },
|
|
745
|
+
hint: "Read the file and copy the snippet exactly, including indentation."
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
if (!input.replaceAll && count !== 1) {
|
|
749
|
+
codingPathRefusal("CONFLICT", `oldText appears ${count} times, so the edit is ambiguous`, relative, {
|
|
750
|
+
details: { occurrences: count },
|
|
751
|
+
hint: "Lengthen the snippet until it is unique, or pass replaceAll: true."
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
const replacements = input.replaceAll ? count : 1;
|
|
755
|
+
const changed = input.replaceAll ? source.replaceAll(input.oldText, input.newText) : source.replace(input.oldText, input.newText);
|
|
756
|
+
const bytes = Buffer.byteLength(changed);
|
|
757
|
+
const resultSha256 = sha256(changed);
|
|
758
|
+
if (bytes > limits.maxWriteBytes) {
|
|
759
|
+
codingPathRefusal("BAD_REQUEST", `The result would be ${bytes} bytes, over the ${limits.maxWriteBytes}-byte limit`, relative, {
|
|
760
|
+
details: { bytes, maxWriteBytes: limits.maxWriteBytes },
|
|
761
|
+
hint: "Make a smaller edit, or split the file."
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
await authorizeCodingTool(config, {
|
|
765
|
+
operation: "edit",
|
|
766
|
+
path: relative,
|
|
767
|
+
baseSha256,
|
|
768
|
+
resultSha256,
|
|
769
|
+
resultBytes: bytes,
|
|
770
|
+
replacements,
|
|
771
|
+
dryRun: input.dryRun
|
|
772
|
+
});
|
|
773
|
+
await assertContainedParentCurrent(root, relative, parent.handle);
|
|
774
|
+
if (!input.dryRun) {
|
|
464
775
|
await writeContainedFile({
|
|
465
776
|
parent,
|
|
466
777
|
content: changed,
|
|
467
778
|
replace: true,
|
|
468
|
-
mode:
|
|
779
|
+
mode: read.mode
|
|
469
780
|
});
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
};
|
|
781
|
+
}
|
|
782
|
+
return {
|
|
783
|
+
path: relative,
|
|
784
|
+
baseSha256,
|
|
785
|
+
sha256: resultSha256,
|
|
786
|
+
replacements,
|
|
787
|
+
bytes,
|
|
788
|
+
applied: !input.dryRun
|
|
789
|
+
};
|
|
790
|
+
});
|
|
480
791
|
} finally {
|
|
481
792
|
await parent.handle.close();
|
|
482
793
|
}
|
|
483
794
|
}
|
|
484
795
|
});
|
|
485
|
-
return [search,
|
|
796
|
+
return [search, edit];
|
|
486
797
|
}
|
|
487
798
|
|
|
488
799
|
// src/agent-runtime/coding-tool-shell.ts
|
|
489
800
|
import { spawn } from "node:child_process";
|
|
490
|
-
import { realpath as
|
|
801
|
+
import { realpath as realpath5, stat } from "node:fs/promises";
|
|
491
802
|
async function runShell(input) {
|
|
492
803
|
const stdoutHeader = Buffer.from(`--- stdout ---
|
|
493
804
|
`);
|
|
@@ -654,7 +965,7 @@ function createShellCodingTool(config, limits) {
|
|
|
654
965
|
const executable = executables[input.executable];
|
|
655
966
|
if (!executable)
|
|
656
967
|
throw new Error("Coding tool executable is not declared");
|
|
657
|
-
const root = await
|
|
968
|
+
const root = await realpath5(config.root);
|
|
658
969
|
const cwd = await existingCodingPath(root, input.cwd, limits.maxPathBytes);
|
|
659
970
|
if (!(await stat(cwd.absolute)).isDirectory()) {
|
|
660
971
|
throw new Error("Coding tool cwd is not a directory");
|
|
@@ -684,7 +995,9 @@ function createShellCodingTool(config, limits) {
|
|
|
684
995
|
|
|
685
996
|
// src/agent-runtime/coding-tools.ts
|
|
686
997
|
var AGENT_CODING_TOOL_NAMES = {
|
|
687
|
-
|
|
998
|
+
editFile: "edit_file",
|
|
999
|
+
glob: "glob",
|
|
1000
|
+
listDirectory: "list_directory",
|
|
688
1001
|
readFile: "read_file",
|
|
689
1002
|
readOutput: "read_output",
|
|
690
1003
|
runCommand: "run_command",
|
|
@@ -692,10 +1005,10 @@ var AGENT_CODING_TOOL_NAMES = {
|
|
|
692
1005
|
writeFile: "write_file"
|
|
693
1006
|
};
|
|
694
1007
|
function createAgentCodingTools(config) {
|
|
695
|
-
if (!
|
|
1008
|
+
if (!path4.isAbsolute(config.root))
|
|
696
1009
|
throw new Error("Coding tool root must be absolute");
|
|
697
1010
|
for (const executable of Object.values(config.executables ?? {})) {
|
|
698
|
-
if (!
|
|
1011
|
+
if (!path4.isAbsolute(executable)) {
|
|
699
1012
|
throw new Error("Coding tool executables must be absolute paths");
|
|
700
1013
|
}
|
|
701
1014
|
}
|
|
@@ -707,17 +1020,17 @@ function createAgentCodingTools(config) {
|
|
|
707
1020
|
name: AGENT_CODING_TOOL_NAMES.readOutput,
|
|
708
1021
|
description: "Read a bounded byte slice from one opaque coding output artifact.",
|
|
709
1022
|
identity: { serviceName: "coding", action: "read-artifact", method: "POST" },
|
|
710
|
-
input:
|
|
711
|
-
reference:
|
|
712
|
-
offset:
|
|
713
|
-
maxBytes:
|
|
1023
|
+
input: z4.object({
|
|
1024
|
+
reference: z4.string().min(1),
|
|
1025
|
+
offset: z4.int().nonnegative().default(0),
|
|
1026
|
+
maxBytes: z4.int().positive().optional()
|
|
714
1027
|
}).strict(),
|
|
715
|
-
output:
|
|
716
|
-
reference:
|
|
717
|
-
offset:
|
|
718
|
-
text:
|
|
719
|
-
bytes:
|
|
720
|
-
totalBytes:
|
|
1028
|
+
output: z4.object({
|
|
1029
|
+
reference: z4.string().min(1),
|
|
1030
|
+
offset: z4.int().nonnegative(),
|
|
1031
|
+
text: z4.string(),
|
|
1032
|
+
bytes: z4.int().nonnegative(),
|
|
1033
|
+
totalBytes: z4.int().nonnegative().optional()
|
|
721
1034
|
}).strict(),
|
|
722
1035
|
transports: ["AGENT"],
|
|
723
1036
|
handler: async ({ input }) => {
|
|
@@ -751,6 +1064,7 @@ function createAgentCodingTools(config) {
|
|
|
751
1064
|
const commandTools = Object.keys(config.executables ?? {}).length ? [createShellCodingTool(config, limits)] : [];
|
|
752
1065
|
return [
|
|
753
1066
|
...createFileCodingTools(config, limits),
|
|
1067
|
+
...createListingCodingTools(config, limits),
|
|
754
1068
|
...createSearchAndPatchCodingTools(config, limits),
|
|
755
1069
|
...commandTools,
|
|
756
1070
|
...artifactTools
|