topchester-ai 0.67.0 → 0.69.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/bin.mjs +1 -1
- package/dist/{cli-DfgLjXLl.mjs → cli-CUjNKJTW.mjs} +169 -28
- package/dist/cli-CUjNKJTW.mjs.map +1 -0
- package/dist/cli.mjs +1 -1
- package/package.json +1 -1
- package/dist/cli-DfgLjXLl.mjs.map +0 -1
package/dist/bin.mjs
CHANGED
|
@@ -421,6 +421,7 @@ function toAiSdkToolSet(definitions) {
|
|
|
421
421
|
//#region src/agent/tools/process-runner.ts
|
|
422
422
|
const DEFAULT_MAX_OUTPUT_BYTES$1 = 4e4;
|
|
423
423
|
const DEFAULT_MAX_OUTPUT_LINES = 1e3;
|
|
424
|
+
const TERMINAL_BENCH_MAX_OUTPUT_BYTES = 2e4;
|
|
424
425
|
async function runProcess(options) {
|
|
425
426
|
const startedAt = Date.now();
|
|
426
427
|
const pathEnv = options.pathEnv ?? process.env.PATH ?? "";
|
|
@@ -786,6 +787,8 @@ async function runBashCommand(workspaceRoot, args, options = {}) {
|
|
|
786
787
|
pathEnv: options.pathEnv,
|
|
787
788
|
timeoutMs: args.timeout_ms,
|
|
788
789
|
abortSignal: options.abortSignal,
|
|
790
|
+
outputLimitBytes: options.benchmarkProfile === "terminal-bench" ? TERMINAL_BENCH_MAX_OUTPUT_BYTES : void 0,
|
|
791
|
+
outputLimitLines: options.benchmarkProfile === "terminal-bench" ? 500 : void 0,
|
|
789
792
|
env: { NO_COLOR: "1" },
|
|
790
793
|
missingExecutableLabel: "bash"
|
|
791
794
|
});
|
|
@@ -3585,7 +3588,10 @@ const inspectCommandTool = defineTool({
|
|
|
3585
3588
|
description: "Run a narrowly validated read-only command for repository orientation.",
|
|
3586
3589
|
prompt: "inspect_command: run a safe read-only discovery command inside the workspace for quick repo orientation; prefer read_file, list_files, grep, and find_file for exact file tasks, and do not use it for builds, tests, installs, network, shell scripts, edits, or user-requested specific commands such as node --version, which node, or pnpm --version. To use it, reply with only JSON: {\"tool\":\"inspect_command\",\"args\":{\"command\":\"pwd && rg --files docs/plans | head -20\",\"workdir\":\".\",\"timeout_ms\":10000}}",
|
|
3587
3590
|
argsSchema: inspectCommandArgsSchema,
|
|
3588
|
-
execute: (context, args) => inspectWorkspaceCommand(context.workspaceRoot, args, {
|
|
3591
|
+
execute: (context, args) => inspectWorkspaceCommand(context.workspaceRoot, args, {
|
|
3592
|
+
pathEnv: context.pathEnv,
|
|
3593
|
+
benchmarkProfile: context.benchmarkProfile
|
|
3594
|
+
})
|
|
3589
3595
|
});
|
|
3590
3596
|
async function inspectWorkspaceCommand(workspaceRoot, args, options = {}) {
|
|
3591
3597
|
const startedAt = Date.now();
|
|
@@ -3597,7 +3603,8 @@ async function inspectWorkspaceCommand(workspaceRoot, args, options = {}) {
|
|
|
3597
3603
|
const result = await executePlan(decision.plan, {
|
|
3598
3604
|
cwd,
|
|
3599
3605
|
pathEnv: options.pathEnv ?? process.env.PATH ?? "",
|
|
3600
|
-
deadlineAt
|
|
3606
|
+
deadlineAt,
|
|
3607
|
+
benchmarkProfile: options.benchmarkProfile
|
|
3601
3608
|
});
|
|
3602
3609
|
const durationMs = Date.now() - startedAt;
|
|
3603
3610
|
return {
|
|
@@ -3635,14 +3642,16 @@ async function executePlan(plan, context) {
|
|
|
3635
3642
|
timedOut: true,
|
|
3636
3643
|
truncated
|
|
3637
3644
|
};
|
|
3645
|
+
const outputLimits = getOutputLimits(context.benchmarkProfile);
|
|
3638
3646
|
const result = await executePipeline(entry.pipeline, {
|
|
3639
3647
|
...context,
|
|
3640
3648
|
timeoutMs: remainingMs
|
|
3641
3649
|
});
|
|
3642
|
-
|
|
3643
|
-
|
|
3650
|
+
const nextStdout = appendBoundedOutput(stdout, result.stdout, outputLimits);
|
|
3651
|
+
stdout = nextStdout.output;
|
|
3652
|
+
const nextStderr = appendBoundedOutput(stderr, result.stderr, outputLimits);
|
|
3644
3653
|
stderr = nextStderr.output;
|
|
3645
|
-
truncated = truncated || result.truncated || nextStderr.truncated;
|
|
3654
|
+
truncated = truncated || result.truncated || nextStdout.truncated || nextStderr.truncated;
|
|
3646
3655
|
timedOut = timedOut || result.timedOut;
|
|
3647
3656
|
lastExitCode = result.exitCode;
|
|
3648
3657
|
if (result.missingExecutable || result.timedOut) return {
|
|
@@ -3682,7 +3691,8 @@ async function executePipeline(pipeline, context) {
|
|
|
3682
3691
|
timeoutMs: remainingMs
|
|
3683
3692
|
});
|
|
3684
3693
|
input = result.stdout;
|
|
3685
|
-
const
|
|
3694
|
+
const outputLimits = getOutputLimits(context.benchmarkProfile);
|
|
3695
|
+
const nextStderr = appendBoundedOutput(stderr, result.stderr, outputLimits);
|
|
3686
3696
|
stderr = nextStderr.output;
|
|
3687
3697
|
exitCode = result.exitCode;
|
|
3688
3698
|
timedOut = timedOut || result.timedOut;
|
|
@@ -3719,6 +3729,8 @@ async function executeSimpleCommand(command, input, context) {
|
|
|
3719
3729
|
cwd: context.cwd,
|
|
3720
3730
|
pathEnv: context.pathEnv,
|
|
3721
3731
|
timeoutMs: context.timeoutMs,
|
|
3732
|
+
outputLimitBytes: context.benchmarkProfile === "terminal-bench" ? TERMINAL_BENCH_MAX_OUTPUT_BYTES : void 0,
|
|
3733
|
+
outputLimitLines: context.benchmarkProfile === "terminal-bench" ? 500 : void 0,
|
|
3722
3734
|
missingExecutableLabel: "inspect_command"
|
|
3723
3735
|
});
|
|
3724
3736
|
return {
|
|
@@ -3741,6 +3753,13 @@ function shouldExecuteEntry(entry, previousExitCode) {
|
|
|
3741
3753
|
function getRemainingTimeoutMs(deadlineAt) {
|
|
3742
3754
|
return deadlineAt - Date.now();
|
|
3743
3755
|
}
|
|
3756
|
+
function getOutputLimits(benchmarkProfile) {
|
|
3757
|
+
if (benchmarkProfile !== "terminal-bench") return {};
|
|
3758
|
+
return {
|
|
3759
|
+
maxBytes: TERMINAL_BENCH_MAX_OUTPUT_BYTES,
|
|
3760
|
+
maxLines: 500
|
|
3761
|
+
};
|
|
3762
|
+
}
|
|
3744
3763
|
function formatInspectCommandContent(result) {
|
|
3745
3764
|
const sections = [];
|
|
3746
3765
|
sections.push(result.stdout.trimEnd() || "(no output)");
|
|
@@ -4110,18 +4129,28 @@ const planTodoTool = defineTool({
|
|
|
4110
4129
|
});
|
|
4111
4130
|
//#endregion
|
|
4112
4131
|
//#region src/agent/tools/read-file.ts
|
|
4113
|
-
const
|
|
4132
|
+
const DEFAULT_MAX_UTF8_READ_BYTES = 512 * 1024;
|
|
4133
|
+
const TERMINAL_BENCH_MAX_UTF8_READ_BYTES = 64 * 1024;
|
|
4114
4134
|
const SAMPLE_BYTES = 256;
|
|
4115
4135
|
const readFileTool = defineTool({
|
|
4116
4136
|
name: "read_file",
|
|
4117
4137
|
description: "Read a UTF-8 file inside the workspace.",
|
|
4118
|
-
prompt: "read_file: read a UTF-8 file inside the workspace. To use it, reply with only JSON: {\"tool\":\"read_file\",\"args\":{\"path\":\"package.json\"}}",
|
|
4119
|
-
argsSchema: z.object({
|
|
4138
|
+
prompt: "read_file: read a UTF-8 file inside the workspace. For large files, use offset and limit to read a focused byte range. To use it, reply with only JSON: {\"tool\":\"read_file\",\"args\":{\"path\":\"package.json\"}}",
|
|
4139
|
+
argsSchema: z.object({
|
|
4140
|
+
path: z.string(),
|
|
4141
|
+
offset: z.number().int().min(0).optional(),
|
|
4142
|
+
limit: z.number().int().min(1).max(DEFAULT_MAX_UTF8_READ_BYTES).optional()
|
|
4143
|
+
}),
|
|
4120
4144
|
parallelSafe: true,
|
|
4121
4145
|
mutatesWorkspace: false,
|
|
4122
4146
|
resourceKeys: (args) => [`file:${args.path}`],
|
|
4123
4147
|
execute: async (context, args) => {
|
|
4124
|
-
const result = await readWorkspaceFile(context.workspaceRoot, args.path
|
|
4148
|
+
const result = await readWorkspaceFile(context.workspaceRoot, args.path, {
|
|
4149
|
+
offset: args.offset,
|
|
4150
|
+
limit: args.limit,
|
|
4151
|
+
benchmarkProfile: context.benchmarkProfile,
|
|
4152
|
+
cache: context.readFileCache
|
|
4153
|
+
});
|
|
4125
4154
|
const projectInstructions = await resolveToolProjectInstructions(context, {
|
|
4126
4155
|
targetPath: args.path,
|
|
4127
4156
|
skipWhenTargetIsInstructionFile: true
|
|
@@ -4133,14 +4162,19 @@ const readFileTool = defineTool({
|
|
|
4133
4162
|
};
|
|
4134
4163
|
}
|
|
4135
4164
|
});
|
|
4136
|
-
async function readWorkspaceFile(workspaceRoot, path) {
|
|
4165
|
+
async function readWorkspaceFile(workspaceRoot, path, options = {}) {
|
|
4137
4166
|
const resolvedWorkspace = resolve(workspaceRoot);
|
|
4138
4167
|
const resolvedPath = isAbsolute(path) ? resolve(path) : resolve(resolvedWorkspace, path);
|
|
4139
4168
|
const relativePath = relative(resolvedWorkspace, resolvedPath);
|
|
4169
|
+
const maxReadBytes = getReadFileMaxBytes(options.benchmarkProfile);
|
|
4140
4170
|
if (relativePath.startsWith("..") || isAbsolute(relativePath)) throw new Error(`read_file can only read files inside the workspace: ${path}`);
|
|
4141
4171
|
const fileStat = await stat(resolvedPath);
|
|
4142
4172
|
if (!fileStat.isFile()) throw new Error(`read_file can only read regular files: ${path}`);
|
|
4143
|
-
|
|
4173
|
+
const offset = options.offset ?? 0;
|
|
4174
|
+
const requestedLimit = options.limit;
|
|
4175
|
+
const hasExplicitRange = options.offset !== void 0 || requestedLimit !== void 0;
|
|
4176
|
+
if (offset > fileStat.size) throw new Error(`read_file offset ${offset} is beyond end of file ${relativePath || "."} (${fileStat.size} bytes).`);
|
|
4177
|
+
if (!hasExplicitRange && fileStat.size > maxReadBytes) {
|
|
4144
4178
|
const [sample, hash] = await Promise.all([readFileSample(resolvedPath, SAMPLE_BYTES), hashFile$2(resolvedPath)]);
|
|
4145
4179
|
return {
|
|
4146
4180
|
tool: "read_file",
|
|
@@ -4149,16 +4183,39 @@ async function readWorkspaceFile(workspaceRoot, path) {
|
|
|
4149
4183
|
reason: "too_large",
|
|
4150
4184
|
relativePath: relativePath || ".",
|
|
4151
4185
|
bytes: fileStat.size,
|
|
4186
|
+
maxReadBytes,
|
|
4152
4187
|
sample
|
|
4153
4188
|
}),
|
|
4154
4189
|
hash,
|
|
4155
4190
|
skipped: "too_large",
|
|
4156
4191
|
bytes: fileStat.size,
|
|
4157
|
-
warning: `Skipped reading ${relativePath || "."}: file is ${fileStat.size} bytes, above the ${
|
|
4192
|
+
warning: `Skipped reading ${relativePath || "."}: file is ${fileStat.size} bytes, above the ${maxReadBytes} byte read_file limit.`
|
|
4158
4193
|
};
|
|
4159
4194
|
}
|
|
4160
|
-
const
|
|
4161
|
-
const
|
|
4195
|
+
const hashPromise = hashFile$2(resolvedPath);
|
|
4196
|
+
const bytes = hasExplicitRange ? await readFileRange(resolvedPath, offset, Math.min(requestedLimit ?? maxReadBytes, maxReadBytes)) : await readFile(resolvedPath);
|
|
4197
|
+
const hash = await hashPromise;
|
|
4198
|
+
const length = bytes.length;
|
|
4199
|
+
const truncated = hasExplicitRange ? offset + length < fileStat.size : false;
|
|
4200
|
+
const cacheKey = makeReadFileCacheKey(relativePath || ".", hash, fileStat.size, offset, length);
|
|
4201
|
+
if (options.cache?.seen.has(cacheKey)) return {
|
|
4202
|
+
tool: "read_file",
|
|
4203
|
+
path: relativePath || ".",
|
|
4204
|
+
content: formatDedupedReadSummary({
|
|
4205
|
+
relativePath: relativePath || ".",
|
|
4206
|
+
bytes: fileStat.size,
|
|
4207
|
+
hash,
|
|
4208
|
+
offset,
|
|
4209
|
+
length
|
|
4210
|
+
}),
|
|
4211
|
+
hash,
|
|
4212
|
+
bytes: fileStat.size,
|
|
4213
|
+
offset,
|
|
4214
|
+
length,
|
|
4215
|
+
deduped: true,
|
|
4216
|
+
truncated,
|
|
4217
|
+
warning: `Skipped repeated read of unchanged ${relativePath || "."} bytes ${offset}-${offset + length}.`
|
|
4218
|
+
};
|
|
4162
4219
|
if (looksBinary$1(bytes) || !isValidUtf8(bytes)) {
|
|
4163
4220
|
const sample = bytes.subarray(0, SAMPLE_BYTES);
|
|
4164
4221
|
return {
|
|
@@ -4168,6 +4225,7 @@ async function readWorkspaceFile(workspaceRoot, path) {
|
|
|
4168
4225
|
reason: "binary",
|
|
4169
4226
|
relativePath: relativePath || ".",
|
|
4170
4227
|
bytes: fileStat.size,
|
|
4228
|
+
maxReadBytes,
|
|
4171
4229
|
sample
|
|
4172
4230
|
}),
|
|
4173
4231
|
hash,
|
|
@@ -4177,12 +4235,36 @@ async function readWorkspaceFile(workspaceRoot, path) {
|
|
|
4177
4235
|
};
|
|
4178
4236
|
}
|
|
4179
4237
|
const content = bytes.toString("utf8");
|
|
4180
|
-
|
|
4238
|
+
options.cache?.seen.set(cacheKey, {
|
|
4239
|
+
hash,
|
|
4240
|
+
bytes: fileStat.size,
|
|
4241
|
+
offset,
|
|
4242
|
+
length
|
|
4243
|
+
});
|
|
4244
|
+
const result = {
|
|
4181
4245
|
tool: "read_file",
|
|
4182
4246
|
path: relativePath || ".",
|
|
4183
|
-
content
|
|
4247
|
+
content: formatReadFileContent({
|
|
4248
|
+
content,
|
|
4249
|
+
relativePath: relativePath || ".",
|
|
4250
|
+
bytes: fileStat.size,
|
|
4251
|
+
offset,
|
|
4252
|
+
length,
|
|
4253
|
+
truncated,
|
|
4254
|
+
ranged: hasExplicitRange
|
|
4255
|
+
}),
|
|
4184
4256
|
hash
|
|
4185
4257
|
};
|
|
4258
|
+
if (hasExplicitRange) {
|
|
4259
|
+
result.bytes = fileStat.size;
|
|
4260
|
+
result.offset = offset;
|
|
4261
|
+
result.length = length;
|
|
4262
|
+
result.truncated = truncated;
|
|
4263
|
+
}
|
|
4264
|
+
return result;
|
|
4265
|
+
}
|
|
4266
|
+
function createReadFileCache() {
|
|
4267
|
+
return { seen: /* @__PURE__ */ new Map() };
|
|
4186
4268
|
}
|
|
4187
4269
|
function looksBinary$1(bytes) {
|
|
4188
4270
|
return bytes.subarray(0, Math.min(bytes.length, SAMPLE_BYTES)).includes(0);
|
|
@@ -4196,14 +4278,28 @@ function isValidUtf8(bytes) {
|
|
|
4196
4278
|
}
|
|
4197
4279
|
}
|
|
4198
4280
|
function formatSkippedReadSummary(options) {
|
|
4199
|
-
const reason = options.reason === "binary" ? "read_file did not return file contents because this file appears to be binary or non-UTF-8." : `read_file did not return file contents because this file is ${options.bytes} bytes, above the ${
|
|
4281
|
+
const reason = options.reason === "binary" ? "read_file did not return file contents because this file appears to be binary or non-UTF-8." : `read_file did not return file contents because this file is ${options.bytes} bytes, above the ${options.maxReadBytes} byte limit.`;
|
|
4200
4282
|
const sampleHex = options.sample.length > 0 ? options.sample.toString("hex").match(/.{1,2}/g)?.join(" ") : "";
|
|
4201
4283
|
return [
|
|
4202
4284
|
reason,
|
|
4203
4285
|
`path: ${options.relativePath}`,
|
|
4204
4286
|
`bytes: ${options.bytes}`,
|
|
4205
4287
|
sampleHex ? `first_${options.sample.length}_bytes_hex: ${sampleHex}` : "first_bytes_hex: <empty>",
|
|
4206
|
-
"Use shell inspection tools such as `file`, `xxd`, `readelf`, `objdump`, `strings`, or a focused parser instead of reading the whole file into context."
|
|
4288
|
+
"Use read_file with offset and limit for a focused byte range, or shell inspection tools such as `file`, `xxd`, `readelf`, `objdump`, `strings`, or a focused parser instead of reading the whole file into context."
|
|
4289
|
+
].join("\n");
|
|
4290
|
+
}
|
|
4291
|
+
function formatReadFileContent(options) {
|
|
4292
|
+
if (!options.ranged) return options.content;
|
|
4293
|
+
return [`read_file range: ${options.relativePath} bytes ${options.offset}-${options.offset + options.length} of ${options.bytes}${options.truncated ? " (truncated)" : ""}`, options.content].join("\n");
|
|
4294
|
+
}
|
|
4295
|
+
function formatDedupedReadSummary(options) {
|
|
4296
|
+
return [
|
|
4297
|
+
"read_file did not return file contents because this exact unchanged file range was already shown in this session.",
|
|
4298
|
+
`path: ${options.relativePath}`,
|
|
4299
|
+
`bytes: ${options.bytes}`,
|
|
4300
|
+
`hash: ${options.hash}`,
|
|
4301
|
+
`range: ${options.offset}-${options.offset + options.length}`,
|
|
4302
|
+
"Use a different offset/limit if you need another part of the file."
|
|
4207
4303
|
].join("\n");
|
|
4208
4304
|
}
|
|
4209
4305
|
async function readFileSample(path, maxBytes) {
|
|
@@ -4216,6 +4312,16 @@ async function readFileSample(path, maxBytes) {
|
|
|
4216
4312
|
await handle.close();
|
|
4217
4313
|
}
|
|
4218
4314
|
}
|
|
4315
|
+
async function readFileRange(path, offset, maxBytes) {
|
|
4316
|
+
const handle = await open(path, "r");
|
|
4317
|
+
try {
|
|
4318
|
+
const sample = Buffer.alloc(maxBytes);
|
|
4319
|
+
const { bytesRead } = await handle.read(sample, 0, maxBytes, offset);
|
|
4320
|
+
return sample.subarray(0, bytesRead);
|
|
4321
|
+
} finally {
|
|
4322
|
+
await handle.close();
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4219
4325
|
async function hashFile$2(path) {
|
|
4220
4326
|
const hash = createHash("sha256");
|
|
4221
4327
|
await new Promise((resolvePromise, reject) => {
|
|
@@ -4226,6 +4332,12 @@ async function hashFile$2(path) {
|
|
|
4226
4332
|
});
|
|
4227
4333
|
return `sha256:${hash.digest("hex")}`;
|
|
4228
4334
|
}
|
|
4335
|
+
function getReadFileMaxBytes(benchmarkProfile) {
|
|
4336
|
+
return benchmarkProfile === "terminal-bench" ? TERMINAL_BENCH_MAX_UTF8_READ_BYTES : DEFAULT_MAX_UTF8_READ_BYTES;
|
|
4337
|
+
}
|
|
4338
|
+
function makeReadFileCacheKey(path, hash, bytes, offset, length) {
|
|
4339
|
+
return `${path}\0${hash}\0${bytes}\0${offset}\0${length}`;
|
|
4340
|
+
}
|
|
4229
4341
|
//#endregion
|
|
4230
4342
|
//#region src/agent/tools/command-policy.ts
|
|
4231
4343
|
const PACKAGE_MANAGERS = new Set([
|
|
@@ -4667,18 +4779,29 @@ const runValidatorTool = defineTool({
|
|
|
4667
4779
|
timeout_ms: z.number().int().min(100).max(6e5).optional().default(12e4)
|
|
4668
4780
|
}),
|
|
4669
4781
|
requiresExclusiveWorkspace: true,
|
|
4670
|
-
execute: async (context, args) => runValidatorCommand(context.workspaceRoot, args,
|
|
4782
|
+
execute: async (context, args) => runValidatorCommand(context.workspaceRoot, args, {
|
|
4783
|
+
pathEnv: context.pathEnv,
|
|
4784
|
+
abortSignal: context.abortSignal,
|
|
4785
|
+
benchmarkProfile: context.benchmarkProfile
|
|
4786
|
+
})
|
|
4671
4787
|
});
|
|
4672
|
-
async function runValidatorCommand(workspaceRoot, args,
|
|
4788
|
+
async function runValidatorCommand(workspaceRoot, args, pathEnvOrOptions, legacyAbortSignal) {
|
|
4789
|
+
const options = typeof pathEnvOrOptions === "string" ? {
|
|
4790
|
+
pathEnv: pathEnvOrOptions,
|
|
4791
|
+
abortSignal: legacyAbortSignal,
|
|
4792
|
+
benchmarkProfile: void 0
|
|
4793
|
+
} : pathEnvOrOptions ?? {};
|
|
4673
4794
|
const decision = await validateValidatorCommand(args, { workspaceRoot });
|
|
4674
4795
|
if (!decision.allowed) throw new Error(decision.reason);
|
|
4675
4796
|
const result = await runProcess({
|
|
4676
4797
|
executable: decision.plan.executable,
|
|
4677
4798
|
args: decision.plan.args,
|
|
4678
4799
|
cwd: decision.plan.cwd,
|
|
4679
|
-
pathEnv,
|
|
4800
|
+
pathEnv: options.pathEnv,
|
|
4680
4801
|
timeoutMs: args.timeout_ms,
|
|
4681
|
-
abortSignal,
|
|
4802
|
+
abortSignal: options.abortSignal,
|
|
4803
|
+
outputLimitBytes: options.benchmarkProfile === "terminal-bench" ? TERMINAL_BENCH_MAX_OUTPUT_BYTES : void 0,
|
|
4804
|
+
outputLimitLines: options.benchmarkProfile === "terminal-bench" ? 500 : void 0,
|
|
4682
4805
|
env: {
|
|
4683
4806
|
CI: "1",
|
|
4684
4807
|
NO_COLOR: "1"
|
|
@@ -5164,8 +5287,8 @@ function formatSkillSource$2(skill) {
|
|
|
5164
5287
|
}
|
|
5165
5288
|
const taskTool = defineTool({
|
|
5166
5289
|
name: "task",
|
|
5167
|
-
description: "Delegate
|
|
5168
|
-
prompt: "task: delegate
|
|
5290
|
+
description: "Delegate read-only file/search/git research to a child agent. Do not use for shell commands, bash, Python/Node scripts, validators, edits, writes, or other execution work.",
|
|
5291
|
+
prompt: "task: delegate read-only file/search/git research to a child agent. Do not use task for shell commands, bash, Python/Node scripts, validators, edits, writes, finish_task, or other execution work; use parent tools directly. To use it, reply with only JSON: {\"tool\":\"task\",\"args\":{\"description\":\"Inspect runtime event flow\",\"prompt\":\"Read the runtime and summarize how events are emitted.\",\"subagent_type\":\"explore\"}}",
|
|
5169
5292
|
argsSchema: z.object({
|
|
5170
5293
|
description: z.string().min(1),
|
|
5171
5294
|
prompt: z.string().min(1),
|
|
@@ -5174,6 +5297,7 @@ const taskTool = defineTool({
|
|
|
5174
5297
|
}),
|
|
5175
5298
|
async execute(context, args) {
|
|
5176
5299
|
if (!context.subagents) throw new Error("task requires a runtime subagent manager.");
|
|
5300
|
+
rejectUnsupportedSubagentPrompt(args);
|
|
5177
5301
|
const result = await context.subagents.runTask({
|
|
5178
5302
|
description: args.description,
|
|
5179
5303
|
prompt: args.prompt,
|
|
@@ -5181,7 +5305,8 @@ const taskTool = defineTool({
|
|
|
5181
5305
|
taskId: args.task_id,
|
|
5182
5306
|
parentToolCallId: context.toolCallId ?? args.task_id ?? "task",
|
|
5183
5307
|
eventSink: context.eventSink,
|
|
5184
|
-
abortSignal: context.abortSignal
|
|
5308
|
+
abortSignal: context.abortSignal,
|
|
5309
|
+
benchmarkProfile: context.benchmarkProfile
|
|
5185
5310
|
});
|
|
5186
5311
|
return {
|
|
5187
5312
|
tool: "task",
|
|
@@ -5198,6 +5323,14 @@ const taskTool = defineTool({
|
|
|
5198
5323
|
};
|
|
5199
5324
|
}
|
|
5200
5325
|
});
|
|
5326
|
+
function rejectUnsupportedSubagentPrompt(args) {
|
|
5327
|
+
const profile = resolveAgentProfile(args.subagent_type ?? "explore");
|
|
5328
|
+
if (isToolAllowed(createToolPermissionView(profile), "bash") || !looksLikeShellExecutionRequest(args.prompt)) return;
|
|
5329
|
+
throw new Error(`task subagent "${profile.id}" cannot run bash, shell commands, Python/Node scripts, validators, or other execution tools. Use the parent bash/run_validator tools directly, or delegate only read-only file/search/git research.`);
|
|
5330
|
+
}
|
|
5331
|
+
function looksLikeShellExecutionRequest(prompt) {
|
|
5332
|
+
return /\b(use|run|execute)\s+(bash|shell|command|commands|python3?|node|npm|npx|pnpm|xxd|readelf|objdump|file)\b/i.test(prompt);
|
|
5333
|
+
}
|
|
5201
5334
|
//#endregion
|
|
5202
5335
|
//#region src/agent/tools/registry.ts
|
|
5203
5336
|
const toolRegistry = {
|
|
@@ -12149,6 +12282,7 @@ async function executeToolCall(workspaceRoot, call, options = {}) {
|
|
|
12149
12282
|
projectInstructions: options.projectInstructions,
|
|
12150
12283
|
currentUserMessage: options.currentUserMessage,
|
|
12151
12284
|
benchmarkProfile: options.benchmarkProfile,
|
|
12285
|
+
readFileCache: options.readFileCache,
|
|
12152
12286
|
eventSink: options.eventSink,
|
|
12153
12287
|
abortSignal: options.abortSignal,
|
|
12154
12288
|
toolCallId: options.toolCallId
|
|
@@ -12660,7 +12794,10 @@ var SubagentManager = class {
|
|
|
12660
12794
|
});
|
|
12661
12795
|
let finalResponse = "";
|
|
12662
12796
|
try {
|
|
12663
|
-
for await (const childEvent of childRuntime.submitMessageStream([], options.prompt, options.abortSignal, {
|
|
12797
|
+
for await (const childEvent of childRuntime.submitMessageStream([], options.prompt, options.abortSignal, {
|
|
12798
|
+
session: child,
|
|
12799
|
+
benchmarkProfile: options.benchmarkProfile
|
|
12800
|
+
})) {
|
|
12664
12801
|
const payload = runtimeEventToSessionPayload(childEvent);
|
|
12665
12802
|
if (payload) await child.append(payload);
|
|
12666
12803
|
if (childEvent.type === "message" && childEvent.role === "assistant") finalResponse = childEvent.text;
|
|
@@ -13403,6 +13540,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
|
|
|
13403
13540
|
const requireFinishTask = isFinishTaskRequiredByEnv() && isToolAllowed(permissions, "finish_task");
|
|
13404
13541
|
const projectInstructionToolState = { shownSourceKeys: /* @__PURE__ */ new Set() };
|
|
13405
13542
|
const persistedProjectInstructionKeys = /* @__PURE__ */ new Set();
|
|
13543
|
+
const readFileCache = createReadFileCache();
|
|
13406
13544
|
try {
|
|
13407
13545
|
for (let toolCalls = 0; toolCalls <= maxToolCallsPerTurn; toolCalls += 1) {
|
|
13408
13546
|
const startedAt = Date.now();
|
|
@@ -13588,6 +13726,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
|
|
|
13588
13726
|
projectInstructions: projectInstructionToolState,
|
|
13589
13727
|
currentUserMessage: message,
|
|
13590
13728
|
benchmarkProfile: options.benchmarkProfile,
|
|
13729
|
+
readFileCache,
|
|
13591
13730
|
abortSignal,
|
|
13592
13731
|
toolCallId: entry.toolCallId,
|
|
13593
13732
|
toolCatalog,
|
|
@@ -13659,6 +13798,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
|
|
|
13659
13798
|
projectInstructions: projectInstructionToolState,
|
|
13660
13799
|
currentUserMessage: message,
|
|
13661
13800
|
benchmarkProfile: options.benchmarkProfile,
|
|
13801
|
+
readFileCache,
|
|
13662
13802
|
abortSignal,
|
|
13663
13803
|
toolCallId: entry.toolCallId,
|
|
13664
13804
|
toolCatalog
|
|
@@ -13737,6 +13877,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
|
|
|
13737
13877
|
projectInstructions: projectInstructionToolState,
|
|
13738
13878
|
currentUserMessage: message,
|
|
13739
13879
|
benchmarkProfile: options.benchmarkProfile,
|
|
13880
|
+
readFileCache,
|
|
13740
13881
|
abortSignal,
|
|
13741
13882
|
toolCallId: toolCall.id,
|
|
13742
13883
|
toolCatalog,
|
|
@@ -16646,4 +16787,4 @@ function formatDryRunSyncStatus(status) {
|
|
|
16646
16787
|
//#endregion
|
|
16647
16788
|
export { runTopchesterCli as t };
|
|
16648
16789
|
|
|
16649
|
-
//# sourceMappingURL=cli-
|
|
16790
|
+
//# sourceMappingURL=cli-CUjNKJTW.mjs.map
|