@ljoukov/llm 3.0.10 → 3.0.12
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 +185 -241
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -31
- package/dist/index.d.ts +31 -31
- package/dist/index.js +184 -240
- 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,
|
|
@@ -234,6 +234,15 @@ var GEMINI_2_5_PRO_PRICING = {
|
|
|
234
234
|
outputRateLow: 10 / 1e6,
|
|
235
235
|
outputRateHigh: 15 / 1e6
|
|
236
236
|
};
|
|
237
|
+
var GEMINI_2_5_FLASH_PRICING = {
|
|
238
|
+
threshold: 2e5,
|
|
239
|
+
inputRateLow: 0.3 / 1e6,
|
|
240
|
+
inputRateHigh: 0.3 / 1e6,
|
|
241
|
+
cachedRateLow: 0.03 / 1e6,
|
|
242
|
+
cachedRateHigh: 0.03 / 1e6,
|
|
243
|
+
outputRateLow: 2.5 / 1e6,
|
|
244
|
+
outputRateHigh: 2.5 / 1e6
|
|
245
|
+
};
|
|
237
246
|
var GEMINI_IMAGE_PREVIEW_PRICING = {
|
|
238
247
|
inputRate: 2 / 1e6,
|
|
239
248
|
cachedRate: 0.2 / 1e6,
|
|
@@ -249,6 +258,9 @@ function getGeminiProPricing(modelId) {
|
|
|
249
258
|
if (modelId.includes("gemini-2.5-pro")) {
|
|
250
259
|
return GEMINI_2_5_PRO_PRICING;
|
|
251
260
|
}
|
|
261
|
+
if (modelId.includes("gemini-2.5-flash") || modelId.includes("gemini-flash-latest")) {
|
|
262
|
+
return GEMINI_2_5_FLASH_PRICING;
|
|
263
|
+
}
|
|
252
264
|
if (modelId.includes("gemini-3-pro") || modelId.includes("gemini-3.1-pro")) {
|
|
253
265
|
return GEMINI_3_PRO_PREVIEW_PRICING;
|
|
254
266
|
}
|
|
@@ -2206,7 +2218,6 @@ function getGoogleAuthOptions(scopes) {
|
|
|
2206
2218
|
|
|
2207
2219
|
// src/google/client.ts
|
|
2208
2220
|
var GEMINI_TEXT_MODEL_IDS = [
|
|
2209
|
-
"gemini-3-pro-preview",
|
|
2210
2221
|
"gemini-3.1-pro-preview",
|
|
2211
2222
|
"gemini-3-flash-preview",
|
|
2212
2223
|
"gemini-2.5-pro",
|
|
@@ -4010,6 +4021,38 @@ function mergeToolOutput(value) {
|
|
|
4010
4021
|
return JSON.stringify({ error: "Failed to serialize tool output", detail: message });
|
|
4011
4022
|
}
|
|
4012
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
|
+
}
|
|
4013
4056
|
function parseOpenAiToolArguments(raw) {
|
|
4014
4057
|
const trimmed = raw.trim();
|
|
4015
4058
|
if (trimmed.length === 0) {
|
|
@@ -4365,7 +4408,6 @@ function resolveGeminiThinkingConfig(modelId) {
|
|
|
4365
4408
|
return void 0;
|
|
4366
4409
|
}
|
|
4367
4410
|
switch (modelId) {
|
|
4368
|
-
case "gemini-3-pro-preview":
|
|
4369
4411
|
case "gemini-3.1-pro-preview":
|
|
4370
4412
|
return { includeThoughts: true };
|
|
4371
4413
|
case "gemini-3-flash-preview":
|
|
@@ -5367,13 +5409,13 @@ async function runToolLoop(request) {
|
|
|
5367
5409
|
toolOutputs.push({
|
|
5368
5410
|
type: "custom_tool_call_output",
|
|
5369
5411
|
call_id: entry.call.call_id,
|
|
5370
|
-
output:
|
|
5412
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
5371
5413
|
});
|
|
5372
5414
|
} else {
|
|
5373
5415
|
toolOutputs.push({
|
|
5374
5416
|
type: "function_call_output",
|
|
5375
5417
|
call_id: entry.call.call_id,
|
|
5376
|
-
output:
|
|
5418
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
5377
5419
|
});
|
|
5378
5420
|
}
|
|
5379
5421
|
}
|
|
@@ -5588,7 +5630,7 @@ async function runToolLoop(request) {
|
|
|
5588
5630
|
toolOutputs.push({
|
|
5589
5631
|
type: "custom_tool_call_output",
|
|
5590
5632
|
call_id: entry.ids.callId,
|
|
5591
|
-
output:
|
|
5633
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
5592
5634
|
});
|
|
5593
5635
|
} else {
|
|
5594
5636
|
toolOutputs.push({
|
|
@@ -5602,7 +5644,7 @@ async function runToolLoop(request) {
|
|
|
5602
5644
|
toolOutputs.push({
|
|
5603
5645
|
type: "function_call_output",
|
|
5604
5646
|
call_id: entry.ids.callId,
|
|
5605
|
-
output:
|
|
5647
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
5606
5648
|
});
|
|
5607
5649
|
}
|
|
5608
5650
|
}
|
|
@@ -7233,6 +7275,7 @@ function sleep2(ms) {
|
|
|
7233
7275
|
|
|
7234
7276
|
// src/tools/filesystemTools.ts
|
|
7235
7277
|
var import_node_path5 = __toESM(require("path"), 1);
|
|
7278
|
+
var import_node_buffer3 = require("buffer");
|
|
7236
7279
|
var import_zod6 = require("zod");
|
|
7237
7280
|
|
|
7238
7281
|
// src/tools/applyPatch.ts
|
|
@@ -7266,6 +7309,10 @@ var InMemoryAgentFilesystem = class {
|
|
|
7266
7309
|
}
|
|
7267
7310
|
return file.content;
|
|
7268
7311
|
}
|
|
7312
|
+
async readBinaryFile(filePath) {
|
|
7313
|
+
const content = await this.readTextFile(filePath);
|
|
7314
|
+
return Buffer.from(content, "utf8");
|
|
7315
|
+
}
|
|
7269
7316
|
async writeTextFile(filePath, content) {
|
|
7270
7317
|
const absolutePath = import_node_path3.default.resolve(filePath);
|
|
7271
7318
|
const parentPath = import_node_path3.default.dirname(absolutePath);
|
|
@@ -7378,6 +7425,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
7378
7425
|
function createNodeAgentFilesystem() {
|
|
7379
7426
|
return {
|
|
7380
7427
|
readTextFile: async (filePath) => import_node_fs3.promises.readFile(filePath, "utf8"),
|
|
7428
|
+
readBinaryFile: async (filePath) => import_node_fs3.promises.readFile(filePath),
|
|
7381
7429
|
writeTextFile: async (filePath, content) => import_node_fs3.promises.writeFile(filePath, content, "utf8"),
|
|
7382
7430
|
deleteFile: async (filePath) => import_node_fs3.promises.unlink(filePath),
|
|
7383
7431
|
ensureDir: async (directoryPath) => {
|
|
@@ -7933,30 +7981,28 @@ function formatSummary(added, modified, deleted) {
|
|
|
7933
7981
|
|
|
7934
7982
|
// src/tools/filesystemTools.ts
|
|
7935
7983
|
var DEFAULT_READ_FILE_LINE_LIMIT = 2e3;
|
|
7936
|
-
var DEFAULT_READ_FILES_LINE_LIMIT = 200;
|
|
7937
|
-
var DEFAULT_READ_FILES_CHAR_LIMIT = 4e3;
|
|
7938
7984
|
var DEFAULT_LIST_DIR_LIMIT = 25;
|
|
7939
7985
|
var DEFAULT_LIST_DIR_DEPTH = 2;
|
|
7940
7986
|
var DEFAULT_GREP_LIMIT = 100;
|
|
7941
7987
|
var MAX_GREP_LIMIT = 2e3;
|
|
7988
|
+
var MAX_VIEW_IMAGE_BYTES = 10 * 1024 * 1024;
|
|
7942
7989
|
var DEFAULT_MAX_LINE_LENGTH = 500;
|
|
7943
7990
|
var DEFAULT_GREP_MAX_SCANNED_FILES = 2e4;
|
|
7944
|
-
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
|
+
};
|
|
7945
7999
|
var codexReadFileInputSchema = import_zod6.z.object({
|
|
7946
8000
|
file_path: import_zod6.z.string().min(1).describe(
|
|
7947
8001
|
"Path to the file (relative to cwd, or absolute. In sandbox mode, / maps to the sandbox root)."
|
|
7948
8002
|
),
|
|
7949
8003
|
offset: import_zod6.z.number().int().min(1).nullish().describe("The line number to start reading from. Must be 1 or greater."),
|
|
7950
|
-
limit: import_zod6.z.number().int().min(1).nullish().describe("The maximum number of lines to return.")
|
|
7951
|
-
|
|
7952
|
-
indentation: import_zod6.z.object({
|
|
7953
|
-
anchor_line: import_zod6.z.number().int().min(1).nullish(),
|
|
7954
|
-
max_levels: import_zod6.z.number().int().min(0).nullish(),
|
|
7955
|
-
include_siblings: import_zod6.z.boolean().nullish(),
|
|
7956
|
-
include_header: import_zod6.z.boolean().nullish(),
|
|
7957
|
-
max_lines: import_zod6.z.number().int().min(1).nullish()
|
|
7958
|
-
}).nullish()
|
|
7959
|
-
});
|
|
8004
|
+
limit: import_zod6.z.number().int().min(1).nullish().describe("The maximum number of lines to return.")
|
|
8005
|
+
}).strict();
|
|
7960
8006
|
var codexListDirInputSchema = import_zod6.z.object({
|
|
7961
8007
|
dir_path: import_zod6.z.string().min(1).describe(
|
|
7962
8008
|
"Path to the directory to list (relative to cwd, or absolute. In sandbox mode, / maps to the sandbox root)."
|
|
@@ -7971,6 +8017,9 @@ var codexGrepFilesInputSchema = import_zod6.z.object({
|
|
|
7971
8017
|
path: import_zod6.z.string().nullish().describe("Directory or file path to search. Defaults to cwd."),
|
|
7972
8018
|
limit: import_zod6.z.number().int().min(1).nullish().describe("Maximum number of file paths to return (defaults to 100).")
|
|
7973
8019
|
});
|
|
8020
|
+
var codexViewImageInputSchema = import_zod6.z.object({
|
|
8021
|
+
path: import_zod6.z.string().min(1).describe("Local filesystem path to an image file")
|
|
8022
|
+
});
|
|
7974
8023
|
var applyPatchInputSchema = import_zod6.z.object({
|
|
7975
8024
|
input: import_zod6.z.string().min(1).describe(CODEX_APPLY_PATCH_INPUT_DESCRIPTION)
|
|
7976
8025
|
});
|
|
@@ -7978,24 +8027,7 @@ var geminiReadFileInputSchema = import_zod6.z.object({
|
|
|
7978
8027
|
file_path: import_zod6.z.string().min(1),
|
|
7979
8028
|
offset: import_zod6.z.number().int().min(0).nullish(),
|
|
7980
8029
|
limit: import_zod6.z.number().int().min(1).nullish()
|
|
7981
|
-
});
|
|
7982
|
-
var geminiReadFilesInputSchema = import_zod6.z.object({
|
|
7983
|
-
paths: import_zod6.z.array(import_zod6.z.string().min(1)).min(1),
|
|
7984
|
-
line_offset: import_zod6.z.number().int().min(0).nullish(),
|
|
7985
|
-
line_limit: import_zod6.z.number().int().min(1).nullish(),
|
|
7986
|
-
char_offset: import_zod6.z.number().int().min(0).nullish(),
|
|
7987
|
-
char_limit: import_zod6.z.number().int().min(1).nullish(),
|
|
7988
|
-
include_line_numbers: import_zod6.z.boolean().nullish()
|
|
7989
|
-
}).superRefine((value, context) => {
|
|
7990
|
-
const hasLineWindow = value.line_offset !== void 0 || value.line_limit !== void 0;
|
|
7991
|
-
const hasCharWindow = value.char_offset !== void 0 || value.char_limit !== void 0;
|
|
7992
|
-
if (hasLineWindow && hasCharWindow) {
|
|
7993
|
-
context.addIssue({
|
|
7994
|
-
code: import_zod6.z.ZodIssueCode.custom,
|
|
7995
|
-
message: "Use either line_* or char_* window arguments, not both."
|
|
7996
|
-
});
|
|
7997
|
-
}
|
|
7998
|
-
});
|
|
8030
|
+
}).strict();
|
|
7999
8031
|
var geminiWriteFileInputSchema = import_zod6.z.object({
|
|
8000
8032
|
file_path: import_zod6.z.string().min(1),
|
|
8001
8033
|
content: import_zod6.z.string()
|
|
@@ -8078,7 +8110,8 @@ function createCodexFilesystemToolSet(options = {}) {
|
|
|
8078
8110
|
apply_patch: createCodexApplyPatchTool(options),
|
|
8079
8111
|
read_file: createCodexReadFileTool(options),
|
|
8080
8112
|
list_dir: createListDirTool(options),
|
|
8081
|
-
grep_files: createGrepFilesTool(options)
|
|
8113
|
+
grep_files: createGrepFilesTool(options),
|
|
8114
|
+
view_image: createViewImageTool(options)
|
|
8082
8115
|
};
|
|
8083
8116
|
}
|
|
8084
8117
|
function createGeminiFilesystemToolSet(options = {}) {
|
|
@@ -8127,7 +8160,7 @@ function createCodexApplyPatchTool(options = {}) {
|
|
|
8127
8160
|
}
|
|
8128
8161
|
function createCodexReadFileTool(options = {}) {
|
|
8129
8162
|
return tool({
|
|
8130
|
-
description: "Reads a local file with 1-indexed line numbers
|
|
8163
|
+
description: "Reads a local UTF-8 text file with 1-indexed line numbers.",
|
|
8131
8164
|
inputSchema: codexReadFileInputSchema,
|
|
8132
8165
|
execute: async (input) => readFileCodex(input, options)
|
|
8133
8166
|
});
|
|
@@ -8146,6 +8179,13 @@ function createGrepFilesTool(options = {}) {
|
|
|
8146
8179
|
execute: async (input) => grepFilesCodex(input, options)
|
|
8147
8180
|
});
|
|
8148
8181
|
}
|
|
8182
|
+
function createViewImageTool(options = {}) {
|
|
8183
|
+
return tool({
|
|
8184
|
+
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).",
|
|
8185
|
+
inputSchema: codexViewImageInputSchema,
|
|
8186
|
+
execute: async (input) => viewImageCodex(input, options)
|
|
8187
|
+
});
|
|
8188
|
+
}
|
|
8149
8189
|
function createGeminiReadFileTool(options = {}) {
|
|
8150
8190
|
return tool({
|
|
8151
8191
|
description: "Reads and returns the content of a specified file. Supports optional 0-based line offset and line limit.",
|
|
@@ -8153,13 +8193,6 @@ function createGeminiReadFileTool(options = {}) {
|
|
|
8153
8193
|
execute: async (input) => readFileGemini(input, options)
|
|
8154
8194
|
});
|
|
8155
8195
|
}
|
|
8156
|
-
function createReadFilesTool(options = {}) {
|
|
8157
|
-
return tool({
|
|
8158
|
-
description: "Reads one or more files with optional line-based or character-based slicing, similar to a controlled head/tail view.",
|
|
8159
|
-
inputSchema: geminiReadFilesInputSchema,
|
|
8160
|
-
execute: async (input) => readFilesGemini(input, options)
|
|
8161
|
-
});
|
|
8162
|
-
}
|
|
8163
8196
|
function createWriteFileTool(options = {}) {
|
|
8164
8197
|
return tool({
|
|
8165
8198
|
description: "Writes content to a specified file in the local filesystem.",
|
|
@@ -8211,44 +8244,37 @@ async function readFileCodex(input, options) {
|
|
|
8211
8244
|
action: "read",
|
|
8212
8245
|
path: filePath
|
|
8213
8246
|
});
|
|
8214
|
-
const
|
|
8247
|
+
const fileBytes = await readBinaryFile(runtime.filesystem, filePath);
|
|
8248
|
+
const imageMimeType = detectImageMimeType(fileBytes, filePath);
|
|
8249
|
+
if (imageMimeType) {
|
|
8250
|
+
throw new Error(
|
|
8251
|
+
`read_file only supports text files; "${toDisplayPath2(filePath, runtime.cwd)}" is an image (${imageMimeType}). Use view_image instead.`
|
|
8252
|
+
);
|
|
8253
|
+
}
|
|
8254
|
+
if (isPdfFile(fileBytes, filePath)) {
|
|
8255
|
+
throw new Error(
|
|
8256
|
+
`read_file only supports text files; "${toDisplayPath2(filePath, runtime.cwd)}" is a PDF.`
|
|
8257
|
+
);
|
|
8258
|
+
}
|
|
8259
|
+
if (!isValidUtf8(fileBytes)) {
|
|
8260
|
+
throw new Error(
|
|
8261
|
+
`read_file only supports UTF-8 text files; "${toDisplayPath2(filePath, runtime.cwd)}" appears to be binary.`
|
|
8262
|
+
);
|
|
8263
|
+
}
|
|
8264
|
+
const content = fileBytes.toString("utf8");
|
|
8215
8265
|
const lines = splitLines(content);
|
|
8216
8266
|
const offset = input.offset ?? 1;
|
|
8217
8267
|
const limit = input.limit ?? DEFAULT_READ_FILE_LINE_LIMIT;
|
|
8218
|
-
const mode = input.mode ?? "slice";
|
|
8219
8268
|
if (offset > lines.length) {
|
|
8220
8269
|
throw new Error("offset exceeds file length");
|
|
8221
8270
|
}
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
return output.join("\n");
|
|
8230
|
-
}
|
|
8231
|
-
const indentation = input.indentation ?? {};
|
|
8232
|
-
const anchorLine = indentation.anchor_line ?? offset;
|
|
8233
|
-
if (anchorLine < 1 || anchorLine > lines.length) {
|
|
8234
|
-
throw new Error("anchor_line exceeds file length");
|
|
8235
|
-
}
|
|
8236
|
-
const records = lines.map((line, index) => ({
|
|
8237
|
-
number: index + 1,
|
|
8238
|
-
raw: line,
|
|
8239
|
-
display: truncateAtCodePointBoundary(line, runtime.maxLineLength),
|
|
8240
|
-
indent: measureIndent(line, DEFAULT_TAB_WIDTH)
|
|
8241
|
-
}));
|
|
8242
|
-
const selected = readWithIndentationMode({
|
|
8243
|
-
records,
|
|
8244
|
-
anchorLine,
|
|
8245
|
-
limit,
|
|
8246
|
-
maxLevels: indentation.max_levels ?? 0,
|
|
8247
|
-
includeSiblings: indentation.include_siblings ?? false,
|
|
8248
|
-
includeHeader: indentation.include_header ?? true,
|
|
8249
|
-
maxLines: indentation.max_lines ?? void 0
|
|
8250
|
-
});
|
|
8251
|
-
return selected.map((record) => `L${record.number}: ${record.display}`).join("\n");
|
|
8271
|
+
const output = [];
|
|
8272
|
+
const lastLine = Math.min(lines.length, offset + limit - 1);
|
|
8273
|
+
for (let lineNumber = offset; lineNumber <= lastLine; lineNumber += 1) {
|
|
8274
|
+
const line = lines[lineNumber - 1] ?? "";
|
|
8275
|
+
output.push(`L${lineNumber}: ${truncateAtCodePointBoundary(line, runtime.maxLineLength)}`);
|
|
8276
|
+
}
|
|
8277
|
+
return output.join("\n");
|
|
8252
8278
|
}
|
|
8253
8279
|
async function listDirectoryCodex(input, options) {
|
|
8254
8280
|
const runtime = resolveRuntime(options);
|
|
@@ -8336,6 +8362,85 @@ async function grepFilesCodex(input, options) {
|
|
|
8336
8362
|
const limit = Math.min(input.limit ?? DEFAULT_GREP_LIMIT, MAX_GREP_LIMIT);
|
|
8337
8363
|
return matches.slice(0, limit).map((match) => match.filePath).join("\n");
|
|
8338
8364
|
}
|
|
8365
|
+
async function viewImageCodex(input, options) {
|
|
8366
|
+
const runtime = resolveRuntime(options);
|
|
8367
|
+
const imagePath = resolvePathWithPolicy(input.path, runtime.cwd, runtime.allowOutsideCwd);
|
|
8368
|
+
await runAccessHook2(runtime, {
|
|
8369
|
+
cwd: runtime.cwd,
|
|
8370
|
+
tool: "view_image",
|
|
8371
|
+
action: "read",
|
|
8372
|
+
path: imagePath
|
|
8373
|
+
});
|
|
8374
|
+
const stats = await runtime.filesystem.stat(imagePath);
|
|
8375
|
+
if (stats.kind !== "file") {
|
|
8376
|
+
throw new Error(`image path \`${toDisplayPath2(imagePath, runtime.cwd)}\` is not a file`);
|
|
8377
|
+
}
|
|
8378
|
+
const bytes = await readBinaryFile(runtime.filesystem, imagePath);
|
|
8379
|
+
if (bytes.byteLength > MAX_VIEW_IMAGE_BYTES) {
|
|
8380
|
+
return [
|
|
8381
|
+
{
|
|
8382
|
+
type: "input_text",
|
|
8383
|
+
text: `Codex cannot attach image at \`${toDisplayPath2(imagePath, runtime.cwd)}\`: image exceeds ${MAX_VIEW_IMAGE_BYTES} bytes.`
|
|
8384
|
+
}
|
|
8385
|
+
];
|
|
8386
|
+
}
|
|
8387
|
+
const mimeType = detectImageMimeType(bytes, imagePath);
|
|
8388
|
+
if (!mimeType) {
|
|
8389
|
+
return [
|
|
8390
|
+
{
|
|
8391
|
+
type: "input_text",
|
|
8392
|
+
text: `Codex cannot attach image at \`${toDisplayPath2(imagePath, runtime.cwd)}\`: unsupported image format.`
|
|
8393
|
+
}
|
|
8394
|
+
];
|
|
8395
|
+
}
|
|
8396
|
+
return [
|
|
8397
|
+
{
|
|
8398
|
+
type: "input_image",
|
|
8399
|
+
image_url: `data:${mimeType};base64,${bytes.toString("base64")}`
|
|
8400
|
+
}
|
|
8401
|
+
];
|
|
8402
|
+
}
|
|
8403
|
+
async function readBinaryFile(filesystem, filePath) {
|
|
8404
|
+
if (typeof filesystem.readBinaryFile === "function") {
|
|
8405
|
+
return await filesystem.readBinaryFile(filePath);
|
|
8406
|
+
}
|
|
8407
|
+
const text = await filesystem.readTextFile(filePath);
|
|
8408
|
+
return import_node_buffer3.Buffer.from(text, "utf8");
|
|
8409
|
+
}
|
|
8410
|
+
function detectImageMimeType(buffer, filePath) {
|
|
8411
|
+
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) {
|
|
8412
|
+
return "image/png";
|
|
8413
|
+
}
|
|
8414
|
+
if (buffer.length >= 3 && buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) {
|
|
8415
|
+
return "image/jpeg";
|
|
8416
|
+
}
|
|
8417
|
+
if (buffer.length >= 6) {
|
|
8418
|
+
const signature = buffer.subarray(0, 6).toString("ascii");
|
|
8419
|
+
if (signature === "GIF87a" || signature === "GIF89a") {
|
|
8420
|
+
return "image/gif";
|
|
8421
|
+
}
|
|
8422
|
+
}
|
|
8423
|
+
if (buffer.length >= 12 && buffer.subarray(0, 4).toString("ascii") === "RIFF" && buffer.subarray(8, 12).toString("ascii") === "WEBP") {
|
|
8424
|
+
return "image/webp";
|
|
8425
|
+
}
|
|
8426
|
+
const fromExtension = IMAGE_MIME_BY_EXTENSION[import_node_path5.default.extname(filePath).toLowerCase()];
|
|
8427
|
+
if (fromExtension && SUPPORTED_IMAGE_MIME_TYPES.has(fromExtension)) {
|
|
8428
|
+
return fromExtension;
|
|
8429
|
+
}
|
|
8430
|
+
return void 0;
|
|
8431
|
+
}
|
|
8432
|
+
function isPdfFile(buffer, filePath) {
|
|
8433
|
+
if (buffer.length >= 5 && buffer.subarray(0, 5).toString("ascii") === "%PDF-") {
|
|
8434
|
+
return true;
|
|
8435
|
+
}
|
|
8436
|
+
return import_node_path5.default.extname(filePath).toLowerCase() === ".pdf";
|
|
8437
|
+
}
|
|
8438
|
+
function isValidUtf8(buffer) {
|
|
8439
|
+
if (buffer.length === 0) {
|
|
8440
|
+
return true;
|
|
8441
|
+
}
|
|
8442
|
+
return import_node_buffer3.Buffer.from(buffer.toString("utf8"), "utf8").equals(buffer);
|
|
8443
|
+
}
|
|
8339
8444
|
async function readFileGemini(input, options) {
|
|
8340
8445
|
const runtime = resolveRuntime(options);
|
|
8341
8446
|
const filePath = resolvePathWithPolicy(input.file_path, runtime.cwd, runtime.allowOutsideCwd);
|
|
@@ -8357,56 +8462,6 @@ async function readFileGemini(input, options) {
|
|
|
8357
8462
|
(line, index) => `L${offset + index + 1}: ${truncateAtCodePointBoundary(line ?? "", runtime.maxLineLength)}`
|
|
8358
8463
|
).join("\n");
|
|
8359
8464
|
}
|
|
8360
|
-
async function readFilesGemini(input, options) {
|
|
8361
|
-
const runtime = resolveRuntime(options);
|
|
8362
|
-
const useCharWindow = input.char_offset !== void 0 || input.char_limit !== void 0;
|
|
8363
|
-
const lineOffset = Math.max(0, input.line_offset ?? 0);
|
|
8364
|
-
const lineLimit = input.line_limit ?? DEFAULT_READ_FILES_LINE_LIMIT;
|
|
8365
|
-
const charOffset = Math.max(0, input.char_offset ?? 0);
|
|
8366
|
-
const charLimit = input.char_limit ?? DEFAULT_READ_FILES_CHAR_LIMIT;
|
|
8367
|
-
const includeLineNumbers = input.include_line_numbers !== false;
|
|
8368
|
-
const sections = [];
|
|
8369
|
-
for (const rawPath of input.paths) {
|
|
8370
|
-
const filePath = resolvePathWithPolicy(rawPath, runtime.cwd, runtime.allowOutsideCwd);
|
|
8371
|
-
await runAccessHook2(runtime, {
|
|
8372
|
-
cwd: runtime.cwd,
|
|
8373
|
-
tool: "read_files",
|
|
8374
|
-
action: "read",
|
|
8375
|
-
path: filePath
|
|
8376
|
-
});
|
|
8377
|
-
const content = await runtime.filesystem.readTextFile(filePath);
|
|
8378
|
-
const displayPath = normalizeSlashes(toDisplayPath2(filePath, runtime.cwd));
|
|
8379
|
-
sections.push(`==> ${displayPath} <==`);
|
|
8380
|
-
if (useCharWindow) {
|
|
8381
|
-
if (charOffset >= content.length) {
|
|
8382
|
-
sections.push("");
|
|
8383
|
-
continue;
|
|
8384
|
-
}
|
|
8385
|
-
const end2 = Math.min(content.length, charOffset + charLimit);
|
|
8386
|
-
sections.push(content.slice(charOffset, end2));
|
|
8387
|
-
continue;
|
|
8388
|
-
}
|
|
8389
|
-
const lines = splitLines(content);
|
|
8390
|
-
if (lineOffset >= lines.length) {
|
|
8391
|
-
sections.push("");
|
|
8392
|
-
continue;
|
|
8393
|
-
}
|
|
8394
|
-
const end = Math.min(lines.length, lineOffset + lineLimit);
|
|
8395
|
-
const selected = lines.slice(lineOffset, end);
|
|
8396
|
-
if (includeLineNumbers) {
|
|
8397
|
-
for (let index = 0; index < selected.length; index += 1) {
|
|
8398
|
-
const lineNumber = lineOffset + index + 1;
|
|
8399
|
-
const line = selected[index] ?? "";
|
|
8400
|
-
sections.push(
|
|
8401
|
-
`L${lineNumber}: ${truncateAtCodePointBoundary(line, runtime.maxLineLength)}`
|
|
8402
|
-
);
|
|
8403
|
-
}
|
|
8404
|
-
continue;
|
|
8405
|
-
}
|
|
8406
|
-
sections.push(selected.join("\n"));
|
|
8407
|
-
}
|
|
8408
|
-
return sections.join("\n");
|
|
8409
|
-
}
|
|
8410
8465
|
async function writeFileGemini(input, options) {
|
|
8411
8466
|
const runtime = resolveRuntime(options);
|
|
8412
8467
|
const filePath = resolvePathWithPolicy(input.file_path, runtime.cwd, runtime.allowOutsideCwd);
|
|
@@ -8715,117 +8770,6 @@ function truncateAtCodePointBoundary(value, maxLength) {
|
|
|
8715
8770
|
}
|
|
8716
8771
|
return Array.from(value).slice(0, maxLength).join("");
|
|
8717
8772
|
}
|
|
8718
|
-
function measureIndent(line, tabWidth) {
|
|
8719
|
-
let count = 0;
|
|
8720
|
-
for (const char of line) {
|
|
8721
|
-
if (char === " ") {
|
|
8722
|
-
count += 1;
|
|
8723
|
-
continue;
|
|
8724
|
-
}
|
|
8725
|
-
if (char === " ") {
|
|
8726
|
-
count += tabWidth;
|
|
8727
|
-
continue;
|
|
8728
|
-
}
|
|
8729
|
-
break;
|
|
8730
|
-
}
|
|
8731
|
-
return count;
|
|
8732
|
-
}
|
|
8733
|
-
function computeEffectiveIndents(records) {
|
|
8734
|
-
const effective = [];
|
|
8735
|
-
let previous = 0;
|
|
8736
|
-
for (const record of records) {
|
|
8737
|
-
if (record.raw.trim().length === 0) {
|
|
8738
|
-
effective.push(previous);
|
|
8739
|
-
} else {
|
|
8740
|
-
previous = record.indent;
|
|
8741
|
-
effective.push(previous);
|
|
8742
|
-
}
|
|
8743
|
-
}
|
|
8744
|
-
return effective;
|
|
8745
|
-
}
|
|
8746
|
-
function trimBoundaryBlankLines(records) {
|
|
8747
|
-
while (records.length > 0 && records[0]?.raw.trim().length === 0) {
|
|
8748
|
-
records.shift();
|
|
8749
|
-
}
|
|
8750
|
-
while (records.length > 0 && records[records.length - 1]?.raw.trim().length === 0) {
|
|
8751
|
-
records.pop();
|
|
8752
|
-
}
|
|
8753
|
-
}
|
|
8754
|
-
function isCommentLine(line) {
|
|
8755
|
-
const trimmed = line.trim();
|
|
8756
|
-
return trimmed.startsWith("#") || trimmed.startsWith("//") || trimmed.startsWith("--");
|
|
8757
|
-
}
|
|
8758
|
-
function readWithIndentationMode(params) {
|
|
8759
|
-
const { records, anchorLine, limit, maxLevels, includeSiblings, includeHeader, maxLines } = params;
|
|
8760
|
-
const anchorIndex = anchorLine - 1;
|
|
8761
|
-
const effectiveIndents = computeEffectiveIndents(records);
|
|
8762
|
-
const anchorIndent = effectiveIndents[anchorIndex] ?? 0;
|
|
8763
|
-
const minIndent = maxLevels === 0 ? 0 : Math.max(anchorIndent - maxLevels * DEFAULT_TAB_WIDTH, 0);
|
|
8764
|
-
const guardLimit = maxLines ?? limit;
|
|
8765
|
-
const finalLimit = Math.min(limit, guardLimit, records.length);
|
|
8766
|
-
if (finalLimit <= 1) {
|
|
8767
|
-
return [records[anchorIndex]].filter((entry) => Boolean(entry));
|
|
8768
|
-
}
|
|
8769
|
-
let upper = anchorIndex - 1;
|
|
8770
|
-
let lower = anchorIndex + 1;
|
|
8771
|
-
let upperMinIndentHits = 0;
|
|
8772
|
-
let lowerMinIndentHits = 0;
|
|
8773
|
-
const output = [records[anchorIndex]].filter(
|
|
8774
|
-
(entry) => Boolean(entry)
|
|
8775
|
-
);
|
|
8776
|
-
while (output.length < finalLimit) {
|
|
8777
|
-
let progressed = 0;
|
|
8778
|
-
if (upper >= 0) {
|
|
8779
|
-
const candidate = records[upper];
|
|
8780
|
-
const candidateIndent = effectiveIndents[upper] ?? 0;
|
|
8781
|
-
if (candidate && candidateIndent >= minIndent) {
|
|
8782
|
-
output.unshift(candidate);
|
|
8783
|
-
progressed += 1;
|
|
8784
|
-
upper -= 1;
|
|
8785
|
-
if (candidateIndent === minIndent && !includeSiblings) {
|
|
8786
|
-
const allowHeaderComment = includeHeader && isCommentLine(candidate.raw);
|
|
8787
|
-
const canTakeLine = allowHeaderComment || upperMinIndentHits === 0;
|
|
8788
|
-
if (canTakeLine) {
|
|
8789
|
-
upperMinIndentHits += 1;
|
|
8790
|
-
} else {
|
|
8791
|
-
output.shift();
|
|
8792
|
-
progressed -= 1;
|
|
8793
|
-
upper = -1;
|
|
8794
|
-
}
|
|
8795
|
-
}
|
|
8796
|
-
if (output.length >= finalLimit) {
|
|
8797
|
-
break;
|
|
8798
|
-
}
|
|
8799
|
-
} else {
|
|
8800
|
-
upper = -1;
|
|
8801
|
-
}
|
|
8802
|
-
}
|
|
8803
|
-
if (lower < records.length) {
|
|
8804
|
-
const candidate = records[lower];
|
|
8805
|
-
const candidateIndent = effectiveIndents[lower] ?? 0;
|
|
8806
|
-
if (candidate && candidateIndent >= minIndent) {
|
|
8807
|
-
output.push(candidate);
|
|
8808
|
-
progressed += 1;
|
|
8809
|
-
lower += 1;
|
|
8810
|
-
if (candidateIndent === minIndent && !includeSiblings) {
|
|
8811
|
-
if (lowerMinIndentHits > 0) {
|
|
8812
|
-
output.pop();
|
|
8813
|
-
progressed -= 1;
|
|
8814
|
-
lower = records.length;
|
|
8815
|
-
}
|
|
8816
|
-
lowerMinIndentHits += 1;
|
|
8817
|
-
}
|
|
8818
|
-
} else {
|
|
8819
|
-
lower = records.length;
|
|
8820
|
-
}
|
|
8821
|
-
}
|
|
8822
|
-
if (progressed === 0) {
|
|
8823
|
-
break;
|
|
8824
|
-
}
|
|
8825
|
-
}
|
|
8826
|
-
trimBoundaryBlankLines(output);
|
|
8827
|
-
return output;
|
|
8828
|
-
}
|
|
8829
8773
|
async function collectDirectoryEntries(filesystem, rootPath, depth, maxLineLength) {
|
|
8830
8774
|
const queue = [
|
|
8831
8775
|
{ path: rootPath, relativePrefix: "", remainingDepth: depth }
|
|
@@ -10144,10 +10088,10 @@ async function runCandidateEvolution(options) {
|
|
|
10144
10088
|
createListDirectoryTool,
|
|
10145
10089
|
createModelAgnosticFilesystemToolSet,
|
|
10146
10090
|
createNodeAgentFilesystem,
|
|
10147
|
-
createReadFilesTool,
|
|
10148
10091
|
createReplaceTool,
|
|
10149
10092
|
createRgSearchTool,
|
|
10150
10093
|
createToolLoopSteeringChannel,
|
|
10094
|
+
createViewImageTool,
|
|
10151
10095
|
createWriteFileTool,
|
|
10152
10096
|
customTool,
|
|
10153
10097
|
encodeChatGptAuthJson,
|