@ljoukov/llm 3.0.11 → 3.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +229 -243
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -32
- package/dist/index.d.ts +33 -32
- package/dist/index.js +228 -242
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -68,10 +68,10 @@ __export(index_exports, {
|
|
|
68
68
|
createListDirectoryTool: () => createListDirectoryTool,
|
|
69
69
|
createModelAgnosticFilesystemToolSet: () => createModelAgnosticFilesystemToolSet,
|
|
70
70
|
createNodeAgentFilesystem: () => createNodeAgentFilesystem,
|
|
71
|
-
createReadFilesTool: () => createReadFilesTool,
|
|
72
71
|
createReplaceTool: () => createReplaceTool,
|
|
73
72
|
createRgSearchTool: () => createRgSearchTool,
|
|
74
73
|
createToolLoopSteeringChannel: () => createToolLoopSteeringChannel,
|
|
74
|
+
createViewImageTool: () => createViewImageTool,
|
|
75
75
|
createWriteFileTool: () => createWriteFileTool,
|
|
76
76
|
customTool: () => customTool,
|
|
77
77
|
encodeChatGptAuthJson: () => encodeChatGptAuthJson,
|
|
@@ -2218,7 +2218,6 @@ function getGoogleAuthOptions(scopes) {
|
|
|
2218
2218
|
|
|
2219
2219
|
// src/google/client.ts
|
|
2220
2220
|
var GEMINI_TEXT_MODEL_IDS = [
|
|
2221
|
-
"gemini-3-pro-preview",
|
|
2222
2221
|
"gemini-3.1-pro-preview",
|
|
2223
2222
|
"gemini-3-flash-preview",
|
|
2224
2223
|
"gemini-2.5-pro",
|
|
@@ -4022,6 +4021,38 @@ function mergeToolOutput(value) {
|
|
|
4022
4021
|
return JSON.stringify({ error: "Failed to serialize tool output", detail: message });
|
|
4023
4022
|
}
|
|
4024
4023
|
}
|
|
4024
|
+
function isLlmToolOutputContentItem(value) {
|
|
4025
|
+
if (!isPlainRecord(value)) {
|
|
4026
|
+
return false;
|
|
4027
|
+
}
|
|
4028
|
+
const itemType = typeof value.type === "string" ? value.type : "";
|
|
4029
|
+
if (itemType === "input_text") {
|
|
4030
|
+
return typeof value.text === "string";
|
|
4031
|
+
}
|
|
4032
|
+
if (itemType === "input_image") {
|
|
4033
|
+
return typeof value.image_url === "string";
|
|
4034
|
+
}
|
|
4035
|
+
if (itemType === "input_file") {
|
|
4036
|
+
const keys = ["file_data", "file_id", "file_url", "filename"];
|
|
4037
|
+
for (const key of keys) {
|
|
4038
|
+
const part = value[key];
|
|
4039
|
+
if (part !== void 0 && part !== null && typeof part !== "string") {
|
|
4040
|
+
return false;
|
|
4041
|
+
}
|
|
4042
|
+
}
|
|
4043
|
+
return true;
|
|
4044
|
+
}
|
|
4045
|
+
return false;
|
|
4046
|
+
}
|
|
4047
|
+
function toOpenAiToolOutput(value) {
|
|
4048
|
+
if (isLlmToolOutputContentItem(value)) {
|
|
4049
|
+
return [value];
|
|
4050
|
+
}
|
|
4051
|
+
if (Array.isArray(value) && value.every((item) => isLlmToolOutputContentItem(item))) {
|
|
4052
|
+
return value;
|
|
4053
|
+
}
|
|
4054
|
+
return mergeToolOutput(value);
|
|
4055
|
+
}
|
|
4025
4056
|
function parseOpenAiToolArguments(raw) {
|
|
4026
4057
|
const trimmed = raw.trim();
|
|
4027
4058
|
if (trimmed.length === 0) {
|
|
@@ -4377,7 +4408,6 @@ function resolveGeminiThinkingConfig(modelId) {
|
|
|
4377
4408
|
return void 0;
|
|
4378
4409
|
}
|
|
4379
4410
|
switch (modelId) {
|
|
4380
|
-
case "gemini-3-pro-preview":
|
|
4381
4411
|
case "gemini-3.1-pro-preview":
|
|
4382
4412
|
return { includeThoughts: true };
|
|
4383
4413
|
case "gemini-3-flash-preview":
|
|
@@ -5379,13 +5409,13 @@ async function runToolLoop(request) {
|
|
|
5379
5409
|
toolOutputs.push({
|
|
5380
5410
|
type: "custom_tool_call_output",
|
|
5381
5411
|
call_id: entry.call.call_id,
|
|
5382
|
-
output:
|
|
5412
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
5383
5413
|
});
|
|
5384
5414
|
} else {
|
|
5385
5415
|
toolOutputs.push({
|
|
5386
5416
|
type: "function_call_output",
|
|
5387
5417
|
call_id: entry.call.call_id,
|
|
5388
|
-
output:
|
|
5418
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
5389
5419
|
});
|
|
5390
5420
|
}
|
|
5391
5421
|
}
|
|
@@ -5600,7 +5630,7 @@ async function runToolLoop(request) {
|
|
|
5600
5630
|
toolOutputs.push({
|
|
5601
5631
|
type: "custom_tool_call_output",
|
|
5602
5632
|
call_id: entry.ids.callId,
|
|
5603
|
-
output:
|
|
5633
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
5604
5634
|
});
|
|
5605
5635
|
} else {
|
|
5606
5636
|
toolOutputs.push({
|
|
@@ -5614,7 +5644,7 @@ async function runToolLoop(request) {
|
|
|
5614
5644
|
toolOutputs.push({
|
|
5615
5645
|
type: "function_call_output",
|
|
5616
5646
|
call_id: entry.ids.callId,
|
|
5617
|
-
output:
|
|
5647
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
5618
5648
|
});
|
|
5619
5649
|
}
|
|
5620
5650
|
}
|
|
@@ -7245,6 +7275,7 @@ function sleep2(ms) {
|
|
|
7245
7275
|
|
|
7246
7276
|
// src/tools/filesystemTools.ts
|
|
7247
7277
|
var import_node_path5 = __toESM(require("path"), 1);
|
|
7278
|
+
var import_node_buffer3 = require("buffer");
|
|
7248
7279
|
var import_zod6 = require("zod");
|
|
7249
7280
|
|
|
7250
7281
|
// src/tools/applyPatch.ts
|
|
@@ -7278,6 +7309,10 @@ var InMemoryAgentFilesystem = class {
|
|
|
7278
7309
|
}
|
|
7279
7310
|
return file.content;
|
|
7280
7311
|
}
|
|
7312
|
+
async readBinaryFile(filePath) {
|
|
7313
|
+
const content = await this.readTextFile(filePath);
|
|
7314
|
+
return Buffer.from(content, "utf8");
|
|
7315
|
+
}
|
|
7281
7316
|
async writeTextFile(filePath, content) {
|
|
7282
7317
|
const absolutePath = import_node_path3.default.resolve(filePath);
|
|
7283
7318
|
const parentPath = import_node_path3.default.dirname(absolutePath);
|
|
@@ -7390,6 +7425,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
7390
7425
|
function createNodeAgentFilesystem() {
|
|
7391
7426
|
return {
|
|
7392
7427
|
readTextFile: async (filePath) => import_node_fs3.promises.readFile(filePath, "utf8"),
|
|
7428
|
+
readBinaryFile: async (filePath) => import_node_fs3.promises.readFile(filePath),
|
|
7393
7429
|
writeTextFile: async (filePath, content) => import_node_fs3.promises.writeFile(filePath, content, "utf8"),
|
|
7394
7430
|
deleteFile: async (filePath) => import_node_fs3.promises.unlink(filePath),
|
|
7395
7431
|
ensureDir: async (directoryPath) => {
|
|
@@ -7945,29 +7981,66 @@ function formatSummary(added, modified, deleted) {
|
|
|
7945
7981
|
|
|
7946
7982
|
// src/tools/filesystemTools.ts
|
|
7947
7983
|
var DEFAULT_READ_FILE_LINE_LIMIT = 2e3;
|
|
7948
|
-
var DEFAULT_READ_FILES_LINE_LIMIT = 200;
|
|
7949
|
-
var DEFAULT_READ_FILES_CHAR_LIMIT = 4e3;
|
|
7950
7984
|
var DEFAULT_LIST_DIR_LIMIT = 25;
|
|
7951
7985
|
var DEFAULT_LIST_DIR_DEPTH = 2;
|
|
7952
7986
|
var DEFAULT_GREP_LIMIT = 100;
|
|
7953
7987
|
var MAX_GREP_LIMIT = 2e3;
|
|
7988
|
+
var MAX_VIEW_IMAGE_BYTES = 10 * 1024 * 1024;
|
|
7954
7989
|
var DEFAULT_MAX_LINE_LENGTH = 500;
|
|
7955
7990
|
var DEFAULT_GREP_MAX_SCANNED_FILES = 2e4;
|
|
7956
|
-
var
|
|
7991
|
+
var SUPPORTED_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp", "image/gif"]);
|
|
7992
|
+
var IMAGE_MIME_BY_EXTENSION = {
|
|
7993
|
+
".png": "image/png",
|
|
7994
|
+
".jpg": "image/jpeg",
|
|
7995
|
+
".jpeg": "image/jpeg",
|
|
7996
|
+
".webp": "image/webp",
|
|
7997
|
+
".gif": "image/gif"
|
|
7998
|
+
};
|
|
7999
|
+
function parseOptionalString(value) {
|
|
8000
|
+
if (value === null || value === void 0) {
|
|
8001
|
+
return void 0;
|
|
8002
|
+
}
|
|
8003
|
+
if (typeof value !== "string") {
|
|
8004
|
+
return void 0;
|
|
8005
|
+
}
|
|
8006
|
+
const trimmed = value.trim();
|
|
8007
|
+
if (trimmed.length === 0) {
|
|
8008
|
+
return void 0;
|
|
8009
|
+
}
|
|
8010
|
+
return trimmed;
|
|
8011
|
+
}
|
|
7957
8012
|
var codexReadFileInputSchema = import_zod6.z.object({
|
|
7958
|
-
file_path: import_zod6.z.
|
|
7959
|
-
|
|
8013
|
+
file_path: import_zod6.z.preprocess(
|
|
8014
|
+
(value) => parseOptionalString(value),
|
|
8015
|
+
import_zod6.z.string().min(1).optional().describe(
|
|
8016
|
+
"Path to the file (relative to cwd, or absolute. In sandbox mode, / maps to the sandbox root)."
|
|
8017
|
+
)
|
|
8018
|
+
),
|
|
8019
|
+
path: import_zod6.z.preprocess(
|
|
8020
|
+
(value) => parseOptionalString(value),
|
|
8021
|
+
import_zod6.z.string().min(1).optional().describe(
|
|
8022
|
+
"Alias for file_path. If both file_path and path are provided they must be identical."
|
|
8023
|
+
)
|
|
7960
8024
|
),
|
|
7961
8025
|
offset: import_zod6.z.number().int().min(1).nullish().describe("The line number to start reading from. Must be 1 or greater."),
|
|
7962
|
-
limit: import_zod6.z.number().int().min(1).nullish().describe("The maximum number of lines to return.")
|
|
7963
|
-
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
8026
|
+
limit: import_zod6.z.number().int().min(1).nullish().describe("The maximum number of lines to return.")
|
|
8027
|
+
}).strict().superRefine((value, context) => {
|
|
8028
|
+
const filePath = value.file_path?.trim() ?? "";
|
|
8029
|
+
const aliasPath = value.path?.trim() ?? "";
|
|
8030
|
+
if (filePath.length === 0 && aliasPath.length === 0) {
|
|
8031
|
+
context.addIssue({
|
|
8032
|
+
code: import_zod6.z.ZodIssueCode.custom,
|
|
8033
|
+
message: "read_file requires file_path (or path alias).",
|
|
8034
|
+
path: ["file_path"]
|
|
8035
|
+
});
|
|
8036
|
+
}
|
|
8037
|
+
if (filePath.length > 0 && aliasPath.length > 0 && filePath !== aliasPath) {
|
|
8038
|
+
context.addIssue({
|
|
8039
|
+
code: import_zod6.z.ZodIssueCode.custom,
|
|
8040
|
+
message: "file_path and path must match when both are provided.",
|
|
8041
|
+
path: ["path"]
|
|
8042
|
+
});
|
|
8043
|
+
}
|
|
7971
8044
|
});
|
|
7972
8045
|
var codexListDirInputSchema = import_zod6.z.object({
|
|
7973
8046
|
dir_path: import_zod6.z.string().min(1).describe(
|
|
@@ -7983,6 +8056,9 @@ var codexGrepFilesInputSchema = import_zod6.z.object({
|
|
|
7983
8056
|
path: import_zod6.z.string().nullish().describe("Directory or file path to search. Defaults to cwd."),
|
|
7984
8057
|
limit: import_zod6.z.number().int().min(1).nullish().describe("Maximum number of file paths to return (defaults to 100).")
|
|
7985
8058
|
});
|
|
8059
|
+
var codexViewImageInputSchema = import_zod6.z.object({
|
|
8060
|
+
path: import_zod6.z.string().min(1).describe("Local filesystem path to an image file")
|
|
8061
|
+
});
|
|
7986
8062
|
var applyPatchInputSchema = import_zod6.z.object({
|
|
7987
8063
|
input: import_zod6.z.string().min(1).describe(CODEX_APPLY_PATCH_INPUT_DESCRIPTION)
|
|
7988
8064
|
});
|
|
@@ -7990,24 +8066,7 @@ var geminiReadFileInputSchema = import_zod6.z.object({
|
|
|
7990
8066
|
file_path: import_zod6.z.string().min(1),
|
|
7991
8067
|
offset: import_zod6.z.number().int().min(0).nullish(),
|
|
7992
8068
|
limit: import_zod6.z.number().int().min(1).nullish()
|
|
7993
|
-
});
|
|
7994
|
-
var geminiReadFilesInputSchema = import_zod6.z.object({
|
|
7995
|
-
paths: import_zod6.z.array(import_zod6.z.string().min(1)).min(1),
|
|
7996
|
-
line_offset: import_zod6.z.number().int().min(0).nullish(),
|
|
7997
|
-
line_limit: import_zod6.z.number().int().min(1).nullish(),
|
|
7998
|
-
char_offset: import_zod6.z.number().int().min(0).nullish(),
|
|
7999
|
-
char_limit: import_zod6.z.number().int().min(1).nullish(),
|
|
8000
|
-
include_line_numbers: import_zod6.z.boolean().nullish()
|
|
8001
|
-
}).superRefine((value, context) => {
|
|
8002
|
-
const hasLineWindow = value.line_offset !== void 0 || value.line_limit !== void 0;
|
|
8003
|
-
const hasCharWindow = value.char_offset !== void 0 || value.char_limit !== void 0;
|
|
8004
|
-
if (hasLineWindow && hasCharWindow) {
|
|
8005
|
-
context.addIssue({
|
|
8006
|
-
code: import_zod6.z.ZodIssueCode.custom,
|
|
8007
|
-
message: "Use either line_* or char_* window arguments, not both."
|
|
8008
|
-
});
|
|
8009
|
-
}
|
|
8010
|
-
});
|
|
8069
|
+
}).strict();
|
|
8011
8070
|
var geminiWriteFileInputSchema = import_zod6.z.object({
|
|
8012
8071
|
file_path: import_zod6.z.string().min(1),
|
|
8013
8072
|
content: import_zod6.z.string()
|
|
@@ -8090,7 +8149,8 @@ function createCodexFilesystemToolSet(options = {}) {
|
|
|
8090
8149
|
apply_patch: createCodexApplyPatchTool(options),
|
|
8091
8150
|
read_file: createCodexReadFileTool(options),
|
|
8092
8151
|
list_dir: createListDirTool(options),
|
|
8093
|
-
grep_files: createGrepFilesTool(options)
|
|
8152
|
+
grep_files: createGrepFilesTool(options),
|
|
8153
|
+
view_image: createViewImageTool(options)
|
|
8094
8154
|
};
|
|
8095
8155
|
}
|
|
8096
8156
|
function createGeminiFilesystemToolSet(options = {}) {
|
|
@@ -8139,7 +8199,7 @@ function createCodexApplyPatchTool(options = {}) {
|
|
|
8139
8199
|
}
|
|
8140
8200
|
function createCodexReadFileTool(options = {}) {
|
|
8141
8201
|
return tool({
|
|
8142
|
-
description: "Reads a local file with 1-indexed line numbers
|
|
8202
|
+
description: "Reads a local UTF-8 text file with 1-indexed line numbers.",
|
|
8143
8203
|
inputSchema: codexReadFileInputSchema,
|
|
8144
8204
|
execute: async (input) => readFileCodex(input, options)
|
|
8145
8205
|
});
|
|
@@ -8158,6 +8218,13 @@ function createGrepFilesTool(options = {}) {
|
|
|
8158
8218
|
execute: async (input) => grepFilesCodex(input, options)
|
|
8159
8219
|
});
|
|
8160
8220
|
}
|
|
8221
|
+
function createViewImageTool(options = {}) {
|
|
8222
|
+
return tool({
|
|
8223
|
+
description: "View a local image from the filesystem (only use if given a full filepath by the user, and the image isn't already attached to the thread context within <image ...> tags).",
|
|
8224
|
+
inputSchema: codexViewImageInputSchema,
|
|
8225
|
+
execute: async (input) => viewImageCodex(input, options)
|
|
8226
|
+
});
|
|
8227
|
+
}
|
|
8161
8228
|
function createGeminiReadFileTool(options = {}) {
|
|
8162
8229
|
return tool({
|
|
8163
8230
|
description: "Reads and returns the content of a specified file. Supports optional 0-based line offset and line limit.",
|
|
@@ -8165,13 +8232,6 @@ function createGeminiReadFileTool(options = {}) {
|
|
|
8165
8232
|
execute: async (input) => readFileGemini(input, options)
|
|
8166
8233
|
});
|
|
8167
8234
|
}
|
|
8168
|
-
function createReadFilesTool(options = {}) {
|
|
8169
|
-
return tool({
|
|
8170
|
-
description: "Reads one or more files with optional line-based or character-based slicing, similar to a controlled head/tail view.",
|
|
8171
|
-
inputSchema: geminiReadFilesInputSchema,
|
|
8172
|
-
execute: async (input) => readFilesGemini(input, options)
|
|
8173
|
-
});
|
|
8174
|
-
}
|
|
8175
8235
|
function createWriteFileTool(options = {}) {
|
|
8176
8236
|
return tool({
|
|
8177
8237
|
description: "Writes content to a specified file in the local filesystem.",
|
|
@@ -8214,53 +8274,61 @@ function createGlobTool(options = {}) {
|
|
|
8214
8274
|
execute: async (input) => globFilesGemini(input, options)
|
|
8215
8275
|
});
|
|
8216
8276
|
}
|
|
8277
|
+
function resolveCodexReadFilePath(input) {
|
|
8278
|
+
const filePath = parseOptionalString(input.file_path);
|
|
8279
|
+
if (filePath) {
|
|
8280
|
+
return filePath;
|
|
8281
|
+
}
|
|
8282
|
+
const aliasPath = parseOptionalString(input.path);
|
|
8283
|
+
if (aliasPath) {
|
|
8284
|
+
return aliasPath;
|
|
8285
|
+
}
|
|
8286
|
+
throw new Error("read_file requires file_path");
|
|
8287
|
+
}
|
|
8217
8288
|
async function readFileCodex(input, options) {
|
|
8218
8289
|
const runtime = resolveRuntime(options);
|
|
8219
|
-
const filePath = resolvePathWithPolicy(
|
|
8290
|
+
const filePath = resolvePathWithPolicy(
|
|
8291
|
+
resolveCodexReadFilePath(input),
|
|
8292
|
+
runtime.cwd,
|
|
8293
|
+
runtime.allowOutsideCwd
|
|
8294
|
+
);
|
|
8220
8295
|
await runAccessHook2(runtime, {
|
|
8221
8296
|
cwd: runtime.cwd,
|
|
8222
8297
|
tool: "read_file",
|
|
8223
8298
|
action: "read",
|
|
8224
8299
|
path: filePath
|
|
8225
8300
|
});
|
|
8226
|
-
const
|
|
8301
|
+
const fileBytes = await readBinaryFile(runtime.filesystem, filePath);
|
|
8302
|
+
const imageMimeType = detectImageMimeType(fileBytes, filePath);
|
|
8303
|
+
if (imageMimeType) {
|
|
8304
|
+
throw new Error(
|
|
8305
|
+
`read_file only supports text files; "${toDisplayPath2(filePath, runtime.cwd)}" is an image (${imageMimeType}). Use view_image instead.`
|
|
8306
|
+
);
|
|
8307
|
+
}
|
|
8308
|
+
if (isPdfFile(fileBytes, filePath)) {
|
|
8309
|
+
throw new Error(
|
|
8310
|
+
`read_file only supports text files; "${toDisplayPath2(filePath, runtime.cwd)}" is a PDF.`
|
|
8311
|
+
);
|
|
8312
|
+
}
|
|
8313
|
+
if (!isValidUtf8(fileBytes)) {
|
|
8314
|
+
throw new Error(
|
|
8315
|
+
`read_file only supports UTF-8 text files; "${toDisplayPath2(filePath, runtime.cwd)}" appears to be binary.`
|
|
8316
|
+
);
|
|
8317
|
+
}
|
|
8318
|
+
const content = fileBytes.toString("utf8");
|
|
8227
8319
|
const lines = splitLines(content);
|
|
8228
8320
|
const offset = input.offset ?? 1;
|
|
8229
8321
|
const limit = input.limit ?? DEFAULT_READ_FILE_LINE_LIMIT;
|
|
8230
|
-
const mode = input.mode ?? "slice";
|
|
8231
8322
|
if (offset > lines.length) {
|
|
8232
8323
|
throw new Error("offset exceeds file length");
|
|
8233
8324
|
}
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
return output.join("\n");
|
|
8242
|
-
}
|
|
8243
|
-
const indentation = input.indentation ?? {};
|
|
8244
|
-
const anchorLine = indentation.anchor_line ?? offset;
|
|
8245
|
-
if (anchorLine < 1 || anchorLine > lines.length) {
|
|
8246
|
-
throw new Error("anchor_line exceeds file length");
|
|
8247
|
-
}
|
|
8248
|
-
const records = lines.map((line, index) => ({
|
|
8249
|
-
number: index + 1,
|
|
8250
|
-
raw: line,
|
|
8251
|
-
display: truncateAtCodePointBoundary(line, runtime.maxLineLength),
|
|
8252
|
-
indent: measureIndent(line, DEFAULT_TAB_WIDTH)
|
|
8253
|
-
}));
|
|
8254
|
-
const selected = readWithIndentationMode({
|
|
8255
|
-
records,
|
|
8256
|
-
anchorLine,
|
|
8257
|
-
limit,
|
|
8258
|
-
maxLevels: indentation.max_levels ?? 0,
|
|
8259
|
-
includeSiblings: indentation.include_siblings ?? false,
|
|
8260
|
-
includeHeader: indentation.include_header ?? true,
|
|
8261
|
-
maxLines: indentation.max_lines ?? void 0
|
|
8262
|
-
});
|
|
8263
|
-
return selected.map((record) => `L${record.number}: ${record.display}`).join("\n");
|
|
8325
|
+
const output = [];
|
|
8326
|
+
const lastLine = Math.min(lines.length, offset + limit - 1);
|
|
8327
|
+
for (let lineNumber = offset; lineNumber <= lastLine; lineNumber += 1) {
|
|
8328
|
+
const line = lines[lineNumber - 1] ?? "";
|
|
8329
|
+
output.push(`L${lineNumber}: ${truncateAtCodePointBoundary(line, runtime.maxLineLength)}`);
|
|
8330
|
+
}
|
|
8331
|
+
return output.join("\n");
|
|
8264
8332
|
}
|
|
8265
8333
|
async function listDirectoryCodex(input, options) {
|
|
8266
8334
|
const runtime = resolveRuntime(options);
|
|
@@ -8348,6 +8416,85 @@ async function grepFilesCodex(input, options) {
|
|
|
8348
8416
|
const limit = Math.min(input.limit ?? DEFAULT_GREP_LIMIT, MAX_GREP_LIMIT);
|
|
8349
8417
|
return matches.slice(0, limit).map((match) => match.filePath).join("\n");
|
|
8350
8418
|
}
|
|
8419
|
+
async function viewImageCodex(input, options) {
|
|
8420
|
+
const runtime = resolveRuntime(options);
|
|
8421
|
+
const imagePath = resolvePathWithPolicy(input.path, runtime.cwd, runtime.allowOutsideCwd);
|
|
8422
|
+
await runAccessHook2(runtime, {
|
|
8423
|
+
cwd: runtime.cwd,
|
|
8424
|
+
tool: "view_image",
|
|
8425
|
+
action: "read",
|
|
8426
|
+
path: imagePath
|
|
8427
|
+
});
|
|
8428
|
+
const stats = await runtime.filesystem.stat(imagePath);
|
|
8429
|
+
if (stats.kind !== "file") {
|
|
8430
|
+
throw new Error(`image path \`${toDisplayPath2(imagePath, runtime.cwd)}\` is not a file`);
|
|
8431
|
+
}
|
|
8432
|
+
const bytes = await readBinaryFile(runtime.filesystem, imagePath);
|
|
8433
|
+
if (bytes.byteLength > MAX_VIEW_IMAGE_BYTES) {
|
|
8434
|
+
return [
|
|
8435
|
+
{
|
|
8436
|
+
type: "input_text",
|
|
8437
|
+
text: `Codex cannot attach image at \`${toDisplayPath2(imagePath, runtime.cwd)}\`: image exceeds ${MAX_VIEW_IMAGE_BYTES} bytes.`
|
|
8438
|
+
}
|
|
8439
|
+
];
|
|
8440
|
+
}
|
|
8441
|
+
const mimeType = detectImageMimeType(bytes, imagePath);
|
|
8442
|
+
if (!mimeType) {
|
|
8443
|
+
return [
|
|
8444
|
+
{
|
|
8445
|
+
type: "input_text",
|
|
8446
|
+
text: `Codex cannot attach image at \`${toDisplayPath2(imagePath, runtime.cwd)}\`: unsupported image format.`
|
|
8447
|
+
}
|
|
8448
|
+
];
|
|
8449
|
+
}
|
|
8450
|
+
return [
|
|
8451
|
+
{
|
|
8452
|
+
type: "input_image",
|
|
8453
|
+
image_url: `data:${mimeType};base64,${bytes.toString("base64")}`
|
|
8454
|
+
}
|
|
8455
|
+
];
|
|
8456
|
+
}
|
|
8457
|
+
async function readBinaryFile(filesystem, filePath) {
|
|
8458
|
+
if (typeof filesystem.readBinaryFile === "function") {
|
|
8459
|
+
return await filesystem.readBinaryFile(filePath);
|
|
8460
|
+
}
|
|
8461
|
+
const text = await filesystem.readTextFile(filePath);
|
|
8462
|
+
return import_node_buffer3.Buffer.from(text, "utf8");
|
|
8463
|
+
}
|
|
8464
|
+
function detectImageMimeType(buffer, filePath) {
|
|
8465
|
+
if (buffer.length >= 8 && buffer[0] === 137 && buffer[1] === 80 && buffer[2] === 78 && buffer[3] === 71 && buffer[4] === 13 && buffer[5] === 10 && buffer[6] === 26 && buffer[7] === 10) {
|
|
8466
|
+
return "image/png";
|
|
8467
|
+
}
|
|
8468
|
+
if (buffer.length >= 3 && buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) {
|
|
8469
|
+
return "image/jpeg";
|
|
8470
|
+
}
|
|
8471
|
+
if (buffer.length >= 6) {
|
|
8472
|
+
const signature = buffer.subarray(0, 6).toString("ascii");
|
|
8473
|
+
if (signature === "GIF87a" || signature === "GIF89a") {
|
|
8474
|
+
return "image/gif";
|
|
8475
|
+
}
|
|
8476
|
+
}
|
|
8477
|
+
if (buffer.length >= 12 && buffer.subarray(0, 4).toString("ascii") === "RIFF" && buffer.subarray(8, 12).toString("ascii") === "WEBP") {
|
|
8478
|
+
return "image/webp";
|
|
8479
|
+
}
|
|
8480
|
+
const fromExtension = IMAGE_MIME_BY_EXTENSION[import_node_path5.default.extname(filePath).toLowerCase()];
|
|
8481
|
+
if (fromExtension && SUPPORTED_IMAGE_MIME_TYPES.has(fromExtension)) {
|
|
8482
|
+
return fromExtension;
|
|
8483
|
+
}
|
|
8484
|
+
return void 0;
|
|
8485
|
+
}
|
|
8486
|
+
function isPdfFile(buffer, filePath) {
|
|
8487
|
+
if (buffer.length >= 5 && buffer.subarray(0, 5).toString("ascii") === "%PDF-") {
|
|
8488
|
+
return true;
|
|
8489
|
+
}
|
|
8490
|
+
return import_node_path5.default.extname(filePath).toLowerCase() === ".pdf";
|
|
8491
|
+
}
|
|
8492
|
+
function isValidUtf8(buffer) {
|
|
8493
|
+
if (buffer.length === 0) {
|
|
8494
|
+
return true;
|
|
8495
|
+
}
|
|
8496
|
+
return import_node_buffer3.Buffer.from(buffer.toString("utf8"), "utf8").equals(buffer);
|
|
8497
|
+
}
|
|
8351
8498
|
async function readFileGemini(input, options) {
|
|
8352
8499
|
const runtime = resolveRuntime(options);
|
|
8353
8500
|
const filePath = resolvePathWithPolicy(input.file_path, runtime.cwd, runtime.allowOutsideCwd);
|
|
@@ -8369,56 +8516,6 @@ async function readFileGemini(input, options) {
|
|
|
8369
8516
|
(line, index) => `L${offset + index + 1}: ${truncateAtCodePointBoundary(line ?? "", runtime.maxLineLength)}`
|
|
8370
8517
|
).join("\n");
|
|
8371
8518
|
}
|
|
8372
|
-
async function readFilesGemini(input, options) {
|
|
8373
|
-
const runtime = resolveRuntime(options);
|
|
8374
|
-
const useCharWindow = input.char_offset !== void 0 || input.char_limit !== void 0;
|
|
8375
|
-
const lineOffset = Math.max(0, input.line_offset ?? 0);
|
|
8376
|
-
const lineLimit = input.line_limit ?? DEFAULT_READ_FILES_LINE_LIMIT;
|
|
8377
|
-
const charOffset = Math.max(0, input.char_offset ?? 0);
|
|
8378
|
-
const charLimit = input.char_limit ?? DEFAULT_READ_FILES_CHAR_LIMIT;
|
|
8379
|
-
const includeLineNumbers = input.include_line_numbers !== false;
|
|
8380
|
-
const sections = [];
|
|
8381
|
-
for (const rawPath of input.paths) {
|
|
8382
|
-
const filePath = resolvePathWithPolicy(rawPath, runtime.cwd, runtime.allowOutsideCwd);
|
|
8383
|
-
await runAccessHook2(runtime, {
|
|
8384
|
-
cwd: runtime.cwd,
|
|
8385
|
-
tool: "read_files",
|
|
8386
|
-
action: "read",
|
|
8387
|
-
path: filePath
|
|
8388
|
-
});
|
|
8389
|
-
const content = await runtime.filesystem.readTextFile(filePath);
|
|
8390
|
-
const displayPath = normalizeSlashes(toDisplayPath2(filePath, runtime.cwd));
|
|
8391
|
-
sections.push(`==> ${displayPath} <==`);
|
|
8392
|
-
if (useCharWindow) {
|
|
8393
|
-
if (charOffset >= content.length) {
|
|
8394
|
-
sections.push("");
|
|
8395
|
-
continue;
|
|
8396
|
-
}
|
|
8397
|
-
const end2 = Math.min(content.length, charOffset + charLimit);
|
|
8398
|
-
sections.push(content.slice(charOffset, end2));
|
|
8399
|
-
continue;
|
|
8400
|
-
}
|
|
8401
|
-
const lines = splitLines(content);
|
|
8402
|
-
if (lineOffset >= lines.length) {
|
|
8403
|
-
sections.push("");
|
|
8404
|
-
continue;
|
|
8405
|
-
}
|
|
8406
|
-
const end = Math.min(lines.length, lineOffset + lineLimit);
|
|
8407
|
-
const selected = lines.slice(lineOffset, end);
|
|
8408
|
-
if (includeLineNumbers) {
|
|
8409
|
-
for (let index = 0; index < selected.length; index += 1) {
|
|
8410
|
-
const lineNumber = lineOffset + index + 1;
|
|
8411
|
-
const line = selected[index] ?? "";
|
|
8412
|
-
sections.push(
|
|
8413
|
-
`L${lineNumber}: ${truncateAtCodePointBoundary(line, runtime.maxLineLength)}`
|
|
8414
|
-
);
|
|
8415
|
-
}
|
|
8416
|
-
continue;
|
|
8417
|
-
}
|
|
8418
|
-
sections.push(selected.join("\n"));
|
|
8419
|
-
}
|
|
8420
|
-
return sections.join("\n");
|
|
8421
|
-
}
|
|
8422
8519
|
async function writeFileGemini(input, options) {
|
|
8423
8520
|
const runtime = resolveRuntime(options);
|
|
8424
8521
|
const filePath = resolvePathWithPolicy(input.file_path, runtime.cwd, runtime.allowOutsideCwd);
|
|
@@ -8727,117 +8824,6 @@ function truncateAtCodePointBoundary(value, maxLength) {
|
|
|
8727
8824
|
}
|
|
8728
8825
|
return Array.from(value).slice(0, maxLength).join("");
|
|
8729
8826
|
}
|
|
8730
|
-
function measureIndent(line, tabWidth) {
|
|
8731
|
-
let count = 0;
|
|
8732
|
-
for (const char of line) {
|
|
8733
|
-
if (char === " ") {
|
|
8734
|
-
count += 1;
|
|
8735
|
-
continue;
|
|
8736
|
-
}
|
|
8737
|
-
if (char === " ") {
|
|
8738
|
-
count += tabWidth;
|
|
8739
|
-
continue;
|
|
8740
|
-
}
|
|
8741
|
-
break;
|
|
8742
|
-
}
|
|
8743
|
-
return count;
|
|
8744
|
-
}
|
|
8745
|
-
function computeEffectiveIndents(records) {
|
|
8746
|
-
const effective = [];
|
|
8747
|
-
let previous = 0;
|
|
8748
|
-
for (const record of records) {
|
|
8749
|
-
if (record.raw.trim().length === 0) {
|
|
8750
|
-
effective.push(previous);
|
|
8751
|
-
} else {
|
|
8752
|
-
previous = record.indent;
|
|
8753
|
-
effective.push(previous);
|
|
8754
|
-
}
|
|
8755
|
-
}
|
|
8756
|
-
return effective;
|
|
8757
|
-
}
|
|
8758
|
-
function trimBoundaryBlankLines(records) {
|
|
8759
|
-
while (records.length > 0 && records[0]?.raw.trim().length === 0) {
|
|
8760
|
-
records.shift();
|
|
8761
|
-
}
|
|
8762
|
-
while (records.length > 0 && records[records.length - 1]?.raw.trim().length === 0) {
|
|
8763
|
-
records.pop();
|
|
8764
|
-
}
|
|
8765
|
-
}
|
|
8766
|
-
function isCommentLine(line) {
|
|
8767
|
-
const trimmed = line.trim();
|
|
8768
|
-
return trimmed.startsWith("#") || trimmed.startsWith("//") || trimmed.startsWith("--");
|
|
8769
|
-
}
|
|
8770
|
-
function readWithIndentationMode(params) {
|
|
8771
|
-
const { records, anchorLine, limit, maxLevels, includeSiblings, includeHeader, maxLines } = params;
|
|
8772
|
-
const anchorIndex = anchorLine - 1;
|
|
8773
|
-
const effectiveIndents = computeEffectiveIndents(records);
|
|
8774
|
-
const anchorIndent = effectiveIndents[anchorIndex] ?? 0;
|
|
8775
|
-
const minIndent = maxLevels === 0 ? 0 : Math.max(anchorIndent - maxLevels * DEFAULT_TAB_WIDTH, 0);
|
|
8776
|
-
const guardLimit = maxLines ?? limit;
|
|
8777
|
-
const finalLimit = Math.min(limit, guardLimit, records.length);
|
|
8778
|
-
if (finalLimit <= 1) {
|
|
8779
|
-
return [records[anchorIndex]].filter((entry) => Boolean(entry));
|
|
8780
|
-
}
|
|
8781
|
-
let upper = anchorIndex - 1;
|
|
8782
|
-
let lower = anchorIndex + 1;
|
|
8783
|
-
let upperMinIndentHits = 0;
|
|
8784
|
-
let lowerMinIndentHits = 0;
|
|
8785
|
-
const output = [records[anchorIndex]].filter(
|
|
8786
|
-
(entry) => Boolean(entry)
|
|
8787
|
-
);
|
|
8788
|
-
while (output.length < finalLimit) {
|
|
8789
|
-
let progressed = 0;
|
|
8790
|
-
if (upper >= 0) {
|
|
8791
|
-
const candidate = records[upper];
|
|
8792
|
-
const candidateIndent = effectiveIndents[upper] ?? 0;
|
|
8793
|
-
if (candidate && candidateIndent >= minIndent) {
|
|
8794
|
-
output.unshift(candidate);
|
|
8795
|
-
progressed += 1;
|
|
8796
|
-
upper -= 1;
|
|
8797
|
-
if (candidateIndent === minIndent && !includeSiblings) {
|
|
8798
|
-
const allowHeaderComment = includeHeader && isCommentLine(candidate.raw);
|
|
8799
|
-
const canTakeLine = allowHeaderComment || upperMinIndentHits === 0;
|
|
8800
|
-
if (canTakeLine) {
|
|
8801
|
-
upperMinIndentHits += 1;
|
|
8802
|
-
} else {
|
|
8803
|
-
output.shift();
|
|
8804
|
-
progressed -= 1;
|
|
8805
|
-
upper = -1;
|
|
8806
|
-
}
|
|
8807
|
-
}
|
|
8808
|
-
if (output.length >= finalLimit) {
|
|
8809
|
-
break;
|
|
8810
|
-
}
|
|
8811
|
-
} else {
|
|
8812
|
-
upper = -1;
|
|
8813
|
-
}
|
|
8814
|
-
}
|
|
8815
|
-
if (lower < records.length) {
|
|
8816
|
-
const candidate = records[lower];
|
|
8817
|
-
const candidateIndent = effectiveIndents[lower] ?? 0;
|
|
8818
|
-
if (candidate && candidateIndent >= minIndent) {
|
|
8819
|
-
output.push(candidate);
|
|
8820
|
-
progressed += 1;
|
|
8821
|
-
lower += 1;
|
|
8822
|
-
if (candidateIndent === minIndent && !includeSiblings) {
|
|
8823
|
-
if (lowerMinIndentHits > 0) {
|
|
8824
|
-
output.pop();
|
|
8825
|
-
progressed -= 1;
|
|
8826
|
-
lower = records.length;
|
|
8827
|
-
}
|
|
8828
|
-
lowerMinIndentHits += 1;
|
|
8829
|
-
}
|
|
8830
|
-
} else {
|
|
8831
|
-
lower = records.length;
|
|
8832
|
-
}
|
|
8833
|
-
}
|
|
8834
|
-
if (progressed === 0) {
|
|
8835
|
-
break;
|
|
8836
|
-
}
|
|
8837
|
-
}
|
|
8838
|
-
trimBoundaryBlankLines(output);
|
|
8839
|
-
return output;
|
|
8840
|
-
}
|
|
8841
8827
|
async function collectDirectoryEntries(filesystem, rootPath, depth, maxLineLength) {
|
|
8842
8828
|
const queue = [
|
|
8843
8829
|
{ path: rootPath, relativePrefix: "", remainingDepth: depth }
|
|
@@ -10156,10 +10142,10 @@ async function runCandidateEvolution(options) {
|
|
|
10156
10142
|
createListDirectoryTool,
|
|
10157
10143
|
createModelAgnosticFilesystemToolSet,
|
|
10158
10144
|
createNodeAgentFilesystem,
|
|
10159
|
-
createReadFilesTool,
|
|
10160
10145
|
createReplaceTool,
|
|
10161
10146
|
createRgSearchTool,
|
|
10162
10147
|
createToolLoopSteeringChannel,
|
|
10148
|
+
createViewImageTool,
|
|
10163
10149
|
createWriteFileTool,
|
|
10164
10150
|
customTool,
|
|
10165
10151
|
encodeChatGptAuthJson,
|