@ljoukov/llm 4.0.11 → 4.1.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 +127 -4
- package/dist/index.cjs +2039 -574
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +85 -13
- package/dist/index.d.ts +85 -13
- package/dist/index.js +1999 -537
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -34,6 +34,7 @@ __export(index_exports, {
|
|
|
34
34
|
CODEX_APPLY_PATCH_FREEFORM_TOOL_DESCRIPTION: () => CODEX_APPLY_PATCH_FREEFORM_TOOL_DESCRIPTION,
|
|
35
35
|
CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION: () => CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION,
|
|
36
36
|
CODEX_APPLY_PATCH_LARK_GRAMMAR: () => CODEX_APPLY_PATCH_LARK_GRAMMAR,
|
|
37
|
+
DEFAULT_FILE_TTL_SECONDS: () => DEFAULT_FILE_TTL_SECONDS,
|
|
37
38
|
FIREWORKS_DEFAULT_GLM_MODEL: () => FIREWORKS_DEFAULT_GLM_MODEL,
|
|
38
39
|
FIREWORKS_DEFAULT_GPT_OSS_120B_MODEL: () => FIREWORKS_DEFAULT_GPT_OSS_120B_MODEL,
|
|
39
40
|
FIREWORKS_DEFAULT_KIMI_MODEL: () => FIREWORKS_DEFAULT_KIMI_MODEL,
|
|
@@ -74,10 +75,12 @@ __export(index_exports, {
|
|
|
74
75
|
createViewImageTool: () => createViewImageTool,
|
|
75
76
|
createWriteFileTool: () => createWriteFileTool,
|
|
76
77
|
customTool: () => customTool,
|
|
78
|
+
emptyFileUploadMetrics: () => emptyFileUploadMetrics,
|
|
77
79
|
encodeChatGptAuthJson: () => encodeChatGptAuthJson,
|
|
78
80
|
encodeChatGptAuthJsonB64: () => encodeChatGptAuthJsonB64,
|
|
79
81
|
estimateCallCostUsd: () => estimateCallCostUsd,
|
|
80
82
|
exchangeChatGptOauthCode: () => exchangeChatGptOauthCode,
|
|
83
|
+
files: () => files,
|
|
81
84
|
generateImageInBatches: () => generateImageInBatches,
|
|
82
85
|
generateImages: () => generateImages,
|
|
83
86
|
generateJson: () => generateJson,
|
|
@@ -115,9 +118,10 @@ __export(index_exports, {
|
|
|
115
118
|
module.exports = __toCommonJS(index_exports);
|
|
116
119
|
|
|
117
120
|
// src/llm.ts
|
|
118
|
-
var
|
|
119
|
-
var
|
|
120
|
-
var
|
|
121
|
+
var import_node_buffer4 = require("buffer");
|
|
122
|
+
var import_node_async_hooks3 = require("async_hooks");
|
|
123
|
+
var import_node_crypto2 = require("crypto");
|
|
124
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
121
125
|
var import_genai2 = require("@google/genai");
|
|
122
126
|
var import_zod_to_json_schema = require("@alcyone-labs/zod-to-json-schema");
|
|
123
127
|
var import_zod3 = require("zod");
|
|
@@ -2357,6 +2361,14 @@ function normaliseConfigValue(value) {
|
|
|
2357
2361
|
const trimmed = value.trim();
|
|
2358
2362
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
2359
2363
|
}
|
|
2364
|
+
function resolveGeminiApiKey() {
|
|
2365
|
+
loadLocalEnv();
|
|
2366
|
+
const raw = process.env.GEMINI_API_KEY ?? process.env.GOOGLE_API_KEY;
|
|
2367
|
+
return normaliseConfigValue(raw);
|
|
2368
|
+
}
|
|
2369
|
+
function getGeminiBackend() {
|
|
2370
|
+
return resolveGeminiApiKey() ? "api" : "vertex";
|
|
2371
|
+
}
|
|
2360
2372
|
function configureGemini(options = {}) {
|
|
2361
2373
|
const nextProjectId = normaliseConfigValue(options.projectId);
|
|
2362
2374
|
const nextLocation = normaliseConfigValue(options.location);
|
|
@@ -2384,6 +2396,10 @@ function resolveLocation() {
|
|
|
2384
2396
|
async function getGeminiClient() {
|
|
2385
2397
|
if (!geminiClientState.clientPromise) {
|
|
2386
2398
|
geminiClientState.clientPromise = Promise.resolve().then(() => {
|
|
2399
|
+
const apiKey = resolveGeminiApiKey();
|
|
2400
|
+
if (apiKey) {
|
|
2401
|
+
return new import_genai.GoogleGenAI({ apiKey });
|
|
2402
|
+
}
|
|
2387
2403
|
const projectId = resolveProjectId();
|
|
2388
2404
|
const location = resolveLocation();
|
|
2389
2405
|
const googleAuthOptions = getGoogleAuthOptions(CLOUD_PLATFORM_SCOPE);
|
|
@@ -3350,14 +3366,708 @@ function getCurrentAgentLoggingSession() {
|
|
|
3350
3366
|
return loggingSessionStorage.getStore();
|
|
3351
3367
|
}
|
|
3352
3368
|
|
|
3369
|
+
// src/files.ts
|
|
3370
|
+
var import_node_async_hooks2 = require("async_hooks");
|
|
3371
|
+
var import_node_buffer3 = require("buffer");
|
|
3372
|
+
var import_node_crypto = require("crypto");
|
|
3373
|
+
var import_node_fs3 = require("fs");
|
|
3374
|
+
var import_promises2 = require("fs/promises");
|
|
3375
|
+
var import_node_os3 = __toESM(require("os"), 1);
|
|
3376
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
3377
|
+
var import_node_stream = require("stream");
|
|
3378
|
+
var import_promises3 = require("stream/promises");
|
|
3379
|
+
var import_storage = require("@google-cloud/storage");
|
|
3380
|
+
var import_mime = __toESM(require("mime"), 1);
|
|
3381
|
+
var DEFAULT_FILE_TTL_SECONDS = 48 * 60 * 60;
|
|
3382
|
+
var OPENAI_FILE_CREATE_MAX_BYTES = 512 * 1024 * 1024;
|
|
3383
|
+
var OPENAI_UPLOAD_PART_MAX_BYTES = 64 * 1024 * 1024;
|
|
3384
|
+
var GEMINI_FILE_POLL_INTERVAL_MS = 1e3;
|
|
3385
|
+
var GEMINI_FILE_POLL_TIMEOUT_MS = 6e4;
|
|
3386
|
+
var FILES_TEMP_ROOT = import_node_path4.default.join(import_node_os3.default.tmpdir(), "ljoukov-llm-files");
|
|
3387
|
+
var filesState = getRuntimeSingleton(/* @__PURE__ */ Symbol.for("@ljoukov/llm.filesState"), () => ({
|
|
3388
|
+
metadataById: /* @__PURE__ */ new Map(),
|
|
3389
|
+
openAiUploadCacheByKey: /* @__PURE__ */ new Map(),
|
|
3390
|
+
materializedById: /* @__PURE__ */ new Map(),
|
|
3391
|
+
geminiMirrorById: /* @__PURE__ */ new Map(),
|
|
3392
|
+
vertexMirrorById: /* @__PURE__ */ new Map(),
|
|
3393
|
+
storageClient: void 0,
|
|
3394
|
+
geminiClientPromise: void 0
|
|
3395
|
+
}));
|
|
3396
|
+
var fileUploadScopeStorage = getRuntimeSingleton(
|
|
3397
|
+
/* @__PURE__ */ Symbol.for("@ljoukov/llm.fileUploadScopeStorage"),
|
|
3398
|
+
() => new import_node_async_hooks2.AsyncLocalStorage()
|
|
3399
|
+
);
|
|
3400
|
+
function summarizeUploadEvents(events) {
|
|
3401
|
+
let totalBytes = 0;
|
|
3402
|
+
let totalLatencyMs = 0;
|
|
3403
|
+
for (const event of events) {
|
|
3404
|
+
totalBytes += Math.max(0, event.bytes);
|
|
3405
|
+
totalLatencyMs += Math.max(0, event.durationMs);
|
|
3406
|
+
}
|
|
3407
|
+
return {
|
|
3408
|
+
count: events.length,
|
|
3409
|
+
totalBytes,
|
|
3410
|
+
totalLatencyMs,
|
|
3411
|
+
events: Array.from(events)
|
|
3412
|
+
};
|
|
3413
|
+
}
|
|
3414
|
+
function emptyFileUploadMetrics() {
|
|
3415
|
+
return summarizeUploadEvents([]);
|
|
3416
|
+
}
|
|
3417
|
+
function getCurrentFileUploadMetrics() {
|
|
3418
|
+
const collector = fileUploadScopeStorage.getStore()?.collectors.at(-1);
|
|
3419
|
+
return summarizeUploadEvents(collector?.events ?? []);
|
|
3420
|
+
}
|
|
3421
|
+
async function collectFileUploadMetrics(fn) {
|
|
3422
|
+
const parent = fileUploadScopeStorage.getStore();
|
|
3423
|
+
const collector = { events: [] };
|
|
3424
|
+
const scope = {
|
|
3425
|
+
collectors: [...parent?.collectors ?? [], collector],
|
|
3426
|
+
source: parent?.source
|
|
3427
|
+
};
|
|
3428
|
+
return await fileUploadScopeStorage.run(scope, async () => {
|
|
3429
|
+
const result = await fn();
|
|
3430
|
+
return {
|
|
3431
|
+
result,
|
|
3432
|
+
uploads: summarizeUploadEvents(collector.events)
|
|
3433
|
+
};
|
|
3434
|
+
});
|
|
3435
|
+
}
|
|
3436
|
+
async function runWithFileUploadSource(source, fn) {
|
|
3437
|
+
const parent = fileUploadScopeStorage.getStore();
|
|
3438
|
+
const scope = {
|
|
3439
|
+
collectors: parent?.collectors ?? [],
|
|
3440
|
+
source
|
|
3441
|
+
};
|
|
3442
|
+
return await fileUploadScopeStorage.run(scope, fn);
|
|
3443
|
+
}
|
|
3444
|
+
function formatUploadLogLine(event) {
|
|
3445
|
+
const parts = [
|
|
3446
|
+
"[upload]",
|
|
3447
|
+
`source=${event.source}`,
|
|
3448
|
+
`backend=${event.backend}`,
|
|
3449
|
+
`mode=${event.mode}`,
|
|
3450
|
+
`filename=${JSON.stringify(event.filename)}`,
|
|
3451
|
+
`bytes=${event.bytes.toString()}`,
|
|
3452
|
+
`durationMs=${event.durationMs.toString()}`
|
|
3453
|
+
];
|
|
3454
|
+
if (event.mimeType) {
|
|
3455
|
+
parts.push(`mimeType=${event.mimeType}`);
|
|
3456
|
+
}
|
|
3457
|
+
if (event.fileId) {
|
|
3458
|
+
parts.push(`fileId=${event.fileId}`);
|
|
3459
|
+
}
|
|
3460
|
+
if (event.mirrorId) {
|
|
3461
|
+
parts.push(`mirrorId=${event.mirrorId}`);
|
|
3462
|
+
}
|
|
3463
|
+
if (event.fileUri) {
|
|
3464
|
+
parts.push(`fileUri=${JSON.stringify(event.fileUri)}`);
|
|
3465
|
+
}
|
|
3466
|
+
return parts.join(" ");
|
|
3467
|
+
}
|
|
3468
|
+
function recordUploadEvent(event) {
|
|
3469
|
+
const scope = fileUploadScopeStorage.getStore();
|
|
3470
|
+
const resolvedSource = event.source ?? scope?.source ?? (event.backend === "openai" ? "files_api" : "provider_mirror");
|
|
3471
|
+
const timestampedEvent = {
|
|
3472
|
+
...event,
|
|
3473
|
+
source: resolvedSource,
|
|
3474
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3475
|
+
};
|
|
3476
|
+
for (const collector of scope?.collectors ?? []) {
|
|
3477
|
+
collector.events.push(timestampedEvent);
|
|
3478
|
+
}
|
|
3479
|
+
getCurrentAgentLoggingSession()?.logLine(formatUploadLogLine(timestampedEvent));
|
|
3480
|
+
}
|
|
3481
|
+
function normaliseFilename(filename, fallback = "attachment.bin") {
|
|
3482
|
+
const trimmed = filename?.trim();
|
|
3483
|
+
if (!trimmed) {
|
|
3484
|
+
return fallback;
|
|
3485
|
+
}
|
|
3486
|
+
const basename = import_node_path4.default.basename(trimmed);
|
|
3487
|
+
return basename.length > 0 ? basename : fallback;
|
|
3488
|
+
}
|
|
3489
|
+
function resolveMimeType(filename, explicitMimeType, fallback = "application/octet-stream") {
|
|
3490
|
+
const trimmed = explicitMimeType?.trim();
|
|
3491
|
+
if (trimmed) {
|
|
3492
|
+
return trimmed;
|
|
3493
|
+
}
|
|
3494
|
+
const inferred = import_mime.default.getType(filename);
|
|
3495
|
+
return typeof inferred === "string" && inferred.length > 0 ? inferred : fallback;
|
|
3496
|
+
}
|
|
3497
|
+
function toBuffer(data) {
|
|
3498
|
+
if (typeof data === "string") {
|
|
3499
|
+
return import_node_buffer3.Buffer.from(data, "utf8");
|
|
3500
|
+
}
|
|
3501
|
+
if (ArrayBuffer.isView(data)) {
|
|
3502
|
+
return import_node_buffer3.Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
|
3503
|
+
}
|
|
3504
|
+
return import_node_buffer3.Buffer.from(data);
|
|
3505
|
+
}
|
|
3506
|
+
function computeSha256Hex(buffer) {
|
|
3507
|
+
return (0, import_node_crypto.createHash)("sha256").update(buffer).digest("hex");
|
|
3508
|
+
}
|
|
3509
|
+
async function computeFileSha256Hex(filePath) {
|
|
3510
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
3511
|
+
const stream = (0, import_node_fs3.createReadStream)(filePath);
|
|
3512
|
+
for await (const chunk of stream) {
|
|
3513
|
+
hash.update(chunk);
|
|
3514
|
+
}
|
|
3515
|
+
return hash.digest("hex");
|
|
3516
|
+
}
|
|
3517
|
+
function toStoredFile(file) {
|
|
3518
|
+
return {
|
|
3519
|
+
id: file.id,
|
|
3520
|
+
bytes: file.bytes,
|
|
3521
|
+
created_at: file.created_at,
|
|
3522
|
+
filename: file.filename,
|
|
3523
|
+
object: "file",
|
|
3524
|
+
purpose: file.purpose,
|
|
3525
|
+
status: file.status,
|
|
3526
|
+
expires_at: file.expires_at
|
|
3527
|
+
};
|
|
3528
|
+
}
|
|
3529
|
+
function buildCacheKey(filename, mimeType, sha256Hex) {
|
|
3530
|
+
return `${sha256Hex}\0${filename}\0${mimeType}`;
|
|
3531
|
+
}
|
|
3532
|
+
function isFresh(file) {
|
|
3533
|
+
if (!file.expires_at) {
|
|
3534
|
+
return true;
|
|
3535
|
+
}
|
|
3536
|
+
return file.expires_at * 1e3 > Date.now() + 3e4;
|
|
3537
|
+
}
|
|
3538
|
+
function recordMetadata(metadata) {
|
|
3539
|
+
filesState.metadataById.set(metadata.file.id, metadata);
|
|
3540
|
+
if (metadata.sha256Hex) {
|
|
3541
|
+
filesState.openAiUploadCacheByKey.set(
|
|
3542
|
+
buildCacheKey(
|
|
3543
|
+
metadata.filename,
|
|
3544
|
+
metadata.mimeType ?? "application/octet-stream",
|
|
3545
|
+
metadata.sha256Hex
|
|
3546
|
+
),
|
|
3547
|
+
metadata
|
|
3548
|
+
);
|
|
3549
|
+
}
|
|
3550
|
+
return metadata;
|
|
3551
|
+
}
|
|
3552
|
+
async function uploadOpenAiFileFromBytes(params) {
|
|
3553
|
+
const cacheKey = buildCacheKey(params.filename, params.mimeType, params.sha256Hex);
|
|
3554
|
+
const cached = filesState.openAiUploadCacheByKey.get(cacheKey);
|
|
3555
|
+
if (cached && isFresh(cached.file)) {
|
|
3556
|
+
return cached;
|
|
3557
|
+
}
|
|
3558
|
+
const client = getOpenAiClient();
|
|
3559
|
+
const startedAtMs = Date.now();
|
|
3560
|
+
let uploaded;
|
|
3561
|
+
let mode;
|
|
3562
|
+
if (params.bytes.byteLength <= OPENAI_FILE_CREATE_MAX_BYTES) {
|
|
3563
|
+
mode = "files.create";
|
|
3564
|
+
uploaded = await client.files.create({
|
|
3565
|
+
file: new import_node_buffer3.File([new Uint8Array(params.bytes)], params.filename, {
|
|
3566
|
+
type: params.mimeType
|
|
3567
|
+
}),
|
|
3568
|
+
purpose: params.purpose,
|
|
3569
|
+
expires_after: {
|
|
3570
|
+
anchor: "created_at",
|
|
3571
|
+
seconds: params.expiresAfterSeconds
|
|
3572
|
+
}
|
|
3573
|
+
});
|
|
3574
|
+
} else {
|
|
3575
|
+
mode = "uploads";
|
|
3576
|
+
const upload = await client.uploads.create({
|
|
3577
|
+
bytes: params.bytes.byteLength,
|
|
3578
|
+
filename: params.filename,
|
|
3579
|
+
mime_type: params.mimeType,
|
|
3580
|
+
purpose: params.purpose
|
|
3581
|
+
});
|
|
3582
|
+
const partIds = [];
|
|
3583
|
+
for (let offset = 0; offset < params.bytes.byteLength; offset += OPENAI_UPLOAD_PART_MAX_BYTES) {
|
|
3584
|
+
const chunk = params.bytes.subarray(
|
|
3585
|
+
offset,
|
|
3586
|
+
Math.min(offset + OPENAI_UPLOAD_PART_MAX_BYTES, params.bytes.byteLength)
|
|
3587
|
+
);
|
|
3588
|
+
const uploadPart = await client.uploads.parts.create(upload.id, {
|
|
3589
|
+
data: new import_node_buffer3.File([new Uint8Array(chunk)], `${params.sha256Hex}.part`, {
|
|
3590
|
+
type: params.mimeType
|
|
3591
|
+
})
|
|
3592
|
+
});
|
|
3593
|
+
partIds.push(uploadPart.id);
|
|
3594
|
+
}
|
|
3595
|
+
const completed = await client.uploads.complete(upload.id, { part_ids: partIds });
|
|
3596
|
+
const fileId = completed.file?.id;
|
|
3597
|
+
if (!fileId) {
|
|
3598
|
+
throw new Error("OpenAI upload completed without a file id.");
|
|
3599
|
+
}
|
|
3600
|
+
uploaded = await client.files.retrieve(fileId);
|
|
3601
|
+
}
|
|
3602
|
+
const file = toStoredFile(uploaded);
|
|
3603
|
+
const metadata = recordMetadata({
|
|
3604
|
+
file,
|
|
3605
|
+
filename: file.filename,
|
|
3606
|
+
bytes: file.bytes,
|
|
3607
|
+
mimeType: params.mimeType,
|
|
3608
|
+
sha256Hex: params.sha256Hex
|
|
3609
|
+
});
|
|
3610
|
+
recordUploadEvent({
|
|
3611
|
+
backend: "openai",
|
|
3612
|
+
mode,
|
|
3613
|
+
filename: metadata.filename,
|
|
3614
|
+
bytes: metadata.bytes,
|
|
3615
|
+
durationMs: Math.max(0, Date.now() - startedAtMs),
|
|
3616
|
+
mimeType: params.mimeType,
|
|
3617
|
+
fileId: metadata.file.id
|
|
3618
|
+
});
|
|
3619
|
+
return metadata;
|
|
3620
|
+
}
|
|
3621
|
+
async function uploadOpenAiFileFromPath(params) {
|
|
3622
|
+
const cacheKey = buildCacheKey(params.filename, params.mimeType, params.sha256Hex);
|
|
3623
|
+
const cached = filesState.openAiUploadCacheByKey.get(cacheKey);
|
|
3624
|
+
if (cached && isFresh(cached.file)) {
|
|
3625
|
+
return cached;
|
|
3626
|
+
}
|
|
3627
|
+
const client = getOpenAiClient();
|
|
3628
|
+
const startedAtMs = Date.now();
|
|
3629
|
+
let uploaded;
|
|
3630
|
+
let mode;
|
|
3631
|
+
if (params.bytes <= OPENAI_FILE_CREATE_MAX_BYTES) {
|
|
3632
|
+
mode = "files.create";
|
|
3633
|
+
const blob = await (0, import_node_fs3.openAsBlob)(params.filePath, { type: params.mimeType });
|
|
3634
|
+
uploaded = await client.files.create({
|
|
3635
|
+
file: new import_node_buffer3.File([blob], params.filename, { type: params.mimeType }),
|
|
3636
|
+
purpose: params.purpose,
|
|
3637
|
+
expires_after: {
|
|
3638
|
+
anchor: "created_at",
|
|
3639
|
+
seconds: params.expiresAfterSeconds
|
|
3640
|
+
}
|
|
3641
|
+
});
|
|
3642
|
+
} else {
|
|
3643
|
+
mode = "uploads";
|
|
3644
|
+
const upload = await client.uploads.create({
|
|
3645
|
+
bytes: params.bytes,
|
|
3646
|
+
filename: params.filename,
|
|
3647
|
+
mime_type: params.mimeType,
|
|
3648
|
+
purpose: params.purpose
|
|
3649
|
+
});
|
|
3650
|
+
const partIds = [];
|
|
3651
|
+
const stream = (0, import_node_fs3.createReadStream)(params.filePath, {
|
|
3652
|
+
highWaterMark: OPENAI_UPLOAD_PART_MAX_BYTES
|
|
3653
|
+
});
|
|
3654
|
+
let partIndex = 0;
|
|
3655
|
+
for await (const chunk of stream) {
|
|
3656
|
+
const buffer = import_node_buffer3.Buffer.isBuffer(chunk) ? chunk : import_node_buffer3.Buffer.from(chunk);
|
|
3657
|
+
const uploadPart = await client.uploads.parts.create(upload.id, {
|
|
3658
|
+
data: new import_node_buffer3.File(
|
|
3659
|
+
[new Uint8Array(buffer)],
|
|
3660
|
+
`${params.sha256Hex}.${partIndex.toString()}.part`,
|
|
3661
|
+
{
|
|
3662
|
+
type: params.mimeType
|
|
3663
|
+
}
|
|
3664
|
+
)
|
|
3665
|
+
});
|
|
3666
|
+
partIds.push(uploadPart.id);
|
|
3667
|
+
partIndex += 1;
|
|
3668
|
+
}
|
|
3669
|
+
const completed = await client.uploads.complete(upload.id, { part_ids: partIds });
|
|
3670
|
+
const fileId = completed.file?.id;
|
|
3671
|
+
if (!fileId) {
|
|
3672
|
+
throw new Error("OpenAI upload completed without a file id.");
|
|
3673
|
+
}
|
|
3674
|
+
uploaded = await client.files.retrieve(fileId);
|
|
3675
|
+
}
|
|
3676
|
+
const file = toStoredFile(uploaded);
|
|
3677
|
+
const metadata = recordMetadata({
|
|
3678
|
+
file,
|
|
3679
|
+
filename: file.filename,
|
|
3680
|
+
bytes: file.bytes,
|
|
3681
|
+
mimeType: params.mimeType,
|
|
3682
|
+
sha256Hex: params.sha256Hex
|
|
3683
|
+
});
|
|
3684
|
+
recordUploadEvent({
|
|
3685
|
+
backend: "openai",
|
|
3686
|
+
mode,
|
|
3687
|
+
filename: metadata.filename,
|
|
3688
|
+
bytes: metadata.bytes,
|
|
3689
|
+
durationMs: Math.max(0, Date.now() - startedAtMs),
|
|
3690
|
+
mimeType: params.mimeType,
|
|
3691
|
+
fileId: metadata.file.id
|
|
3692
|
+
});
|
|
3693
|
+
return metadata;
|
|
3694
|
+
}
|
|
3695
|
+
async function retrieveOpenAiFile(fileId) {
|
|
3696
|
+
const cached = filesState.metadataById.get(fileId);
|
|
3697
|
+
if (cached && isFresh(cached.file)) {
|
|
3698
|
+
return cached;
|
|
3699
|
+
}
|
|
3700
|
+
const client = getOpenAiClient();
|
|
3701
|
+
const retrieved = await client.files.retrieve(fileId);
|
|
3702
|
+
const file = toStoredFile(retrieved);
|
|
3703
|
+
return recordMetadata({
|
|
3704
|
+
file,
|
|
3705
|
+
filename: file.filename,
|
|
3706
|
+
bytes: file.bytes,
|
|
3707
|
+
mimeType: cached?.mimeType ?? resolveMimeType(file.filename, void 0),
|
|
3708
|
+
sha256Hex: cached?.sha256Hex,
|
|
3709
|
+
localPath: cached?.localPath
|
|
3710
|
+
});
|
|
3711
|
+
}
|
|
3712
|
+
function buildGeminiMirrorName(sha256Hex) {
|
|
3713
|
+
return `files/${sha256Hex.slice(0, 40)}`;
|
|
3714
|
+
}
|
|
3715
|
+
async function waitForGeminiFileActive(client, name) {
|
|
3716
|
+
const startedAt = Date.now();
|
|
3717
|
+
while (true) {
|
|
3718
|
+
const file = await client.files.get({ name });
|
|
3719
|
+
if (!file.state || file.state === "ACTIVE") {
|
|
3720
|
+
return;
|
|
3721
|
+
}
|
|
3722
|
+
if (file.state === "FAILED") {
|
|
3723
|
+
throw new Error(file.error?.message ?? `Gemini file ${name} failed processing.`);
|
|
3724
|
+
}
|
|
3725
|
+
if (Date.now() - startedAt >= GEMINI_FILE_POLL_TIMEOUT_MS) {
|
|
3726
|
+
throw new Error(`Timed out waiting for Gemini file ${name} to become active.`);
|
|
3727
|
+
}
|
|
3728
|
+
await new Promise((resolve) => setTimeout(resolve, GEMINI_FILE_POLL_INTERVAL_MS));
|
|
3729
|
+
}
|
|
3730
|
+
}
|
|
3731
|
+
function resolveVertexMirrorBucket() {
|
|
3732
|
+
const raw = process.env.VERTEX_GCS_BUCKET ?? process.env.LLM_VERTEX_GCS_BUCKET;
|
|
3733
|
+
const trimmed = raw?.trim();
|
|
3734
|
+
if (!trimmed) {
|
|
3735
|
+
throw new Error(
|
|
3736
|
+
"VERTEX_GCS_BUCKET must be set to use OpenAI-backed file ids with Vertex Gemini models."
|
|
3737
|
+
);
|
|
3738
|
+
}
|
|
3739
|
+
return trimmed.replace(/^gs:\/\//u, "").replace(/\/+$/u, "");
|
|
3740
|
+
}
|
|
3741
|
+
function resolveVertexMirrorPrefix() {
|
|
3742
|
+
const raw = process.env.VERTEX_GCS_PREFIX ?? process.env.LLM_VERTEX_GCS_PREFIX;
|
|
3743
|
+
const trimmed = raw?.trim().replace(/^\/+/u, "").replace(/\/+$/u, "");
|
|
3744
|
+
return trimmed ? `${trimmed}/` : "";
|
|
3745
|
+
}
|
|
3746
|
+
function getStorageClient() {
|
|
3747
|
+
if (filesState.storageClient) {
|
|
3748
|
+
return filesState.storageClient;
|
|
3749
|
+
}
|
|
3750
|
+
const serviceAccount = getGoogleServiceAccount();
|
|
3751
|
+
filesState.storageClient = new import_storage.Storage({
|
|
3752
|
+
projectId: serviceAccount.projectId,
|
|
3753
|
+
credentials: {
|
|
3754
|
+
client_email: serviceAccount.clientEmail,
|
|
3755
|
+
private_key: serviceAccount.privateKey
|
|
3756
|
+
}
|
|
3757
|
+
});
|
|
3758
|
+
return filesState.storageClient;
|
|
3759
|
+
}
|
|
3760
|
+
function getGeminiMirrorClient() {
|
|
3761
|
+
if (!filesState.geminiClientPromise) {
|
|
3762
|
+
filesState.geminiClientPromise = getGeminiClient();
|
|
3763
|
+
}
|
|
3764
|
+
return filesState.geminiClientPromise;
|
|
3765
|
+
}
|
|
3766
|
+
async function materializeOpenAiFile(fileId) {
|
|
3767
|
+
const cachedPromise = filesState.materializedById.get(fileId);
|
|
3768
|
+
if (cachedPromise) {
|
|
3769
|
+
return await cachedPromise;
|
|
3770
|
+
}
|
|
3771
|
+
const promise = (async () => {
|
|
3772
|
+
const metadata = await retrieveOpenAiFile(fileId);
|
|
3773
|
+
if (metadata.localPath && metadata.sha256Hex && metadata.mimeType) {
|
|
3774
|
+
return {
|
|
3775
|
+
file: metadata.file,
|
|
3776
|
+
filename: metadata.filename,
|
|
3777
|
+
bytes: metadata.bytes,
|
|
3778
|
+
mimeType: metadata.mimeType,
|
|
3779
|
+
sha256Hex: metadata.sha256Hex,
|
|
3780
|
+
localPath: metadata.localPath
|
|
3781
|
+
};
|
|
3782
|
+
}
|
|
3783
|
+
await (0, import_promises2.mkdir)(FILES_TEMP_ROOT, { recursive: true });
|
|
3784
|
+
const tempDir = await (0, import_promises2.mkdtemp)(
|
|
3785
|
+
import_node_path4.default.join(FILES_TEMP_ROOT, `${fileId.replace(/[^a-z0-9_-]/giu, "")}-`)
|
|
3786
|
+
);
|
|
3787
|
+
const localPath = import_node_path4.default.join(tempDir, normaliseFilename(metadata.filename, `${fileId}.bin`));
|
|
3788
|
+
const response = await getOpenAiClient().files.content(fileId);
|
|
3789
|
+
if (!response.ok) {
|
|
3790
|
+
throw new Error(
|
|
3791
|
+
`Failed to download OpenAI file ${fileId}: ${response.status} ${response.statusText}`
|
|
3792
|
+
);
|
|
3793
|
+
}
|
|
3794
|
+
const responseMimeType = response.headers.get("content-type")?.trim() || void 0;
|
|
3795
|
+
const mimeType = resolveMimeType(metadata.filename, responseMimeType);
|
|
3796
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
3797
|
+
let bytes = 0;
|
|
3798
|
+
if (response.body) {
|
|
3799
|
+
const source = import_node_stream.Readable.fromWeb(response.body);
|
|
3800
|
+
const writable = (0, import_node_fs3.createWriteStream)(localPath, { flags: "wx" });
|
|
3801
|
+
source.on("data", (chunk) => {
|
|
3802
|
+
const buffer = import_node_buffer3.Buffer.isBuffer(chunk) ? chunk : import_node_buffer3.Buffer.from(chunk);
|
|
3803
|
+
hash.update(buffer);
|
|
3804
|
+
bytes += buffer.byteLength;
|
|
3805
|
+
});
|
|
3806
|
+
await (0, import_promises3.pipeline)(source, writable);
|
|
3807
|
+
} else {
|
|
3808
|
+
const buffer = import_node_buffer3.Buffer.from(await response.arrayBuffer());
|
|
3809
|
+
hash.update(buffer);
|
|
3810
|
+
bytes = buffer.byteLength;
|
|
3811
|
+
await (0, import_promises2.writeFile)(localPath, buffer);
|
|
3812
|
+
}
|
|
3813
|
+
const sha256Hex = hash.digest("hex");
|
|
3814
|
+
const updated = recordMetadata({
|
|
3815
|
+
file: metadata.file,
|
|
3816
|
+
filename: metadata.filename,
|
|
3817
|
+
bytes: bytes || metadata.bytes,
|
|
3818
|
+
mimeType,
|
|
3819
|
+
sha256Hex,
|
|
3820
|
+
localPath
|
|
3821
|
+
});
|
|
3822
|
+
return {
|
|
3823
|
+
file: updated.file,
|
|
3824
|
+
filename: updated.filename,
|
|
3825
|
+
bytes: updated.bytes,
|
|
3826
|
+
mimeType: updated.mimeType ?? mimeType,
|
|
3827
|
+
sha256Hex,
|
|
3828
|
+
localPath
|
|
3829
|
+
};
|
|
3830
|
+
})();
|
|
3831
|
+
filesState.materializedById.set(fileId, promise);
|
|
3832
|
+
try {
|
|
3833
|
+
return await promise;
|
|
3834
|
+
} catch (error) {
|
|
3835
|
+
filesState.materializedById.delete(fileId);
|
|
3836
|
+
throw error;
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
async function ensureGeminiFileMirror(fileId) {
|
|
3840
|
+
const cached = filesState.geminiMirrorById.get(fileId);
|
|
3841
|
+
if (cached) {
|
|
3842
|
+
return cached;
|
|
3843
|
+
}
|
|
3844
|
+
const materialized = await materializeOpenAiFile(fileId);
|
|
3845
|
+
const client = await getGeminiMirrorClient();
|
|
3846
|
+
const name = buildGeminiMirrorName(materialized.sha256Hex);
|
|
3847
|
+
try {
|
|
3848
|
+
const existing = await client.files.get({ name });
|
|
3849
|
+
if (existing.name && existing.uri && existing.mimeType) {
|
|
3850
|
+
const mirror2 = {
|
|
3851
|
+
openAiFileId: fileId,
|
|
3852
|
+
name: existing.name,
|
|
3853
|
+
uri: existing.uri,
|
|
3854
|
+
mimeType: existing.mimeType,
|
|
3855
|
+
displayName: existing.displayName ?? materialized.filename
|
|
3856
|
+
};
|
|
3857
|
+
filesState.geminiMirrorById.set(fileId, mirror2);
|
|
3858
|
+
return mirror2;
|
|
3859
|
+
}
|
|
3860
|
+
} catch {
|
|
3861
|
+
}
|
|
3862
|
+
const startedAtMs = Date.now();
|
|
3863
|
+
const uploaded = await client.files.upload({
|
|
3864
|
+
file: materialized.localPath,
|
|
3865
|
+
config: {
|
|
3866
|
+
name,
|
|
3867
|
+
mimeType: materialized.mimeType,
|
|
3868
|
+
displayName: materialized.filename
|
|
3869
|
+
}
|
|
3870
|
+
});
|
|
3871
|
+
if (uploaded.name && uploaded.state && uploaded.state !== "ACTIVE") {
|
|
3872
|
+
await waitForGeminiFileActive(client, uploaded.name);
|
|
3873
|
+
}
|
|
3874
|
+
const resolved = await client.files.get({ name: uploaded.name ?? name });
|
|
3875
|
+
if (!resolved.name || !resolved.uri || !resolved.mimeType) {
|
|
3876
|
+
throw new Error("Gemini file upload completed without a usable URI.");
|
|
3877
|
+
}
|
|
3878
|
+
const mirror = {
|
|
3879
|
+
openAiFileId: fileId,
|
|
3880
|
+
name: resolved.name,
|
|
3881
|
+
uri: resolved.uri,
|
|
3882
|
+
mimeType: resolved.mimeType,
|
|
3883
|
+
displayName: resolved.displayName ?? materialized.filename
|
|
3884
|
+
};
|
|
3885
|
+
filesState.geminiMirrorById.set(fileId, mirror);
|
|
3886
|
+
recordUploadEvent({
|
|
3887
|
+
backend: "gemini",
|
|
3888
|
+
mode: "mirror",
|
|
3889
|
+
filename: materialized.filename,
|
|
3890
|
+
bytes: materialized.bytes,
|
|
3891
|
+
durationMs: Math.max(0, Date.now() - startedAtMs),
|
|
3892
|
+
mimeType: materialized.mimeType,
|
|
3893
|
+
fileId,
|
|
3894
|
+
mirrorId: mirror.name,
|
|
3895
|
+
fileUri: mirror.uri
|
|
3896
|
+
});
|
|
3897
|
+
return mirror;
|
|
3898
|
+
}
|
|
3899
|
+
async function ensureVertexFileMirror(fileId) {
|
|
3900
|
+
const cached = filesState.vertexMirrorById.get(fileId);
|
|
3901
|
+
if (cached) {
|
|
3902
|
+
return cached;
|
|
3903
|
+
}
|
|
3904
|
+
const materialized = await materializeOpenAiFile(fileId);
|
|
3905
|
+
const bucketName = resolveVertexMirrorBucket();
|
|
3906
|
+
const prefix = resolveVertexMirrorPrefix();
|
|
3907
|
+
const extension = import_mime.default.getExtension(materialized.mimeType) ?? import_node_path4.default.extname(materialized.filename).replace(/^\./u, "") ?? "bin";
|
|
3908
|
+
const objectName = `${prefix}${materialized.sha256Hex}.${extension}`;
|
|
3909
|
+
const file = getStorageClient().bucket(bucketName).file(objectName);
|
|
3910
|
+
let uploaded = false;
|
|
3911
|
+
const startedAtMs = Date.now();
|
|
3912
|
+
try {
|
|
3913
|
+
await file.getMetadata();
|
|
3914
|
+
} catch (error) {
|
|
3915
|
+
const code = error.code;
|
|
3916
|
+
if (code !== 404 && code !== "404") {
|
|
3917
|
+
throw error;
|
|
3918
|
+
}
|
|
3919
|
+
try {
|
|
3920
|
+
await (0, import_promises3.pipeline)(
|
|
3921
|
+
(0, import_node_fs3.createReadStream)(materialized.localPath),
|
|
3922
|
+
file.createWriteStream({
|
|
3923
|
+
resumable: materialized.bytes >= 10 * 1024 * 1024,
|
|
3924
|
+
preconditionOpts: { ifGenerationMatch: 0 },
|
|
3925
|
+
metadata: {
|
|
3926
|
+
contentType: materialized.mimeType,
|
|
3927
|
+
customTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3928
|
+
metadata: {
|
|
3929
|
+
filename: materialized.filename,
|
|
3930
|
+
sha256: materialized.sha256Hex,
|
|
3931
|
+
expiresAt: new Date(Date.now() + DEFAULT_FILE_TTL_SECONDS * 1e3).toISOString()
|
|
3932
|
+
}
|
|
3933
|
+
}
|
|
3934
|
+
})
|
|
3935
|
+
);
|
|
3936
|
+
uploaded = true;
|
|
3937
|
+
} catch (uploadError) {
|
|
3938
|
+
const uploadCode = uploadError.code;
|
|
3939
|
+
if (uploadCode !== 412 && uploadCode !== "412") {
|
|
3940
|
+
throw uploadError;
|
|
3941
|
+
}
|
|
3942
|
+
}
|
|
3943
|
+
}
|
|
3944
|
+
const mirror = {
|
|
3945
|
+
openAiFileId: fileId,
|
|
3946
|
+
bucket: bucketName,
|
|
3947
|
+
objectName,
|
|
3948
|
+
fileUri: `gs://${bucketName}/${objectName}`,
|
|
3949
|
+
mimeType: materialized.mimeType
|
|
3950
|
+
};
|
|
3951
|
+
filesState.vertexMirrorById.set(fileId, mirror);
|
|
3952
|
+
if (uploaded) {
|
|
3953
|
+
recordUploadEvent({
|
|
3954
|
+
backend: "vertex",
|
|
3955
|
+
mode: "mirror",
|
|
3956
|
+
filename: materialized.filename,
|
|
3957
|
+
bytes: materialized.bytes,
|
|
3958
|
+
durationMs: Math.max(0, Date.now() - startedAtMs),
|
|
3959
|
+
mimeType: materialized.mimeType,
|
|
3960
|
+
fileId,
|
|
3961
|
+
mirrorId: mirror.objectName,
|
|
3962
|
+
fileUri: mirror.fileUri
|
|
3963
|
+
});
|
|
3964
|
+
}
|
|
3965
|
+
return mirror;
|
|
3966
|
+
}
|
|
3967
|
+
async function filesCreate(params) {
|
|
3968
|
+
const purpose = params.purpose ?? "user_data";
|
|
3969
|
+
const expiresAfterSeconds = params.expiresAfterSeconds ?? DEFAULT_FILE_TTL_SECONDS;
|
|
3970
|
+
if ("path" in params) {
|
|
3971
|
+
const filePath = import_node_path4.default.resolve(params.path);
|
|
3972
|
+
const info = await (0, import_promises2.stat)(filePath);
|
|
3973
|
+
const filename2 = normaliseFilename(params.filename, import_node_path4.default.basename(filePath));
|
|
3974
|
+
const mimeType2 = resolveMimeType(filename2, params.mimeType);
|
|
3975
|
+
const sha256Hex2 = await computeFileSha256Hex(filePath);
|
|
3976
|
+
const uploaded2 = await uploadOpenAiFileFromPath({
|
|
3977
|
+
filePath,
|
|
3978
|
+
filename: filename2,
|
|
3979
|
+
mimeType: mimeType2,
|
|
3980
|
+
purpose,
|
|
3981
|
+
expiresAfterSeconds,
|
|
3982
|
+
sha256Hex: sha256Hex2,
|
|
3983
|
+
bytes: info.size
|
|
3984
|
+
});
|
|
3985
|
+
return uploaded2.file;
|
|
3986
|
+
}
|
|
3987
|
+
const filename = normaliseFilename(params.filename);
|
|
3988
|
+
const bytes = toBuffer(params.data);
|
|
3989
|
+
const mimeType = resolveMimeType(filename, params.mimeType, "text/plain");
|
|
3990
|
+
const sha256Hex = computeSha256Hex(bytes);
|
|
3991
|
+
const uploaded = await uploadOpenAiFileFromBytes({
|
|
3992
|
+
bytes,
|
|
3993
|
+
filename,
|
|
3994
|
+
mimeType,
|
|
3995
|
+
purpose,
|
|
3996
|
+
expiresAfterSeconds,
|
|
3997
|
+
sha256Hex
|
|
3998
|
+
});
|
|
3999
|
+
return uploaded.file;
|
|
4000
|
+
}
|
|
4001
|
+
async function filesRetrieve(fileId) {
|
|
4002
|
+
return (await retrieveOpenAiFile(fileId)).file;
|
|
4003
|
+
}
|
|
4004
|
+
async function filesDelete(fileId) {
|
|
4005
|
+
const cachedGemini = filesState.geminiMirrorById.get(fileId);
|
|
4006
|
+
if (cachedGemini) {
|
|
4007
|
+
try {
|
|
4008
|
+
const client = await getGeminiMirrorClient();
|
|
4009
|
+
await client.files.delete({ name: cachedGemini.name });
|
|
4010
|
+
} catch {
|
|
4011
|
+
}
|
|
4012
|
+
filesState.geminiMirrorById.delete(fileId);
|
|
4013
|
+
}
|
|
4014
|
+
const cachedVertex = filesState.vertexMirrorById.get(fileId);
|
|
4015
|
+
if (cachedVertex) {
|
|
4016
|
+
try {
|
|
4017
|
+
await getStorageClient().bucket(cachedVertex.bucket).file(cachedVertex.objectName).delete({ ignoreNotFound: true });
|
|
4018
|
+
} catch {
|
|
4019
|
+
}
|
|
4020
|
+
filesState.vertexMirrorById.delete(fileId);
|
|
4021
|
+
}
|
|
4022
|
+
const cachedMaterialized = filesState.metadataById.get(fileId)?.localPath;
|
|
4023
|
+
if (cachedMaterialized) {
|
|
4024
|
+
try {
|
|
4025
|
+
await (0, import_promises2.unlink)(cachedMaterialized);
|
|
4026
|
+
} catch {
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4029
|
+
const response = await getOpenAiClient().files.delete(fileId);
|
|
4030
|
+
filesState.metadataById.delete(fileId);
|
|
4031
|
+
filesState.materializedById.delete(fileId);
|
|
4032
|
+
return {
|
|
4033
|
+
id: response.id,
|
|
4034
|
+
deleted: response.deleted,
|
|
4035
|
+
object: "file"
|
|
4036
|
+
};
|
|
4037
|
+
}
|
|
4038
|
+
async function filesContent(fileId) {
|
|
4039
|
+
return await getOpenAiClient().files.content(fileId);
|
|
4040
|
+
}
|
|
4041
|
+
async function getCanonicalFileMetadata(fileId) {
|
|
4042
|
+
const metadata = await retrieveOpenAiFile(fileId);
|
|
4043
|
+
const mimeType = metadata.mimeType ?? resolveMimeType(metadata.filename, void 0);
|
|
4044
|
+
const updated = metadata.mimeType === mimeType ? metadata : recordMetadata({
|
|
4045
|
+
...metadata,
|
|
4046
|
+
mimeType
|
|
4047
|
+
});
|
|
4048
|
+
return {
|
|
4049
|
+
...updated,
|
|
4050
|
+
mimeType
|
|
4051
|
+
};
|
|
4052
|
+
}
|
|
4053
|
+
var files = {
|
|
4054
|
+
create: filesCreate,
|
|
4055
|
+
retrieve: filesRetrieve,
|
|
4056
|
+
delete: filesDelete,
|
|
4057
|
+
content: filesContent
|
|
4058
|
+
};
|
|
4059
|
+
|
|
3353
4060
|
// src/llm.ts
|
|
3354
4061
|
var toolCallContextStorage = getRuntimeSingleton(
|
|
3355
4062
|
/* @__PURE__ */ Symbol.for("@ljoukov/llm.toolCallContextStorage"),
|
|
3356
|
-
() => new
|
|
4063
|
+
() => new import_node_async_hooks3.AsyncLocalStorage()
|
|
3357
4064
|
);
|
|
3358
4065
|
function getCurrentToolCallContext() {
|
|
3359
4066
|
return toolCallContextStorage.getStore() ?? null;
|
|
3360
4067
|
}
|
|
4068
|
+
var INLINE_ATTACHMENT_FILENAME_SYMBOL = /* @__PURE__ */ Symbol.for("@ljoukov/llm.inlineAttachmentFilename");
|
|
4069
|
+
var INLINE_ATTACHMENT_PROMPT_THRESHOLD_BYTES = 20 * 1024 * 1024;
|
|
4070
|
+
var TOOL_OUTPUT_SPILL_THRESHOLD_BYTES = 1 * 1024 * 1024;
|
|
3361
4071
|
var LLM_TEXT_MODEL_IDS = [
|
|
3362
4072
|
...OPENAI_MODEL_IDS,
|
|
3363
4073
|
...CHATGPT_MODEL_IDS,
|
|
@@ -3635,6 +4345,52 @@ function isJsonSchemaObject(schema) {
|
|
|
3635
4345
|
}
|
|
3636
4346
|
return false;
|
|
3637
4347
|
}
|
|
4348
|
+
var CANONICAL_GEMINI_FILE_URI_PREFIX = "openai://file/";
|
|
4349
|
+
function buildCanonicalGeminiFileUri(fileId) {
|
|
4350
|
+
return `${CANONICAL_GEMINI_FILE_URI_PREFIX}${fileId}`;
|
|
4351
|
+
}
|
|
4352
|
+
function parseCanonicalGeminiFileId(fileUri) {
|
|
4353
|
+
if (!fileUri?.startsWith(CANONICAL_GEMINI_FILE_URI_PREFIX)) {
|
|
4354
|
+
return void 0;
|
|
4355
|
+
}
|
|
4356
|
+
const fileId = fileUri.slice(CANONICAL_GEMINI_FILE_URI_PREFIX.length).trim();
|
|
4357
|
+
return fileId.length > 0 ? fileId : void 0;
|
|
4358
|
+
}
|
|
4359
|
+
function cloneContentPart(part) {
|
|
4360
|
+
switch (part.type) {
|
|
4361
|
+
case "text":
|
|
4362
|
+
return {
|
|
4363
|
+
type: "text",
|
|
4364
|
+
text: part.text,
|
|
4365
|
+
thought: part.thought === true ? true : void 0
|
|
4366
|
+
};
|
|
4367
|
+
case "inlineData":
|
|
4368
|
+
return {
|
|
4369
|
+
type: "inlineData",
|
|
4370
|
+
data: part.data,
|
|
4371
|
+
mimeType: part.mimeType,
|
|
4372
|
+
filename: part.filename
|
|
4373
|
+
};
|
|
4374
|
+
case "input_image":
|
|
4375
|
+
return {
|
|
4376
|
+
type: "input_image",
|
|
4377
|
+
image_url: part.image_url ?? void 0,
|
|
4378
|
+
file_id: part.file_id ?? void 0,
|
|
4379
|
+
detail: part.detail,
|
|
4380
|
+
filename: part.filename ?? void 0
|
|
4381
|
+
};
|
|
4382
|
+
case "input_file":
|
|
4383
|
+
return {
|
|
4384
|
+
type: "input_file",
|
|
4385
|
+
file_data: part.file_data ?? void 0,
|
|
4386
|
+
file_id: part.file_id ?? void 0,
|
|
4387
|
+
file_url: part.file_url ?? void 0,
|
|
4388
|
+
filename: part.filename ?? void 0
|
|
4389
|
+
};
|
|
4390
|
+
default:
|
|
4391
|
+
return part;
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
3638
4394
|
function sanitisePartForLogging(part) {
|
|
3639
4395
|
switch (part.type) {
|
|
3640
4396
|
case "text":
|
|
@@ -3646,16 +4402,33 @@ function sanitisePartForLogging(part) {
|
|
|
3646
4402
|
case "inlineData": {
|
|
3647
4403
|
let omittedBytes;
|
|
3648
4404
|
try {
|
|
3649
|
-
omittedBytes =
|
|
4405
|
+
omittedBytes = import_node_buffer4.Buffer.from(part.data, "base64").byteLength;
|
|
3650
4406
|
} catch {
|
|
3651
|
-
omittedBytes =
|
|
4407
|
+
omittedBytes = import_node_buffer4.Buffer.byteLength(part.data, "utf8");
|
|
3652
4408
|
}
|
|
3653
4409
|
return {
|
|
3654
4410
|
type: "inlineData",
|
|
3655
4411
|
mimeType: part.mimeType,
|
|
4412
|
+
filename: part.filename,
|
|
3656
4413
|
data: `[omitted:${omittedBytes}b]`
|
|
3657
4414
|
};
|
|
3658
4415
|
}
|
|
4416
|
+
case "input_image":
|
|
4417
|
+
return {
|
|
4418
|
+
type: "input_image",
|
|
4419
|
+
file_id: part.file_id ?? void 0,
|
|
4420
|
+
filename: part.filename ?? void 0,
|
|
4421
|
+
detail: part.detail ?? void 0,
|
|
4422
|
+
image_url: typeof part.image_url === "string" ? part.image_url.startsWith("data:") ? "[omitted:data-url]" : part.image_url : void 0
|
|
4423
|
+
};
|
|
4424
|
+
case "input_file":
|
|
4425
|
+
return {
|
|
4426
|
+
type: "input_file",
|
|
4427
|
+
file_id: part.file_id ?? void 0,
|
|
4428
|
+
filename: part.filename ?? void 0,
|
|
4429
|
+
file_url: typeof part.file_url === "string" ? part.file_url.startsWith("data:") ? "[omitted:data-url]" : part.file_url : void 0,
|
|
4430
|
+
file_data: typeof part.file_data === "string" ? `[omitted:${import_node_buffer4.Buffer.byteLength(part.file_data, "utf8")}b]` : void 0
|
|
4431
|
+
};
|
|
3659
4432
|
default:
|
|
3660
4433
|
return "[unknown part]";
|
|
3661
4434
|
}
|
|
@@ -3676,12 +4449,17 @@ function convertGooglePartsToLlmParts(parts) {
|
|
|
3676
4449
|
result.push({
|
|
3677
4450
|
type: "inlineData",
|
|
3678
4451
|
data: inline.data,
|
|
3679
|
-
mimeType: inline.mimeType
|
|
4452
|
+
mimeType: inline.mimeType,
|
|
4453
|
+
filename: inline.displayName
|
|
3680
4454
|
});
|
|
3681
4455
|
continue;
|
|
3682
4456
|
}
|
|
3683
4457
|
if (part.fileData?.fileUri) {
|
|
3684
|
-
|
|
4458
|
+
result.push({
|
|
4459
|
+
type: "input_file",
|
|
4460
|
+
file_url: part.fileData.fileUri,
|
|
4461
|
+
filename: part.fileData.displayName
|
|
4462
|
+
});
|
|
3685
4463
|
}
|
|
3686
4464
|
}
|
|
3687
4465
|
return result;
|
|
@@ -3713,37 +4491,110 @@ function toGeminiPart(part) {
|
|
|
3713
4491
|
text: part.text,
|
|
3714
4492
|
thought: part.thought === true ? true : void 0
|
|
3715
4493
|
};
|
|
3716
|
-
case "inlineData":
|
|
4494
|
+
case "inlineData": {
|
|
4495
|
+
const inlineData = {
|
|
4496
|
+
data: part.data,
|
|
4497
|
+
mimeType: part.mimeType
|
|
4498
|
+
};
|
|
4499
|
+
setInlineAttachmentFilename(inlineData, part.filename);
|
|
3717
4500
|
return {
|
|
3718
4501
|
inlineData: {
|
|
3719
|
-
|
|
3720
|
-
mimeType: part.mimeType
|
|
4502
|
+
...inlineData
|
|
3721
4503
|
}
|
|
3722
4504
|
};
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
}
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
4505
|
+
}
|
|
4506
|
+
case "input_image": {
|
|
4507
|
+
if (part.file_id) {
|
|
4508
|
+
return {
|
|
4509
|
+
fileData: {
|
|
4510
|
+
fileUri: buildCanonicalGeminiFileUri(part.file_id),
|
|
4511
|
+
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream",
|
|
4512
|
+
displayName: part.filename ?? void 0
|
|
4513
|
+
}
|
|
4514
|
+
};
|
|
4515
|
+
}
|
|
4516
|
+
if (typeof part.image_url !== "string" || part.image_url.trim().length === 0) {
|
|
4517
|
+
throw new Error("input_image requires image_url or file_id.");
|
|
4518
|
+
}
|
|
4519
|
+
const parsed = parseDataUrlPayload(part.image_url);
|
|
4520
|
+
if (parsed) {
|
|
4521
|
+
const geminiPart = (0, import_genai2.createPartFromBase64)(parsed.dataBase64, parsed.mimeType);
|
|
4522
|
+
if (part.filename && geminiPart.inlineData) {
|
|
4523
|
+
geminiPart.inlineData.displayName = part.filename;
|
|
4524
|
+
}
|
|
4525
|
+
return geminiPart;
|
|
4526
|
+
}
|
|
4527
|
+
return {
|
|
4528
|
+
fileData: {
|
|
4529
|
+
fileUri: part.image_url,
|
|
4530
|
+
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream",
|
|
4531
|
+
displayName: part.filename ?? void 0
|
|
4532
|
+
}
|
|
4533
|
+
};
|
|
4534
|
+
}
|
|
4535
|
+
case "input_file": {
|
|
4536
|
+
if (part.file_id) {
|
|
4537
|
+
return {
|
|
4538
|
+
fileData: {
|
|
4539
|
+
fileUri: buildCanonicalGeminiFileUri(part.file_id),
|
|
4540
|
+
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream",
|
|
4541
|
+
displayName: part.filename ?? void 0
|
|
4542
|
+
}
|
|
4543
|
+
};
|
|
4544
|
+
}
|
|
4545
|
+
if (typeof part.file_data === "string" && part.file_data.trim().length > 0) {
|
|
4546
|
+
const geminiPart = (0, import_genai2.createPartFromBase64)(
|
|
4547
|
+
part.file_data,
|
|
4548
|
+
inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4549
|
+
);
|
|
4550
|
+
if (part.filename && geminiPart.inlineData) {
|
|
4551
|
+
geminiPart.inlineData.displayName = part.filename;
|
|
4552
|
+
}
|
|
4553
|
+
return geminiPart;
|
|
4554
|
+
}
|
|
4555
|
+
if (typeof part.file_url === "string" && part.file_url.trim().length > 0) {
|
|
4556
|
+
const parsed = parseDataUrlPayload(part.file_url);
|
|
4557
|
+
if (parsed) {
|
|
4558
|
+
const geminiPart = (0, import_genai2.createPartFromBase64)(parsed.dataBase64, parsed.mimeType);
|
|
4559
|
+
if (part.filename && geminiPart.inlineData) {
|
|
4560
|
+
geminiPart.inlineData.displayName = part.filename;
|
|
4561
|
+
}
|
|
4562
|
+
return geminiPart;
|
|
4563
|
+
}
|
|
4564
|
+
return {
|
|
4565
|
+
fileData: {
|
|
4566
|
+
fileUri: part.file_url,
|
|
4567
|
+
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream",
|
|
4568
|
+
displayName: part.filename ?? void 0
|
|
4569
|
+
}
|
|
4570
|
+
};
|
|
4571
|
+
}
|
|
4572
|
+
throw new Error("input_file requires file_id, file_data, or file_url.");
|
|
4573
|
+
}
|
|
4574
|
+
default:
|
|
4575
|
+
throw new Error("Unsupported LLM content part");
|
|
4576
|
+
}
|
|
4577
|
+
}
|
|
4578
|
+
function convertLlmContentToGeminiContent(content) {
|
|
4579
|
+
const role = content.role === "assistant" ? "model" : "user";
|
|
4580
|
+
return {
|
|
4581
|
+
role,
|
|
4582
|
+
parts: content.parts.map(toGeminiPart)
|
|
4583
|
+
};
|
|
4584
|
+
}
|
|
4585
|
+
function resolveProvider(model) {
|
|
4586
|
+
if (isChatGptModelId(model)) {
|
|
4587
|
+
return {
|
|
4588
|
+
provider: "chatgpt",
|
|
4589
|
+
model: resolveChatGptProviderModel(model),
|
|
4590
|
+
serviceTier: resolveChatGptServiceTier(model)
|
|
4591
|
+
};
|
|
4592
|
+
}
|
|
4593
|
+
if (isGeminiTextModelId(model) || isGeminiImageModelId(model)) {
|
|
4594
|
+
return { provider: "gemini", model };
|
|
4595
|
+
}
|
|
4596
|
+
if (isFireworksModelId(model)) {
|
|
4597
|
+
const fireworksModel = resolveFireworksModelId(model);
|
|
3747
4598
|
if (fireworksModel) {
|
|
3748
4599
|
return { provider: "fireworks", model: fireworksModel };
|
|
3749
4600
|
}
|
|
@@ -3816,6 +4667,14 @@ function isInlineImageMime(mimeType) {
|
|
|
3816
4667
|
}
|
|
3817
4668
|
function guessInlineDataFilename(mimeType) {
|
|
3818
4669
|
switch (mimeType) {
|
|
4670
|
+
case "image/jpeg":
|
|
4671
|
+
return "image.jpg";
|
|
4672
|
+
case "image/png":
|
|
4673
|
+
return "image.png";
|
|
4674
|
+
case "image/webp":
|
|
4675
|
+
return "image.webp";
|
|
4676
|
+
case "image/gif":
|
|
4677
|
+
return "image.gif";
|
|
3819
4678
|
case "application/pdf":
|
|
3820
4679
|
return "document.pdf";
|
|
3821
4680
|
case "application/json":
|
|
@@ -3828,6 +4687,261 @@ function guessInlineDataFilename(mimeType) {
|
|
|
3828
4687
|
return "attachment.bin";
|
|
3829
4688
|
}
|
|
3830
4689
|
}
|
|
4690
|
+
function normaliseAttachmentFilename(value, fallback) {
|
|
4691
|
+
const trimmed = value?.trim();
|
|
4692
|
+
if (!trimmed) {
|
|
4693
|
+
return fallback;
|
|
4694
|
+
}
|
|
4695
|
+
const basename = import_node_path5.default.basename(trimmed).replace(/[^\w.-]+/g, "-");
|
|
4696
|
+
return basename.length > 0 ? basename : fallback;
|
|
4697
|
+
}
|
|
4698
|
+
function setInlineAttachmentFilename(target, filename) {
|
|
4699
|
+
const normalized = filename?.trim();
|
|
4700
|
+
if (!normalized) {
|
|
4701
|
+
return;
|
|
4702
|
+
}
|
|
4703
|
+
target[INLINE_ATTACHMENT_FILENAME_SYMBOL] = normalized;
|
|
4704
|
+
}
|
|
4705
|
+
function getInlineAttachmentFilename(target) {
|
|
4706
|
+
if (!target || typeof target !== "object") {
|
|
4707
|
+
return void 0;
|
|
4708
|
+
}
|
|
4709
|
+
const value = target[INLINE_ATTACHMENT_FILENAME_SYMBOL];
|
|
4710
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
4711
|
+
}
|
|
4712
|
+
function estimateInlinePayloadBytes(value) {
|
|
4713
|
+
return import_node_buffer4.Buffer.byteLength(value, "utf8");
|
|
4714
|
+
}
|
|
4715
|
+
function isOpenAiNativeContentItem(value) {
|
|
4716
|
+
return !!value && typeof value === "object" && typeof value.type === "string";
|
|
4717
|
+
}
|
|
4718
|
+
function estimateOpenAiInlinePromptBytes(input) {
|
|
4719
|
+
let total = 0;
|
|
4720
|
+
const visitItems = (items) => {
|
|
4721
|
+
for (const item of items) {
|
|
4722
|
+
if (!item || typeof item !== "object") {
|
|
4723
|
+
continue;
|
|
4724
|
+
}
|
|
4725
|
+
if (Array.isArray(item.content)) {
|
|
4726
|
+
visitItems(item.content);
|
|
4727
|
+
}
|
|
4728
|
+
if (Array.isArray(item.output)) {
|
|
4729
|
+
visitItems(item.output);
|
|
4730
|
+
}
|
|
4731
|
+
if (!isOpenAiNativeContentItem(item)) {
|
|
4732
|
+
continue;
|
|
4733
|
+
}
|
|
4734
|
+
if (item.type === "input_image" && typeof item.image_url === "string" && item.image_url.trim().toLowerCase().startsWith("data:")) {
|
|
4735
|
+
total += estimateInlinePayloadBytes(item.image_url);
|
|
4736
|
+
}
|
|
4737
|
+
if (item.type === "input_file" && typeof item.file_data === "string" && item.file_data.trim().length > 0) {
|
|
4738
|
+
total += estimateInlinePayloadBytes(item.file_data);
|
|
4739
|
+
}
|
|
4740
|
+
if (item.type === "input_file" && typeof item.file_url === "string" && item.file_url.trim().toLowerCase().startsWith("data:")) {
|
|
4741
|
+
total += estimateInlinePayloadBytes(item.file_url);
|
|
4742
|
+
}
|
|
4743
|
+
}
|
|
4744
|
+
};
|
|
4745
|
+
visitItems(input);
|
|
4746
|
+
return total;
|
|
4747
|
+
}
|
|
4748
|
+
async function storeCanonicalPromptFile(options) {
|
|
4749
|
+
const file = await runWithFileUploadSource("prompt_inline_offload", async () => {
|
|
4750
|
+
return await filesCreate({
|
|
4751
|
+
data: options.bytes,
|
|
4752
|
+
filename: options.filename,
|
|
4753
|
+
mimeType: options.mimeType,
|
|
4754
|
+
expiresAfterSeconds: DEFAULT_FILE_TTL_SECONDS
|
|
4755
|
+
});
|
|
4756
|
+
});
|
|
4757
|
+
return {
|
|
4758
|
+
fileId: file.id,
|
|
4759
|
+
filename: file.filename,
|
|
4760
|
+
mimeType: options.mimeType
|
|
4761
|
+
};
|
|
4762
|
+
}
|
|
4763
|
+
async function prepareOpenAiPromptContentItem(item) {
|
|
4764
|
+
if (!isOpenAiNativeContentItem(item)) {
|
|
4765
|
+
return item;
|
|
4766
|
+
}
|
|
4767
|
+
if (item.type === "input_image" && typeof item.image_url === "string" && item.image_url.trim().toLowerCase().startsWith("data:")) {
|
|
4768
|
+
const parsed = parseDataUrlPayload(item.image_url);
|
|
4769
|
+
if (!parsed) {
|
|
4770
|
+
return item;
|
|
4771
|
+
}
|
|
4772
|
+
const uploaded = await storeCanonicalPromptFile({
|
|
4773
|
+
bytes: parsed.bytes,
|
|
4774
|
+
mimeType: parsed.mimeType ?? "application/octet-stream",
|
|
4775
|
+
filename: normaliseAttachmentFilename(
|
|
4776
|
+
getInlineAttachmentFilename(item),
|
|
4777
|
+
guessInlineDataFilename(parsed.mimeType)
|
|
4778
|
+
)
|
|
4779
|
+
});
|
|
4780
|
+
return {
|
|
4781
|
+
type: "input_image",
|
|
4782
|
+
detail: item.detail === "high" || item.detail === "low" ? item.detail : "auto",
|
|
4783
|
+
file_id: uploaded.fileId
|
|
4784
|
+
};
|
|
4785
|
+
}
|
|
4786
|
+
if (item.type !== "input_file" || item.file_id) {
|
|
4787
|
+
return item;
|
|
4788
|
+
}
|
|
4789
|
+
if (typeof item.file_data === "string" && item.file_data.trim().length > 0) {
|
|
4790
|
+
const filename = normaliseAttachmentFilename(
|
|
4791
|
+
typeof item.filename === "string" ? item.filename : void 0,
|
|
4792
|
+
guessInlineDataFilename(void 0)
|
|
4793
|
+
);
|
|
4794
|
+
const mimeType = inferToolOutputMimeTypeFromFilename(filename) ?? "application/octet-stream";
|
|
4795
|
+
const uploaded = await storeCanonicalPromptFile({
|
|
4796
|
+
bytes: decodeInlineDataBuffer(item.file_data),
|
|
4797
|
+
mimeType,
|
|
4798
|
+
filename
|
|
4799
|
+
});
|
|
4800
|
+
return { type: "input_file", file_id: uploaded.fileId, filename: uploaded.filename };
|
|
4801
|
+
}
|
|
4802
|
+
if (typeof item.file_url === "string" && item.file_url.trim().toLowerCase().startsWith("data:")) {
|
|
4803
|
+
const parsed = parseDataUrlPayload(item.file_url);
|
|
4804
|
+
if (!parsed) {
|
|
4805
|
+
return item;
|
|
4806
|
+
}
|
|
4807
|
+
const uploaded = await storeCanonicalPromptFile({
|
|
4808
|
+
bytes: parsed.bytes,
|
|
4809
|
+
mimeType: parsed.mimeType ?? "application/octet-stream",
|
|
4810
|
+
filename: normaliseAttachmentFilename(
|
|
4811
|
+
typeof item.filename === "string" ? item.filename : void 0,
|
|
4812
|
+
guessInlineDataFilename(parsed.mimeType)
|
|
4813
|
+
)
|
|
4814
|
+
});
|
|
4815
|
+
return { type: "input_file", file_id: uploaded.fileId, filename: uploaded.filename };
|
|
4816
|
+
}
|
|
4817
|
+
return item;
|
|
4818
|
+
}
|
|
4819
|
+
async function prepareOpenAiPromptInput(input) {
|
|
4820
|
+
const prepareItem = async (item) => {
|
|
4821
|
+
if (!item || typeof item !== "object") {
|
|
4822
|
+
return item;
|
|
4823
|
+
}
|
|
4824
|
+
const record = item;
|
|
4825
|
+
if (Array.isArray(record.content)) {
|
|
4826
|
+
return {
|
|
4827
|
+
...record,
|
|
4828
|
+
content: await Promise.all(
|
|
4829
|
+
record.content.map((part) => prepareOpenAiPromptContentItem(part))
|
|
4830
|
+
)
|
|
4831
|
+
};
|
|
4832
|
+
}
|
|
4833
|
+
if (Array.isArray(record.output)) {
|
|
4834
|
+
return {
|
|
4835
|
+
...record,
|
|
4836
|
+
output: await Promise.all(
|
|
4837
|
+
record.output.map((part) => prepareOpenAiPromptContentItem(part))
|
|
4838
|
+
)
|
|
4839
|
+
};
|
|
4840
|
+
}
|
|
4841
|
+
return await prepareOpenAiPromptContentItem(item);
|
|
4842
|
+
};
|
|
4843
|
+
return await Promise.all(input.map((item) => prepareItem(item)));
|
|
4844
|
+
}
|
|
4845
|
+
async function maybePrepareOpenAiPromptInput(input) {
|
|
4846
|
+
if (estimateOpenAiInlinePromptBytes(input) <= INLINE_ATTACHMENT_PROMPT_THRESHOLD_BYTES) {
|
|
4847
|
+
return Array.from(input);
|
|
4848
|
+
}
|
|
4849
|
+
return await prepareOpenAiPromptInput(input);
|
|
4850
|
+
}
|
|
4851
|
+
function estimateGeminiInlinePromptBytes(contents) {
|
|
4852
|
+
let total = 0;
|
|
4853
|
+
for (const content of contents) {
|
|
4854
|
+
for (const part of content.parts ?? []) {
|
|
4855
|
+
if (part.inlineData?.data) {
|
|
4856
|
+
total += estimateInlinePayloadBytes(part.inlineData.data);
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4859
|
+
}
|
|
4860
|
+
return total;
|
|
4861
|
+
}
|
|
4862
|
+
function hasCanonicalGeminiFileReferences(contents) {
|
|
4863
|
+
for (const content of contents) {
|
|
4864
|
+
for (const part of content.parts ?? []) {
|
|
4865
|
+
if (parseCanonicalGeminiFileId(part.fileData?.fileUri)) {
|
|
4866
|
+
return true;
|
|
4867
|
+
}
|
|
4868
|
+
}
|
|
4869
|
+
}
|
|
4870
|
+
return false;
|
|
4871
|
+
}
|
|
4872
|
+
async function prepareGeminiPromptContents(contents) {
|
|
4873
|
+
const backend = getGeminiBackend();
|
|
4874
|
+
const preparedContents = [];
|
|
4875
|
+
for (const content of contents) {
|
|
4876
|
+
const parts = [];
|
|
4877
|
+
for (const part of content.parts ?? []) {
|
|
4878
|
+
const canonicalFileId = parseCanonicalGeminiFileId(part.fileData?.fileUri);
|
|
4879
|
+
if (canonicalFileId) {
|
|
4880
|
+
const metadata = await getCanonicalFileMetadata(canonicalFileId);
|
|
4881
|
+
if (backend === "api") {
|
|
4882
|
+
const mirrored = await ensureGeminiFileMirror(canonicalFileId);
|
|
4883
|
+
const mirroredPart = (0, import_genai2.createPartFromUri)(mirrored.uri, mirrored.mimeType);
|
|
4884
|
+
if (metadata.filename && mirroredPart.fileData) {
|
|
4885
|
+
mirroredPart.fileData.displayName = metadata.filename;
|
|
4886
|
+
}
|
|
4887
|
+
parts.push(mirroredPart);
|
|
4888
|
+
} else {
|
|
4889
|
+
const mirrored = await ensureVertexFileMirror(canonicalFileId);
|
|
4890
|
+
parts.push({
|
|
4891
|
+
fileData: {
|
|
4892
|
+
fileUri: mirrored.fileUri,
|
|
4893
|
+
mimeType: mirrored.mimeType,
|
|
4894
|
+
displayName: metadata.filename
|
|
4895
|
+
}
|
|
4896
|
+
});
|
|
4897
|
+
}
|
|
4898
|
+
continue;
|
|
4899
|
+
}
|
|
4900
|
+
if (part.inlineData?.data) {
|
|
4901
|
+
const mimeType = part.inlineData.mimeType ?? "application/octet-stream";
|
|
4902
|
+
const filename = normaliseAttachmentFilename(
|
|
4903
|
+
getInlineAttachmentFilename(part.inlineData) ?? part.inlineData.displayName ?? guessInlineDataFilename(mimeType),
|
|
4904
|
+
guessInlineDataFilename(mimeType)
|
|
4905
|
+
);
|
|
4906
|
+
const stored = await storeCanonicalPromptFile({
|
|
4907
|
+
bytes: decodeInlineDataBuffer(part.inlineData.data),
|
|
4908
|
+
mimeType,
|
|
4909
|
+
filename
|
|
4910
|
+
});
|
|
4911
|
+
if (backend === "api") {
|
|
4912
|
+
const mirrored = await ensureGeminiFileMirror(stored.fileId);
|
|
4913
|
+
const mirroredPart = (0, import_genai2.createPartFromUri)(mirrored.uri, mirrored.mimeType);
|
|
4914
|
+
if (filename && mirroredPart.fileData) {
|
|
4915
|
+
mirroredPart.fileData.displayName = filename;
|
|
4916
|
+
}
|
|
4917
|
+
parts.push(mirroredPart);
|
|
4918
|
+
} else {
|
|
4919
|
+
const mirrored = await ensureVertexFileMirror(stored.fileId);
|
|
4920
|
+
parts.push({
|
|
4921
|
+
fileData: {
|
|
4922
|
+
fileUri: mirrored.fileUri,
|
|
4923
|
+
mimeType: mirrored.mimeType,
|
|
4924
|
+
displayName: filename
|
|
4925
|
+
}
|
|
4926
|
+
});
|
|
4927
|
+
}
|
|
4928
|
+
continue;
|
|
4929
|
+
}
|
|
4930
|
+
parts.push(part);
|
|
4931
|
+
}
|
|
4932
|
+
preparedContents.push({
|
|
4933
|
+
...content,
|
|
4934
|
+
parts
|
|
4935
|
+
});
|
|
4936
|
+
}
|
|
4937
|
+
return preparedContents;
|
|
4938
|
+
}
|
|
4939
|
+
async function maybePrepareGeminiPromptContents(contents) {
|
|
4940
|
+
if (!hasCanonicalGeminiFileReferences(contents) && estimateGeminiInlinePromptBytes(contents) <= INLINE_ATTACHMENT_PROMPT_THRESHOLD_BYTES) {
|
|
4941
|
+
return Array.from(contents);
|
|
4942
|
+
}
|
|
4943
|
+
return await prepareGeminiPromptContents(contents);
|
|
4944
|
+
}
|
|
3831
4945
|
function mergeConsecutiveTextParts(parts) {
|
|
3832
4946
|
if (parts.length === 0) {
|
|
3833
4947
|
return [];
|
|
@@ -3835,7 +4949,7 @@ function mergeConsecutiveTextParts(parts) {
|
|
|
3835
4949
|
const merged = [];
|
|
3836
4950
|
for (const part of parts) {
|
|
3837
4951
|
if (part.type !== "text") {
|
|
3838
|
-
merged.push(
|
|
4952
|
+
merged.push(cloneContentPart(part));
|
|
3839
4953
|
continue;
|
|
3840
4954
|
}
|
|
3841
4955
|
const isThought = part.thought === true;
|
|
@@ -4266,13 +5380,7 @@ function resolveTextContents(input) {
|
|
|
4266
5380
|
const parts = typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content;
|
|
4267
5381
|
contents.push({
|
|
4268
5382
|
role: message.role,
|
|
4269
|
-
parts: parts.map(
|
|
4270
|
-
(part) => part.type === "text" ? {
|
|
4271
|
-
type: "text",
|
|
4272
|
-
text: part.text,
|
|
4273
|
-
thought: "thought" in part && part.thought === true ? true : void 0
|
|
4274
|
-
} : { type: "inlineData", data: part.data, mimeType: part.mimeType }
|
|
4275
|
-
)
|
|
5383
|
+
parts: parts.map((part) => cloneContentPart(part))
|
|
4276
5384
|
});
|
|
4277
5385
|
}
|
|
4278
5386
|
return contents;
|
|
@@ -4288,22 +5396,58 @@ function toOpenAiInput(contents) {
|
|
|
4288
5396
|
return contents.map((content) => {
|
|
4289
5397
|
const parts = [];
|
|
4290
5398
|
for (const part of content.parts) {
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
5399
|
+
switch (part.type) {
|
|
5400
|
+
case "text":
|
|
5401
|
+
parts.push({ type: "input_text", text: part.text });
|
|
5402
|
+
break;
|
|
5403
|
+
case "inlineData": {
|
|
5404
|
+
const mimeType = part.mimeType;
|
|
5405
|
+
if (isInlineImageMime(mimeType)) {
|
|
5406
|
+
const dataUrl = `data:${mimeType};base64,${part.data}`;
|
|
5407
|
+
const imagePart = {
|
|
5408
|
+
type: "input_image",
|
|
5409
|
+
image_url: dataUrl,
|
|
5410
|
+
detail: "auto"
|
|
5411
|
+
};
|
|
5412
|
+
setInlineAttachmentFilename(
|
|
5413
|
+
imagePart,
|
|
5414
|
+
normaliseAttachmentFilename(part.filename, guessInlineDataFilename(mimeType))
|
|
5415
|
+
);
|
|
5416
|
+
parts.push(imagePart);
|
|
5417
|
+
break;
|
|
5418
|
+
}
|
|
5419
|
+
parts.push({
|
|
5420
|
+
type: "input_file",
|
|
5421
|
+
filename: normaliseAttachmentFilename(part.filename, guessInlineDataFilename(mimeType)),
|
|
5422
|
+
file_data: part.data
|
|
5423
|
+
});
|
|
5424
|
+
break;
|
|
5425
|
+
}
|
|
5426
|
+
case "input_image": {
|
|
5427
|
+
const imagePart = {
|
|
5428
|
+
type: "input_image",
|
|
5429
|
+
...part.file_id ? { file_id: part.file_id } : {},
|
|
5430
|
+
...part.image_url ? { image_url: part.image_url } : {},
|
|
5431
|
+
detail: part.detail === "high" || part.detail === "low" ? part.detail : "auto"
|
|
5432
|
+
};
|
|
5433
|
+
if (part.filename) {
|
|
5434
|
+
setInlineAttachmentFilename(imagePart, part.filename);
|
|
5435
|
+
}
|
|
5436
|
+
parts.push(imagePart);
|
|
5437
|
+
break;
|
|
5438
|
+
}
|
|
5439
|
+
case "input_file":
|
|
5440
|
+
parts.push({
|
|
5441
|
+
type: "input_file",
|
|
5442
|
+
...part.file_id ? { file_id: part.file_id } : {},
|
|
5443
|
+
...part.file_data ? { file_data: part.file_data } : {},
|
|
5444
|
+
...part.file_url ? { file_url: part.file_url } : {},
|
|
5445
|
+
...part.filename ? { filename: part.filename } : {}
|
|
5446
|
+
});
|
|
5447
|
+
break;
|
|
5448
|
+
default:
|
|
5449
|
+
throw new Error("Unsupported LLM content part");
|
|
4300
5450
|
}
|
|
4301
|
-
const fileData = decodeInlineDataBuffer(part.data).toString("base64");
|
|
4302
|
-
parts.push({
|
|
4303
|
-
type: "input_file",
|
|
4304
|
-
filename: guessInlineDataFilename(mimeType),
|
|
4305
|
-
file_data: fileData
|
|
4306
|
-
});
|
|
4307
5451
|
}
|
|
4308
5452
|
if (parts.length === 1 && parts[0]?.type === "input_text" && typeof parts[0].text === "string") {
|
|
4309
5453
|
return {
|
|
@@ -4340,28 +5484,54 @@ function toChatGptInput(contents) {
|
|
|
4340
5484
|
continue;
|
|
4341
5485
|
}
|
|
4342
5486
|
if (isAssistant) {
|
|
4343
|
-
const mimeType = part.mimeType ?? "application/octet-stream";
|
|
5487
|
+
const mimeType = part.type === "inlineData" ? part.mimeType ?? "application/octet-stream" : inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream";
|
|
4344
5488
|
parts.push({
|
|
4345
5489
|
type: "output_text",
|
|
4346
|
-
text: isInlineImageMime(part.mimeType) ? `[image:${mimeType}]` : `[file:${mimeType}]`
|
|
5490
|
+
text: part.type === "input_image" || isInlineImageMime(part.mimeType) ? `[image:${mimeType}]` : `[file:${mimeType}]`
|
|
4347
5491
|
});
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
5492
|
+
continue;
|
|
5493
|
+
}
|
|
5494
|
+
switch (part.type) {
|
|
5495
|
+
case "inlineData": {
|
|
5496
|
+
if (isInlineImageMime(part.mimeType)) {
|
|
5497
|
+
const mimeType = part.mimeType ?? "application/octet-stream";
|
|
5498
|
+
const dataUrl = `data:${mimeType};base64,${part.data}`;
|
|
5499
|
+
parts.push({
|
|
5500
|
+
type: "input_image",
|
|
5501
|
+
image_url: dataUrl,
|
|
5502
|
+
detail: "auto"
|
|
5503
|
+
});
|
|
5504
|
+
} else {
|
|
5505
|
+
parts.push({
|
|
5506
|
+
type: "input_file",
|
|
5507
|
+
filename: normaliseAttachmentFilename(
|
|
5508
|
+
part.filename,
|
|
5509
|
+
guessInlineDataFilename(part.mimeType)
|
|
5510
|
+
),
|
|
5511
|
+
file_data: part.data
|
|
5512
|
+
});
|
|
5513
|
+
}
|
|
5514
|
+
break;
|
|
5515
|
+
}
|
|
5516
|
+
case "input_image":
|
|
4352
5517
|
parts.push({
|
|
4353
5518
|
type: "input_image",
|
|
4354
|
-
|
|
4355
|
-
|
|
5519
|
+
...part.file_id ? { file_id: part.file_id } : {},
|
|
5520
|
+
...part.image_url ? { image_url: part.image_url } : {},
|
|
5521
|
+
detail: part.detail === "high" || part.detail === "low" ? part.detail : "auto"
|
|
4356
5522
|
});
|
|
4357
|
-
|
|
4358
|
-
|
|
5523
|
+
break;
|
|
5524
|
+
case "input_file":
|
|
4359
5525
|
parts.push({
|
|
4360
5526
|
type: "input_file",
|
|
4361
|
-
|
|
4362
|
-
file_data:
|
|
5527
|
+
...part.file_id ? { file_id: part.file_id } : {},
|
|
5528
|
+
...part.file_data ? { file_data: part.file_data } : {},
|
|
5529
|
+
...part.file_url ? { file_url: part.file_url } : {},
|
|
5530
|
+
...part.filename ? { filename: part.filename } : {}
|
|
4363
5531
|
});
|
|
4364
|
-
|
|
5532
|
+
break;
|
|
5533
|
+
default:
|
|
5534
|
+
throw new Error("Unsupported LLM content part");
|
|
4365
5535
|
}
|
|
4366
5536
|
}
|
|
4367
5537
|
if (parts.length === 0) {
|
|
@@ -4405,8 +5575,8 @@ ${JSON.stringify(options.responseJsonSchema)}`);
|
|
|
4405
5575
|
if (part.type === "text") {
|
|
4406
5576
|
return part.text;
|
|
4407
5577
|
}
|
|
4408
|
-
const mimeType = part.mimeType ?? "application/octet-stream";
|
|
4409
|
-
if (isInlineImageMime(mimeType)) {
|
|
5578
|
+
const mimeType = part.type === "inlineData" ? part.mimeType ?? "application/octet-stream" : inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream";
|
|
5579
|
+
if (part.type === "input_image" || isInlineImageMime(mimeType)) {
|
|
4410
5580
|
return `[image:${mimeType}]`;
|
|
4411
5581
|
}
|
|
4412
5582
|
return `[file:${mimeType}]`;
|
|
@@ -4677,7 +5847,14 @@ function isLlmToolOutputContentItem(value) {
|
|
|
4677
5847
|
return typeof value.text === "string";
|
|
4678
5848
|
}
|
|
4679
5849
|
if (itemType === "input_image") {
|
|
4680
|
-
|
|
5850
|
+
const keys = ["image_url", "file_id", "filename"];
|
|
5851
|
+
for (const key of keys) {
|
|
5852
|
+
const part = value[key];
|
|
5853
|
+
if (part !== void 0 && part !== null && typeof part !== "string") {
|
|
5854
|
+
return false;
|
|
5855
|
+
}
|
|
5856
|
+
}
|
|
5857
|
+
return value.image_url !== void 0 || value.file_id !== void 0;
|
|
4681
5858
|
}
|
|
4682
5859
|
if (itemType === "input_file") {
|
|
4683
5860
|
const keys = ["file_data", "file_id", "file_url", "filename"];
|
|
@@ -4746,15 +5923,252 @@ function inferToolOutputMimeTypeFromFilename(filename) {
|
|
|
4746
5923
|
}
|
|
4747
5924
|
return void 0;
|
|
4748
5925
|
}
|
|
4749
|
-
function
|
|
5926
|
+
function estimateToolOutputItemBytes(item) {
|
|
5927
|
+
if (item.type === "input_text") {
|
|
5928
|
+
return import_node_buffer4.Buffer.byteLength(item.text, "utf8");
|
|
5929
|
+
}
|
|
4750
5930
|
if (item.type === "input_image") {
|
|
5931
|
+
return typeof item.image_url === "string" ? estimateInlinePayloadBytes(item.image_url) : 0;
|
|
5932
|
+
}
|
|
5933
|
+
if (typeof item.file_data === "string" && item.file_data.trim().length > 0) {
|
|
5934
|
+
return estimateInlinePayloadBytes(item.file_data);
|
|
5935
|
+
}
|
|
5936
|
+
if (typeof item.file_url === "string" && item.file_url.trim().length > 0) {
|
|
5937
|
+
return estimateInlinePayloadBytes(item.file_url);
|
|
5938
|
+
}
|
|
5939
|
+
return 0;
|
|
5940
|
+
}
|
|
5941
|
+
async function spillTextToolOutputToFile(options) {
|
|
5942
|
+
const stored = await runWithFileUploadSource("tool_output_spill", async () => {
|
|
5943
|
+
return await filesCreate({
|
|
5944
|
+
data: options.text,
|
|
5945
|
+
filename: options.filename,
|
|
5946
|
+
mimeType: options.mimeType,
|
|
5947
|
+
expiresAfterSeconds: DEFAULT_FILE_TTL_SECONDS
|
|
5948
|
+
});
|
|
5949
|
+
});
|
|
5950
|
+
return [
|
|
5951
|
+
{
|
|
5952
|
+
type: "input_text",
|
|
5953
|
+
text: `Tool output was attached as ${stored.filename} (${stored.id}) because it exceeded the inline payload threshold.`
|
|
5954
|
+
},
|
|
5955
|
+
{
|
|
5956
|
+
type: "input_file",
|
|
5957
|
+
file_id: stored.id,
|
|
5958
|
+
filename: stored.filename
|
|
5959
|
+
}
|
|
5960
|
+
];
|
|
5961
|
+
}
|
|
5962
|
+
async function maybeSpillToolOutputItem(item, toolName, options) {
|
|
5963
|
+
if (options?.force !== true && estimateToolOutputItemBytes(item) <= TOOL_OUTPUT_SPILL_THRESHOLD_BYTES) {
|
|
5964
|
+
return item;
|
|
5965
|
+
}
|
|
5966
|
+
if (item.type === "input_text") {
|
|
5967
|
+
return await spillTextToolOutputToFile({
|
|
5968
|
+
text: item.text,
|
|
5969
|
+
filename: normaliseAttachmentFilename(`${toolName}.txt`, "tool-output.txt"),
|
|
5970
|
+
mimeType: "text/plain"
|
|
5971
|
+
});
|
|
5972
|
+
}
|
|
5973
|
+
if (item.type === "input_image") {
|
|
5974
|
+
if (item.file_id || !item.image_url) {
|
|
5975
|
+
return item;
|
|
5976
|
+
}
|
|
4751
5977
|
const parsed = parseDataUrlPayload(item.image_url);
|
|
4752
5978
|
if (!parsed) {
|
|
5979
|
+
return item;
|
|
5980
|
+
}
|
|
5981
|
+
const stored = await runWithFileUploadSource("tool_output_spill", async () => {
|
|
5982
|
+
return await filesCreate({
|
|
5983
|
+
data: parsed.bytes,
|
|
5984
|
+
filename: normaliseAttachmentFilename(
|
|
5985
|
+
item.filename ?? guessInlineDataFilename(parsed.mimeType),
|
|
5986
|
+
guessInlineDataFilename(parsed.mimeType)
|
|
5987
|
+
),
|
|
5988
|
+
mimeType: parsed.mimeType,
|
|
5989
|
+
expiresAfterSeconds: DEFAULT_FILE_TTL_SECONDS
|
|
5990
|
+
});
|
|
5991
|
+
});
|
|
5992
|
+
return {
|
|
5993
|
+
type: "input_image",
|
|
5994
|
+
file_id: stored.id,
|
|
5995
|
+
detail: item.detail ?? "auto",
|
|
5996
|
+
filename: stored.filename
|
|
5997
|
+
};
|
|
5998
|
+
}
|
|
5999
|
+
if (item.file_id) {
|
|
6000
|
+
return item;
|
|
6001
|
+
}
|
|
6002
|
+
if (typeof item.file_data === "string" && item.file_data.trim().length > 0) {
|
|
6003
|
+
const fileData = item.file_data;
|
|
6004
|
+
const filename = normaliseAttachmentFilename(
|
|
6005
|
+
item.filename ?? `${toolName}.bin`,
|
|
6006
|
+
`${toolName}.bin`
|
|
6007
|
+
);
|
|
6008
|
+
const stored = await runWithFileUploadSource("tool_output_spill", async () => {
|
|
6009
|
+
return await filesCreate({
|
|
6010
|
+
data: decodeInlineDataBuffer(fileData),
|
|
6011
|
+
filename,
|
|
6012
|
+
mimeType: inferToolOutputMimeTypeFromFilename(filename) ?? "application/octet-stream",
|
|
6013
|
+
expiresAfterSeconds: DEFAULT_FILE_TTL_SECONDS
|
|
6014
|
+
});
|
|
6015
|
+
});
|
|
6016
|
+
return {
|
|
6017
|
+
type: "input_file",
|
|
6018
|
+
file_id: stored.id,
|
|
6019
|
+
filename: stored.filename
|
|
6020
|
+
};
|
|
6021
|
+
}
|
|
6022
|
+
if (typeof item.file_url === "string" && item.file_url.trim().length > 0) {
|
|
6023
|
+
const parsed = parseDataUrlPayload(item.file_url);
|
|
6024
|
+
if (!parsed) {
|
|
6025
|
+
return item;
|
|
6026
|
+
}
|
|
6027
|
+
const stored = await runWithFileUploadSource("tool_output_spill", async () => {
|
|
6028
|
+
return await filesCreate({
|
|
6029
|
+
data: parsed.bytes,
|
|
6030
|
+
filename: normaliseAttachmentFilename(
|
|
6031
|
+
item.filename ?? guessInlineDataFilename(parsed.mimeType),
|
|
6032
|
+
guessInlineDataFilename(parsed.mimeType)
|
|
6033
|
+
),
|
|
6034
|
+
mimeType: parsed.mimeType,
|
|
6035
|
+
expiresAfterSeconds: DEFAULT_FILE_TTL_SECONDS
|
|
6036
|
+
});
|
|
6037
|
+
});
|
|
6038
|
+
return {
|
|
6039
|
+
type: "input_file",
|
|
6040
|
+
file_id: stored.id,
|
|
6041
|
+
filename: stored.filename
|
|
6042
|
+
};
|
|
6043
|
+
}
|
|
6044
|
+
return item;
|
|
6045
|
+
}
|
|
6046
|
+
async function maybeSpillToolOutput(value, toolName, options) {
|
|
6047
|
+
if (typeof value === "string") {
|
|
6048
|
+
if (options?.force !== true && import_node_buffer4.Buffer.byteLength(value, "utf8") <= TOOL_OUTPUT_SPILL_THRESHOLD_BYTES) {
|
|
6049
|
+
return value;
|
|
6050
|
+
}
|
|
6051
|
+
return await spillTextToolOutputToFile({
|
|
6052
|
+
text: value,
|
|
6053
|
+
filename: normaliseAttachmentFilename(`${toolName}.txt`, "tool-output.txt"),
|
|
6054
|
+
mimeType: "text/plain"
|
|
6055
|
+
});
|
|
6056
|
+
}
|
|
6057
|
+
if (isLlmToolOutputContentItem(value)) {
|
|
6058
|
+
return await maybeSpillToolOutputItem(value, toolName, options);
|
|
6059
|
+
}
|
|
6060
|
+
if (Array.isArray(value) && value.every((item) => isLlmToolOutputContentItem(item))) {
|
|
6061
|
+
const spilledItems = [];
|
|
6062
|
+
for (const item of value) {
|
|
6063
|
+
const maybeSpilled = await maybeSpillToolOutputItem(item, toolName, options);
|
|
6064
|
+
if (Array.isArray(maybeSpilled)) {
|
|
6065
|
+
spilledItems.push(...maybeSpilled);
|
|
6066
|
+
} else {
|
|
6067
|
+
spilledItems.push(maybeSpilled);
|
|
6068
|
+
}
|
|
6069
|
+
}
|
|
6070
|
+
return spilledItems;
|
|
6071
|
+
}
|
|
6072
|
+
try {
|
|
6073
|
+
const serialized = JSON.stringify(value, null, 2);
|
|
6074
|
+
if (options?.force !== true && import_node_buffer4.Buffer.byteLength(serialized, "utf8") <= TOOL_OUTPUT_SPILL_THRESHOLD_BYTES) {
|
|
6075
|
+
return value;
|
|
6076
|
+
}
|
|
6077
|
+
return await spillTextToolOutputToFile({
|
|
6078
|
+
text: serialized,
|
|
6079
|
+
filename: normaliseAttachmentFilename(`${toolName}.json`, "tool-output.json"),
|
|
6080
|
+
mimeType: "application/json"
|
|
6081
|
+
});
|
|
6082
|
+
} catch {
|
|
6083
|
+
return value;
|
|
6084
|
+
}
|
|
6085
|
+
}
|
|
6086
|
+
function estimateToolOutputPayloadBytes(value) {
|
|
6087
|
+
if (typeof value === "string") {
|
|
6088
|
+
return import_node_buffer4.Buffer.byteLength(value, "utf8");
|
|
6089
|
+
}
|
|
6090
|
+
if (isLlmToolOutputContentItem(value)) {
|
|
6091
|
+
return value.type === "input_text" ? 0 : estimateToolOutputItemBytes(value);
|
|
6092
|
+
}
|
|
6093
|
+
if (Array.isArray(value) && value.every((item) => isLlmToolOutputContentItem(item))) {
|
|
6094
|
+
return value.reduce((total, item) => {
|
|
6095
|
+
return total + (item.type === "input_text" ? 0 : estimateToolOutputItemBytes(item));
|
|
6096
|
+
}, 0);
|
|
6097
|
+
}
|
|
6098
|
+
return 0;
|
|
6099
|
+
}
|
|
6100
|
+
async function maybeSpillCombinedToolCallOutputs(callResults) {
|
|
6101
|
+
const totalBytes = callResults.reduce(
|
|
6102
|
+
(sum, callResult) => sum + estimateToolOutputPayloadBytes(callResult.outputPayload),
|
|
6103
|
+
0
|
|
6104
|
+
);
|
|
6105
|
+
if (totalBytes <= INLINE_ATTACHMENT_PROMPT_THRESHOLD_BYTES) {
|
|
6106
|
+
return Array.from(callResults);
|
|
6107
|
+
}
|
|
6108
|
+
return await Promise.all(
|
|
6109
|
+
callResults.map(async (callResult) => {
|
|
6110
|
+
if (estimateToolOutputPayloadBytes(callResult.outputPayload) === 0) {
|
|
6111
|
+
return callResult;
|
|
6112
|
+
}
|
|
6113
|
+
const outputPayload = await maybeSpillToolOutput(
|
|
6114
|
+
callResult.outputPayload,
|
|
6115
|
+
callResult.entry.toolName,
|
|
6116
|
+
{
|
|
6117
|
+
force: true
|
|
6118
|
+
}
|
|
6119
|
+
);
|
|
6120
|
+
return {
|
|
6121
|
+
...callResult,
|
|
6122
|
+
outputPayload,
|
|
6123
|
+
result: {
|
|
6124
|
+
...callResult.result,
|
|
6125
|
+
output: outputPayload
|
|
6126
|
+
}
|
|
6127
|
+
};
|
|
6128
|
+
})
|
|
6129
|
+
);
|
|
6130
|
+
}
|
|
6131
|
+
function buildGeminiToolOutputMediaPart(item) {
|
|
6132
|
+
if (item.type === "input_image") {
|
|
6133
|
+
if (typeof item.file_id === "string" && item.file_id.trim().length > 0) {
|
|
6134
|
+
return {
|
|
6135
|
+
fileData: {
|
|
6136
|
+
fileUri: buildCanonicalGeminiFileUri(item.file_id),
|
|
6137
|
+
mimeType: inferToolOutputMimeTypeFromFilename(item.filename) ?? "application/octet-stream",
|
|
6138
|
+
displayName: item.filename ?? void 0
|
|
6139
|
+
}
|
|
6140
|
+
};
|
|
6141
|
+
}
|
|
6142
|
+
if (typeof item.image_url !== "string" || item.image_url.trim().length === 0) {
|
|
4753
6143
|
return null;
|
|
4754
6144
|
}
|
|
4755
|
-
|
|
6145
|
+
const parsed = parseDataUrlPayload(item.image_url);
|
|
6146
|
+
if (parsed) {
|
|
6147
|
+
const part = (0, import_genai2.createPartFromBase64)(parsed.dataBase64, parsed.mimeType);
|
|
6148
|
+
const displayName = item.filename?.trim();
|
|
6149
|
+
if (displayName && part.inlineData) {
|
|
6150
|
+
part.inlineData.displayName = displayName;
|
|
6151
|
+
}
|
|
6152
|
+
return part;
|
|
6153
|
+
}
|
|
6154
|
+
return {
|
|
6155
|
+
fileData: {
|
|
6156
|
+
fileUri: item.image_url,
|
|
6157
|
+
mimeType: inferToolOutputMimeTypeFromFilename(item.filename) ?? "application/octet-stream",
|
|
6158
|
+
displayName: item.filename ?? void 0
|
|
6159
|
+
}
|
|
6160
|
+
};
|
|
4756
6161
|
}
|
|
4757
6162
|
if (item.type === "input_file") {
|
|
6163
|
+
if (typeof item.file_id === "string" && item.file_id.trim().length > 0) {
|
|
6164
|
+
return {
|
|
6165
|
+
fileData: {
|
|
6166
|
+
fileUri: buildCanonicalGeminiFileUri(item.file_id),
|
|
6167
|
+
mimeType: inferToolOutputMimeTypeFromFilename(item.filename) ?? "application/octet-stream",
|
|
6168
|
+
displayName: item.filename ?? void 0
|
|
6169
|
+
}
|
|
6170
|
+
};
|
|
6171
|
+
}
|
|
4758
6172
|
const dataUrl = typeof item.file_url === "string" ? parseDataUrlPayload(item.file_url) : null;
|
|
4759
6173
|
if (dataUrl) {
|
|
4760
6174
|
const part = (0, import_genai2.createPartFromBase64)(dataUrl.dataBase64, dataUrl.mimeType);
|
|
@@ -4792,11 +6206,12 @@ function toGeminiToolOutputPlaceholder(item) {
|
|
|
4792
6206
|
};
|
|
4793
6207
|
}
|
|
4794
6208
|
if (item.type === "input_image") {
|
|
4795
|
-
const parsed = parseDataUrlPayload(item.image_url);
|
|
6209
|
+
const parsed = typeof item.image_url === "string" ? parseDataUrlPayload(item.image_url) : null;
|
|
4796
6210
|
return {
|
|
4797
6211
|
type: item.type,
|
|
6212
|
+
fileId: item.file_id ?? void 0,
|
|
4798
6213
|
mimeType: parsed?.mimeType ?? void 0,
|
|
4799
|
-
media: "attached-inline-data"
|
|
6214
|
+
media: item.file_id ? "attached-file-id" : parsed ? "attached-inline-data" : item.image_url ? "attached-file-data" : void 0
|
|
4800
6215
|
};
|
|
4801
6216
|
}
|
|
4802
6217
|
const dataUrl = typeof item.file_url === "string" ? parseDataUrlPayload(item.file_url) : null;
|
|
@@ -4805,7 +6220,7 @@ function toGeminiToolOutputPlaceholder(item) {
|
|
|
4805
6220
|
filename: item.filename ?? void 0,
|
|
4806
6221
|
fileId: item.file_id ?? void 0,
|
|
4807
6222
|
mimeType: dataUrl?.mimeType ?? inferToolOutputMimeTypeFromFilename(item.filename) ?? void 0,
|
|
4808
|
-
media: dataUrl || typeof item.file_data === "string" && item.file_data.trim().length > 0 ? "attached-inline-data" : typeof item.file_url === "string" && item.file_url.trim().length > 0 ? "attached-file-data" : void 0
|
|
6223
|
+
media: item.file_id ? "attached-file-id" : dataUrl || typeof item.file_data === "string" && item.file_data.trim().length > 0 ? "attached-inline-data" : typeof item.file_url === "string" && item.file_url.trim().length > 0 ? "attached-file-data" : void 0
|
|
4809
6224
|
};
|
|
4810
6225
|
}
|
|
4811
6226
|
function buildGeminiFunctionResponseParts(options) {
|
|
@@ -4853,8 +6268,8 @@ function parseOpenAiToolArguments(raw) {
|
|
|
4853
6268
|
function formatZodIssues(issues) {
|
|
4854
6269
|
const messages = [];
|
|
4855
6270
|
for (const issue of issues) {
|
|
4856
|
-
const
|
|
4857
|
-
messages.push(`${
|
|
6271
|
+
const path10 = issue.path.length > 0 ? issue.path.map(String).join(".") : "input";
|
|
6272
|
+
messages.push(`${path10}: ${issue.message}`);
|
|
4858
6273
|
}
|
|
4859
6274
|
return messages.join("; ");
|
|
4860
6275
|
}
|
|
@@ -4972,8 +6387,9 @@ async function executeToolCall(params) {
|
|
|
4972
6387
|
const input = typeof rawInput === "string" ? rawInput : String(rawInput ?? "");
|
|
4973
6388
|
try {
|
|
4974
6389
|
const output = await tool2.execute(input);
|
|
4975
|
-
const
|
|
4976
|
-
|
|
6390
|
+
const outputPayload = await maybeSpillToolOutput(output, toolName);
|
|
6391
|
+
const metrics = toolName === "spawn_agent" ? extractSpawnStartupMetrics(outputPayload) : void 0;
|
|
6392
|
+
return finalize({ toolName, input, output: outputPayload }, outputPayload, metrics);
|
|
4977
6393
|
} catch (error) {
|
|
4978
6394
|
const message = error instanceof Error ? error.message : String(error);
|
|
4979
6395
|
const outputPayload = buildToolErrorOutput(`Tool ${toolName} failed: ${message}`);
|
|
@@ -5007,8 +6423,13 @@ async function executeToolCall(params) {
|
|
|
5007
6423
|
}
|
|
5008
6424
|
try {
|
|
5009
6425
|
const output = await tool2.execute(parsed.data);
|
|
5010
|
-
const
|
|
5011
|
-
|
|
6426
|
+
const outputPayload = await maybeSpillToolOutput(output, toolName);
|
|
6427
|
+
const metrics = toolName === "spawn_agent" ? extractSpawnStartupMetrics(outputPayload) : void 0;
|
|
6428
|
+
return finalize(
|
|
6429
|
+
{ toolName, input: parsed.data, output: outputPayload },
|
|
6430
|
+
outputPayload,
|
|
6431
|
+
metrics
|
|
6432
|
+
);
|
|
5012
6433
|
} catch (error) {
|
|
5013
6434
|
const message = error instanceof Error ? error.message : String(error);
|
|
5014
6435
|
const outputPayload = buildToolErrorOutput(`Tool ${toolName} failed: ${message}`);
|
|
@@ -5024,7 +6445,7 @@ function buildToolLogId(turn, toolIndex) {
|
|
|
5024
6445
|
function sanitizeChatGptToolId(value) {
|
|
5025
6446
|
const cleaned = value.replace(/[^A-Za-z0-9_-]/gu, "");
|
|
5026
6447
|
if (cleaned.length === 0) {
|
|
5027
|
-
return (0,
|
|
6448
|
+
return (0, import_node_crypto2.randomBytes)(8).toString("hex");
|
|
5028
6449
|
}
|
|
5029
6450
|
return cleaned.slice(0, 64);
|
|
5030
6451
|
}
|
|
@@ -5042,7 +6463,7 @@ function normalizeChatGptToolIds(params) {
|
|
|
5042
6463
|
rawCallId = nextCallId ?? rawCallId;
|
|
5043
6464
|
rawItemId = nextItemId ?? rawItemId;
|
|
5044
6465
|
}
|
|
5045
|
-
const callValue = sanitizeChatGptToolId(rawCallId || rawItemId || (0,
|
|
6466
|
+
const callValue = sanitizeChatGptToolId(rawCallId || rawItemId || (0, import_node_crypto2.randomBytes)(8).toString("hex"));
|
|
5046
6467
|
let itemValue = sanitizeChatGptToolId(rawItemId || callValue);
|
|
5047
6468
|
if (params.callKind === "custom") {
|
|
5048
6469
|
if (!itemValue.startsWith("ctc")) {
|
|
@@ -5209,7 +6630,7 @@ function toGemini25ProThinkingBudget(thinkingLevel) {
|
|
|
5209
6630
|
}
|
|
5210
6631
|
}
|
|
5211
6632
|
function resolveGeminiThinkingConfig(modelId, thinkingLevel) {
|
|
5212
|
-
if (isGeminiImageModelId(modelId)) {
|
|
6633
|
+
if (isGeminiImageModelId(modelId) || modelId === "gemini-flash-lite-latest") {
|
|
5213
6634
|
return void 0;
|
|
5214
6635
|
}
|
|
5215
6636
|
if (thinkingLevel) {
|
|
@@ -5240,9 +6661,9 @@ function resolveGeminiThinkingConfig(modelId, thinkingLevel) {
|
|
|
5240
6661
|
}
|
|
5241
6662
|
function decodeInlineDataBuffer(base64) {
|
|
5242
6663
|
try {
|
|
5243
|
-
return
|
|
6664
|
+
return import_node_buffer4.Buffer.from(base64, "base64");
|
|
5244
6665
|
} catch {
|
|
5245
|
-
return
|
|
6666
|
+
return import_node_buffer4.Buffer.from(base64, "base64url");
|
|
5246
6667
|
}
|
|
5247
6668
|
}
|
|
5248
6669
|
function extractImages(content) {
|
|
@@ -5312,7 +6733,7 @@ function parseDataUrlPayload(value) {
|
|
|
5312
6733
|
const isBase64 = /;base64(?:;|$)/iu.test(header);
|
|
5313
6734
|
const mimeType = (header.split(";")[0] ?? "application/octet-stream").trim().toLowerCase();
|
|
5314
6735
|
try {
|
|
5315
|
-
const bytes = isBase64 ?
|
|
6736
|
+
const bytes = isBase64 ? import_node_buffer4.Buffer.from(payload, "base64") : import_node_buffer4.Buffer.from(decodeURIComponent(payload), "utf8");
|
|
5316
6737
|
return {
|
|
5317
6738
|
mimeType,
|
|
5318
6739
|
dataBase64: bytes.toString("base64"),
|
|
@@ -5415,7 +6836,10 @@ function collectLoggedAttachmentsFromLlmParts(parts, prefix) {
|
|
|
5415
6836
|
continue;
|
|
5416
6837
|
}
|
|
5417
6838
|
attachments.push({
|
|
5418
|
-
filename:
|
|
6839
|
+
filename: normaliseAttachmentFilename(
|
|
6840
|
+
part.filename,
|
|
6841
|
+
buildLoggedAttachmentFilename(prefix, index, part.mimeType)
|
|
6842
|
+
),
|
|
5419
6843
|
bytes: decodeInlineDataBuffer(part.data)
|
|
5420
6844
|
});
|
|
5421
6845
|
index += 1;
|
|
@@ -5544,15 +6968,19 @@ function startLlmCallLoggerFromContents(options) {
|
|
|
5544
6968
|
sections.push(part.text);
|
|
5545
6969
|
continue;
|
|
5546
6970
|
}
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
6971
|
+
if (part.type === "inlineData") {
|
|
6972
|
+
const filename = buildLoggedAttachmentFilename("input", attachmentIndex, part.mimeType);
|
|
6973
|
+
attachments.push({
|
|
6974
|
+
filename,
|
|
6975
|
+
bytes: decodeInlineDataBuffer(part.data)
|
|
6976
|
+
});
|
|
6977
|
+
attachmentIndex += 1;
|
|
6978
|
+
sections.push(
|
|
6979
|
+
`[inlineData] file=${filename} mime=${part.mimeType ?? "application/octet-stream"} bytes=${attachments[attachments.length - 1]?.bytes.byteLength ?? 0}`
|
|
6980
|
+
);
|
|
6981
|
+
continue;
|
|
6982
|
+
}
|
|
6983
|
+
sections.push(`[${part.type}] file_id=${"file_id" in part ? part.file_id ?? "" : ""}`);
|
|
5556
6984
|
}
|
|
5557
6985
|
sections.push("");
|
|
5558
6986
|
}
|
|
@@ -5683,307 +7111,317 @@ async function runTextCall(params) {
|
|
|
5683
7111
|
return abortController.signal;
|
|
5684
7112
|
};
|
|
5685
7113
|
const signal = resolveAbortSignal();
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
const delta = event.delta ?? "";
|
|
5715
|
-
pushDelta("response", typeof delta === "string" ? delta : "");
|
|
5716
|
-
break;
|
|
5717
|
-
}
|
|
5718
|
-
case "response.reasoning_summary_text.delta": {
|
|
5719
|
-
const delta = event.delta ?? "";
|
|
5720
|
-
pushDelta("thought", typeof delta === "string" ? delta : "");
|
|
5721
|
-
break;
|
|
5722
|
-
}
|
|
5723
|
-
case "response.refusal.delta": {
|
|
5724
|
-
blocked = true;
|
|
5725
|
-
queue.push({ type: "blocked" });
|
|
5726
|
-
break;
|
|
5727
|
-
}
|
|
5728
|
-
default:
|
|
5729
|
-
break;
|
|
5730
|
-
}
|
|
5731
|
-
}
|
|
5732
|
-
const finalResponse = await stream.finalResponse();
|
|
5733
|
-
modelVersion = typeof finalResponse.model === "string" ? finalResponse.model : request.model;
|
|
5734
|
-
queue.push({ type: "model", modelVersion });
|
|
5735
|
-
if (finalResponse.error) {
|
|
5736
|
-
const message = typeof finalResponse.error.message === "string" ? finalResponse.error.message : "OpenAI response failed";
|
|
5737
|
-
throw new Error(message);
|
|
5738
|
-
}
|
|
5739
|
-
if (finalResponse.status && finalResponse.status !== "completed" && finalResponse.status !== "in_progress") {
|
|
5740
|
-
const detail = finalResponse.incomplete_details?.reason;
|
|
5741
|
-
throw new Error(
|
|
5742
|
-
`OpenAI response status ${finalResponse.status}${detail ? ` (${detail})` : ""}`
|
|
7114
|
+
const { result } = await collectFileUploadMetrics(async () => {
|
|
7115
|
+
try {
|
|
7116
|
+
if (provider === "openai") {
|
|
7117
|
+
const openAiInput = await maybePrepareOpenAiPromptInput(toOpenAiInput(contents));
|
|
7118
|
+
const openAiTools = toOpenAiTools(request.tools);
|
|
7119
|
+
const reasoningEffort = resolveOpenAiReasoningEffort(
|
|
7120
|
+
modelForProvider,
|
|
7121
|
+
request.thinkingLevel
|
|
7122
|
+
);
|
|
7123
|
+
const openAiTextConfig = {
|
|
7124
|
+
format: request.openAiTextFormat ?? { type: "text" },
|
|
7125
|
+
verbosity: resolveOpenAiVerbosity(modelForProvider)
|
|
7126
|
+
};
|
|
7127
|
+
const reasoning = {
|
|
7128
|
+
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
7129
|
+
summary: "detailed"
|
|
7130
|
+
};
|
|
7131
|
+
await runOpenAiCall(async (client) => {
|
|
7132
|
+
const stream = client.responses.stream(
|
|
7133
|
+
{
|
|
7134
|
+
model: modelForProvider,
|
|
7135
|
+
input: openAiInput,
|
|
7136
|
+
reasoning,
|
|
7137
|
+
text: openAiTextConfig,
|
|
7138
|
+
...openAiTools ? { tools: openAiTools } : {},
|
|
7139
|
+
include: ["code_interpreter_call.outputs", "reasoning.encrypted_content"]
|
|
7140
|
+
},
|
|
7141
|
+
{ signal }
|
|
5743
7142
|
);
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
7143
|
+
for await (const event of stream) {
|
|
7144
|
+
switch (event.type) {
|
|
7145
|
+
case "response.output_text.delta": {
|
|
7146
|
+
const delta = event.delta ?? "";
|
|
7147
|
+
pushDelta("response", typeof delta === "string" ? delta : "");
|
|
7148
|
+
break;
|
|
7149
|
+
}
|
|
7150
|
+
case "response.reasoning_summary_text.delta": {
|
|
7151
|
+
const delta = event.delta ?? "";
|
|
7152
|
+
pushDelta("thought", typeof delta === "string" ? delta : "");
|
|
7153
|
+
break;
|
|
7154
|
+
}
|
|
7155
|
+
case "response.refusal.delta": {
|
|
7156
|
+
blocked = true;
|
|
7157
|
+
queue.push({ type: "blocked" });
|
|
7158
|
+
break;
|
|
7159
|
+
}
|
|
7160
|
+
default:
|
|
7161
|
+
break;
|
|
5754
7162
|
}
|
|
5755
7163
|
}
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
const requestPayload = {
|
|
5763
|
-
model: modelForProvider,
|
|
5764
|
-
store: false,
|
|
5765
|
-
stream: true,
|
|
5766
|
-
...providerInfo.serviceTier ? { service_tier: providerInfo.serviceTier } : {},
|
|
5767
|
-
instructions: chatGptInput.instructions ?? "You are a helpful assistant.",
|
|
5768
|
-
input: chatGptInput.input,
|
|
5769
|
-
include: ["reasoning.encrypted_content"],
|
|
5770
|
-
reasoning: {
|
|
5771
|
-
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
5772
|
-
summary: "detailed"
|
|
5773
|
-
},
|
|
5774
|
-
text: {
|
|
5775
|
-
format: request.openAiTextFormat ?? { type: "text" },
|
|
5776
|
-
verbosity: resolveOpenAiVerbosity(request.model)
|
|
5777
|
-
},
|
|
5778
|
-
...openAiTools ? { tools: openAiTools } : {}
|
|
5779
|
-
};
|
|
5780
|
-
let sawResponseDelta = false;
|
|
5781
|
-
let sawThoughtDelta = false;
|
|
5782
|
-
const result = await collectChatGptCodexResponseWithRetry({
|
|
5783
|
-
request: requestPayload,
|
|
5784
|
-
signal,
|
|
5785
|
-
onDelta: (delta) => {
|
|
5786
|
-
if (delta.thoughtDelta) {
|
|
5787
|
-
sawThoughtDelta = true;
|
|
5788
|
-
pushDelta("thought", delta.thoughtDelta);
|
|
7164
|
+
const finalResponse = await stream.finalResponse();
|
|
7165
|
+
modelVersion = typeof finalResponse.model === "string" ? finalResponse.model : request.model;
|
|
7166
|
+
queue.push({ type: "model", modelVersion });
|
|
7167
|
+
if (finalResponse.error) {
|
|
7168
|
+
const message = typeof finalResponse.error.message === "string" ? finalResponse.error.message : "OpenAI response failed";
|
|
7169
|
+
throw new Error(message);
|
|
5789
7170
|
}
|
|
5790
|
-
if (
|
|
5791
|
-
|
|
5792
|
-
|
|
7171
|
+
if (finalResponse.status && finalResponse.status !== "completed" && finalResponse.status !== "in_progress") {
|
|
7172
|
+
const detail = finalResponse.incomplete_details?.reason;
|
|
7173
|
+
throw new Error(
|
|
7174
|
+
`OpenAI response status ${finalResponse.status}${detail ? ` (${detail})` : ""}`
|
|
7175
|
+
);
|
|
5793
7176
|
}
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
const fallbackText = typeof result.text === "string" ? result.text : "";
|
|
5806
|
-
const fallbackThoughts = typeof result.reasoningSummaryText === "string" && result.reasoningSummaryText.length > 0 ? result.reasoningSummaryText : typeof result.reasoningText === "string" ? result.reasoningText : "";
|
|
5807
|
-
if (!sawThoughtDelta && fallbackThoughts.length > 0) {
|
|
5808
|
-
pushDelta("thought", fallbackThoughts);
|
|
5809
|
-
}
|
|
5810
|
-
if (!sawResponseDelta && fallbackText.length > 0) {
|
|
5811
|
-
pushDelta("response", fallbackText);
|
|
5812
|
-
}
|
|
5813
|
-
} else if (provider === "fireworks") {
|
|
5814
|
-
if (request.tools && request.tools.length > 0) {
|
|
5815
|
-
throw new Error(
|
|
5816
|
-
"Fireworks provider does not support provider-native tools in generateText; use runToolLoop for function tools."
|
|
5817
|
-
);
|
|
5818
|
-
}
|
|
5819
|
-
const fireworksMessages = toFireworksMessages(contents, {
|
|
5820
|
-
responseMimeType: request.responseMimeType,
|
|
5821
|
-
responseJsonSchema: request.responseJsonSchema
|
|
5822
|
-
});
|
|
5823
|
-
await runFireworksCall(async (client) => {
|
|
5824
|
-
const responseFormat = request.responseJsonSchema ? {
|
|
5825
|
-
type: "json_schema",
|
|
5826
|
-
json_schema: {
|
|
5827
|
-
name: "llm-response",
|
|
5828
|
-
schema: request.responseJsonSchema
|
|
7177
|
+
latestUsage = extractOpenAiUsageTokens(finalResponse.usage);
|
|
7178
|
+
if (responseParts.length === 0) {
|
|
7179
|
+
const fallback = extractOpenAiResponseParts(finalResponse);
|
|
7180
|
+
blocked = blocked || fallback.blocked;
|
|
7181
|
+
for (const part of fallback.parts) {
|
|
7182
|
+
if (part.type === "text") {
|
|
7183
|
+
pushDelta(part.thought === true ? "thought" : "response", part.text);
|
|
7184
|
+
} else if (part.type === "inlineData") {
|
|
7185
|
+
pushInline(part.data, part.mimeType);
|
|
7186
|
+
}
|
|
7187
|
+
}
|
|
5829
7188
|
}
|
|
5830
|
-
}
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
7189
|
+
}, modelForProvider);
|
|
7190
|
+
} else if (provider === "chatgpt") {
|
|
7191
|
+
const chatGptInput = toChatGptInput(contents);
|
|
7192
|
+
const reasoningEffort = resolveOpenAiReasoningEffort(request.model, request.thinkingLevel);
|
|
7193
|
+
const openAiTools = toOpenAiTools(request.tools);
|
|
7194
|
+
const requestPayload = {
|
|
7195
|
+
model: modelForProvider,
|
|
7196
|
+
store: false,
|
|
7197
|
+
stream: true,
|
|
7198
|
+
...providerInfo.serviceTier ? { service_tier: providerInfo.serviceTier } : {},
|
|
7199
|
+
instructions: chatGptInput.instructions ?? "You are a helpful assistant.",
|
|
7200
|
+
input: chatGptInput.input,
|
|
7201
|
+
include: ["reasoning.encrypted_content"],
|
|
7202
|
+
reasoning: {
|
|
7203
|
+
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
7204
|
+
summary: "detailed"
|
|
5836
7205
|
},
|
|
5837
|
-
{
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
7206
|
+
text: {
|
|
7207
|
+
format: request.openAiTextFormat ?? { type: "text" },
|
|
7208
|
+
verbosity: resolveOpenAiVerbosity(request.model)
|
|
7209
|
+
},
|
|
7210
|
+
...openAiTools ? { tools: openAiTools } : {}
|
|
7211
|
+
};
|
|
7212
|
+
let sawResponseDelta = false;
|
|
7213
|
+
let sawThoughtDelta = false;
|
|
7214
|
+
const result2 = await collectChatGptCodexResponseWithRetry({
|
|
7215
|
+
request: requestPayload,
|
|
7216
|
+
signal,
|
|
7217
|
+
onDelta: (delta) => {
|
|
7218
|
+
if (delta.thoughtDelta) {
|
|
7219
|
+
sawThoughtDelta = true;
|
|
7220
|
+
pushDelta("thought", delta.thoughtDelta);
|
|
7221
|
+
}
|
|
7222
|
+
if (delta.textDelta) {
|
|
7223
|
+
sawResponseDelta = true;
|
|
7224
|
+
pushDelta("response", delta.textDelta);
|
|
7225
|
+
}
|
|
7226
|
+
}
|
|
7227
|
+
});
|
|
7228
|
+
blocked = blocked || result2.blocked;
|
|
7229
|
+
if (blocked) {
|
|
5844
7230
|
queue.push({ type: "blocked" });
|
|
5845
7231
|
}
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
if (textOutput.length > 0) {
|
|
5850
|
-
pushDelta("response", textOutput);
|
|
7232
|
+
if (result2.model) {
|
|
7233
|
+
modelVersion = providerInfo.serviceTier ? request.model : `chatgpt-${result2.model}`;
|
|
7234
|
+
queue.push({ type: "model", modelVersion });
|
|
5851
7235
|
}
|
|
5852
|
-
latestUsage =
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
const geminiTools = toGeminiTools(request.tools);
|
|
5871
|
-
if (geminiTools) {
|
|
5872
|
-
config.tools = geminiTools;
|
|
5873
|
-
}
|
|
5874
|
-
await runGeminiCall(async (client) => {
|
|
5875
|
-
const stream = await client.models.generateContentStream({
|
|
5876
|
-
model: modelForProvider,
|
|
5877
|
-
contents: geminiContents,
|
|
5878
|
-
config
|
|
7236
|
+
latestUsage = extractChatGptUsageTokens(result2.usage);
|
|
7237
|
+
const fallbackText = typeof result2.text === "string" ? result2.text : "";
|
|
7238
|
+
const fallbackThoughts = typeof result2.reasoningSummaryText === "string" && result2.reasoningSummaryText.length > 0 ? result2.reasoningSummaryText : typeof result2.reasoningText === "string" ? result2.reasoningText : "";
|
|
7239
|
+
if (!sawThoughtDelta && fallbackThoughts.length > 0) {
|
|
7240
|
+
pushDelta("thought", fallbackThoughts);
|
|
7241
|
+
}
|
|
7242
|
+
if (!sawResponseDelta && fallbackText.length > 0) {
|
|
7243
|
+
pushDelta("response", fallbackText);
|
|
7244
|
+
}
|
|
7245
|
+
} else if (provider === "fireworks") {
|
|
7246
|
+
if (request.tools && request.tools.length > 0) {
|
|
7247
|
+
throw new Error(
|
|
7248
|
+
"Fireworks provider does not support provider-native tools in generateText; use runToolLoop for function tools."
|
|
7249
|
+
);
|
|
7250
|
+
}
|
|
7251
|
+
const fireworksMessages = toFireworksMessages(contents, {
|
|
7252
|
+
responseMimeType: request.responseMimeType,
|
|
7253
|
+
responseJsonSchema: request.responseJsonSchema
|
|
5879
7254
|
});
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
7255
|
+
await runFireworksCall(async (client) => {
|
|
7256
|
+
const responseFormat = request.responseJsonSchema ? {
|
|
7257
|
+
type: "json_schema",
|
|
7258
|
+
json_schema: {
|
|
7259
|
+
name: "llm-response",
|
|
7260
|
+
schema: request.responseJsonSchema
|
|
7261
|
+
}
|
|
7262
|
+
} : request.responseMimeType === "application/json" ? { type: "json_object" } : void 0;
|
|
7263
|
+
const response = await client.chat.completions.create(
|
|
7264
|
+
{
|
|
7265
|
+
model: modelForProvider,
|
|
7266
|
+
messages: fireworksMessages,
|
|
7267
|
+
...responseFormat ? { response_format: responseFormat } : {}
|
|
7268
|
+
},
|
|
7269
|
+
{ signal }
|
|
7270
|
+
);
|
|
7271
|
+
modelVersion = typeof response.model === "string" ? response.model : request.model;
|
|
7272
|
+
queue.push({ type: "model", modelVersion });
|
|
7273
|
+
const choice = Array.isArray(response.choices) ? response.choices[0] : void 0;
|
|
7274
|
+
if (choice?.finish_reason === "content_filter") {
|
|
5887
7275
|
blocked = true;
|
|
5888
7276
|
queue.push({ type: "blocked" });
|
|
5889
7277
|
}
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
extractGeminiUsageTokens(chunk.usageMetadata)
|
|
7278
|
+
const textOutput = extractFireworksMessageText(
|
|
7279
|
+
choice?.message
|
|
5893
7280
|
);
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
continue;
|
|
5897
|
-
}
|
|
5898
|
-
const primary = candidates[0];
|
|
5899
|
-
if (primary && isModerationFinish(primary.finishReason)) {
|
|
5900
|
-
blocked = true;
|
|
5901
|
-
queue.push({ type: "blocked" });
|
|
7281
|
+
if (textOutput.length > 0) {
|
|
7282
|
+
pushDelta("response", textOutput);
|
|
5902
7283
|
}
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
7284
|
+
latestUsage = extractFireworksUsageTokens(response.usage);
|
|
7285
|
+
}, modelForProvider);
|
|
7286
|
+
} else {
|
|
7287
|
+
const geminiContents = await maybePrepareGeminiPromptContents(
|
|
7288
|
+
contents.map(convertLlmContentToGeminiContent)
|
|
7289
|
+
);
|
|
7290
|
+
const thinkingConfig = resolveGeminiThinkingConfig(modelForProvider, request.thinkingLevel);
|
|
7291
|
+
const config = {
|
|
7292
|
+
maxOutputTokens: 32e3,
|
|
7293
|
+
...thinkingConfig ? { thinkingConfig } : {},
|
|
7294
|
+
...request.responseMimeType ? { responseMimeType: request.responseMimeType } : {},
|
|
7295
|
+
...request.responseJsonSchema ? { responseJsonSchema: request.responseJsonSchema } : {},
|
|
7296
|
+
...request.responseModalities ? { responseModalities: Array.from(request.responseModalities) } : {},
|
|
7297
|
+
...request.imageAspectRatio || request.imageSize ? {
|
|
7298
|
+
imageConfig: {
|
|
7299
|
+
...request.imageAspectRatio ? { aspectRatio: request.imageAspectRatio } : {},
|
|
7300
|
+
...request.imageSize ? { imageSize: request.imageSize } : {}
|
|
7301
|
+
}
|
|
7302
|
+
} : {}
|
|
7303
|
+
};
|
|
7304
|
+
const geminiTools = toGeminiTools(request.tools);
|
|
7305
|
+
if (geminiTools) {
|
|
7306
|
+
config.tools = geminiTools;
|
|
7307
|
+
}
|
|
7308
|
+
await runGeminiCall(async (client) => {
|
|
7309
|
+
const stream = await client.models.generateContentStream({
|
|
7310
|
+
model: modelForProvider,
|
|
7311
|
+
contents: geminiContents,
|
|
7312
|
+
config
|
|
7313
|
+
});
|
|
7314
|
+
let latestGrounding;
|
|
7315
|
+
for await (const chunk of stream) {
|
|
7316
|
+
if (chunk.modelVersion) {
|
|
7317
|
+
modelVersion = chunk.modelVersion;
|
|
7318
|
+
queue.push({ type: "model", modelVersion });
|
|
5907
7319
|
}
|
|
5908
|
-
if (
|
|
5909
|
-
|
|
7320
|
+
if (chunk.promptFeedback?.blockReason) {
|
|
7321
|
+
blocked = true;
|
|
7322
|
+
queue.push({ type: "blocked" });
|
|
5910
7323
|
}
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
7324
|
+
latestUsage = mergeTokenUpdates(
|
|
7325
|
+
latestUsage,
|
|
7326
|
+
extractGeminiUsageTokens(chunk.usageMetadata)
|
|
7327
|
+
);
|
|
7328
|
+
const candidates = chunk.candidates;
|
|
7329
|
+
if (!candidates || candidates.length === 0) {
|
|
7330
|
+
continue;
|
|
5914
7331
|
}
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
7332
|
+
const primary = candidates[0];
|
|
7333
|
+
if (primary && isModerationFinish(primary.finishReason)) {
|
|
7334
|
+
blocked = true;
|
|
7335
|
+
queue.push({ type: "blocked" });
|
|
7336
|
+
}
|
|
7337
|
+
for (const candidate of candidates) {
|
|
7338
|
+
const candidateContent = candidate.content;
|
|
7339
|
+
if (!candidateContent) {
|
|
7340
|
+
continue;
|
|
7341
|
+
}
|
|
7342
|
+
if (candidate.groundingMetadata) {
|
|
7343
|
+
latestGrounding = candidate.groundingMetadata;
|
|
7344
|
+
}
|
|
7345
|
+
const content2 = convertGeminiContentToLlmContent(candidateContent);
|
|
7346
|
+
if (!responseRole) {
|
|
7347
|
+
responseRole = content2.role;
|
|
7348
|
+
}
|
|
7349
|
+
for (const part of content2.parts) {
|
|
7350
|
+
if (part.type === "text") {
|
|
7351
|
+
pushDelta(part.thought === true ? "thought" : "response", part.text);
|
|
7352
|
+
} else if (part.type === "inlineData") {
|
|
7353
|
+
pushInline(part.data, part.mimeType);
|
|
7354
|
+
}
|
|
5920
7355
|
}
|
|
5921
7356
|
}
|
|
5922
7357
|
}
|
|
7358
|
+
grounding = latestGrounding;
|
|
7359
|
+
}, modelForProvider);
|
|
7360
|
+
}
|
|
7361
|
+
const mergedParts = mergeConsecutiveTextParts(responseParts);
|
|
7362
|
+
const content = mergedParts.length > 0 ? { role: responseRole ?? "assistant", parts: mergedParts } : void 0;
|
|
7363
|
+
const { text, thoughts } = extractTextByChannel(content);
|
|
7364
|
+
const outputAttachments = collectLoggedAttachmentsFromLlmParts(mergedParts, "output");
|
|
7365
|
+
const costUsd = estimateCallCostUsd({
|
|
7366
|
+
modelId: modelVersion,
|
|
7367
|
+
tokens: latestUsage,
|
|
7368
|
+
responseImages,
|
|
7369
|
+
imageSize: request.imageSize
|
|
7370
|
+
});
|
|
7371
|
+
if (latestUsage) {
|
|
7372
|
+
queue.push({ type: "usage", usage: latestUsage, costUsd, modelVersion });
|
|
7373
|
+
}
|
|
7374
|
+
callLogger?.complete({
|
|
7375
|
+
responseText: text,
|
|
7376
|
+
attachments: outputAttachments,
|
|
7377
|
+
metadata: {
|
|
7378
|
+
provider,
|
|
7379
|
+
model: request.model,
|
|
7380
|
+
modelVersion,
|
|
7381
|
+
blocked,
|
|
7382
|
+
costUsd,
|
|
7383
|
+
usage: latestUsage,
|
|
7384
|
+
grounding: grounding ? sanitiseLogValue(grounding) : void 0,
|
|
7385
|
+
responseChars: text.length,
|
|
7386
|
+
thoughtChars: thoughts.length,
|
|
7387
|
+
responseImages,
|
|
7388
|
+
uploads: getCurrentFileUploadMetrics()
|
|
5923
7389
|
}
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
}
|
|
5927
|
-
const mergedParts = mergeConsecutiveTextParts(responseParts);
|
|
5928
|
-
const content = mergedParts.length > 0 ? { role: responseRole ?? "assistant", parts: mergedParts } : void 0;
|
|
5929
|
-
const { text, thoughts } = extractTextByChannel(content);
|
|
5930
|
-
const outputAttachments = collectLoggedAttachmentsFromLlmParts(mergedParts, "output");
|
|
5931
|
-
const costUsd = estimateCallCostUsd({
|
|
5932
|
-
modelId: modelVersion,
|
|
5933
|
-
tokens: latestUsage,
|
|
5934
|
-
responseImages,
|
|
5935
|
-
imageSize: request.imageSize
|
|
5936
|
-
});
|
|
5937
|
-
if (latestUsage) {
|
|
5938
|
-
queue.push({ type: "usage", usage: latestUsage, costUsd, modelVersion });
|
|
5939
|
-
}
|
|
5940
|
-
callLogger?.complete({
|
|
5941
|
-
responseText: text,
|
|
5942
|
-
attachments: outputAttachments,
|
|
5943
|
-
metadata: {
|
|
5944
|
-
provider,
|
|
5945
|
-
model: request.model,
|
|
5946
|
-
modelVersion,
|
|
5947
|
-
blocked,
|
|
5948
|
-
costUsd,
|
|
5949
|
-
usage: latestUsage,
|
|
5950
|
-
grounding: grounding ? sanitiseLogValue(grounding) : void 0,
|
|
5951
|
-
responseChars: text.length,
|
|
5952
|
-
thoughtChars: thoughts.length,
|
|
5953
|
-
responseImages
|
|
5954
|
-
}
|
|
5955
|
-
});
|
|
5956
|
-
return {
|
|
5957
|
-
provider,
|
|
5958
|
-
model: request.model,
|
|
5959
|
-
modelVersion,
|
|
5960
|
-
content,
|
|
5961
|
-
text,
|
|
5962
|
-
thoughts,
|
|
5963
|
-
blocked,
|
|
5964
|
-
usage: latestUsage,
|
|
5965
|
-
costUsd,
|
|
5966
|
-
grounding
|
|
5967
|
-
};
|
|
5968
|
-
} catch (error) {
|
|
5969
|
-
const partialParts = mergeConsecutiveTextParts(responseParts);
|
|
5970
|
-
const partialContent = partialParts.length > 0 ? { role: responseRole ?? "assistant", parts: partialParts } : void 0;
|
|
5971
|
-
const { text: partialText } = extractTextByChannel(partialContent);
|
|
5972
|
-
callLogger?.fail(error, {
|
|
5973
|
-
responseText: partialText,
|
|
5974
|
-
attachments: collectLoggedAttachmentsFromLlmParts(partialParts, "output"),
|
|
5975
|
-
metadata: {
|
|
7390
|
+
});
|
|
7391
|
+
return {
|
|
5976
7392
|
provider,
|
|
5977
7393
|
model: request.model,
|
|
5978
7394
|
modelVersion,
|
|
7395
|
+
content,
|
|
7396
|
+
text,
|
|
7397
|
+
thoughts,
|
|
5979
7398
|
blocked,
|
|
5980
7399
|
usage: latestUsage,
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
}
|
|
5984
|
-
})
|
|
5985
|
-
|
|
5986
|
-
|
|
7400
|
+
costUsd,
|
|
7401
|
+
grounding
|
|
7402
|
+
};
|
|
7403
|
+
} catch (error) {
|
|
7404
|
+
const partialParts = mergeConsecutiveTextParts(responseParts);
|
|
7405
|
+
const partialContent = partialParts.length > 0 ? { role: responseRole ?? "assistant", parts: partialParts } : void 0;
|
|
7406
|
+
const { text: partialText } = extractTextByChannel(partialContent);
|
|
7407
|
+
callLogger?.fail(error, {
|
|
7408
|
+
responseText: partialText,
|
|
7409
|
+
attachments: collectLoggedAttachmentsFromLlmParts(partialParts, "output"),
|
|
7410
|
+
metadata: {
|
|
7411
|
+
provider,
|
|
7412
|
+
model: request.model,
|
|
7413
|
+
modelVersion,
|
|
7414
|
+
blocked,
|
|
7415
|
+
usage: latestUsage,
|
|
7416
|
+
partialResponseParts: responseParts.length,
|
|
7417
|
+
responseImages,
|
|
7418
|
+
uploads: getCurrentFileUploadMetrics()
|
|
7419
|
+
}
|
|
7420
|
+
});
|
|
7421
|
+
throw error;
|
|
7422
|
+
}
|
|
7423
|
+
});
|
|
7424
|
+
return result;
|
|
5987
7425
|
}
|
|
5988
7426
|
function streamText(request) {
|
|
5989
7427
|
const queue = createAsyncQueue();
|
|
@@ -6266,7 +7704,12 @@ function normalizeToolLoopSteeringInput(input) {
|
|
|
6266
7704
|
if (part.type === "text") {
|
|
6267
7705
|
parts.push({ type: "text", text: part.text });
|
|
6268
7706
|
} else {
|
|
6269
|
-
parts.push({
|
|
7707
|
+
parts.push({
|
|
7708
|
+
type: "inlineData",
|
|
7709
|
+
data: part.data,
|
|
7710
|
+
mimeType: part.mimeType,
|
|
7711
|
+
filename: part.filename
|
|
7712
|
+
});
|
|
6270
7713
|
}
|
|
6271
7714
|
}
|
|
6272
7715
|
if (parts.length > 0) {
|
|
@@ -6454,9 +7897,10 @@ async function runToolLoop(request) {
|
|
|
6454
7897
|
let reasoningSummary = "";
|
|
6455
7898
|
let stepToolCallText;
|
|
6456
7899
|
let stepToolCallPayload;
|
|
7900
|
+
const preparedInput = await maybePrepareOpenAiPromptInput(input);
|
|
6457
7901
|
const stepRequestPayload = {
|
|
6458
7902
|
model: providerInfo.model,
|
|
6459
|
-
input,
|
|
7903
|
+
input: preparedInput,
|
|
6460
7904
|
...previousResponseId ? { previous_response_id: previousResponseId } : {},
|
|
6461
7905
|
...openAiTools.length > 0 ? { tools: openAiTools } : {},
|
|
6462
7906
|
...openAiTools.length > 0 ? { parallel_tool_calls: true } : {},
|
|
@@ -6484,7 +7928,7 @@ async function runToolLoop(request) {
|
|
|
6484
7928
|
const stream = client.responses.stream(
|
|
6485
7929
|
{
|
|
6486
7930
|
model: providerInfo.model,
|
|
6487
|
-
input,
|
|
7931
|
+
input: preparedInput,
|
|
6488
7932
|
...previousResponseId ? { previous_response_id: previousResponseId } : {},
|
|
6489
7933
|
...openAiTools.length > 0 ? { tools: openAiTools } : {},
|
|
6490
7934
|
...openAiTools.length > 0 ? { parallel_tool_calls: true } : {},
|
|
@@ -6661,27 +8105,29 @@ async function runToolLoop(request) {
|
|
|
6661
8105
|
input: entry.value
|
|
6662
8106
|
});
|
|
6663
8107
|
}
|
|
6664
|
-
const callResults = await
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
toolId: entry.toolId,
|
|
6670
|
-
turn: entry.turn,
|
|
6671
|
-
toolIndex: entry.toolIndex
|
|
6672
|
-
},
|
|
6673
|
-
async () => {
|
|
6674
|
-
const { result, outputPayload } = await executeToolCall({
|
|
6675
|
-
callKind: entry.call.kind,
|
|
8108
|
+
const callResults = await maybeSpillCombinedToolCallOutputs(
|
|
8109
|
+
await Promise.all(
|
|
8110
|
+
callInputs.map(async (entry) => {
|
|
8111
|
+
return await toolCallContextStorage.run(
|
|
8112
|
+
{
|
|
6676
8113
|
toolName: entry.toolName,
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
}
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
8114
|
+
toolId: entry.toolId,
|
|
8115
|
+
turn: entry.turn,
|
|
8116
|
+
toolIndex: entry.toolIndex
|
|
8117
|
+
},
|
|
8118
|
+
async () => {
|
|
8119
|
+
const { result, outputPayload } = await executeToolCall({
|
|
8120
|
+
callKind: entry.call.kind,
|
|
8121
|
+
toolName: entry.toolName,
|
|
8122
|
+
tool: request.tools[entry.toolName],
|
|
8123
|
+
rawInput: entry.value,
|
|
8124
|
+
parseError: entry.parseError
|
|
8125
|
+
});
|
|
8126
|
+
return { entry, result, outputPayload };
|
|
8127
|
+
}
|
|
8128
|
+
);
|
|
8129
|
+
})
|
|
8130
|
+
)
|
|
6685
8131
|
);
|
|
6686
8132
|
const toolOutputs = [];
|
|
6687
8133
|
let toolExecutionMs = 0;
|
|
@@ -6788,7 +8234,7 @@ async function runToolLoop(request) {
|
|
|
6788
8234
|
const openAiTools = openAiNativeTools ? [...openAiNativeTools, ...openAiAgentTools] : [...openAiAgentTools];
|
|
6789
8235
|
const reasoningEffort = resolveOpenAiReasoningEffort(request.model, request.thinkingLevel);
|
|
6790
8236
|
const toolLoopInput = toChatGptInput(contents);
|
|
6791
|
-
const conversationId = `tool-loop-${(0,
|
|
8237
|
+
const conversationId = `tool-loop-${(0, import_node_crypto2.randomBytes)(8).toString("hex")}`;
|
|
6792
8238
|
const promptCacheKey = conversationId;
|
|
6793
8239
|
let input = [...toolLoopInput.input];
|
|
6794
8240
|
for (let stepIndex = 0; stepIndex < maxSteps; stepIndex += 1) {
|
|
@@ -6962,27 +8408,29 @@ async function runToolLoop(request) {
|
|
|
6962
8408
|
input: entry.value
|
|
6963
8409
|
});
|
|
6964
8410
|
}
|
|
6965
|
-
const callResults = await
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
toolId: entry.toolId,
|
|
6971
|
-
turn: entry.turn,
|
|
6972
|
-
toolIndex: entry.toolIndex
|
|
6973
|
-
},
|
|
6974
|
-
async () => {
|
|
6975
|
-
const { result, outputPayload } = await executeToolCall({
|
|
6976
|
-
callKind: entry.call.kind,
|
|
8411
|
+
const callResults = await maybeSpillCombinedToolCallOutputs(
|
|
8412
|
+
await Promise.all(
|
|
8413
|
+
callInputs.map(async (entry) => {
|
|
8414
|
+
return await toolCallContextStorage.run(
|
|
8415
|
+
{
|
|
6977
8416
|
toolName: entry.toolName,
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
}
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
8417
|
+
toolId: entry.toolId,
|
|
8418
|
+
turn: entry.turn,
|
|
8419
|
+
toolIndex: entry.toolIndex
|
|
8420
|
+
},
|
|
8421
|
+
async () => {
|
|
8422
|
+
const { result, outputPayload } = await executeToolCall({
|
|
8423
|
+
callKind: entry.call.kind,
|
|
8424
|
+
toolName: entry.toolName,
|
|
8425
|
+
tool: request.tools[entry.toolName],
|
|
8426
|
+
rawInput: entry.value,
|
|
8427
|
+
parseError: entry.parseError
|
|
8428
|
+
});
|
|
8429
|
+
return { entry, result, outputPayload };
|
|
8430
|
+
}
|
|
8431
|
+
);
|
|
8432
|
+
})
|
|
8433
|
+
)
|
|
6986
8434
|
);
|
|
6987
8435
|
let toolExecutionMs = 0;
|
|
6988
8436
|
let waitToolMs = 0;
|
|
@@ -7254,27 +8702,29 @@ async function runToolLoop(request) {
|
|
|
7254
8702
|
input: entry.value
|
|
7255
8703
|
});
|
|
7256
8704
|
}
|
|
7257
|
-
const callResults = await
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
toolId: entry.toolId,
|
|
7263
|
-
turn: entry.turn,
|
|
7264
|
-
toolIndex: entry.toolIndex
|
|
7265
|
-
},
|
|
7266
|
-
async () => {
|
|
7267
|
-
const { result, outputPayload } = await executeToolCall({
|
|
7268
|
-
callKind: "function",
|
|
8705
|
+
const callResults = await maybeSpillCombinedToolCallOutputs(
|
|
8706
|
+
await Promise.all(
|
|
8707
|
+
callInputs.map(async (entry) => {
|
|
8708
|
+
return await toolCallContextStorage.run(
|
|
8709
|
+
{
|
|
7269
8710
|
toolName: entry.toolName,
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
}
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
|
|
7277
|
-
|
|
8711
|
+
toolId: entry.toolId,
|
|
8712
|
+
turn: entry.turn,
|
|
8713
|
+
toolIndex: entry.toolIndex
|
|
8714
|
+
},
|
|
8715
|
+
async () => {
|
|
8716
|
+
const { result, outputPayload } = await executeToolCall({
|
|
8717
|
+
callKind: "function",
|
|
8718
|
+
toolName: entry.toolName,
|
|
8719
|
+
tool: request.tools[entry.toolName],
|
|
8720
|
+
rawInput: entry.value,
|
|
8721
|
+
parseError: entry.parseError
|
|
8722
|
+
});
|
|
8723
|
+
return { entry, result, outputPayload };
|
|
8724
|
+
}
|
|
8725
|
+
);
|
|
8726
|
+
})
|
|
8727
|
+
)
|
|
7278
8728
|
);
|
|
7279
8729
|
const assistantToolCalls = [];
|
|
7280
8730
|
const toolMessages = [];
|
|
@@ -7413,9 +8863,10 @@ async function runToolLoop(request) {
|
|
|
7413
8863
|
...thinkingConfig ? { thinkingConfig } : {}
|
|
7414
8864
|
};
|
|
7415
8865
|
const onEvent = request.onEvent;
|
|
8866
|
+
const preparedGeminiContents = await maybePrepareGeminiPromptContents(geminiContents);
|
|
7416
8867
|
const stepRequestPayload = {
|
|
7417
8868
|
model: request.model,
|
|
7418
|
-
contents:
|
|
8869
|
+
contents: preparedGeminiContents,
|
|
7419
8870
|
config
|
|
7420
8871
|
};
|
|
7421
8872
|
const stepCallLogger = startLlmCallLoggerFromPayload({
|
|
@@ -7429,15 +8880,13 @@ async function runToolLoop(request) {
|
|
|
7429
8880
|
async (client) => {
|
|
7430
8881
|
const stream = await client.models.generateContentStream({
|
|
7431
8882
|
model: request.model,
|
|
7432
|
-
contents:
|
|
8883
|
+
contents: preparedGeminiContents,
|
|
7433
8884
|
config
|
|
7434
8885
|
});
|
|
7435
8886
|
let responseText2 = "";
|
|
7436
8887
|
let thoughtsText2 = "";
|
|
7437
8888
|
const modelParts = [];
|
|
7438
8889
|
const functionCalls = [];
|
|
7439
|
-
const seenFunctionCallIds = /* @__PURE__ */ new Set();
|
|
7440
|
-
const seenFunctionCallKeys = /* @__PURE__ */ new Set();
|
|
7441
8890
|
let latestUsageMetadata;
|
|
7442
8891
|
let resolvedModelVersion;
|
|
7443
8892
|
for await (const chunk of stream) {
|
|
@@ -7454,34 +8903,13 @@ async function runToolLoop(request) {
|
|
|
7454
8903
|
continue;
|
|
7455
8904
|
}
|
|
7456
8905
|
const primary = candidates[0];
|
|
7457
|
-
const parts = primary?.content?.parts;
|
|
7458
|
-
|
|
8906
|
+
const parts = primary?.content?.parts ?? [];
|
|
8907
|
+
const chunkFunctionCalls = chunk.functionCalls ?? [];
|
|
8908
|
+
if (parts.length === 0 && chunkFunctionCalls.length === 0) {
|
|
7459
8909
|
continue;
|
|
7460
8910
|
}
|
|
7461
8911
|
for (const part of parts) {
|
|
7462
8912
|
modelParts.push(part);
|
|
7463
|
-
const call = part.functionCall;
|
|
7464
|
-
if (call) {
|
|
7465
|
-
const id = typeof call.id === "string" ? call.id : "";
|
|
7466
|
-
const shouldAdd = (() => {
|
|
7467
|
-
if (id.length > 0) {
|
|
7468
|
-
if (seenFunctionCallIds.has(id)) {
|
|
7469
|
-
return false;
|
|
7470
|
-
}
|
|
7471
|
-
seenFunctionCallIds.add(id);
|
|
7472
|
-
return true;
|
|
7473
|
-
}
|
|
7474
|
-
const key = JSON.stringify({ name: call.name ?? "", args: call.args ?? null });
|
|
7475
|
-
if (seenFunctionCallKeys.has(key)) {
|
|
7476
|
-
return false;
|
|
7477
|
-
}
|
|
7478
|
-
seenFunctionCallKeys.add(key);
|
|
7479
|
-
return true;
|
|
7480
|
-
})();
|
|
7481
|
-
if (shouldAdd) {
|
|
7482
|
-
functionCalls.push(call);
|
|
7483
|
-
}
|
|
7484
|
-
}
|
|
7485
8913
|
if (typeof part.text === "string" && part.text.length > 0) {
|
|
7486
8914
|
if (part.thought) {
|
|
7487
8915
|
thoughtsText2 += part.text;
|
|
@@ -7494,6 +8922,15 @@ async function runToolLoop(request) {
|
|
|
7494
8922
|
}
|
|
7495
8923
|
}
|
|
7496
8924
|
}
|
|
8925
|
+
if (chunkFunctionCalls.length > 0) {
|
|
8926
|
+
functionCalls.push(...chunkFunctionCalls);
|
|
8927
|
+
continue;
|
|
8928
|
+
}
|
|
8929
|
+
for (const part of parts) {
|
|
8930
|
+
if (part.functionCall) {
|
|
8931
|
+
functionCalls.push(part.functionCall);
|
|
8932
|
+
}
|
|
8933
|
+
}
|
|
7497
8934
|
}
|
|
7498
8935
|
return {
|
|
7499
8936
|
responseText: responseText2,
|
|
@@ -7619,26 +9056,28 @@ async function runToolLoop(request) {
|
|
|
7619
9056
|
input: entry.rawInput
|
|
7620
9057
|
});
|
|
7621
9058
|
}
|
|
7622
|
-
const callResults = await
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
toolId: entry.toolId,
|
|
7628
|
-
turn: entry.turn,
|
|
7629
|
-
toolIndex: entry.toolIndex
|
|
7630
|
-
},
|
|
7631
|
-
async () => {
|
|
7632
|
-
const { result, outputPayload } = await executeToolCall({
|
|
7633
|
-
callKind: "function",
|
|
9059
|
+
const callResults = await maybeSpillCombinedToolCallOutputs(
|
|
9060
|
+
await Promise.all(
|
|
9061
|
+
callInputs.map(async (entry) => {
|
|
9062
|
+
return await toolCallContextStorage.run(
|
|
9063
|
+
{
|
|
7634
9064
|
toolName: entry.toolName,
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
9065
|
+
toolId: entry.toolId,
|
|
9066
|
+
turn: entry.turn,
|
|
9067
|
+
toolIndex: entry.toolIndex
|
|
9068
|
+
},
|
|
9069
|
+
async () => {
|
|
9070
|
+
const { result, outputPayload } = await executeToolCall({
|
|
9071
|
+
callKind: "function",
|
|
9072
|
+
toolName: entry.toolName,
|
|
9073
|
+
tool: request.tools[entry.toolName],
|
|
9074
|
+
rawInput: entry.rawInput
|
|
9075
|
+
});
|
|
9076
|
+
return { entry, result, outputPayload };
|
|
9077
|
+
}
|
|
9078
|
+
);
|
|
9079
|
+
})
|
|
9080
|
+
)
|
|
7642
9081
|
);
|
|
7643
9082
|
let toolExecutionMs = 0;
|
|
7644
9083
|
let waitToolMs = 0;
|
|
@@ -8042,11 +9481,11 @@ ${lines}`;
|
|
|
8042
9481
|
}
|
|
8043
9482
|
|
|
8044
9483
|
// src/agent.ts
|
|
8045
|
-
var
|
|
8046
|
-
var
|
|
9484
|
+
var import_node_crypto4 = require("crypto");
|
|
9485
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
8047
9486
|
|
|
8048
9487
|
// src/agent/subagents.ts
|
|
8049
|
-
var
|
|
9488
|
+
var import_node_crypto3 = require("crypto");
|
|
8050
9489
|
var import_zod4 = require("zod");
|
|
8051
9490
|
var DEFAULT_SUBAGENT_MAX_AGENTS = 6;
|
|
8052
9491
|
var DEFAULT_SUBAGENT_MAX_DEPTH = 1;
|
|
@@ -8266,7 +9705,7 @@ function createSubagentToolController(options) {
|
|
|
8266
9705
|
}
|
|
8267
9706
|
model = input.model;
|
|
8268
9707
|
}
|
|
8269
|
-
const id = `agent_${(0,
|
|
9708
|
+
const id = `agent_${(0, import_node_crypto3.randomBytes)(6).toString("hex")}`;
|
|
8270
9709
|
const now = Date.now();
|
|
8271
9710
|
const { roleName, roleInstructions } = resolveAgentType(input.agent_type);
|
|
8272
9711
|
const nickname = reserveAgentNickname(roleName, roleNicknameCounts);
|
|
@@ -8518,26 +9957,26 @@ function resolveInputItemsText(items) {
|
|
|
8518
9957
|
}
|
|
8519
9958
|
const itemType = typeof item.type === "string" ? item.type.trim() : "";
|
|
8520
9959
|
const name = typeof item.name === "string" ? item.name.trim() : "";
|
|
8521
|
-
const
|
|
9960
|
+
const path10 = typeof item.path === "string" ? item.path.trim() : "";
|
|
8522
9961
|
const imageUrl = typeof item.image_url === "string" ? item.image_url.trim() : "";
|
|
8523
9962
|
if (itemType === "image") {
|
|
8524
9963
|
lines.push("[image]");
|
|
8525
9964
|
continue;
|
|
8526
9965
|
}
|
|
8527
|
-
if (itemType === "local_image" &&
|
|
8528
|
-
lines.push(`[local_image:${
|
|
9966
|
+
if (itemType === "local_image" && path10) {
|
|
9967
|
+
lines.push(`[local_image:${path10}]`);
|
|
8529
9968
|
continue;
|
|
8530
9969
|
}
|
|
8531
|
-
if (itemType === "skill" && name &&
|
|
8532
|
-
lines.push(`[skill:$${name}](${
|
|
9970
|
+
if (itemType === "skill" && name && path10) {
|
|
9971
|
+
lines.push(`[skill:$${name}](${path10})`);
|
|
8533
9972
|
continue;
|
|
8534
9973
|
}
|
|
8535
|
-
if (itemType === "mention" && name &&
|
|
8536
|
-
lines.push(`[mention:$${name}](${
|
|
9974
|
+
if (itemType === "mention" && name && path10) {
|
|
9975
|
+
lines.push(`[mention:$${name}](${path10})`);
|
|
8537
9976
|
continue;
|
|
8538
9977
|
}
|
|
8539
|
-
if (
|
|
8540
|
-
lines.push(`[${itemType || "input"}:${
|
|
9978
|
+
if (path10 || imageUrl) {
|
|
9979
|
+
lines.push(`[${itemType || "input"}:${path10 || imageUrl}]`);
|
|
8541
9980
|
continue;
|
|
8542
9981
|
}
|
|
8543
9982
|
if (name) {
|
|
@@ -8826,7 +10265,7 @@ function joinInstructionBlocks(...blocks) {
|
|
|
8826
10265
|
return parts.join("\n\n");
|
|
8827
10266
|
}
|
|
8828
10267
|
function randomSubmissionId() {
|
|
8829
|
-
return `sub_${(0,
|
|
10268
|
+
return `sub_${(0, import_node_crypto3.randomBytes)(6).toString("hex")}`;
|
|
8830
10269
|
}
|
|
8831
10270
|
function normalizeInteger(value, fallback, min, max) {
|
|
8832
10271
|
const parsed = Number.isFinite(value) ? Math.floor(value) : fallback;
|
|
@@ -8855,27 +10294,27 @@ function sleep2(ms) {
|
|
|
8855
10294
|
}
|
|
8856
10295
|
|
|
8857
10296
|
// src/tools/filesystemTools.ts
|
|
8858
|
-
var
|
|
8859
|
-
var
|
|
10297
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
10298
|
+
var import_node_buffer5 = require("buffer");
|
|
8860
10299
|
var import_zod6 = require("zod");
|
|
8861
10300
|
|
|
8862
10301
|
// src/tools/applyPatch.ts
|
|
8863
|
-
var
|
|
10302
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
8864
10303
|
var import_zod5 = require("zod");
|
|
8865
10304
|
|
|
8866
10305
|
// src/tools/filesystem.ts
|
|
8867
|
-
var
|
|
8868
|
-
var
|
|
10306
|
+
var import_node_fs4 = require("fs");
|
|
10307
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
8869
10308
|
var InMemoryAgentFilesystem = class {
|
|
8870
10309
|
#files = /* @__PURE__ */ new Map();
|
|
8871
10310
|
#dirs = /* @__PURE__ */ new Map();
|
|
8872
10311
|
#clock = 0;
|
|
8873
10312
|
constructor(initialFiles = {}) {
|
|
8874
|
-
const root =
|
|
10313
|
+
const root = import_node_path6.default.resolve("/");
|
|
8875
10314
|
this.#dirs.set(root, { mtimeMs: this.#nextMtime() });
|
|
8876
10315
|
for (const [filePath, content] of Object.entries(initialFiles)) {
|
|
8877
|
-
const absolutePath =
|
|
8878
|
-
this.#ensureDirSync(
|
|
10316
|
+
const absolutePath = import_node_path6.default.resolve(filePath);
|
|
10317
|
+
this.#ensureDirSync(import_node_path6.default.dirname(absolutePath));
|
|
8879
10318
|
this.#files.set(absolutePath, {
|
|
8880
10319
|
content,
|
|
8881
10320
|
mtimeMs: this.#nextMtime()
|
|
@@ -8883,7 +10322,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
8883
10322
|
}
|
|
8884
10323
|
}
|
|
8885
10324
|
async readTextFile(filePath) {
|
|
8886
|
-
const absolutePath =
|
|
10325
|
+
const absolutePath = import_node_path6.default.resolve(filePath);
|
|
8887
10326
|
const file = this.#files.get(absolutePath);
|
|
8888
10327
|
if (!file) {
|
|
8889
10328
|
throw createNoSuchFileError("open", absolutePath);
|
|
@@ -8895,24 +10334,24 @@ var InMemoryAgentFilesystem = class {
|
|
|
8895
10334
|
return Buffer.from(content, "utf8");
|
|
8896
10335
|
}
|
|
8897
10336
|
async writeTextFile(filePath, content) {
|
|
8898
|
-
const absolutePath =
|
|
8899
|
-
const parentPath =
|
|
10337
|
+
const absolutePath = import_node_path6.default.resolve(filePath);
|
|
10338
|
+
const parentPath = import_node_path6.default.dirname(absolutePath);
|
|
8900
10339
|
if (!this.#dirs.has(parentPath)) {
|
|
8901
10340
|
throw createNoSuchFileError("open", parentPath);
|
|
8902
10341
|
}
|
|
8903
10342
|
this.#files.set(absolutePath, { content, mtimeMs: this.#nextMtime() });
|
|
8904
10343
|
}
|
|
8905
10344
|
async deleteFile(filePath) {
|
|
8906
|
-
const absolutePath =
|
|
10345
|
+
const absolutePath = import_node_path6.default.resolve(filePath);
|
|
8907
10346
|
if (!this.#files.delete(absolutePath)) {
|
|
8908
10347
|
throw createNoSuchFileError("unlink", absolutePath);
|
|
8909
10348
|
}
|
|
8910
10349
|
}
|
|
8911
10350
|
async ensureDir(directoryPath) {
|
|
8912
|
-
this.#ensureDirSync(
|
|
10351
|
+
this.#ensureDirSync(import_node_path6.default.resolve(directoryPath));
|
|
8913
10352
|
}
|
|
8914
10353
|
async readDir(directoryPath) {
|
|
8915
|
-
const absolutePath =
|
|
10354
|
+
const absolutePath = import_node_path6.default.resolve(directoryPath);
|
|
8916
10355
|
const directory = this.#dirs.get(absolutePath);
|
|
8917
10356
|
if (!directory) {
|
|
8918
10357
|
throw createNoSuchFileError("scandir", absolutePath);
|
|
@@ -8923,10 +10362,10 @@ var InMemoryAgentFilesystem = class {
|
|
|
8923
10362
|
if (dirPath === absolutePath) {
|
|
8924
10363
|
continue;
|
|
8925
10364
|
}
|
|
8926
|
-
if (
|
|
10365
|
+
if (import_node_path6.default.dirname(dirPath) !== absolutePath) {
|
|
8927
10366
|
continue;
|
|
8928
10367
|
}
|
|
8929
|
-
const name =
|
|
10368
|
+
const name = import_node_path6.default.basename(dirPath);
|
|
8930
10369
|
if (seenNames.has(name)) {
|
|
8931
10370
|
continue;
|
|
8932
10371
|
}
|
|
@@ -8939,10 +10378,10 @@ var InMemoryAgentFilesystem = class {
|
|
|
8939
10378
|
});
|
|
8940
10379
|
}
|
|
8941
10380
|
for (const [filePath, fileRecord] of this.#files.entries()) {
|
|
8942
|
-
if (
|
|
10381
|
+
if (import_node_path6.default.dirname(filePath) !== absolutePath) {
|
|
8943
10382
|
continue;
|
|
8944
10383
|
}
|
|
8945
|
-
const name =
|
|
10384
|
+
const name = import_node_path6.default.basename(filePath);
|
|
8946
10385
|
if (seenNames.has(name)) {
|
|
8947
10386
|
continue;
|
|
8948
10387
|
}
|
|
@@ -8958,7 +10397,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
8958
10397
|
return entries;
|
|
8959
10398
|
}
|
|
8960
10399
|
async stat(entryPath) {
|
|
8961
|
-
const absolutePath =
|
|
10400
|
+
const absolutePath = import_node_path6.default.resolve(entryPath);
|
|
8962
10401
|
const file = this.#files.get(absolutePath);
|
|
8963
10402
|
if (file) {
|
|
8964
10403
|
return { kind: "file", mtimeMs: file.mtimeMs };
|
|
@@ -8974,7 +10413,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
8974
10413
|
return Object.fromEntries(entries.map(([filePath, record]) => [filePath, record.content]));
|
|
8975
10414
|
}
|
|
8976
10415
|
#ensureDirSync(directoryPath) {
|
|
8977
|
-
const absolutePath =
|
|
10416
|
+
const absolutePath = import_node_path6.default.resolve(directoryPath);
|
|
8978
10417
|
const parts = [];
|
|
8979
10418
|
let cursor = absolutePath;
|
|
8980
10419
|
for (; ; ) {
|
|
@@ -8982,7 +10421,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
8982
10421
|
break;
|
|
8983
10422
|
}
|
|
8984
10423
|
parts.push(cursor);
|
|
8985
|
-
const parent =
|
|
10424
|
+
const parent = import_node_path6.default.dirname(cursor);
|
|
8986
10425
|
if (parent === cursor) {
|
|
8987
10426
|
break;
|
|
8988
10427
|
}
|
|
@@ -9005,19 +10444,19 @@ var InMemoryAgentFilesystem = class {
|
|
|
9005
10444
|
};
|
|
9006
10445
|
function createNodeAgentFilesystem() {
|
|
9007
10446
|
return {
|
|
9008
|
-
readTextFile: async (filePath) =>
|
|
9009
|
-
readBinaryFile: async (filePath) =>
|
|
9010
|
-
writeTextFile: async (filePath, content) =>
|
|
9011
|
-
deleteFile: async (filePath) =>
|
|
10447
|
+
readTextFile: async (filePath) => import_node_fs4.promises.readFile(filePath, "utf8"),
|
|
10448
|
+
readBinaryFile: async (filePath) => import_node_fs4.promises.readFile(filePath),
|
|
10449
|
+
writeTextFile: async (filePath, content) => import_node_fs4.promises.writeFile(filePath, content, "utf8"),
|
|
10450
|
+
deleteFile: async (filePath) => import_node_fs4.promises.unlink(filePath),
|
|
9012
10451
|
ensureDir: async (directoryPath) => {
|
|
9013
|
-
await
|
|
10452
|
+
await import_node_fs4.promises.mkdir(directoryPath, { recursive: true });
|
|
9014
10453
|
},
|
|
9015
10454
|
readDir: async (directoryPath) => {
|
|
9016
|
-
const entries = await
|
|
10455
|
+
const entries = await import_node_fs4.promises.readdir(directoryPath, { withFileTypes: true });
|
|
9017
10456
|
const result = [];
|
|
9018
10457
|
for (const entry of entries) {
|
|
9019
|
-
const entryPath =
|
|
9020
|
-
const stats = await
|
|
10458
|
+
const entryPath = import_node_path6.default.resolve(directoryPath, entry.name);
|
|
10459
|
+
const stats = await import_node_fs4.promises.lstat(entryPath);
|
|
9021
10460
|
result.push({
|
|
9022
10461
|
name: entry.name,
|
|
9023
10462
|
path: entryPath,
|
|
@@ -9028,7 +10467,7 @@ function createNodeAgentFilesystem() {
|
|
|
9028
10467
|
return result;
|
|
9029
10468
|
},
|
|
9030
10469
|
stat: async (entryPath) => {
|
|
9031
|
-
const stats = await
|
|
10470
|
+
const stats = await import_node_fs4.promises.lstat(entryPath);
|
|
9032
10471
|
return {
|
|
9033
10472
|
kind: statsToKind(stats),
|
|
9034
10473
|
mtimeMs: stats.mtimeMs
|
|
@@ -9180,7 +10619,7 @@ function createApplyPatchTool(options = {}) {
|
|
|
9180
10619
|
});
|
|
9181
10620
|
}
|
|
9182
10621
|
async function applyPatch(request) {
|
|
9183
|
-
const cwd =
|
|
10622
|
+
const cwd = import_node_path7.default.resolve(request.cwd ?? process.cwd());
|
|
9184
10623
|
const adapter = request.fs ?? createNodeAgentFilesystem();
|
|
9185
10624
|
const allowOutsideCwd = request.allowOutsideCwd === true;
|
|
9186
10625
|
const patchBytes = Buffer.byteLength(request.patch, "utf8");
|
|
@@ -9202,7 +10641,7 @@ async function applyPatch(request) {
|
|
|
9202
10641
|
kind: "add",
|
|
9203
10642
|
path: absolutePath2
|
|
9204
10643
|
});
|
|
9205
|
-
await adapter.ensureDir(
|
|
10644
|
+
await adapter.ensureDir(import_node_path7.default.dirname(absolutePath2));
|
|
9206
10645
|
await adapter.writeTextFile(absolutePath2, operation.content);
|
|
9207
10646
|
added.push(toDisplayPath(absolutePath2, cwd));
|
|
9208
10647
|
continue;
|
|
@@ -9236,7 +10675,7 @@ async function applyPatch(request) {
|
|
|
9236
10675
|
fromPath: absolutePath,
|
|
9237
10676
|
toPath: destinationPath
|
|
9238
10677
|
});
|
|
9239
|
-
await adapter.ensureDir(
|
|
10678
|
+
await adapter.ensureDir(import_node_path7.default.dirname(destinationPath));
|
|
9240
10679
|
await adapter.writeTextFile(destinationPath, next);
|
|
9241
10680
|
await adapter.deleteFile(absolutePath);
|
|
9242
10681
|
modified.push(toDisplayPath(destinationPath, cwd));
|
|
@@ -9267,22 +10706,22 @@ function resolvePatchPath(rawPath, cwd, allowOutsideCwd) {
|
|
|
9267
10706
|
if (trimmed.length === 0) {
|
|
9268
10707
|
throw new Error("apply_patch failed: empty file path");
|
|
9269
10708
|
}
|
|
9270
|
-
const absolutePath =
|
|
10709
|
+
const absolutePath = import_node_path7.default.isAbsolute(trimmed) ? import_node_path7.default.resolve(trimmed) : import_node_path7.default.resolve(cwd, trimmed);
|
|
9271
10710
|
if (!allowOutsideCwd && !isPathInsideCwd(absolutePath, cwd)) {
|
|
9272
10711
|
throw new Error(`apply_patch failed: path "${trimmed}" resolves outside cwd "${cwd}"`);
|
|
9273
10712
|
}
|
|
9274
10713
|
return absolutePath;
|
|
9275
10714
|
}
|
|
9276
10715
|
function isPathInsideCwd(candidatePath, cwd) {
|
|
9277
|
-
const relative =
|
|
9278
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
10716
|
+
const relative = import_node_path7.default.relative(cwd, candidatePath);
|
|
10717
|
+
return relative === "" || !relative.startsWith("..") && !import_node_path7.default.isAbsolute(relative);
|
|
9279
10718
|
}
|
|
9280
10719
|
function toDisplayPath(absolutePath, cwd) {
|
|
9281
|
-
const relative =
|
|
10720
|
+
const relative = import_node_path7.default.relative(cwd, absolutePath);
|
|
9282
10721
|
if (relative === "") {
|
|
9283
10722
|
return ".";
|
|
9284
10723
|
}
|
|
9285
|
-
if (!relative.startsWith("..") && !
|
|
10724
|
+
if (!relative.startsWith("..") && !import_node_path7.default.isAbsolute(relative)) {
|
|
9286
10725
|
return relative;
|
|
9287
10726
|
}
|
|
9288
10727
|
return absolutePath;
|
|
@@ -10049,7 +11488,7 @@ async function readBinaryFile(filesystem, filePath) {
|
|
|
10049
11488
|
return await filesystem.readBinaryFile(filePath);
|
|
10050
11489
|
}
|
|
10051
11490
|
const text = await filesystem.readTextFile(filePath);
|
|
10052
|
-
return
|
|
11491
|
+
return import_node_buffer5.Buffer.from(text, "utf8");
|
|
10053
11492
|
}
|
|
10054
11493
|
function detectImageMimeType(buffer, filePath) {
|
|
10055
11494
|
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) {
|
|
@@ -10067,7 +11506,7 @@ function detectImageMimeType(buffer, filePath) {
|
|
|
10067
11506
|
if (buffer.length >= 12 && buffer.subarray(0, 4).toString("ascii") === "RIFF" && buffer.subarray(8, 12).toString("ascii") === "WEBP") {
|
|
10068
11507
|
return "image/webp";
|
|
10069
11508
|
}
|
|
10070
|
-
const fromExtension = IMAGE_MIME_BY_EXTENSION[
|
|
11509
|
+
const fromExtension = IMAGE_MIME_BY_EXTENSION[import_node_path8.default.extname(filePath).toLowerCase()];
|
|
10071
11510
|
if (fromExtension && SUPPORTED_IMAGE_MIME_TYPES.has(fromExtension)) {
|
|
10072
11511
|
return fromExtension;
|
|
10073
11512
|
}
|
|
@@ -10077,13 +11516,13 @@ function isPdfFile(buffer, filePath) {
|
|
|
10077
11516
|
if (buffer.length >= 5 && buffer.subarray(0, 5).toString("ascii") === "%PDF-") {
|
|
10078
11517
|
return true;
|
|
10079
11518
|
}
|
|
10080
|
-
return
|
|
11519
|
+
return import_node_path8.default.extname(filePath).toLowerCase() === ".pdf";
|
|
10081
11520
|
}
|
|
10082
11521
|
function isValidUtf8(buffer) {
|
|
10083
11522
|
if (buffer.length === 0) {
|
|
10084
11523
|
return true;
|
|
10085
11524
|
}
|
|
10086
|
-
return
|
|
11525
|
+
return import_node_buffer5.Buffer.from(buffer.toString("utf8"), "utf8").equals(buffer);
|
|
10087
11526
|
}
|
|
10088
11527
|
async function readFileGemini(input, options) {
|
|
10089
11528
|
const runtime = resolveRuntime(options);
|
|
@@ -10115,7 +11554,7 @@ async function writeFileGemini(input, options) {
|
|
|
10115
11554
|
action: "write",
|
|
10116
11555
|
path: filePath
|
|
10117
11556
|
});
|
|
10118
|
-
await runtime.filesystem.ensureDir(
|
|
11557
|
+
await runtime.filesystem.ensureDir(import_node_path8.default.dirname(filePath));
|
|
10119
11558
|
await runtime.filesystem.writeTextFile(filePath, input.content);
|
|
10120
11559
|
return `Successfully wrote file: ${toDisplayPath2(filePath, runtime.cwd)}`;
|
|
10121
11560
|
}
|
|
@@ -10136,7 +11575,7 @@ async function replaceFileContentGemini(input, options) {
|
|
|
10136
11575
|
originalContent = await runtime.filesystem.readTextFile(filePath);
|
|
10137
11576
|
} catch (error) {
|
|
10138
11577
|
if (isNoEntError(error) && oldValue.length === 0) {
|
|
10139
|
-
await runtime.filesystem.ensureDir(
|
|
11578
|
+
await runtime.filesystem.ensureDir(import_node_path8.default.dirname(filePath));
|
|
10140
11579
|
await runtime.filesystem.writeTextFile(filePath, newValue);
|
|
10141
11580
|
return `Successfully wrote new file: ${toDisplayPath2(filePath, runtime.cwd)}`;
|
|
10142
11581
|
}
|
|
@@ -10306,15 +11745,15 @@ async function globFilesGemini(input, options) {
|
|
|
10306
11745
|
throw new Error(`Path is not a directory: ${dirPath}`);
|
|
10307
11746
|
}
|
|
10308
11747
|
const matcher = createGlobMatcher(input.pattern, input.case_sensitive === true);
|
|
10309
|
-
const
|
|
11748
|
+
const files2 = await collectSearchFiles({
|
|
10310
11749
|
filesystem: runtime.filesystem,
|
|
10311
11750
|
searchPath: dirPath,
|
|
10312
11751
|
rootKind: "directory",
|
|
10313
11752
|
maxScannedFiles: runtime.grepMaxScannedFiles
|
|
10314
11753
|
});
|
|
10315
11754
|
const matched = [];
|
|
10316
|
-
for (const filePath of
|
|
10317
|
-
const relativePath = normalizeSlashes(
|
|
11755
|
+
for (const filePath of files2) {
|
|
11756
|
+
const relativePath = normalizeSlashes(import_node_path8.default.relative(dirPath, filePath));
|
|
10318
11757
|
if (!matcher(relativePath)) {
|
|
10319
11758
|
continue;
|
|
10320
11759
|
}
|
|
@@ -10332,7 +11771,7 @@ async function globFilesGemini(input, options) {
|
|
|
10332
11771
|
}
|
|
10333
11772
|
function resolveRuntime(options) {
|
|
10334
11773
|
return {
|
|
10335
|
-
cwd:
|
|
11774
|
+
cwd: import_node_path8.default.resolve(options.cwd ?? process.cwd()),
|
|
10336
11775
|
filesystem: options.fs ?? createNodeAgentFilesystem(),
|
|
10337
11776
|
allowOutsideCwd: options.allowOutsideCwd === true,
|
|
10338
11777
|
checkAccess: options.checkAccess,
|
|
@@ -10363,13 +11802,13 @@ function mapApplyPatchAction(action) {
|
|
|
10363
11802
|
return "move";
|
|
10364
11803
|
}
|
|
10365
11804
|
function resolvePathWithPolicy(inputPath, cwd, allowOutsideCwd) {
|
|
10366
|
-
const absolutePath =
|
|
11805
|
+
const absolutePath = import_node_path8.default.isAbsolute(inputPath) ? import_node_path8.default.resolve(inputPath) : import_node_path8.default.resolve(cwd, inputPath);
|
|
10367
11806
|
if (allowOutsideCwd || isPathInsideCwd2(absolutePath, cwd)) {
|
|
10368
11807
|
return absolutePath;
|
|
10369
11808
|
}
|
|
10370
|
-
if (
|
|
11809
|
+
if (import_node_path8.default.isAbsolute(inputPath)) {
|
|
10371
11810
|
const sandboxRelativePath = inputPath.replace(/^[/\\]+/, "");
|
|
10372
|
-
const sandboxRootedPath =
|
|
11811
|
+
const sandboxRootedPath = import_node_path8.default.resolve(cwd, sandboxRelativePath);
|
|
10373
11812
|
if (isPathInsideCwd2(sandboxRootedPath, cwd)) {
|
|
10374
11813
|
return sandboxRootedPath;
|
|
10375
11814
|
}
|
|
@@ -10377,25 +11816,25 @@ function resolvePathWithPolicy(inputPath, cwd, allowOutsideCwd) {
|
|
|
10377
11816
|
throw new Error(`path "${inputPath}" resolves outside cwd "${cwd}"`);
|
|
10378
11817
|
}
|
|
10379
11818
|
function isPathInsideCwd2(candidatePath, cwd) {
|
|
10380
|
-
const relative =
|
|
10381
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
11819
|
+
const relative = import_node_path8.default.relative(cwd, candidatePath);
|
|
11820
|
+
return relative === "" || !relative.startsWith("..") && !import_node_path8.default.isAbsolute(relative);
|
|
10382
11821
|
}
|
|
10383
11822
|
function toDisplayPath2(absolutePath, cwd) {
|
|
10384
|
-
const relative =
|
|
11823
|
+
const relative = import_node_path8.default.relative(cwd, absolutePath);
|
|
10385
11824
|
if (relative === "") {
|
|
10386
11825
|
return ".";
|
|
10387
11826
|
}
|
|
10388
|
-
if (!relative.startsWith("..") && !
|
|
11827
|
+
if (!relative.startsWith("..") && !import_node_path8.default.isAbsolute(relative)) {
|
|
10389
11828
|
return relative;
|
|
10390
11829
|
}
|
|
10391
11830
|
return absolutePath;
|
|
10392
11831
|
}
|
|
10393
11832
|
function toSandboxDisplayPath(absolutePath, cwd) {
|
|
10394
|
-
const relative =
|
|
11833
|
+
const relative = import_node_path8.default.relative(cwd, absolutePath);
|
|
10395
11834
|
if (relative === "") {
|
|
10396
11835
|
return "/";
|
|
10397
11836
|
}
|
|
10398
|
-
if (!relative.startsWith("..") && !
|
|
11837
|
+
if (!relative.startsWith("..") && !import_node_path8.default.isAbsolute(relative)) {
|
|
10399
11838
|
return `/${normalizeSlashes(relative)}`;
|
|
10400
11839
|
}
|
|
10401
11840
|
return normalizeSlashes(absolutePath);
|
|
@@ -10471,7 +11910,7 @@ async function collectSearchFiles(params) {
|
|
|
10471
11910
|
return [searchPath];
|
|
10472
11911
|
}
|
|
10473
11912
|
const queue = [searchPath];
|
|
10474
|
-
const
|
|
11913
|
+
const files2 = [];
|
|
10475
11914
|
while (queue.length > 0) {
|
|
10476
11915
|
const current = queue.shift();
|
|
10477
11916
|
if (!current) {
|
|
@@ -10486,13 +11925,13 @@ async function collectSearchFiles(params) {
|
|
|
10486
11925
|
if (entry.kind !== "file") {
|
|
10487
11926
|
continue;
|
|
10488
11927
|
}
|
|
10489
|
-
|
|
10490
|
-
if (
|
|
10491
|
-
return
|
|
11928
|
+
files2.push(entry.path);
|
|
11929
|
+
if (files2.length >= maxScannedFiles) {
|
|
11930
|
+
return files2;
|
|
10492
11931
|
}
|
|
10493
11932
|
}
|
|
10494
11933
|
}
|
|
10495
|
-
return
|
|
11934
|
+
return files2;
|
|
10496
11935
|
}
|
|
10497
11936
|
function compileRegex(pattern, flags = "m") {
|
|
10498
11937
|
try {
|
|
@@ -10511,7 +11950,7 @@ function createGlobMatcher(pattern, caseSensitive = false) {
|
|
|
10511
11950
|
}));
|
|
10512
11951
|
return (candidatePath) => {
|
|
10513
11952
|
const normalizedPath = normalizeSlashes(candidatePath);
|
|
10514
|
-
const basename =
|
|
11953
|
+
const basename = import_node_path8.default.posix.basename(normalizedPath);
|
|
10515
11954
|
return compiled.some(
|
|
10516
11955
|
(entry) => entry.regex.test(entry.applyToBasename ? basename : normalizedPath)
|
|
10517
11956
|
);
|
|
@@ -10788,13 +12227,24 @@ async function runAgentLoopInternal(request, context) {
|
|
|
10788
12227
|
}
|
|
10789
12228
|
streamEventLogger?.appendEvent(event);
|
|
10790
12229
|
} : void 0;
|
|
12230
|
+
let uploadMetrics = emptyFileUploadMetrics();
|
|
10791
12231
|
try {
|
|
10792
|
-
|
|
10793
|
-
|
|
10794
|
-
|
|
10795
|
-
|
|
10796
|
-
|
|
12232
|
+
let result;
|
|
12233
|
+
await collectFileUploadMetrics(async () => {
|
|
12234
|
+
try {
|
|
12235
|
+
result = await runToolLoop({
|
|
12236
|
+
...toolLoopRequestWithSteering,
|
|
12237
|
+
...instructions ? { instructions } : {},
|
|
12238
|
+
...wrappedOnEvent ? { onEvent: wrappedOnEvent } : {},
|
|
12239
|
+
tools: mergedTools
|
|
12240
|
+
});
|
|
12241
|
+
} finally {
|
|
12242
|
+
uploadMetrics = getCurrentFileUploadMetrics();
|
|
12243
|
+
}
|
|
10797
12244
|
});
|
|
12245
|
+
if (!result) {
|
|
12246
|
+
throw new Error("runToolLoop returned no result.");
|
|
12247
|
+
}
|
|
10798
12248
|
streamEventLogger?.flush();
|
|
10799
12249
|
emitTelemetry({
|
|
10800
12250
|
type: "agent.run.completed",
|
|
@@ -10803,7 +12253,10 @@ async function runAgentLoopInternal(request, context) {
|
|
|
10803
12253
|
stepCount: result.steps.length,
|
|
10804
12254
|
toolCallCount: countToolCalls(result),
|
|
10805
12255
|
totalCostUsd: result.totalCostUsd,
|
|
10806
|
-
usage: summarizeResultUsage(result)
|
|
12256
|
+
usage: summarizeResultUsage(result),
|
|
12257
|
+
uploadCount: uploadMetrics.count,
|
|
12258
|
+
uploadBytes: uploadMetrics.totalBytes,
|
|
12259
|
+
uploadLatencyMs: uploadMetrics.totalLatencyMs
|
|
10807
12260
|
});
|
|
10808
12261
|
loggingSession?.logLine(
|
|
10809
12262
|
[
|
|
@@ -10812,7 +12265,10 @@ async function runAgentLoopInternal(request, context) {
|
|
|
10812
12265
|
`durationMs=${Math.max(0, Date.now() - startedAtMs).toString()}`,
|
|
10813
12266
|
`steps=${result.steps.length.toString()}`,
|
|
10814
12267
|
`toolCalls=${countToolCalls(result).toString()}`,
|
|
10815
|
-
`totalCostUsd=${(result.totalCostUsd ?? 0).toFixed(6)}
|
|
12268
|
+
`totalCostUsd=${(result.totalCostUsd ?? 0).toFixed(6)}`,
|
|
12269
|
+
`uploadCount=${uploadMetrics.count.toString()}`,
|
|
12270
|
+
`uploadBytes=${uploadMetrics.totalBytes.toString()}`,
|
|
12271
|
+
`uploadLatencyMs=${uploadMetrics.totalLatencyMs.toString()}`
|
|
10816
12272
|
].join(" ")
|
|
10817
12273
|
);
|
|
10818
12274
|
for (const step of result.steps) {
|
|
@@ -10833,6 +12289,9 @@ async function runAgentLoopInternal(request, context) {
|
|
|
10833
12289
|
type: "agent.run.completed",
|
|
10834
12290
|
success: false,
|
|
10835
12291
|
durationMs: Math.max(0, Date.now() - startedAtMs),
|
|
12292
|
+
uploadCount: uploadMetrics.count,
|
|
12293
|
+
uploadBytes: uploadMetrics.totalBytes,
|
|
12294
|
+
uploadLatencyMs: uploadMetrics.totalLatencyMs,
|
|
10836
12295
|
error: toErrorMessage3(error)
|
|
10837
12296
|
});
|
|
10838
12297
|
loggingSession?.logLine(
|
|
@@ -10840,6 +12299,9 @@ async function runAgentLoopInternal(request, context) {
|
|
|
10840
12299
|
`[agent:${runId}] run_completed`,
|
|
10841
12300
|
`status=error`,
|
|
10842
12301
|
`durationMs=${Math.max(0, Date.now() - startedAtMs).toString()}`,
|
|
12302
|
+
`uploadCount=${uploadMetrics.count.toString()}`,
|
|
12303
|
+
`uploadBytes=${uploadMetrics.totalBytes.toString()}`,
|
|
12304
|
+
`uploadLatencyMs=${uploadMetrics.totalLatencyMs.toString()}`,
|
|
10843
12305
|
`error=${toErrorMessage3(error)}`
|
|
10844
12306
|
].join(" ")
|
|
10845
12307
|
);
|
|
@@ -10977,7 +12439,7 @@ function trimToUndefined2(value) {
|
|
|
10977
12439
|
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
10978
12440
|
}
|
|
10979
12441
|
function randomRunId() {
|
|
10980
|
-
return (0,
|
|
12442
|
+
return (0, import_node_crypto4.randomBytes)(8).toString("hex");
|
|
10981
12443
|
}
|
|
10982
12444
|
function toIsoNow2() {
|
|
10983
12445
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -11046,7 +12508,7 @@ function resolveWorkspaceDirForLogging(request) {
|
|
|
11046
12508
|
if (explicitSelection && typeof explicitSelection === "object" && !Array.isArray(explicitSelection)) {
|
|
11047
12509
|
const cwd = explicitSelection.options?.cwd;
|
|
11048
12510
|
if (typeof cwd === "string" && cwd.trim().length > 0) {
|
|
11049
|
-
return
|
|
12511
|
+
return import_node_path9.default.resolve(cwd);
|
|
11050
12512
|
}
|
|
11051
12513
|
}
|
|
11052
12514
|
return process.cwd();
|
|
@@ -11056,7 +12518,7 @@ function createRootAgentLoggingSession(request) {
|
|
|
11056
12518
|
if (!selected) {
|
|
11057
12519
|
return void 0;
|
|
11058
12520
|
}
|
|
11059
|
-
const workspaceDir = typeof selected.workspaceDir === "string" && selected.workspaceDir.trim().length > 0 ?
|
|
12521
|
+
const workspaceDir = typeof selected.workspaceDir === "string" && selected.workspaceDir.trim().length > 0 ? import_node_path9.default.resolve(selected.workspaceDir) : resolveWorkspaceDirForLogging(request);
|
|
11060
12522
|
return createAgentLoggingSession({
|
|
11061
12523
|
...selected,
|
|
11062
12524
|
workspaceDir,
|
|
@@ -11134,7 +12596,7 @@ function createAgentTelemetryEmitter(params) {
|
|
|
11134
12596
|
}
|
|
11135
12597
|
|
|
11136
12598
|
// src/agent/candidateEvolution.ts
|
|
11137
|
-
var
|
|
12599
|
+
var import_node_crypto5 = require("crypto");
|
|
11138
12600
|
var DEFAULT_BATCH_SIZE = 1;
|
|
11139
12601
|
var DEFAULT_GENERATION_CONCURRENCY = 8;
|
|
11140
12602
|
var DEFAULT_ASSESSMENT_CONCURRENCY = 8;
|
|
@@ -11166,7 +12628,7 @@ function addStats(left, right) {
|
|
|
11166
12628
|
};
|
|
11167
12629
|
}
|
|
11168
12630
|
function randomId(prefix) {
|
|
11169
|
-
return `${prefix}_${(0,
|
|
12631
|
+
return `${prefix}_${(0, import_node_crypto5.randomBytes)(8).toString("hex")}`;
|
|
11170
12632
|
}
|
|
11171
12633
|
function toFiniteNumber(value, fallback) {
|
|
11172
12634
|
if (!Number.isFinite(value)) {
|
|
@@ -11791,6 +13253,7 @@ async function runCandidateEvolution(options) {
|
|
|
11791
13253
|
CODEX_APPLY_PATCH_FREEFORM_TOOL_DESCRIPTION,
|
|
11792
13254
|
CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION,
|
|
11793
13255
|
CODEX_APPLY_PATCH_LARK_GRAMMAR,
|
|
13256
|
+
DEFAULT_FILE_TTL_SECONDS,
|
|
11794
13257
|
FIREWORKS_DEFAULT_GLM_MODEL,
|
|
11795
13258
|
FIREWORKS_DEFAULT_GPT_OSS_120B_MODEL,
|
|
11796
13259
|
FIREWORKS_DEFAULT_KIMI_MODEL,
|
|
@@ -11831,10 +13294,12 @@ async function runCandidateEvolution(options) {
|
|
|
11831
13294
|
createViewImageTool,
|
|
11832
13295
|
createWriteFileTool,
|
|
11833
13296
|
customTool,
|
|
13297
|
+
emptyFileUploadMetrics,
|
|
11834
13298
|
encodeChatGptAuthJson,
|
|
11835
13299
|
encodeChatGptAuthJsonB64,
|
|
11836
13300
|
estimateCallCostUsd,
|
|
11837
13301
|
exchangeChatGptOauthCode,
|
|
13302
|
+
files,
|
|
11838
13303
|
generateImageInBatches,
|
|
11839
13304
|
generateImages,
|
|
11840
13305
|
generateJson,
|