@ljoukov/llm 4.0.12 → 4.1.1
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 +2105 -540
- 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 +2082 -520
- 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);
|
|
@@ -2658,7 +2674,7 @@ function getOpenAiFetch() {
|
|
|
2658
2674
|
headersTimeout: timeoutMs
|
|
2659
2675
|
});
|
|
2660
2676
|
openAiClientState.cachedFetch = ((input, init) => {
|
|
2661
|
-
return
|
|
2677
|
+
return fetch(input, {
|
|
2662
2678
|
...init ?? {},
|
|
2663
2679
|
dispatcher
|
|
2664
2680
|
});
|
|
@@ -3350,14 +3366,816 @@ 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 FILES_CACHE_ROOT = import_node_path4.default.join(FILES_TEMP_ROOT, "cache");
|
|
3388
|
+
var FILES_CACHE_CONTENT_ROOT = import_node_path4.default.join(FILES_CACHE_ROOT, "content");
|
|
3389
|
+
var FILES_CACHE_METADATA_ROOT = import_node_path4.default.join(FILES_CACHE_ROOT, "metadata");
|
|
3390
|
+
var filesState = getRuntimeSingleton(/* @__PURE__ */ Symbol.for("@ljoukov/llm.filesState"), () => ({
|
|
3391
|
+
metadataById: /* @__PURE__ */ new Map(),
|
|
3392
|
+
openAiUploadCacheByKey: /* @__PURE__ */ new Map(),
|
|
3393
|
+
materializedById: /* @__PURE__ */ new Map(),
|
|
3394
|
+
geminiMirrorById: /* @__PURE__ */ new Map(),
|
|
3395
|
+
vertexMirrorById: /* @__PURE__ */ new Map(),
|
|
3396
|
+
storageClient: void 0,
|
|
3397
|
+
geminiClientPromise: void 0
|
|
3398
|
+
}));
|
|
3399
|
+
var fileUploadScopeStorage = getRuntimeSingleton(
|
|
3400
|
+
/* @__PURE__ */ Symbol.for("@ljoukov/llm.fileUploadScopeStorage"),
|
|
3401
|
+
() => new import_node_async_hooks2.AsyncLocalStorage()
|
|
3402
|
+
);
|
|
3403
|
+
function summarizeUploadEvents(events) {
|
|
3404
|
+
let totalBytes = 0;
|
|
3405
|
+
let totalLatencyMs = 0;
|
|
3406
|
+
for (const event of events) {
|
|
3407
|
+
totalBytes += Math.max(0, event.bytes);
|
|
3408
|
+
totalLatencyMs += Math.max(0, event.durationMs);
|
|
3409
|
+
}
|
|
3410
|
+
return {
|
|
3411
|
+
count: events.length,
|
|
3412
|
+
totalBytes,
|
|
3413
|
+
totalLatencyMs,
|
|
3414
|
+
events: Array.from(events)
|
|
3415
|
+
};
|
|
3416
|
+
}
|
|
3417
|
+
function emptyFileUploadMetrics() {
|
|
3418
|
+
return summarizeUploadEvents([]);
|
|
3419
|
+
}
|
|
3420
|
+
function getCurrentFileUploadMetrics() {
|
|
3421
|
+
const collector = fileUploadScopeStorage.getStore()?.collectors.at(-1);
|
|
3422
|
+
return summarizeUploadEvents(collector?.events ?? []);
|
|
3423
|
+
}
|
|
3424
|
+
async function collectFileUploadMetrics(fn) {
|
|
3425
|
+
const parent = fileUploadScopeStorage.getStore();
|
|
3426
|
+
const collector = { events: [] };
|
|
3427
|
+
const scope = {
|
|
3428
|
+
collectors: [...parent?.collectors ?? [], collector],
|
|
3429
|
+
source: parent?.source
|
|
3430
|
+
};
|
|
3431
|
+
return await fileUploadScopeStorage.run(scope, async () => {
|
|
3432
|
+
const result = await fn();
|
|
3433
|
+
return {
|
|
3434
|
+
result,
|
|
3435
|
+
uploads: summarizeUploadEvents(collector.events)
|
|
3436
|
+
};
|
|
3437
|
+
});
|
|
3438
|
+
}
|
|
3439
|
+
async function runWithFileUploadSource(source, fn) {
|
|
3440
|
+
const parent = fileUploadScopeStorage.getStore();
|
|
3441
|
+
const scope = {
|
|
3442
|
+
collectors: parent?.collectors ?? [],
|
|
3443
|
+
source
|
|
3444
|
+
};
|
|
3445
|
+
return await fileUploadScopeStorage.run(scope, fn);
|
|
3446
|
+
}
|
|
3447
|
+
function formatUploadLogLine(event) {
|
|
3448
|
+
const parts = [
|
|
3449
|
+
"[upload]",
|
|
3450
|
+
`source=${event.source}`,
|
|
3451
|
+
`backend=${event.backend}`,
|
|
3452
|
+
`mode=${event.mode}`,
|
|
3453
|
+
`filename=${JSON.stringify(event.filename)}`,
|
|
3454
|
+
`bytes=${event.bytes.toString()}`,
|
|
3455
|
+
`durationMs=${event.durationMs.toString()}`
|
|
3456
|
+
];
|
|
3457
|
+
if (event.mimeType) {
|
|
3458
|
+
parts.push(`mimeType=${event.mimeType}`);
|
|
3459
|
+
}
|
|
3460
|
+
if (event.fileId) {
|
|
3461
|
+
parts.push(`fileId=${event.fileId}`);
|
|
3462
|
+
}
|
|
3463
|
+
if (event.mirrorId) {
|
|
3464
|
+
parts.push(`mirrorId=${event.mirrorId}`);
|
|
3465
|
+
}
|
|
3466
|
+
if (event.fileUri) {
|
|
3467
|
+
parts.push(`fileUri=${JSON.stringify(event.fileUri)}`);
|
|
3468
|
+
}
|
|
3469
|
+
return parts.join(" ");
|
|
3470
|
+
}
|
|
3471
|
+
function recordUploadEvent(event) {
|
|
3472
|
+
const scope = fileUploadScopeStorage.getStore();
|
|
3473
|
+
const resolvedSource = event.source ?? scope?.source ?? (event.backend === "openai" ? "files_api" : "provider_mirror");
|
|
3474
|
+
const timestampedEvent = {
|
|
3475
|
+
...event,
|
|
3476
|
+
source: resolvedSource,
|
|
3477
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3478
|
+
};
|
|
3479
|
+
for (const collector of scope?.collectors ?? []) {
|
|
3480
|
+
collector.events.push(timestampedEvent);
|
|
3481
|
+
}
|
|
3482
|
+
getCurrentAgentLoggingSession()?.logLine(formatUploadLogLine(timestampedEvent));
|
|
3483
|
+
}
|
|
3484
|
+
function normaliseFilename(filename, fallback = "attachment.bin") {
|
|
3485
|
+
const trimmed = filename?.trim();
|
|
3486
|
+
if (!trimmed) {
|
|
3487
|
+
return fallback;
|
|
3488
|
+
}
|
|
3489
|
+
const basename = import_node_path4.default.basename(trimmed);
|
|
3490
|
+
return basename.length > 0 ? basename : fallback;
|
|
3491
|
+
}
|
|
3492
|
+
function resolveMimeType(filename, explicitMimeType, fallback = "application/octet-stream") {
|
|
3493
|
+
const trimmed = explicitMimeType?.trim();
|
|
3494
|
+
if (trimmed) {
|
|
3495
|
+
return trimmed;
|
|
3496
|
+
}
|
|
3497
|
+
const inferred = import_mime.default.getType(filename);
|
|
3498
|
+
return typeof inferred === "string" && inferred.length > 0 ? inferred : fallback;
|
|
3499
|
+
}
|
|
3500
|
+
function toBuffer(data) {
|
|
3501
|
+
if (typeof data === "string") {
|
|
3502
|
+
return import_node_buffer3.Buffer.from(data, "utf8");
|
|
3503
|
+
}
|
|
3504
|
+
if (ArrayBuffer.isView(data)) {
|
|
3505
|
+
return import_node_buffer3.Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
|
3506
|
+
}
|
|
3507
|
+
return import_node_buffer3.Buffer.from(data);
|
|
3508
|
+
}
|
|
3509
|
+
function computeSha256Hex(buffer) {
|
|
3510
|
+
return (0, import_node_crypto.createHash)("sha256").update(buffer).digest("hex");
|
|
3511
|
+
}
|
|
3512
|
+
async function computeFileSha256Hex(filePath) {
|
|
3513
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
3514
|
+
const stream = (0, import_node_fs3.createReadStream)(filePath);
|
|
3515
|
+
for await (const chunk of stream) {
|
|
3516
|
+
hash.update(chunk);
|
|
3517
|
+
}
|
|
3518
|
+
return hash.digest("hex");
|
|
3519
|
+
}
|
|
3520
|
+
function toStoredFile(file) {
|
|
3521
|
+
return {
|
|
3522
|
+
id: file.id,
|
|
3523
|
+
bytes: file.bytes,
|
|
3524
|
+
created_at: file.created_at,
|
|
3525
|
+
filename: file.filename,
|
|
3526
|
+
object: "file",
|
|
3527
|
+
purpose: file.purpose,
|
|
3528
|
+
status: file.status,
|
|
3529
|
+
expires_at: file.expires_at
|
|
3530
|
+
};
|
|
3531
|
+
}
|
|
3532
|
+
function buildCacheKey(filename, mimeType, sha256Hex) {
|
|
3533
|
+
return `${sha256Hex}\0${filename}\0${mimeType}`;
|
|
3534
|
+
}
|
|
3535
|
+
function buildCachedContentPath(sha256Hex) {
|
|
3536
|
+
return import_node_path4.default.join(FILES_CACHE_CONTENT_ROOT, sha256Hex);
|
|
3537
|
+
}
|
|
3538
|
+
function buildCachedMetadataPath(fileId) {
|
|
3539
|
+
return import_node_path4.default.join(FILES_CACHE_METADATA_ROOT, `${fileId}.json`);
|
|
3540
|
+
}
|
|
3541
|
+
function isFresh(file) {
|
|
3542
|
+
if (!file.expires_at) {
|
|
3543
|
+
return true;
|
|
3544
|
+
}
|
|
3545
|
+
return file.expires_at * 1e3 > Date.now() + 3e4;
|
|
3546
|
+
}
|
|
3547
|
+
function recordMetadata(metadata) {
|
|
3548
|
+
filesState.metadataById.set(metadata.file.id, metadata);
|
|
3549
|
+
if (metadata.sha256Hex) {
|
|
3550
|
+
filesState.openAiUploadCacheByKey.set(
|
|
3551
|
+
buildCacheKey(
|
|
3552
|
+
metadata.filename,
|
|
3553
|
+
metadata.mimeType ?? "application/octet-stream",
|
|
3554
|
+
metadata.sha256Hex
|
|
3555
|
+
),
|
|
3556
|
+
metadata
|
|
3557
|
+
);
|
|
3558
|
+
}
|
|
3559
|
+
return metadata;
|
|
3560
|
+
}
|
|
3561
|
+
async function ensureFilesCacheReady() {
|
|
3562
|
+
await (0, import_promises2.mkdir)(FILES_CACHE_CONTENT_ROOT, { recursive: true });
|
|
3563
|
+
await (0, import_promises2.mkdir)(FILES_CACHE_METADATA_ROOT, { recursive: true });
|
|
3564
|
+
}
|
|
3565
|
+
async function cacheBufferLocally(bytes, sha256Hex) {
|
|
3566
|
+
await ensureFilesCacheReady();
|
|
3567
|
+
const localPath = buildCachedContentPath(sha256Hex);
|
|
3568
|
+
try {
|
|
3569
|
+
await (0, import_promises2.writeFile)(localPath, bytes, { flag: "wx" });
|
|
3570
|
+
} catch (error) {
|
|
3571
|
+
const code = error.code;
|
|
3572
|
+
if (code !== "EEXIST") {
|
|
3573
|
+
throw error;
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
return localPath;
|
|
3577
|
+
}
|
|
3578
|
+
async function cacheFileLocally(filePath, sha256Hex) {
|
|
3579
|
+
await ensureFilesCacheReady();
|
|
3580
|
+
const localPath = buildCachedContentPath(sha256Hex);
|
|
3581
|
+
try {
|
|
3582
|
+
await (0, import_promises2.copyFile)(filePath, localPath);
|
|
3583
|
+
} catch (error) {
|
|
3584
|
+
const code = error.code;
|
|
3585
|
+
if (code !== "EEXIST") {
|
|
3586
|
+
throw error;
|
|
3587
|
+
}
|
|
3588
|
+
}
|
|
3589
|
+
return localPath;
|
|
3590
|
+
}
|
|
3591
|
+
async function persistMetadataToDisk(metadata) {
|
|
3592
|
+
await ensureFilesCacheReady();
|
|
3593
|
+
const payload = {
|
|
3594
|
+
file: metadata.file,
|
|
3595
|
+
filename: metadata.filename,
|
|
3596
|
+
bytes: metadata.bytes,
|
|
3597
|
+
mimeType: metadata.mimeType,
|
|
3598
|
+
sha256Hex: metadata.sha256Hex,
|
|
3599
|
+
localPath: metadata.localPath
|
|
3600
|
+
};
|
|
3601
|
+
await (0, import_promises2.writeFile)(
|
|
3602
|
+
buildCachedMetadataPath(metadata.file.id),
|
|
3603
|
+
`${JSON.stringify(payload, null, 2)}
|
|
3604
|
+
`
|
|
3605
|
+
);
|
|
3606
|
+
}
|
|
3607
|
+
async function loadPersistedMetadata(fileId) {
|
|
3608
|
+
try {
|
|
3609
|
+
const payload = JSON.parse(
|
|
3610
|
+
await (0, import_promises2.readFile)(buildCachedMetadataPath(fileId), "utf8")
|
|
3611
|
+
);
|
|
3612
|
+
if (!payload || typeof payload !== "object" || !payload.file) {
|
|
3613
|
+
return void 0;
|
|
3614
|
+
}
|
|
3615
|
+
if (payload.localPath) {
|
|
3616
|
+
try {
|
|
3617
|
+
const localStats = await (0, import_promises2.stat)(payload.localPath);
|
|
3618
|
+
if (!localStats.isFile()) {
|
|
3619
|
+
return void 0;
|
|
3620
|
+
}
|
|
3621
|
+
} catch {
|
|
3622
|
+
return void 0;
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
return recordMetadata({
|
|
3626
|
+
file: payload.file,
|
|
3627
|
+
filename: payload.filename,
|
|
3628
|
+
bytes: payload.bytes,
|
|
3629
|
+
mimeType: payload.mimeType,
|
|
3630
|
+
sha256Hex: payload.sha256Hex,
|
|
3631
|
+
localPath: payload.localPath
|
|
3632
|
+
});
|
|
3633
|
+
} catch {
|
|
3634
|
+
return void 0;
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
async function uploadOpenAiFileFromBytes(params) {
|
|
3638
|
+
const cacheKey = buildCacheKey(params.filename, params.mimeType, params.sha256Hex);
|
|
3639
|
+
const cached = filesState.openAiUploadCacheByKey.get(cacheKey);
|
|
3640
|
+
if (cached && isFresh(cached.file)) {
|
|
3641
|
+
return cached;
|
|
3642
|
+
}
|
|
3643
|
+
const client = getOpenAiClient();
|
|
3644
|
+
const startedAtMs = Date.now();
|
|
3645
|
+
let uploaded;
|
|
3646
|
+
let mode;
|
|
3647
|
+
if (params.bytes.byteLength <= OPENAI_FILE_CREATE_MAX_BYTES) {
|
|
3648
|
+
mode = "files.create";
|
|
3649
|
+
uploaded = await client.files.create({
|
|
3650
|
+
file: new import_node_buffer3.File([new Uint8Array(params.bytes)], params.filename, {
|
|
3651
|
+
type: params.mimeType
|
|
3652
|
+
}),
|
|
3653
|
+
purpose: params.purpose,
|
|
3654
|
+
expires_after: {
|
|
3655
|
+
anchor: "created_at",
|
|
3656
|
+
seconds: params.expiresAfterSeconds
|
|
3657
|
+
}
|
|
3658
|
+
});
|
|
3659
|
+
} else {
|
|
3660
|
+
mode = "uploads";
|
|
3661
|
+
const upload = await client.uploads.create({
|
|
3662
|
+
bytes: params.bytes.byteLength,
|
|
3663
|
+
filename: params.filename,
|
|
3664
|
+
mime_type: params.mimeType,
|
|
3665
|
+
purpose: params.purpose
|
|
3666
|
+
});
|
|
3667
|
+
const partIds = [];
|
|
3668
|
+
for (let offset = 0; offset < params.bytes.byteLength; offset += OPENAI_UPLOAD_PART_MAX_BYTES) {
|
|
3669
|
+
const chunk = params.bytes.subarray(
|
|
3670
|
+
offset,
|
|
3671
|
+
Math.min(offset + OPENAI_UPLOAD_PART_MAX_BYTES, params.bytes.byteLength)
|
|
3672
|
+
);
|
|
3673
|
+
const uploadPart = await client.uploads.parts.create(upload.id, {
|
|
3674
|
+
data: new import_node_buffer3.File([new Uint8Array(chunk)], `${params.sha256Hex}.part`, {
|
|
3675
|
+
type: params.mimeType
|
|
3676
|
+
})
|
|
3677
|
+
});
|
|
3678
|
+
partIds.push(uploadPart.id);
|
|
3679
|
+
}
|
|
3680
|
+
const completed = await client.uploads.complete(upload.id, { part_ids: partIds });
|
|
3681
|
+
const fileId = completed.file?.id;
|
|
3682
|
+
if (!fileId) {
|
|
3683
|
+
throw new Error("OpenAI upload completed without a file id.");
|
|
3684
|
+
}
|
|
3685
|
+
uploaded = await client.files.retrieve(fileId);
|
|
3686
|
+
}
|
|
3687
|
+
const file = toStoredFile(uploaded);
|
|
3688
|
+
const metadata = recordMetadata({
|
|
3689
|
+
file,
|
|
3690
|
+
filename: file.filename,
|
|
3691
|
+
bytes: file.bytes,
|
|
3692
|
+
mimeType: params.mimeType,
|
|
3693
|
+
sha256Hex: params.sha256Hex
|
|
3694
|
+
});
|
|
3695
|
+
recordUploadEvent({
|
|
3696
|
+
backend: "openai",
|
|
3697
|
+
mode,
|
|
3698
|
+
filename: metadata.filename,
|
|
3699
|
+
bytes: metadata.bytes,
|
|
3700
|
+
durationMs: Math.max(0, Date.now() - startedAtMs),
|
|
3701
|
+
mimeType: params.mimeType,
|
|
3702
|
+
fileId: metadata.file.id
|
|
3703
|
+
});
|
|
3704
|
+
return metadata;
|
|
3705
|
+
}
|
|
3706
|
+
async function uploadOpenAiFileFromPath(params) {
|
|
3707
|
+
const cacheKey = buildCacheKey(params.filename, params.mimeType, params.sha256Hex);
|
|
3708
|
+
const cached = filesState.openAiUploadCacheByKey.get(cacheKey);
|
|
3709
|
+
if (cached && isFresh(cached.file)) {
|
|
3710
|
+
return cached;
|
|
3711
|
+
}
|
|
3712
|
+
const client = getOpenAiClient();
|
|
3713
|
+
const startedAtMs = Date.now();
|
|
3714
|
+
let uploaded;
|
|
3715
|
+
let mode;
|
|
3716
|
+
if (params.bytes <= OPENAI_FILE_CREATE_MAX_BYTES) {
|
|
3717
|
+
mode = "files.create";
|
|
3718
|
+
const blob = await (0, import_node_fs3.openAsBlob)(params.filePath, { type: params.mimeType });
|
|
3719
|
+
uploaded = await client.files.create({
|
|
3720
|
+
file: new import_node_buffer3.File([blob], params.filename, { type: params.mimeType }),
|
|
3721
|
+
purpose: params.purpose,
|
|
3722
|
+
expires_after: {
|
|
3723
|
+
anchor: "created_at",
|
|
3724
|
+
seconds: params.expiresAfterSeconds
|
|
3725
|
+
}
|
|
3726
|
+
});
|
|
3727
|
+
} else {
|
|
3728
|
+
mode = "uploads";
|
|
3729
|
+
const upload = await client.uploads.create({
|
|
3730
|
+
bytes: params.bytes,
|
|
3731
|
+
filename: params.filename,
|
|
3732
|
+
mime_type: params.mimeType,
|
|
3733
|
+
purpose: params.purpose
|
|
3734
|
+
});
|
|
3735
|
+
const partIds = [];
|
|
3736
|
+
const stream = (0, import_node_fs3.createReadStream)(params.filePath, {
|
|
3737
|
+
highWaterMark: OPENAI_UPLOAD_PART_MAX_BYTES
|
|
3738
|
+
});
|
|
3739
|
+
let partIndex = 0;
|
|
3740
|
+
for await (const chunk of stream) {
|
|
3741
|
+
const buffer = import_node_buffer3.Buffer.isBuffer(chunk) ? chunk : import_node_buffer3.Buffer.from(chunk);
|
|
3742
|
+
const uploadPart = await client.uploads.parts.create(upload.id, {
|
|
3743
|
+
data: new import_node_buffer3.File(
|
|
3744
|
+
[new Uint8Array(buffer)],
|
|
3745
|
+
`${params.sha256Hex}.${partIndex.toString()}.part`,
|
|
3746
|
+
{
|
|
3747
|
+
type: params.mimeType
|
|
3748
|
+
}
|
|
3749
|
+
)
|
|
3750
|
+
});
|
|
3751
|
+
partIds.push(uploadPart.id);
|
|
3752
|
+
partIndex += 1;
|
|
3753
|
+
}
|
|
3754
|
+
const completed = await client.uploads.complete(upload.id, { part_ids: partIds });
|
|
3755
|
+
const fileId = completed.file?.id;
|
|
3756
|
+
if (!fileId) {
|
|
3757
|
+
throw new Error("OpenAI upload completed without a file id.");
|
|
3758
|
+
}
|
|
3759
|
+
uploaded = await client.files.retrieve(fileId);
|
|
3760
|
+
}
|
|
3761
|
+
const file = toStoredFile(uploaded);
|
|
3762
|
+
const metadata = recordMetadata({
|
|
3763
|
+
file,
|
|
3764
|
+
filename: file.filename,
|
|
3765
|
+
bytes: file.bytes,
|
|
3766
|
+
mimeType: params.mimeType,
|
|
3767
|
+
sha256Hex: params.sha256Hex
|
|
3768
|
+
});
|
|
3769
|
+
recordUploadEvent({
|
|
3770
|
+
backend: "openai",
|
|
3771
|
+
mode,
|
|
3772
|
+
filename: metadata.filename,
|
|
3773
|
+
bytes: metadata.bytes,
|
|
3774
|
+
durationMs: Math.max(0, Date.now() - startedAtMs),
|
|
3775
|
+
mimeType: params.mimeType,
|
|
3776
|
+
fileId: metadata.file.id
|
|
3777
|
+
});
|
|
3778
|
+
return metadata;
|
|
3779
|
+
}
|
|
3780
|
+
async function retrieveOpenAiFile(fileId) {
|
|
3781
|
+
const cached = filesState.metadataById.get(fileId);
|
|
3782
|
+
if (cached && isFresh(cached.file)) {
|
|
3783
|
+
return cached;
|
|
3784
|
+
}
|
|
3785
|
+
const persisted = await loadPersistedMetadata(fileId);
|
|
3786
|
+
if (persisted && isFresh(persisted.file)) {
|
|
3787
|
+
return persisted;
|
|
3788
|
+
}
|
|
3789
|
+
const client = getOpenAiClient();
|
|
3790
|
+
const retrieved = await client.files.retrieve(fileId);
|
|
3791
|
+
const file = toStoredFile(retrieved);
|
|
3792
|
+
const metadata = recordMetadata({
|
|
3793
|
+
file,
|
|
3794
|
+
filename: file.filename,
|
|
3795
|
+
bytes: file.bytes,
|
|
3796
|
+
mimeType: cached?.mimeType ?? persisted?.mimeType ?? resolveMimeType(file.filename, void 0),
|
|
3797
|
+
sha256Hex: cached?.sha256Hex ?? persisted?.sha256Hex,
|
|
3798
|
+
localPath: cached?.localPath ?? persisted?.localPath
|
|
3799
|
+
});
|
|
3800
|
+
await persistMetadataToDisk(metadata);
|
|
3801
|
+
return metadata;
|
|
3802
|
+
}
|
|
3803
|
+
function buildGeminiMirrorName(sha256Hex) {
|
|
3804
|
+
return `files/${sha256Hex.slice(0, 40)}`;
|
|
3805
|
+
}
|
|
3806
|
+
async function waitForGeminiFileActive(client, name) {
|
|
3807
|
+
const startedAt = Date.now();
|
|
3808
|
+
while (true) {
|
|
3809
|
+
const file = await client.files.get({ name });
|
|
3810
|
+
if (!file.state || file.state === "ACTIVE") {
|
|
3811
|
+
return;
|
|
3812
|
+
}
|
|
3813
|
+
if (file.state === "FAILED") {
|
|
3814
|
+
throw new Error(file.error?.message ?? `Gemini file ${name} failed processing.`);
|
|
3815
|
+
}
|
|
3816
|
+
if (Date.now() - startedAt >= GEMINI_FILE_POLL_TIMEOUT_MS) {
|
|
3817
|
+
throw new Error(`Timed out waiting for Gemini file ${name} to become active.`);
|
|
3818
|
+
}
|
|
3819
|
+
await new Promise((resolve) => setTimeout(resolve, GEMINI_FILE_POLL_INTERVAL_MS));
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
function resolveVertexMirrorBucket() {
|
|
3823
|
+
const raw = process.env.VERTEX_GCS_BUCKET ?? process.env.LLM_VERTEX_GCS_BUCKET;
|
|
3824
|
+
const trimmed = raw?.trim();
|
|
3825
|
+
if (!trimmed) {
|
|
3826
|
+
throw new Error(
|
|
3827
|
+
"VERTEX_GCS_BUCKET must be set to use OpenAI-backed file ids with Vertex Gemini models."
|
|
3828
|
+
);
|
|
3829
|
+
}
|
|
3830
|
+
return trimmed.replace(/^gs:\/\//u, "").replace(/\/+$/u, "");
|
|
3831
|
+
}
|
|
3832
|
+
function resolveVertexMirrorPrefix() {
|
|
3833
|
+
const raw = process.env.VERTEX_GCS_PREFIX ?? process.env.LLM_VERTEX_GCS_PREFIX;
|
|
3834
|
+
const trimmed = raw?.trim().replace(/^\/+/u, "").replace(/\/+$/u, "");
|
|
3835
|
+
return trimmed ? `${trimmed}/` : "";
|
|
3836
|
+
}
|
|
3837
|
+
function getStorageClient() {
|
|
3838
|
+
if (filesState.storageClient) {
|
|
3839
|
+
return filesState.storageClient;
|
|
3840
|
+
}
|
|
3841
|
+
const serviceAccount = getGoogleServiceAccount();
|
|
3842
|
+
filesState.storageClient = new import_storage.Storage({
|
|
3843
|
+
projectId: serviceAccount.projectId,
|
|
3844
|
+
credentials: {
|
|
3845
|
+
client_email: serviceAccount.clientEmail,
|
|
3846
|
+
private_key: serviceAccount.privateKey
|
|
3847
|
+
}
|
|
3848
|
+
});
|
|
3849
|
+
return filesState.storageClient;
|
|
3850
|
+
}
|
|
3851
|
+
function getGeminiMirrorClient() {
|
|
3852
|
+
if (!filesState.geminiClientPromise) {
|
|
3853
|
+
filesState.geminiClientPromise = getGeminiClient();
|
|
3854
|
+
}
|
|
3855
|
+
return filesState.geminiClientPromise;
|
|
3856
|
+
}
|
|
3857
|
+
async function materializeOpenAiFile(fileId) {
|
|
3858
|
+
const cachedPromise = filesState.materializedById.get(fileId);
|
|
3859
|
+
if (cachedPromise) {
|
|
3860
|
+
return await cachedPromise;
|
|
3861
|
+
}
|
|
3862
|
+
const promise = (async () => {
|
|
3863
|
+
const metadata = await retrieveOpenAiFile(fileId);
|
|
3864
|
+
if (metadata.localPath && metadata.sha256Hex && metadata.mimeType) {
|
|
3865
|
+
return {
|
|
3866
|
+
file: metadata.file,
|
|
3867
|
+
filename: metadata.filename,
|
|
3868
|
+
bytes: metadata.bytes,
|
|
3869
|
+
mimeType: metadata.mimeType,
|
|
3870
|
+
sha256Hex: metadata.sha256Hex,
|
|
3871
|
+
localPath: metadata.localPath
|
|
3872
|
+
};
|
|
3873
|
+
}
|
|
3874
|
+
await (0, import_promises2.mkdir)(FILES_TEMP_ROOT, { recursive: true });
|
|
3875
|
+
const tempDir = await (0, import_promises2.mkdtemp)(
|
|
3876
|
+
import_node_path4.default.join(FILES_TEMP_ROOT, `${fileId.replace(/[^a-z0-9_-]/giu, "")}-`)
|
|
3877
|
+
);
|
|
3878
|
+
const localPath = import_node_path4.default.join(tempDir, normaliseFilename(metadata.filename, `${fileId}.bin`));
|
|
3879
|
+
const response = await getOpenAiClient().files.content(fileId);
|
|
3880
|
+
if (!response.ok) {
|
|
3881
|
+
throw new Error(
|
|
3882
|
+
`Failed to download OpenAI file ${fileId}: ${response.status} ${response.statusText}`
|
|
3883
|
+
);
|
|
3884
|
+
}
|
|
3885
|
+
const responseMimeType = response.headers.get("content-type")?.trim() || void 0;
|
|
3886
|
+
const mimeType = resolveMimeType(metadata.filename, responseMimeType);
|
|
3887
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
3888
|
+
let bytes = 0;
|
|
3889
|
+
if (response.body) {
|
|
3890
|
+
const source = import_node_stream.Readable.fromWeb(response.body);
|
|
3891
|
+
const writable = (0, import_node_fs3.createWriteStream)(localPath, { flags: "wx" });
|
|
3892
|
+
source.on("data", (chunk) => {
|
|
3893
|
+
const buffer = import_node_buffer3.Buffer.isBuffer(chunk) ? chunk : import_node_buffer3.Buffer.from(chunk);
|
|
3894
|
+
hash.update(buffer);
|
|
3895
|
+
bytes += buffer.byteLength;
|
|
3896
|
+
});
|
|
3897
|
+
await (0, import_promises3.pipeline)(source, writable);
|
|
3898
|
+
} else {
|
|
3899
|
+
const buffer = import_node_buffer3.Buffer.from(await response.arrayBuffer());
|
|
3900
|
+
hash.update(buffer);
|
|
3901
|
+
bytes = buffer.byteLength;
|
|
3902
|
+
await (0, import_promises2.writeFile)(localPath, buffer);
|
|
3903
|
+
}
|
|
3904
|
+
const sha256Hex = hash.digest("hex");
|
|
3905
|
+
const updated = recordMetadata({
|
|
3906
|
+
file: metadata.file,
|
|
3907
|
+
filename: metadata.filename,
|
|
3908
|
+
bytes: bytes || metadata.bytes,
|
|
3909
|
+
mimeType,
|
|
3910
|
+
sha256Hex,
|
|
3911
|
+
localPath
|
|
3912
|
+
});
|
|
3913
|
+
await persistMetadataToDisk(updated);
|
|
3914
|
+
return {
|
|
3915
|
+
file: updated.file,
|
|
3916
|
+
filename: updated.filename,
|
|
3917
|
+
bytes: updated.bytes,
|
|
3918
|
+
mimeType: updated.mimeType ?? mimeType,
|
|
3919
|
+
sha256Hex,
|
|
3920
|
+
localPath
|
|
3921
|
+
};
|
|
3922
|
+
})();
|
|
3923
|
+
filesState.materializedById.set(fileId, promise);
|
|
3924
|
+
try {
|
|
3925
|
+
return await promise;
|
|
3926
|
+
} catch (error) {
|
|
3927
|
+
filesState.materializedById.delete(fileId);
|
|
3928
|
+
throw error;
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
async function ensureGeminiFileMirror(fileId) {
|
|
3932
|
+
const cached = filesState.geminiMirrorById.get(fileId);
|
|
3933
|
+
if (cached) {
|
|
3934
|
+
return cached;
|
|
3935
|
+
}
|
|
3936
|
+
const materialized = await materializeOpenAiFile(fileId);
|
|
3937
|
+
const client = await getGeminiMirrorClient();
|
|
3938
|
+
const name = buildGeminiMirrorName(materialized.sha256Hex);
|
|
3939
|
+
try {
|
|
3940
|
+
const existing = await client.files.get({ name });
|
|
3941
|
+
if (existing.name && existing.uri && existing.mimeType) {
|
|
3942
|
+
const mirror2 = {
|
|
3943
|
+
openAiFileId: fileId,
|
|
3944
|
+
name: existing.name,
|
|
3945
|
+
uri: existing.uri,
|
|
3946
|
+
mimeType: existing.mimeType,
|
|
3947
|
+
displayName: existing.displayName ?? materialized.filename
|
|
3948
|
+
};
|
|
3949
|
+
filesState.geminiMirrorById.set(fileId, mirror2);
|
|
3950
|
+
return mirror2;
|
|
3951
|
+
}
|
|
3952
|
+
} catch {
|
|
3953
|
+
}
|
|
3954
|
+
const startedAtMs = Date.now();
|
|
3955
|
+
const uploaded = await client.files.upload({
|
|
3956
|
+
file: materialized.localPath,
|
|
3957
|
+
config: {
|
|
3958
|
+
name,
|
|
3959
|
+
mimeType: materialized.mimeType,
|
|
3960
|
+
displayName: materialized.filename
|
|
3961
|
+
}
|
|
3962
|
+
});
|
|
3963
|
+
if (uploaded.name && uploaded.state && uploaded.state !== "ACTIVE") {
|
|
3964
|
+
await waitForGeminiFileActive(client, uploaded.name);
|
|
3965
|
+
}
|
|
3966
|
+
const resolved = await client.files.get({ name: uploaded.name ?? name });
|
|
3967
|
+
if (!resolved.name || !resolved.uri || !resolved.mimeType) {
|
|
3968
|
+
throw new Error("Gemini file upload completed without a usable URI.");
|
|
3969
|
+
}
|
|
3970
|
+
const mirror = {
|
|
3971
|
+
openAiFileId: fileId,
|
|
3972
|
+
name: resolved.name,
|
|
3973
|
+
uri: resolved.uri,
|
|
3974
|
+
mimeType: resolved.mimeType,
|
|
3975
|
+
displayName: resolved.displayName ?? materialized.filename
|
|
3976
|
+
};
|
|
3977
|
+
filesState.geminiMirrorById.set(fileId, mirror);
|
|
3978
|
+
recordUploadEvent({
|
|
3979
|
+
backend: "gemini",
|
|
3980
|
+
mode: "mirror",
|
|
3981
|
+
filename: materialized.filename,
|
|
3982
|
+
bytes: materialized.bytes,
|
|
3983
|
+
durationMs: Math.max(0, Date.now() - startedAtMs),
|
|
3984
|
+
mimeType: materialized.mimeType,
|
|
3985
|
+
fileId,
|
|
3986
|
+
mirrorId: mirror.name,
|
|
3987
|
+
fileUri: mirror.uri
|
|
3988
|
+
});
|
|
3989
|
+
return mirror;
|
|
3990
|
+
}
|
|
3991
|
+
async function ensureVertexFileMirror(fileId) {
|
|
3992
|
+
const cached = filesState.vertexMirrorById.get(fileId);
|
|
3993
|
+
if (cached) {
|
|
3994
|
+
return cached;
|
|
3995
|
+
}
|
|
3996
|
+
const materialized = await materializeOpenAiFile(fileId);
|
|
3997
|
+
const bucketName = resolveVertexMirrorBucket();
|
|
3998
|
+
const prefix = resolveVertexMirrorPrefix();
|
|
3999
|
+
const extension = import_mime.default.getExtension(materialized.mimeType) ?? import_node_path4.default.extname(materialized.filename).replace(/^\./u, "") ?? "bin";
|
|
4000
|
+
const objectName = `${prefix}${materialized.sha256Hex}.${extension}`;
|
|
4001
|
+
const file = getStorageClient().bucket(bucketName).file(objectName);
|
|
4002
|
+
let uploaded = false;
|
|
4003
|
+
const startedAtMs = Date.now();
|
|
4004
|
+
try {
|
|
4005
|
+
await file.getMetadata();
|
|
4006
|
+
} catch (error) {
|
|
4007
|
+
const code = error.code;
|
|
4008
|
+
if (code !== 404 && code !== "404") {
|
|
4009
|
+
throw error;
|
|
4010
|
+
}
|
|
4011
|
+
try {
|
|
4012
|
+
await (0, import_promises3.pipeline)(
|
|
4013
|
+
(0, import_node_fs3.createReadStream)(materialized.localPath),
|
|
4014
|
+
file.createWriteStream({
|
|
4015
|
+
resumable: materialized.bytes >= 10 * 1024 * 1024,
|
|
4016
|
+
preconditionOpts: { ifGenerationMatch: 0 },
|
|
4017
|
+
metadata: {
|
|
4018
|
+
contentType: materialized.mimeType,
|
|
4019
|
+
customTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4020
|
+
metadata: {
|
|
4021
|
+
filename: materialized.filename,
|
|
4022
|
+
sha256: materialized.sha256Hex,
|
|
4023
|
+
expiresAt: new Date(Date.now() + DEFAULT_FILE_TTL_SECONDS * 1e3).toISOString()
|
|
4024
|
+
}
|
|
4025
|
+
}
|
|
4026
|
+
})
|
|
4027
|
+
);
|
|
4028
|
+
uploaded = true;
|
|
4029
|
+
} catch (uploadError) {
|
|
4030
|
+
const uploadCode = uploadError.code;
|
|
4031
|
+
if (uploadCode !== 412 && uploadCode !== "412") {
|
|
4032
|
+
throw uploadError;
|
|
4033
|
+
}
|
|
4034
|
+
}
|
|
4035
|
+
}
|
|
4036
|
+
const mirror = {
|
|
4037
|
+
openAiFileId: fileId,
|
|
4038
|
+
bucket: bucketName,
|
|
4039
|
+
objectName,
|
|
4040
|
+
fileUri: `gs://${bucketName}/${objectName}`,
|
|
4041
|
+
mimeType: materialized.mimeType
|
|
4042
|
+
};
|
|
4043
|
+
filesState.vertexMirrorById.set(fileId, mirror);
|
|
4044
|
+
if (uploaded) {
|
|
4045
|
+
recordUploadEvent({
|
|
4046
|
+
backend: "vertex",
|
|
4047
|
+
mode: "mirror",
|
|
4048
|
+
filename: materialized.filename,
|
|
4049
|
+
bytes: materialized.bytes,
|
|
4050
|
+
durationMs: Math.max(0, Date.now() - startedAtMs),
|
|
4051
|
+
mimeType: materialized.mimeType,
|
|
4052
|
+
fileId,
|
|
4053
|
+
mirrorId: mirror.objectName,
|
|
4054
|
+
fileUri: mirror.fileUri
|
|
4055
|
+
});
|
|
4056
|
+
}
|
|
4057
|
+
return mirror;
|
|
4058
|
+
}
|
|
4059
|
+
async function filesCreate(params) {
|
|
4060
|
+
const purpose = params.purpose ?? "user_data";
|
|
4061
|
+
const expiresAfterSeconds = params.expiresAfterSeconds ?? DEFAULT_FILE_TTL_SECONDS;
|
|
4062
|
+
if ("path" in params) {
|
|
4063
|
+
const filePath = import_node_path4.default.resolve(params.path);
|
|
4064
|
+
const info = await (0, import_promises2.stat)(filePath);
|
|
4065
|
+
const filename2 = normaliseFilename(params.filename, import_node_path4.default.basename(filePath));
|
|
4066
|
+
const mimeType2 = resolveMimeType(filename2, params.mimeType);
|
|
4067
|
+
const sha256Hex2 = await computeFileSha256Hex(filePath);
|
|
4068
|
+
const uploaded2 = await uploadOpenAiFileFromPath({
|
|
4069
|
+
filePath,
|
|
4070
|
+
filename: filename2,
|
|
4071
|
+
mimeType: mimeType2,
|
|
4072
|
+
purpose,
|
|
4073
|
+
expiresAfterSeconds,
|
|
4074
|
+
sha256Hex: sha256Hex2,
|
|
4075
|
+
bytes: info.size
|
|
4076
|
+
});
|
|
4077
|
+
const localPath2 = await cacheFileLocally(filePath, sha256Hex2);
|
|
4078
|
+
const cached2 = recordMetadata({
|
|
4079
|
+
...uploaded2,
|
|
4080
|
+
localPath: localPath2
|
|
4081
|
+
});
|
|
4082
|
+
await persistMetadataToDisk(cached2);
|
|
4083
|
+
return cached2.file;
|
|
4084
|
+
}
|
|
4085
|
+
const filename = normaliseFilename(params.filename);
|
|
4086
|
+
const bytes = toBuffer(params.data);
|
|
4087
|
+
const mimeType = resolveMimeType(filename, params.mimeType, "text/plain");
|
|
4088
|
+
const sha256Hex = computeSha256Hex(bytes);
|
|
4089
|
+
const uploaded = await uploadOpenAiFileFromBytes({
|
|
4090
|
+
bytes,
|
|
4091
|
+
filename,
|
|
4092
|
+
mimeType,
|
|
4093
|
+
purpose,
|
|
4094
|
+
expiresAfterSeconds,
|
|
4095
|
+
sha256Hex
|
|
4096
|
+
});
|
|
4097
|
+
const localPath = await cacheBufferLocally(bytes, sha256Hex);
|
|
4098
|
+
const cached = recordMetadata({
|
|
4099
|
+
...uploaded,
|
|
4100
|
+
localPath
|
|
4101
|
+
});
|
|
4102
|
+
await persistMetadataToDisk(cached);
|
|
4103
|
+
return cached.file;
|
|
4104
|
+
}
|
|
4105
|
+
async function filesRetrieve(fileId) {
|
|
4106
|
+
return (await retrieveOpenAiFile(fileId)).file;
|
|
4107
|
+
}
|
|
4108
|
+
async function filesDelete(fileId) {
|
|
4109
|
+
const cachedGemini = filesState.geminiMirrorById.get(fileId);
|
|
4110
|
+
if (cachedGemini) {
|
|
4111
|
+
try {
|
|
4112
|
+
const client = await getGeminiMirrorClient();
|
|
4113
|
+
await client.files.delete({ name: cachedGemini.name });
|
|
4114
|
+
} catch {
|
|
4115
|
+
}
|
|
4116
|
+
filesState.geminiMirrorById.delete(fileId);
|
|
4117
|
+
}
|
|
4118
|
+
const cachedVertex = filesState.vertexMirrorById.get(fileId);
|
|
4119
|
+
if (cachedVertex) {
|
|
4120
|
+
try {
|
|
4121
|
+
await getStorageClient().bucket(cachedVertex.bucket).file(cachedVertex.objectName).delete({ ignoreNotFound: true });
|
|
4122
|
+
} catch {
|
|
4123
|
+
}
|
|
4124
|
+
filesState.vertexMirrorById.delete(fileId);
|
|
4125
|
+
}
|
|
4126
|
+
const cachedMaterialized = filesState.metadataById.get(fileId)?.localPath;
|
|
4127
|
+
if (cachedMaterialized) {
|
|
4128
|
+
try {
|
|
4129
|
+
await (0, import_promises2.unlink)(cachedMaterialized);
|
|
4130
|
+
} catch {
|
|
4131
|
+
}
|
|
4132
|
+
}
|
|
4133
|
+
const response = await getOpenAiClient().files.delete(fileId);
|
|
4134
|
+
filesState.metadataById.delete(fileId);
|
|
4135
|
+
filesState.materializedById.delete(fileId);
|
|
4136
|
+
try {
|
|
4137
|
+
await (0, import_promises2.unlink)(buildCachedMetadataPath(fileId));
|
|
4138
|
+
} catch {
|
|
4139
|
+
}
|
|
4140
|
+
return {
|
|
4141
|
+
id: response.id,
|
|
4142
|
+
deleted: response.deleted,
|
|
4143
|
+
object: "file"
|
|
4144
|
+
};
|
|
4145
|
+
}
|
|
4146
|
+
async function filesContent(fileId) {
|
|
4147
|
+
return await getOpenAiClient().files.content(fileId);
|
|
4148
|
+
}
|
|
4149
|
+
async function getCanonicalFileMetadata(fileId) {
|
|
4150
|
+
const metadata = await retrieveOpenAiFile(fileId);
|
|
4151
|
+
const mimeType = metadata.mimeType ?? resolveMimeType(metadata.filename, void 0);
|
|
4152
|
+
const updated = metadata.mimeType === mimeType ? metadata : recordMetadata({
|
|
4153
|
+
...metadata,
|
|
4154
|
+
mimeType
|
|
4155
|
+
});
|
|
4156
|
+
return {
|
|
4157
|
+
...updated,
|
|
4158
|
+
mimeType
|
|
4159
|
+
};
|
|
4160
|
+
}
|
|
4161
|
+
var files = {
|
|
4162
|
+
create: filesCreate,
|
|
4163
|
+
retrieve: filesRetrieve,
|
|
4164
|
+
delete: filesDelete,
|
|
4165
|
+
content: filesContent
|
|
4166
|
+
};
|
|
4167
|
+
|
|
3353
4168
|
// src/llm.ts
|
|
3354
4169
|
var toolCallContextStorage = getRuntimeSingleton(
|
|
3355
4170
|
/* @__PURE__ */ Symbol.for("@ljoukov/llm.toolCallContextStorage"),
|
|
3356
|
-
() => new
|
|
4171
|
+
() => new import_node_async_hooks3.AsyncLocalStorage()
|
|
3357
4172
|
);
|
|
3358
4173
|
function getCurrentToolCallContext() {
|
|
3359
4174
|
return toolCallContextStorage.getStore() ?? null;
|
|
3360
4175
|
}
|
|
4176
|
+
var INLINE_ATTACHMENT_FILENAME_SYMBOL = /* @__PURE__ */ Symbol.for("@ljoukov/llm.inlineAttachmentFilename");
|
|
4177
|
+
var INLINE_ATTACHMENT_PROMPT_THRESHOLD_BYTES = 20 * 1024 * 1024;
|
|
4178
|
+
var TOOL_OUTPUT_SPILL_THRESHOLD_BYTES = 1 * 1024 * 1024;
|
|
3361
4179
|
var LLM_TEXT_MODEL_IDS = [
|
|
3362
4180
|
...OPENAI_MODEL_IDS,
|
|
3363
4181
|
...CHATGPT_MODEL_IDS,
|
|
@@ -3635,27 +4453,90 @@ function isJsonSchemaObject(schema) {
|
|
|
3635
4453
|
}
|
|
3636
4454
|
return false;
|
|
3637
4455
|
}
|
|
3638
|
-
|
|
4456
|
+
var CANONICAL_GEMINI_FILE_URI_PREFIX = "openai://file/";
|
|
4457
|
+
function buildCanonicalGeminiFileUri(fileId) {
|
|
4458
|
+
return `${CANONICAL_GEMINI_FILE_URI_PREFIX}${fileId}`;
|
|
4459
|
+
}
|
|
4460
|
+
function parseCanonicalGeminiFileId(fileUri) {
|
|
4461
|
+
if (!fileUri?.startsWith(CANONICAL_GEMINI_FILE_URI_PREFIX)) {
|
|
4462
|
+
return void 0;
|
|
4463
|
+
}
|
|
4464
|
+
const fileId = fileUri.slice(CANONICAL_GEMINI_FILE_URI_PREFIX.length).trim();
|
|
4465
|
+
return fileId.length > 0 ? fileId : void 0;
|
|
4466
|
+
}
|
|
4467
|
+
function cloneContentPart(part) {
|
|
3639
4468
|
switch (part.type) {
|
|
3640
4469
|
case "text":
|
|
3641
4470
|
return {
|
|
3642
4471
|
type: "text",
|
|
3643
|
-
|
|
3644
|
-
|
|
4472
|
+
text: part.text,
|
|
4473
|
+
thought: part.thought === true ? true : void 0
|
|
3645
4474
|
};
|
|
3646
|
-
case "inlineData":
|
|
3647
|
-
let omittedBytes;
|
|
3648
|
-
try {
|
|
3649
|
-
omittedBytes = import_node_buffer3.Buffer.from(part.data, "base64").byteLength;
|
|
3650
|
-
} catch {
|
|
3651
|
-
omittedBytes = import_node_buffer3.Buffer.byteLength(part.data, "utf8");
|
|
3652
|
-
}
|
|
4475
|
+
case "inlineData":
|
|
3653
4476
|
return {
|
|
3654
4477
|
type: "inlineData",
|
|
4478
|
+
data: part.data,
|
|
3655
4479
|
mimeType: part.mimeType,
|
|
3656
|
-
|
|
4480
|
+
filename: part.filename
|
|
4481
|
+
};
|
|
4482
|
+
case "input_image":
|
|
4483
|
+
return {
|
|
4484
|
+
type: "input_image",
|
|
4485
|
+
image_url: part.image_url ?? void 0,
|
|
4486
|
+
file_id: part.file_id ?? void 0,
|
|
4487
|
+
detail: part.detail,
|
|
4488
|
+
filename: part.filename ?? void 0
|
|
4489
|
+
};
|
|
4490
|
+
case "input_file":
|
|
4491
|
+
return {
|
|
4492
|
+
type: "input_file",
|
|
4493
|
+
file_data: part.file_data ?? void 0,
|
|
4494
|
+
file_id: part.file_id ?? void 0,
|
|
4495
|
+
file_url: part.file_url ?? void 0,
|
|
4496
|
+
filename: part.filename ?? void 0
|
|
4497
|
+
};
|
|
4498
|
+
default:
|
|
4499
|
+
return part;
|
|
4500
|
+
}
|
|
4501
|
+
}
|
|
4502
|
+
function sanitisePartForLogging(part) {
|
|
4503
|
+
switch (part.type) {
|
|
4504
|
+
case "text":
|
|
4505
|
+
return {
|
|
4506
|
+
type: "text",
|
|
4507
|
+
thought: part.thought === true ? true : void 0,
|
|
4508
|
+
preview: part.text.slice(0, 200)
|
|
4509
|
+
};
|
|
4510
|
+
case "inlineData": {
|
|
4511
|
+
let omittedBytes;
|
|
4512
|
+
try {
|
|
4513
|
+
omittedBytes = import_node_buffer4.Buffer.from(part.data, "base64").byteLength;
|
|
4514
|
+
} catch {
|
|
4515
|
+
omittedBytes = import_node_buffer4.Buffer.byteLength(part.data, "utf8");
|
|
4516
|
+
}
|
|
4517
|
+
return {
|
|
4518
|
+
type: "inlineData",
|
|
4519
|
+
mimeType: part.mimeType,
|
|
4520
|
+
filename: part.filename,
|
|
4521
|
+
data: `[omitted:${omittedBytes}b]`
|
|
4522
|
+
};
|
|
4523
|
+
}
|
|
4524
|
+
case "input_image":
|
|
4525
|
+
return {
|
|
4526
|
+
type: "input_image",
|
|
4527
|
+
file_id: part.file_id ?? void 0,
|
|
4528
|
+
filename: part.filename ?? void 0,
|
|
4529
|
+
detail: part.detail ?? void 0,
|
|
4530
|
+
image_url: typeof part.image_url === "string" ? part.image_url.startsWith("data:") ? "[omitted:data-url]" : part.image_url : void 0
|
|
4531
|
+
};
|
|
4532
|
+
case "input_file":
|
|
4533
|
+
return {
|
|
4534
|
+
type: "input_file",
|
|
4535
|
+
file_id: part.file_id ?? void 0,
|
|
4536
|
+
filename: part.filename ?? void 0,
|
|
4537
|
+
file_url: typeof part.file_url === "string" ? part.file_url.startsWith("data:") ? "[omitted:data-url]" : part.file_url : void 0,
|
|
4538
|
+
file_data: typeof part.file_data === "string" ? `[omitted:${import_node_buffer4.Buffer.byteLength(part.file_data, "utf8")}b]` : void 0
|
|
3657
4539
|
};
|
|
3658
|
-
}
|
|
3659
4540
|
default:
|
|
3660
4541
|
return "[unknown part]";
|
|
3661
4542
|
}
|
|
@@ -3676,12 +4557,17 @@ function convertGooglePartsToLlmParts(parts) {
|
|
|
3676
4557
|
result.push({
|
|
3677
4558
|
type: "inlineData",
|
|
3678
4559
|
data: inline.data,
|
|
3679
|
-
mimeType: inline.mimeType
|
|
4560
|
+
mimeType: inline.mimeType,
|
|
4561
|
+
filename: inline.displayName
|
|
3680
4562
|
});
|
|
3681
4563
|
continue;
|
|
3682
4564
|
}
|
|
3683
4565
|
if (part.fileData?.fileUri) {
|
|
3684
|
-
|
|
4566
|
+
result.push({
|
|
4567
|
+
type: "input_file",
|
|
4568
|
+
file_url: part.fileData.fileUri,
|
|
4569
|
+
filename: part.fileData.displayName
|
|
4570
|
+
});
|
|
3685
4571
|
}
|
|
3686
4572
|
}
|
|
3687
4573
|
return result;
|
|
@@ -3713,13 +4599,82 @@ function toGeminiPart(part) {
|
|
|
3713
4599
|
text: part.text,
|
|
3714
4600
|
thought: part.thought === true ? true : void 0
|
|
3715
4601
|
};
|
|
3716
|
-
case "inlineData":
|
|
4602
|
+
case "inlineData": {
|
|
4603
|
+
const inlineData = {
|
|
4604
|
+
data: part.data,
|
|
4605
|
+
mimeType: part.mimeType
|
|
4606
|
+
};
|
|
4607
|
+
setInlineAttachmentFilename(inlineData, part.filename);
|
|
3717
4608
|
return {
|
|
3718
4609
|
inlineData: {
|
|
3719
|
-
|
|
3720
|
-
|
|
4610
|
+
...inlineData
|
|
4611
|
+
}
|
|
4612
|
+
};
|
|
4613
|
+
}
|
|
4614
|
+
case "input_image": {
|
|
4615
|
+
if (part.file_id) {
|
|
4616
|
+
return {
|
|
4617
|
+
fileData: {
|
|
4618
|
+
fileUri: buildCanonicalGeminiFileUri(part.file_id),
|
|
4619
|
+
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4620
|
+
}
|
|
4621
|
+
};
|
|
4622
|
+
}
|
|
4623
|
+
if (typeof part.image_url !== "string" || part.image_url.trim().length === 0) {
|
|
4624
|
+
throw new Error("input_image requires image_url or file_id.");
|
|
4625
|
+
}
|
|
4626
|
+
const parsed = parseDataUrlPayload(part.image_url);
|
|
4627
|
+
if (parsed) {
|
|
4628
|
+
const geminiPart = (0, import_genai2.createPartFromBase64)(parsed.dataBase64, parsed.mimeType);
|
|
4629
|
+
if (part.filename && geminiPart.inlineData) {
|
|
4630
|
+
geminiPart.inlineData.displayName = part.filename;
|
|
4631
|
+
}
|
|
4632
|
+
return geminiPart;
|
|
4633
|
+
}
|
|
4634
|
+
return {
|
|
4635
|
+
fileData: {
|
|
4636
|
+
fileUri: part.image_url,
|
|
4637
|
+
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
3721
4638
|
}
|
|
3722
4639
|
};
|
|
4640
|
+
}
|
|
4641
|
+
case "input_file": {
|
|
4642
|
+
if (part.file_id) {
|
|
4643
|
+
return {
|
|
4644
|
+
fileData: {
|
|
4645
|
+
fileUri: buildCanonicalGeminiFileUri(part.file_id),
|
|
4646
|
+
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4647
|
+
}
|
|
4648
|
+
};
|
|
4649
|
+
}
|
|
4650
|
+
if (typeof part.file_data === "string" && part.file_data.trim().length > 0) {
|
|
4651
|
+
const geminiPart = (0, import_genai2.createPartFromBase64)(
|
|
4652
|
+
part.file_data,
|
|
4653
|
+
inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4654
|
+
);
|
|
4655
|
+
if (part.filename && geminiPart.inlineData) {
|
|
4656
|
+
geminiPart.inlineData.displayName = part.filename;
|
|
4657
|
+
}
|
|
4658
|
+
return geminiPart;
|
|
4659
|
+
}
|
|
4660
|
+
if (typeof part.file_url === "string" && part.file_url.trim().length > 0) {
|
|
4661
|
+
const parsed = parseDataUrlPayload(part.file_url);
|
|
4662
|
+
if (parsed) {
|
|
4663
|
+
const geminiPart = (0, import_genai2.createPartFromBase64)(parsed.dataBase64, parsed.mimeType);
|
|
4664
|
+
if (part.filename && geminiPart.inlineData) {
|
|
4665
|
+
geminiPart.inlineData.displayName = part.filename;
|
|
4666
|
+
}
|
|
4667
|
+
return geminiPart;
|
|
4668
|
+
}
|
|
4669
|
+
return {
|
|
4670
|
+
fileData: {
|
|
4671
|
+
fileUri: part.file_url,
|
|
4672
|
+
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4673
|
+
}
|
|
4674
|
+
};
|
|
4675
|
+
}
|
|
4676
|
+
throw new Error("input_file requires file_id, file_data, or file_url.");
|
|
4677
|
+
}
|
|
3723
4678
|
default:
|
|
3724
4679
|
throw new Error("Unsupported LLM content part");
|
|
3725
4680
|
}
|
|
@@ -3816,6 +4771,14 @@ function isInlineImageMime(mimeType) {
|
|
|
3816
4771
|
}
|
|
3817
4772
|
function guessInlineDataFilename(mimeType) {
|
|
3818
4773
|
switch (mimeType) {
|
|
4774
|
+
case "image/jpeg":
|
|
4775
|
+
return "image.jpg";
|
|
4776
|
+
case "image/png":
|
|
4777
|
+
return "image.png";
|
|
4778
|
+
case "image/webp":
|
|
4779
|
+
return "image.webp";
|
|
4780
|
+
case "image/gif":
|
|
4781
|
+
return "image.gif";
|
|
3819
4782
|
case "application/pdf":
|
|
3820
4783
|
return "document.pdf";
|
|
3821
4784
|
case "application/json":
|
|
@@ -3828,6 +4791,251 @@ function guessInlineDataFilename(mimeType) {
|
|
|
3828
4791
|
return "attachment.bin";
|
|
3829
4792
|
}
|
|
3830
4793
|
}
|
|
4794
|
+
function normaliseAttachmentFilename(value, fallback) {
|
|
4795
|
+
const trimmed = value?.trim();
|
|
4796
|
+
if (!trimmed) {
|
|
4797
|
+
return fallback;
|
|
4798
|
+
}
|
|
4799
|
+
const basename = import_node_path5.default.basename(trimmed).replace(/[^\w.-]+/g, "-");
|
|
4800
|
+
return basename.length > 0 ? basename : fallback;
|
|
4801
|
+
}
|
|
4802
|
+
function setInlineAttachmentFilename(target, filename) {
|
|
4803
|
+
const normalized = filename?.trim();
|
|
4804
|
+
if (!normalized) {
|
|
4805
|
+
return;
|
|
4806
|
+
}
|
|
4807
|
+
target[INLINE_ATTACHMENT_FILENAME_SYMBOL] = normalized;
|
|
4808
|
+
}
|
|
4809
|
+
function getInlineAttachmentFilename(target) {
|
|
4810
|
+
if (!target || typeof target !== "object") {
|
|
4811
|
+
return void 0;
|
|
4812
|
+
}
|
|
4813
|
+
const value = target[INLINE_ATTACHMENT_FILENAME_SYMBOL];
|
|
4814
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
4815
|
+
}
|
|
4816
|
+
function estimateInlinePayloadBytes(value) {
|
|
4817
|
+
return import_node_buffer4.Buffer.byteLength(value, "utf8");
|
|
4818
|
+
}
|
|
4819
|
+
function isOpenAiNativeContentItem(value) {
|
|
4820
|
+
return !!value && typeof value === "object" && typeof value.type === "string";
|
|
4821
|
+
}
|
|
4822
|
+
function estimateOpenAiInlinePromptBytes(input) {
|
|
4823
|
+
let total = 0;
|
|
4824
|
+
const visitItems = (items) => {
|
|
4825
|
+
for (const item of items) {
|
|
4826
|
+
if (!item || typeof item !== "object") {
|
|
4827
|
+
continue;
|
|
4828
|
+
}
|
|
4829
|
+
if (Array.isArray(item.content)) {
|
|
4830
|
+
visitItems(item.content);
|
|
4831
|
+
}
|
|
4832
|
+
if (Array.isArray(item.output)) {
|
|
4833
|
+
visitItems(item.output);
|
|
4834
|
+
}
|
|
4835
|
+
if (!isOpenAiNativeContentItem(item)) {
|
|
4836
|
+
continue;
|
|
4837
|
+
}
|
|
4838
|
+
if (item.type === "input_image" && typeof item.image_url === "string" && item.image_url.trim().toLowerCase().startsWith("data:")) {
|
|
4839
|
+
total += estimateInlinePayloadBytes(item.image_url);
|
|
4840
|
+
}
|
|
4841
|
+
if (item.type === "input_file" && typeof item.file_data === "string" && item.file_data.trim().length > 0) {
|
|
4842
|
+
total += estimateInlinePayloadBytes(item.file_data);
|
|
4843
|
+
}
|
|
4844
|
+
if (item.type === "input_file" && typeof item.file_url === "string" && item.file_url.trim().toLowerCase().startsWith("data:")) {
|
|
4845
|
+
total += estimateInlinePayloadBytes(item.file_url);
|
|
4846
|
+
}
|
|
4847
|
+
}
|
|
4848
|
+
};
|
|
4849
|
+
visitItems(input);
|
|
4850
|
+
return total;
|
|
4851
|
+
}
|
|
4852
|
+
async function storeCanonicalPromptFile(options) {
|
|
4853
|
+
const file = await runWithFileUploadSource("prompt_inline_offload", async () => {
|
|
4854
|
+
return await filesCreate({
|
|
4855
|
+
data: options.bytes,
|
|
4856
|
+
filename: options.filename,
|
|
4857
|
+
mimeType: options.mimeType,
|
|
4858
|
+
expiresAfterSeconds: DEFAULT_FILE_TTL_SECONDS
|
|
4859
|
+
});
|
|
4860
|
+
});
|
|
4861
|
+
return {
|
|
4862
|
+
fileId: file.id,
|
|
4863
|
+
filename: file.filename,
|
|
4864
|
+
mimeType: options.mimeType
|
|
4865
|
+
};
|
|
4866
|
+
}
|
|
4867
|
+
async function prepareOpenAiPromptContentItem(item) {
|
|
4868
|
+
if (!isOpenAiNativeContentItem(item)) {
|
|
4869
|
+
return item;
|
|
4870
|
+
}
|
|
4871
|
+
if (item.type === "input_image" && typeof item.image_url === "string" && item.image_url.trim().toLowerCase().startsWith("data:")) {
|
|
4872
|
+
const parsed = parseDataUrlPayload(item.image_url);
|
|
4873
|
+
if (!parsed) {
|
|
4874
|
+
return item;
|
|
4875
|
+
}
|
|
4876
|
+
const uploaded = await storeCanonicalPromptFile({
|
|
4877
|
+
bytes: parsed.bytes,
|
|
4878
|
+
mimeType: parsed.mimeType ?? "application/octet-stream",
|
|
4879
|
+
filename: normaliseAttachmentFilename(
|
|
4880
|
+
getInlineAttachmentFilename(item),
|
|
4881
|
+
guessInlineDataFilename(parsed.mimeType)
|
|
4882
|
+
)
|
|
4883
|
+
});
|
|
4884
|
+
return {
|
|
4885
|
+
type: "input_image",
|
|
4886
|
+
detail: item.detail === "high" || item.detail === "low" ? item.detail : "auto",
|
|
4887
|
+
file_id: uploaded.fileId
|
|
4888
|
+
};
|
|
4889
|
+
}
|
|
4890
|
+
if (item.type !== "input_file" || item.file_id) {
|
|
4891
|
+
return item;
|
|
4892
|
+
}
|
|
4893
|
+
if (typeof item.file_data === "string" && item.file_data.trim().length > 0) {
|
|
4894
|
+
const filename = normaliseAttachmentFilename(
|
|
4895
|
+
typeof item.filename === "string" ? item.filename : void 0,
|
|
4896
|
+
guessInlineDataFilename(void 0)
|
|
4897
|
+
);
|
|
4898
|
+
const mimeType = inferToolOutputMimeTypeFromFilename(filename) ?? "application/octet-stream";
|
|
4899
|
+
const uploaded = await storeCanonicalPromptFile({
|
|
4900
|
+
bytes: decodeInlineDataBuffer(item.file_data),
|
|
4901
|
+
mimeType,
|
|
4902
|
+
filename
|
|
4903
|
+
});
|
|
4904
|
+
return { type: "input_file", file_id: uploaded.fileId };
|
|
4905
|
+
}
|
|
4906
|
+
if (typeof item.file_url === "string" && item.file_url.trim().toLowerCase().startsWith("data:")) {
|
|
4907
|
+
const parsed = parseDataUrlPayload(item.file_url);
|
|
4908
|
+
if (!parsed) {
|
|
4909
|
+
return item;
|
|
4910
|
+
}
|
|
4911
|
+
const uploaded = await storeCanonicalPromptFile({
|
|
4912
|
+
bytes: parsed.bytes,
|
|
4913
|
+
mimeType: parsed.mimeType ?? "application/octet-stream",
|
|
4914
|
+
filename: normaliseAttachmentFilename(
|
|
4915
|
+
typeof item.filename === "string" ? item.filename : void 0,
|
|
4916
|
+
guessInlineDataFilename(parsed.mimeType)
|
|
4917
|
+
)
|
|
4918
|
+
});
|
|
4919
|
+
return { type: "input_file", file_id: uploaded.fileId };
|
|
4920
|
+
}
|
|
4921
|
+
return item;
|
|
4922
|
+
}
|
|
4923
|
+
async function prepareOpenAiPromptInput(input) {
|
|
4924
|
+
const prepareItem = async (item) => {
|
|
4925
|
+
if (!item || typeof item !== "object") {
|
|
4926
|
+
return item;
|
|
4927
|
+
}
|
|
4928
|
+
const record = item;
|
|
4929
|
+
if (Array.isArray(record.content)) {
|
|
4930
|
+
return {
|
|
4931
|
+
...record,
|
|
4932
|
+
content: await Promise.all(
|
|
4933
|
+
record.content.map((part) => prepareOpenAiPromptContentItem(part))
|
|
4934
|
+
)
|
|
4935
|
+
};
|
|
4936
|
+
}
|
|
4937
|
+
if (Array.isArray(record.output)) {
|
|
4938
|
+
return {
|
|
4939
|
+
...record,
|
|
4940
|
+
output: await Promise.all(
|
|
4941
|
+
record.output.map((part) => prepareOpenAiPromptContentItem(part))
|
|
4942
|
+
)
|
|
4943
|
+
};
|
|
4944
|
+
}
|
|
4945
|
+
return await prepareOpenAiPromptContentItem(item);
|
|
4946
|
+
};
|
|
4947
|
+
return await Promise.all(input.map((item) => prepareItem(item)));
|
|
4948
|
+
}
|
|
4949
|
+
async function maybePrepareOpenAiPromptInput(input) {
|
|
4950
|
+
if (estimateOpenAiInlinePromptBytes(input) <= INLINE_ATTACHMENT_PROMPT_THRESHOLD_BYTES) {
|
|
4951
|
+
return Array.from(input);
|
|
4952
|
+
}
|
|
4953
|
+
return await prepareOpenAiPromptInput(input);
|
|
4954
|
+
}
|
|
4955
|
+
function estimateGeminiInlinePromptBytes(contents) {
|
|
4956
|
+
let total = 0;
|
|
4957
|
+
for (const content of contents) {
|
|
4958
|
+
for (const part of content.parts ?? []) {
|
|
4959
|
+
if (part.inlineData?.data) {
|
|
4960
|
+
total += estimateInlinePayloadBytes(part.inlineData.data);
|
|
4961
|
+
}
|
|
4962
|
+
}
|
|
4963
|
+
}
|
|
4964
|
+
return total;
|
|
4965
|
+
}
|
|
4966
|
+
function hasCanonicalGeminiFileReferences(contents) {
|
|
4967
|
+
for (const content of contents) {
|
|
4968
|
+
for (const part of content.parts ?? []) {
|
|
4969
|
+
if (parseCanonicalGeminiFileId(part.fileData?.fileUri)) {
|
|
4970
|
+
return true;
|
|
4971
|
+
}
|
|
4972
|
+
}
|
|
4973
|
+
}
|
|
4974
|
+
return false;
|
|
4975
|
+
}
|
|
4976
|
+
async function prepareGeminiPromptContents(contents) {
|
|
4977
|
+
const backend = getGeminiBackend();
|
|
4978
|
+
const preparedContents = [];
|
|
4979
|
+
for (const content of contents) {
|
|
4980
|
+
const parts = [];
|
|
4981
|
+
for (const part of content.parts ?? []) {
|
|
4982
|
+
const canonicalFileId = parseCanonicalGeminiFileId(part.fileData?.fileUri);
|
|
4983
|
+
if (canonicalFileId) {
|
|
4984
|
+
await getCanonicalFileMetadata(canonicalFileId);
|
|
4985
|
+
if (backend === "api") {
|
|
4986
|
+
const mirrored = await ensureGeminiFileMirror(canonicalFileId);
|
|
4987
|
+
parts.push((0, import_genai2.createPartFromUri)(mirrored.uri, mirrored.mimeType));
|
|
4988
|
+
} else {
|
|
4989
|
+
const mirrored = await ensureVertexFileMirror(canonicalFileId);
|
|
4990
|
+
parts.push({
|
|
4991
|
+
fileData: {
|
|
4992
|
+
fileUri: mirrored.fileUri,
|
|
4993
|
+
mimeType: mirrored.mimeType
|
|
4994
|
+
}
|
|
4995
|
+
});
|
|
4996
|
+
}
|
|
4997
|
+
continue;
|
|
4998
|
+
}
|
|
4999
|
+
if (part.inlineData?.data) {
|
|
5000
|
+
const mimeType = part.inlineData.mimeType ?? "application/octet-stream";
|
|
5001
|
+
const filename = normaliseAttachmentFilename(
|
|
5002
|
+
getInlineAttachmentFilename(part.inlineData) ?? part.inlineData.displayName ?? guessInlineDataFilename(mimeType),
|
|
5003
|
+
guessInlineDataFilename(mimeType)
|
|
5004
|
+
);
|
|
5005
|
+
const stored = await storeCanonicalPromptFile({
|
|
5006
|
+
bytes: decodeInlineDataBuffer(part.inlineData.data),
|
|
5007
|
+
mimeType,
|
|
5008
|
+
filename
|
|
5009
|
+
});
|
|
5010
|
+
if (backend === "api") {
|
|
5011
|
+
const mirrored = await ensureGeminiFileMirror(stored.fileId);
|
|
5012
|
+
parts.push((0, import_genai2.createPartFromUri)(mirrored.uri, mirrored.mimeType));
|
|
5013
|
+
} else {
|
|
5014
|
+
const mirrored = await ensureVertexFileMirror(stored.fileId);
|
|
5015
|
+
parts.push({
|
|
5016
|
+
fileData: {
|
|
5017
|
+
fileUri: mirrored.fileUri,
|
|
5018
|
+
mimeType: mirrored.mimeType
|
|
5019
|
+
}
|
|
5020
|
+
});
|
|
5021
|
+
}
|
|
5022
|
+
continue;
|
|
5023
|
+
}
|
|
5024
|
+
parts.push(part);
|
|
5025
|
+
}
|
|
5026
|
+
preparedContents.push({
|
|
5027
|
+
...content,
|
|
5028
|
+
parts
|
|
5029
|
+
});
|
|
5030
|
+
}
|
|
5031
|
+
return preparedContents;
|
|
5032
|
+
}
|
|
5033
|
+
async function maybePrepareGeminiPromptContents(contents) {
|
|
5034
|
+
if (!hasCanonicalGeminiFileReferences(contents) && estimateGeminiInlinePromptBytes(contents) <= INLINE_ATTACHMENT_PROMPT_THRESHOLD_BYTES) {
|
|
5035
|
+
return Array.from(contents);
|
|
5036
|
+
}
|
|
5037
|
+
return await prepareGeminiPromptContents(contents);
|
|
5038
|
+
}
|
|
3831
5039
|
function mergeConsecutiveTextParts(parts) {
|
|
3832
5040
|
if (parts.length === 0) {
|
|
3833
5041
|
return [];
|
|
@@ -3835,7 +5043,7 @@ function mergeConsecutiveTextParts(parts) {
|
|
|
3835
5043
|
const merged = [];
|
|
3836
5044
|
for (const part of parts) {
|
|
3837
5045
|
if (part.type !== "text") {
|
|
3838
|
-
merged.push(
|
|
5046
|
+
merged.push(cloneContentPart(part));
|
|
3839
5047
|
continue;
|
|
3840
5048
|
}
|
|
3841
5049
|
const isThought = part.thought === true;
|
|
@@ -4266,13 +5474,7 @@ function resolveTextContents(input) {
|
|
|
4266
5474
|
const parts = typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content;
|
|
4267
5475
|
contents.push({
|
|
4268
5476
|
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
|
-
)
|
|
5477
|
+
parts: parts.map((part) => cloneContentPart(part))
|
|
4276
5478
|
});
|
|
4277
5479
|
}
|
|
4278
5480
|
return contents;
|
|
@@ -4288,22 +5490,58 @@ function toOpenAiInput(contents) {
|
|
|
4288
5490
|
return contents.map((content) => {
|
|
4289
5491
|
const parts = [];
|
|
4290
5492
|
for (const part of content.parts) {
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
5493
|
+
switch (part.type) {
|
|
5494
|
+
case "text":
|
|
5495
|
+
parts.push({ type: "input_text", text: part.text });
|
|
5496
|
+
break;
|
|
5497
|
+
case "inlineData": {
|
|
5498
|
+
const mimeType = part.mimeType;
|
|
5499
|
+
if (isInlineImageMime(mimeType)) {
|
|
5500
|
+
const dataUrl = `data:${mimeType};base64,${part.data}`;
|
|
5501
|
+
const imagePart = {
|
|
5502
|
+
type: "input_image",
|
|
5503
|
+
image_url: dataUrl,
|
|
5504
|
+
detail: "auto"
|
|
5505
|
+
};
|
|
5506
|
+
setInlineAttachmentFilename(
|
|
5507
|
+
imagePart,
|
|
5508
|
+
normaliseAttachmentFilename(part.filename, guessInlineDataFilename(mimeType))
|
|
5509
|
+
);
|
|
5510
|
+
parts.push(imagePart);
|
|
5511
|
+
break;
|
|
5512
|
+
}
|
|
5513
|
+
parts.push({
|
|
5514
|
+
type: "input_file",
|
|
5515
|
+
filename: normaliseAttachmentFilename(part.filename, guessInlineDataFilename(mimeType)),
|
|
5516
|
+
file_data: part.data
|
|
5517
|
+
});
|
|
5518
|
+
break;
|
|
5519
|
+
}
|
|
5520
|
+
case "input_image": {
|
|
5521
|
+
const imagePart = {
|
|
5522
|
+
type: "input_image",
|
|
5523
|
+
...part.file_id ? { file_id: part.file_id } : {},
|
|
5524
|
+
...part.image_url ? { image_url: part.image_url } : {},
|
|
5525
|
+
detail: part.detail === "high" || part.detail === "low" ? part.detail : "auto"
|
|
5526
|
+
};
|
|
5527
|
+
if (part.filename) {
|
|
5528
|
+
setInlineAttachmentFilename(imagePart, part.filename);
|
|
5529
|
+
}
|
|
5530
|
+
parts.push(imagePart);
|
|
5531
|
+
break;
|
|
5532
|
+
}
|
|
5533
|
+
case "input_file":
|
|
5534
|
+
parts.push({
|
|
5535
|
+
type: "input_file",
|
|
5536
|
+
...part.file_id ? { file_id: part.file_id } : {},
|
|
5537
|
+
...part.file_data ? { file_data: part.file_data } : {},
|
|
5538
|
+
...part.file_url ? { file_url: part.file_url } : {},
|
|
5539
|
+
...!part.file_id && part.filename ? { filename: part.filename } : {}
|
|
5540
|
+
});
|
|
5541
|
+
break;
|
|
5542
|
+
default:
|
|
5543
|
+
throw new Error("Unsupported LLM content part");
|
|
4300
5544
|
}
|
|
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
5545
|
}
|
|
4308
5546
|
if (parts.length === 1 && parts[0]?.type === "input_text" && typeof parts[0].text === "string") {
|
|
4309
5547
|
return {
|
|
@@ -4340,28 +5578,54 @@ function toChatGptInput(contents) {
|
|
|
4340
5578
|
continue;
|
|
4341
5579
|
}
|
|
4342
5580
|
if (isAssistant) {
|
|
4343
|
-
const mimeType = part.mimeType ?? "application/octet-stream";
|
|
5581
|
+
const mimeType = part.type === "inlineData" ? part.mimeType ?? "application/octet-stream" : inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream";
|
|
4344
5582
|
parts.push({
|
|
4345
5583
|
type: "output_text",
|
|
4346
|
-
text: isInlineImageMime(part.mimeType) ? `[image:${mimeType}]` : `[file:${mimeType}]`
|
|
5584
|
+
text: part.type === "input_image" || isInlineImageMime(part.mimeType) ? `[image:${mimeType}]` : `[file:${mimeType}]`
|
|
4347
5585
|
});
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
5586
|
+
continue;
|
|
5587
|
+
}
|
|
5588
|
+
switch (part.type) {
|
|
5589
|
+
case "inlineData": {
|
|
5590
|
+
if (isInlineImageMime(part.mimeType)) {
|
|
5591
|
+
const mimeType = part.mimeType ?? "application/octet-stream";
|
|
5592
|
+
const dataUrl = `data:${mimeType};base64,${part.data}`;
|
|
5593
|
+
parts.push({
|
|
5594
|
+
type: "input_image",
|
|
5595
|
+
image_url: dataUrl,
|
|
5596
|
+
detail: "auto"
|
|
5597
|
+
});
|
|
5598
|
+
} else {
|
|
5599
|
+
parts.push({
|
|
5600
|
+
type: "input_file",
|
|
5601
|
+
filename: normaliseAttachmentFilename(
|
|
5602
|
+
part.filename,
|
|
5603
|
+
guessInlineDataFilename(part.mimeType)
|
|
5604
|
+
),
|
|
5605
|
+
file_data: part.data
|
|
5606
|
+
});
|
|
5607
|
+
}
|
|
5608
|
+
break;
|
|
5609
|
+
}
|
|
5610
|
+
case "input_image":
|
|
4352
5611
|
parts.push({
|
|
4353
5612
|
type: "input_image",
|
|
4354
|
-
|
|
4355
|
-
|
|
5613
|
+
...part.file_id ? { file_id: part.file_id } : {},
|
|
5614
|
+
...part.image_url ? { image_url: part.image_url } : {},
|
|
5615
|
+
detail: part.detail === "high" || part.detail === "low" ? part.detail : "auto"
|
|
4356
5616
|
});
|
|
4357
|
-
|
|
4358
|
-
|
|
5617
|
+
break;
|
|
5618
|
+
case "input_file":
|
|
4359
5619
|
parts.push({
|
|
4360
5620
|
type: "input_file",
|
|
4361
|
-
|
|
4362
|
-
file_data:
|
|
5621
|
+
...part.file_id ? { file_id: part.file_id } : {},
|
|
5622
|
+
...part.file_data ? { file_data: part.file_data } : {},
|
|
5623
|
+
...part.file_url ? { file_url: part.file_url } : {},
|
|
5624
|
+
...!part.file_id && part.filename ? { filename: part.filename } : {}
|
|
4363
5625
|
});
|
|
4364
|
-
|
|
5626
|
+
break;
|
|
5627
|
+
default:
|
|
5628
|
+
throw new Error("Unsupported LLM content part");
|
|
4365
5629
|
}
|
|
4366
5630
|
}
|
|
4367
5631
|
if (parts.length === 0) {
|
|
@@ -4405,8 +5669,8 @@ ${JSON.stringify(options.responseJsonSchema)}`);
|
|
|
4405
5669
|
if (part.type === "text") {
|
|
4406
5670
|
return part.text;
|
|
4407
5671
|
}
|
|
4408
|
-
const mimeType = part.mimeType ?? "application/octet-stream";
|
|
4409
|
-
if (isInlineImageMime(mimeType)) {
|
|
5672
|
+
const mimeType = part.type === "inlineData" ? part.mimeType ?? "application/octet-stream" : inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream";
|
|
5673
|
+
if (part.type === "input_image" || isInlineImageMime(mimeType)) {
|
|
4410
5674
|
return `[image:${mimeType}]`;
|
|
4411
5675
|
}
|
|
4412
5676
|
return `[file:${mimeType}]`;
|
|
@@ -4677,7 +5941,14 @@ function isLlmToolOutputContentItem(value) {
|
|
|
4677
5941
|
return typeof value.text === "string";
|
|
4678
5942
|
}
|
|
4679
5943
|
if (itemType === "input_image") {
|
|
4680
|
-
|
|
5944
|
+
const keys = ["image_url", "file_id", "filename"];
|
|
5945
|
+
for (const key of keys) {
|
|
5946
|
+
const part = value[key];
|
|
5947
|
+
if (part !== void 0 && part !== null && typeof part !== "string") {
|
|
5948
|
+
return false;
|
|
5949
|
+
}
|
|
5950
|
+
}
|
|
5951
|
+
return value.image_url !== void 0 || value.file_id !== void 0;
|
|
4681
5952
|
}
|
|
4682
5953
|
if (itemType === "input_file") {
|
|
4683
5954
|
const keys = ["file_data", "file_id", "file_url", "filename"];
|
|
@@ -4746,15 +6017,249 @@ function inferToolOutputMimeTypeFromFilename(filename) {
|
|
|
4746
6017
|
}
|
|
4747
6018
|
return void 0;
|
|
4748
6019
|
}
|
|
4749
|
-
function
|
|
6020
|
+
function estimateToolOutputItemBytes(item) {
|
|
6021
|
+
if (item.type === "input_text") {
|
|
6022
|
+
return import_node_buffer4.Buffer.byteLength(item.text, "utf8");
|
|
6023
|
+
}
|
|
6024
|
+
if (item.type === "input_image") {
|
|
6025
|
+
return typeof item.image_url === "string" ? estimateInlinePayloadBytes(item.image_url) : 0;
|
|
6026
|
+
}
|
|
6027
|
+
if (typeof item.file_data === "string" && item.file_data.trim().length > 0) {
|
|
6028
|
+
return estimateInlinePayloadBytes(item.file_data);
|
|
6029
|
+
}
|
|
6030
|
+
if (typeof item.file_url === "string" && item.file_url.trim().length > 0) {
|
|
6031
|
+
return estimateInlinePayloadBytes(item.file_url);
|
|
6032
|
+
}
|
|
6033
|
+
return 0;
|
|
6034
|
+
}
|
|
6035
|
+
async function spillTextToolOutputToFile(options) {
|
|
6036
|
+
const stored = await runWithFileUploadSource("tool_output_spill", async () => {
|
|
6037
|
+
return await filesCreate({
|
|
6038
|
+
data: options.text,
|
|
6039
|
+
filename: options.filename,
|
|
6040
|
+
mimeType: options.mimeType,
|
|
6041
|
+
expiresAfterSeconds: DEFAULT_FILE_TTL_SECONDS
|
|
6042
|
+
});
|
|
6043
|
+
});
|
|
6044
|
+
return [
|
|
6045
|
+
{
|
|
6046
|
+
type: "input_text",
|
|
6047
|
+
text: `Tool output was attached as ${stored.filename} (${stored.id}) because it exceeded the inline payload threshold.`
|
|
6048
|
+
},
|
|
6049
|
+
{
|
|
6050
|
+
type: "input_file",
|
|
6051
|
+
file_id: stored.id,
|
|
6052
|
+
filename: stored.filename
|
|
6053
|
+
}
|
|
6054
|
+
];
|
|
6055
|
+
}
|
|
6056
|
+
async function maybeSpillToolOutputItem(item, toolName, options) {
|
|
6057
|
+
if (options?.force !== true && estimateToolOutputItemBytes(item) <= TOOL_OUTPUT_SPILL_THRESHOLD_BYTES) {
|
|
6058
|
+
return item;
|
|
6059
|
+
}
|
|
6060
|
+
if (item.type === "input_text") {
|
|
6061
|
+
return await spillTextToolOutputToFile({
|
|
6062
|
+
text: item.text,
|
|
6063
|
+
filename: normaliseAttachmentFilename(`${toolName}.txt`, "tool-output.txt"),
|
|
6064
|
+
mimeType: "text/plain"
|
|
6065
|
+
});
|
|
6066
|
+
}
|
|
4750
6067
|
if (item.type === "input_image") {
|
|
6068
|
+
if (item.file_id || !item.image_url) {
|
|
6069
|
+
return item;
|
|
6070
|
+
}
|
|
4751
6071
|
const parsed = parseDataUrlPayload(item.image_url);
|
|
4752
6072
|
if (!parsed) {
|
|
6073
|
+
return item;
|
|
6074
|
+
}
|
|
6075
|
+
const stored = await runWithFileUploadSource("tool_output_spill", async () => {
|
|
6076
|
+
return await filesCreate({
|
|
6077
|
+
data: parsed.bytes,
|
|
6078
|
+
filename: normaliseAttachmentFilename(
|
|
6079
|
+
item.filename ?? guessInlineDataFilename(parsed.mimeType),
|
|
6080
|
+
guessInlineDataFilename(parsed.mimeType)
|
|
6081
|
+
),
|
|
6082
|
+
mimeType: parsed.mimeType,
|
|
6083
|
+
expiresAfterSeconds: DEFAULT_FILE_TTL_SECONDS
|
|
6084
|
+
});
|
|
6085
|
+
});
|
|
6086
|
+
return {
|
|
6087
|
+
type: "input_image",
|
|
6088
|
+
file_id: stored.id,
|
|
6089
|
+
detail: item.detail ?? "auto",
|
|
6090
|
+
filename: stored.filename
|
|
6091
|
+
};
|
|
6092
|
+
}
|
|
6093
|
+
if (item.file_id) {
|
|
6094
|
+
return item;
|
|
6095
|
+
}
|
|
6096
|
+
if (typeof item.file_data === "string" && item.file_data.trim().length > 0) {
|
|
6097
|
+
const fileData = item.file_data;
|
|
6098
|
+
const filename = normaliseAttachmentFilename(
|
|
6099
|
+
item.filename ?? `${toolName}.bin`,
|
|
6100
|
+
`${toolName}.bin`
|
|
6101
|
+
);
|
|
6102
|
+
const stored = await runWithFileUploadSource("tool_output_spill", async () => {
|
|
6103
|
+
return await filesCreate({
|
|
6104
|
+
data: decodeInlineDataBuffer(fileData),
|
|
6105
|
+
filename,
|
|
6106
|
+
mimeType: inferToolOutputMimeTypeFromFilename(filename) ?? "application/octet-stream",
|
|
6107
|
+
expiresAfterSeconds: DEFAULT_FILE_TTL_SECONDS
|
|
6108
|
+
});
|
|
6109
|
+
});
|
|
6110
|
+
return {
|
|
6111
|
+
type: "input_file",
|
|
6112
|
+
file_id: stored.id,
|
|
6113
|
+
filename: stored.filename
|
|
6114
|
+
};
|
|
6115
|
+
}
|
|
6116
|
+
if (typeof item.file_url === "string" && item.file_url.trim().length > 0) {
|
|
6117
|
+
const parsed = parseDataUrlPayload(item.file_url);
|
|
6118
|
+
if (!parsed) {
|
|
6119
|
+
return item;
|
|
6120
|
+
}
|
|
6121
|
+
const stored = await runWithFileUploadSource("tool_output_spill", async () => {
|
|
6122
|
+
return await filesCreate({
|
|
6123
|
+
data: parsed.bytes,
|
|
6124
|
+
filename: normaliseAttachmentFilename(
|
|
6125
|
+
item.filename ?? guessInlineDataFilename(parsed.mimeType),
|
|
6126
|
+
guessInlineDataFilename(parsed.mimeType)
|
|
6127
|
+
),
|
|
6128
|
+
mimeType: parsed.mimeType,
|
|
6129
|
+
expiresAfterSeconds: DEFAULT_FILE_TTL_SECONDS
|
|
6130
|
+
});
|
|
6131
|
+
});
|
|
6132
|
+
return {
|
|
6133
|
+
type: "input_file",
|
|
6134
|
+
file_id: stored.id,
|
|
6135
|
+
filename: stored.filename
|
|
6136
|
+
};
|
|
6137
|
+
}
|
|
6138
|
+
return item;
|
|
6139
|
+
}
|
|
6140
|
+
async function maybeSpillToolOutput(value, toolName, options) {
|
|
6141
|
+
if (typeof value === "string") {
|
|
6142
|
+
if (options?.force !== true && import_node_buffer4.Buffer.byteLength(value, "utf8") <= TOOL_OUTPUT_SPILL_THRESHOLD_BYTES) {
|
|
6143
|
+
return value;
|
|
6144
|
+
}
|
|
6145
|
+
return await spillTextToolOutputToFile({
|
|
6146
|
+
text: value,
|
|
6147
|
+
filename: normaliseAttachmentFilename(`${toolName}.txt`, "tool-output.txt"),
|
|
6148
|
+
mimeType: "text/plain"
|
|
6149
|
+
});
|
|
6150
|
+
}
|
|
6151
|
+
if (isLlmToolOutputContentItem(value)) {
|
|
6152
|
+
return await maybeSpillToolOutputItem(value, toolName, options);
|
|
6153
|
+
}
|
|
6154
|
+
if (Array.isArray(value) && value.every((item) => isLlmToolOutputContentItem(item))) {
|
|
6155
|
+
const spilledItems = [];
|
|
6156
|
+
for (const item of value) {
|
|
6157
|
+
const maybeSpilled = await maybeSpillToolOutputItem(item, toolName, options);
|
|
6158
|
+
if (Array.isArray(maybeSpilled)) {
|
|
6159
|
+
spilledItems.push(...maybeSpilled);
|
|
6160
|
+
} else {
|
|
6161
|
+
spilledItems.push(maybeSpilled);
|
|
6162
|
+
}
|
|
6163
|
+
}
|
|
6164
|
+
return spilledItems;
|
|
6165
|
+
}
|
|
6166
|
+
try {
|
|
6167
|
+
const serialized = JSON.stringify(value, null, 2);
|
|
6168
|
+
if (options?.force !== true && import_node_buffer4.Buffer.byteLength(serialized, "utf8") <= TOOL_OUTPUT_SPILL_THRESHOLD_BYTES) {
|
|
6169
|
+
return value;
|
|
6170
|
+
}
|
|
6171
|
+
return await spillTextToolOutputToFile({
|
|
6172
|
+
text: serialized,
|
|
6173
|
+
filename: normaliseAttachmentFilename(`${toolName}.json`, "tool-output.json"),
|
|
6174
|
+
mimeType: "application/json"
|
|
6175
|
+
});
|
|
6176
|
+
} catch {
|
|
6177
|
+
return value;
|
|
6178
|
+
}
|
|
6179
|
+
}
|
|
6180
|
+
function estimateToolOutputPayloadBytes(value) {
|
|
6181
|
+
if (typeof value === "string") {
|
|
6182
|
+
return import_node_buffer4.Buffer.byteLength(value, "utf8");
|
|
6183
|
+
}
|
|
6184
|
+
if (isLlmToolOutputContentItem(value)) {
|
|
6185
|
+
return value.type === "input_text" ? 0 : estimateToolOutputItemBytes(value);
|
|
6186
|
+
}
|
|
6187
|
+
if (Array.isArray(value) && value.every((item) => isLlmToolOutputContentItem(item))) {
|
|
6188
|
+
return value.reduce((total, item) => {
|
|
6189
|
+
return total + (item.type === "input_text" ? 0 : estimateToolOutputItemBytes(item));
|
|
6190
|
+
}, 0);
|
|
6191
|
+
}
|
|
6192
|
+
return 0;
|
|
6193
|
+
}
|
|
6194
|
+
async function maybeSpillCombinedToolCallOutputs(callResults) {
|
|
6195
|
+
const totalBytes = callResults.reduce(
|
|
6196
|
+
(sum, callResult) => sum + estimateToolOutputPayloadBytes(callResult.outputPayload),
|
|
6197
|
+
0
|
|
6198
|
+
);
|
|
6199
|
+
if (totalBytes <= INLINE_ATTACHMENT_PROMPT_THRESHOLD_BYTES) {
|
|
6200
|
+
return Array.from(callResults);
|
|
6201
|
+
}
|
|
6202
|
+
return await Promise.all(
|
|
6203
|
+
callResults.map(async (callResult) => {
|
|
6204
|
+
if (estimateToolOutputPayloadBytes(callResult.outputPayload) === 0) {
|
|
6205
|
+
return callResult;
|
|
6206
|
+
}
|
|
6207
|
+
const outputPayload = await maybeSpillToolOutput(
|
|
6208
|
+
callResult.outputPayload,
|
|
6209
|
+
callResult.entry.toolName,
|
|
6210
|
+
{
|
|
6211
|
+
force: true
|
|
6212
|
+
}
|
|
6213
|
+
);
|
|
6214
|
+
return {
|
|
6215
|
+
...callResult,
|
|
6216
|
+
outputPayload,
|
|
6217
|
+
result: {
|
|
6218
|
+
...callResult.result,
|
|
6219
|
+
output: outputPayload
|
|
6220
|
+
}
|
|
6221
|
+
};
|
|
6222
|
+
})
|
|
6223
|
+
);
|
|
6224
|
+
}
|
|
6225
|
+
function buildGeminiToolOutputMediaPart(item) {
|
|
6226
|
+
if (item.type === "input_image") {
|
|
6227
|
+
if (typeof item.file_id === "string" && item.file_id.trim().length > 0) {
|
|
6228
|
+
return {
|
|
6229
|
+
fileData: {
|
|
6230
|
+
fileUri: buildCanonicalGeminiFileUri(item.file_id),
|
|
6231
|
+
mimeType: inferToolOutputMimeTypeFromFilename(item.filename) ?? "application/octet-stream"
|
|
6232
|
+
}
|
|
6233
|
+
};
|
|
6234
|
+
}
|
|
6235
|
+
if (typeof item.image_url !== "string" || item.image_url.trim().length === 0) {
|
|
4753
6236
|
return null;
|
|
4754
6237
|
}
|
|
4755
|
-
|
|
6238
|
+
const parsed = parseDataUrlPayload(item.image_url);
|
|
6239
|
+
if (parsed) {
|
|
6240
|
+
const part = (0, import_genai2.createPartFromBase64)(parsed.dataBase64, parsed.mimeType);
|
|
6241
|
+
const displayName = item.filename?.trim();
|
|
6242
|
+
if (displayName && part.inlineData) {
|
|
6243
|
+
part.inlineData.displayName = displayName;
|
|
6244
|
+
}
|
|
6245
|
+
return part;
|
|
6246
|
+
}
|
|
6247
|
+
return {
|
|
6248
|
+
fileData: {
|
|
6249
|
+
fileUri: item.image_url,
|
|
6250
|
+
mimeType: inferToolOutputMimeTypeFromFilename(item.filename) ?? "application/octet-stream"
|
|
6251
|
+
}
|
|
6252
|
+
};
|
|
4756
6253
|
}
|
|
4757
6254
|
if (item.type === "input_file") {
|
|
6255
|
+
if (typeof item.file_id === "string" && item.file_id.trim().length > 0) {
|
|
6256
|
+
return {
|
|
6257
|
+
fileData: {
|
|
6258
|
+
fileUri: buildCanonicalGeminiFileUri(item.file_id),
|
|
6259
|
+
mimeType: inferToolOutputMimeTypeFromFilename(item.filename) ?? "application/octet-stream"
|
|
6260
|
+
}
|
|
6261
|
+
};
|
|
6262
|
+
}
|
|
4758
6263
|
const dataUrl = typeof item.file_url === "string" ? parseDataUrlPayload(item.file_url) : null;
|
|
4759
6264
|
if (dataUrl) {
|
|
4760
6265
|
const part = (0, import_genai2.createPartFromBase64)(dataUrl.dataBase64, dataUrl.mimeType);
|
|
@@ -4774,12 +6279,7 @@ function buildGeminiToolOutputMediaPart(item) {
|
|
|
4774
6279
|
return part;
|
|
4775
6280
|
}
|
|
4776
6281
|
if (typeof item.file_url === "string" && item.file_url.trim().length > 0 && inferredMimeType) {
|
|
4777
|
-
|
|
4778
|
-
const displayName = item.filename?.trim();
|
|
4779
|
-
if (displayName && part.fileData) {
|
|
4780
|
-
part.fileData.displayName = displayName;
|
|
4781
|
-
}
|
|
4782
|
-
return part;
|
|
6282
|
+
return (0, import_genai2.createPartFromUri)(item.file_url, inferredMimeType);
|
|
4783
6283
|
}
|
|
4784
6284
|
}
|
|
4785
6285
|
return null;
|
|
@@ -4792,11 +6292,12 @@ function toGeminiToolOutputPlaceholder(item) {
|
|
|
4792
6292
|
};
|
|
4793
6293
|
}
|
|
4794
6294
|
if (item.type === "input_image") {
|
|
4795
|
-
const parsed = parseDataUrlPayload(item.image_url);
|
|
6295
|
+
const parsed = typeof item.image_url === "string" ? parseDataUrlPayload(item.image_url) : null;
|
|
4796
6296
|
return {
|
|
4797
6297
|
type: item.type,
|
|
6298
|
+
fileId: item.file_id ?? void 0,
|
|
4798
6299
|
mimeType: parsed?.mimeType ?? void 0,
|
|
4799
|
-
media: "attached-inline-data"
|
|
6300
|
+
media: item.file_id ? "attached-file-id" : parsed ? "attached-inline-data" : item.image_url ? "attached-file-data" : void 0
|
|
4800
6301
|
};
|
|
4801
6302
|
}
|
|
4802
6303
|
const dataUrl = typeof item.file_url === "string" ? parseDataUrlPayload(item.file_url) : null;
|
|
@@ -4805,7 +6306,7 @@ function toGeminiToolOutputPlaceholder(item) {
|
|
|
4805
6306
|
filename: item.filename ?? void 0,
|
|
4806
6307
|
fileId: item.file_id ?? void 0,
|
|
4807
6308
|
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
|
|
6309
|
+
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
6310
|
};
|
|
4810
6311
|
}
|
|
4811
6312
|
function buildGeminiFunctionResponseParts(options) {
|
|
@@ -4853,8 +6354,8 @@ function parseOpenAiToolArguments(raw) {
|
|
|
4853
6354
|
function formatZodIssues(issues) {
|
|
4854
6355
|
const messages = [];
|
|
4855
6356
|
for (const issue of issues) {
|
|
4856
|
-
const
|
|
4857
|
-
messages.push(`${
|
|
6357
|
+
const path10 = issue.path.length > 0 ? issue.path.map(String).join(".") : "input";
|
|
6358
|
+
messages.push(`${path10}: ${issue.message}`);
|
|
4858
6359
|
}
|
|
4859
6360
|
return messages.join("; ");
|
|
4860
6361
|
}
|
|
@@ -4972,8 +6473,9 @@ async function executeToolCall(params) {
|
|
|
4972
6473
|
const input = typeof rawInput === "string" ? rawInput : String(rawInput ?? "");
|
|
4973
6474
|
try {
|
|
4974
6475
|
const output = await tool2.execute(input);
|
|
4975
|
-
const
|
|
4976
|
-
|
|
6476
|
+
const outputPayload = await maybeSpillToolOutput(output, toolName);
|
|
6477
|
+
const metrics = toolName === "spawn_agent" ? extractSpawnStartupMetrics(outputPayload) : void 0;
|
|
6478
|
+
return finalize({ toolName, input, output: outputPayload }, outputPayload, metrics);
|
|
4977
6479
|
} catch (error) {
|
|
4978
6480
|
const message = error instanceof Error ? error.message : String(error);
|
|
4979
6481
|
const outputPayload = buildToolErrorOutput(`Tool ${toolName} failed: ${message}`);
|
|
@@ -5007,8 +6509,13 @@ async function executeToolCall(params) {
|
|
|
5007
6509
|
}
|
|
5008
6510
|
try {
|
|
5009
6511
|
const output = await tool2.execute(parsed.data);
|
|
5010
|
-
const
|
|
5011
|
-
|
|
6512
|
+
const outputPayload = await maybeSpillToolOutput(output, toolName);
|
|
6513
|
+
const metrics = toolName === "spawn_agent" ? extractSpawnStartupMetrics(outputPayload) : void 0;
|
|
6514
|
+
return finalize(
|
|
6515
|
+
{ toolName, input: parsed.data, output: outputPayload },
|
|
6516
|
+
outputPayload,
|
|
6517
|
+
metrics
|
|
6518
|
+
);
|
|
5012
6519
|
} catch (error) {
|
|
5013
6520
|
const message = error instanceof Error ? error.message : String(error);
|
|
5014
6521
|
const outputPayload = buildToolErrorOutput(`Tool ${toolName} failed: ${message}`);
|
|
@@ -5024,7 +6531,7 @@ function buildToolLogId(turn, toolIndex) {
|
|
|
5024
6531
|
function sanitizeChatGptToolId(value) {
|
|
5025
6532
|
const cleaned = value.replace(/[^A-Za-z0-9_-]/gu, "");
|
|
5026
6533
|
if (cleaned.length === 0) {
|
|
5027
|
-
return (0,
|
|
6534
|
+
return (0, import_node_crypto2.randomBytes)(8).toString("hex");
|
|
5028
6535
|
}
|
|
5029
6536
|
return cleaned.slice(0, 64);
|
|
5030
6537
|
}
|
|
@@ -5042,7 +6549,7 @@ function normalizeChatGptToolIds(params) {
|
|
|
5042
6549
|
rawCallId = nextCallId ?? rawCallId;
|
|
5043
6550
|
rawItemId = nextItemId ?? rawItemId;
|
|
5044
6551
|
}
|
|
5045
|
-
const callValue = sanitizeChatGptToolId(rawCallId || rawItemId || (0,
|
|
6552
|
+
const callValue = sanitizeChatGptToolId(rawCallId || rawItemId || (0, import_node_crypto2.randomBytes)(8).toString("hex"));
|
|
5046
6553
|
let itemValue = sanitizeChatGptToolId(rawItemId || callValue);
|
|
5047
6554
|
if (params.callKind === "custom") {
|
|
5048
6555
|
if (!itemValue.startsWith("ctc")) {
|
|
@@ -5209,7 +6716,7 @@ function toGemini25ProThinkingBudget(thinkingLevel) {
|
|
|
5209
6716
|
}
|
|
5210
6717
|
}
|
|
5211
6718
|
function resolveGeminiThinkingConfig(modelId, thinkingLevel) {
|
|
5212
|
-
if (isGeminiImageModelId(modelId)) {
|
|
6719
|
+
if (isGeminiImageModelId(modelId) || modelId === "gemini-flash-lite-latest") {
|
|
5213
6720
|
return void 0;
|
|
5214
6721
|
}
|
|
5215
6722
|
if (thinkingLevel) {
|
|
@@ -5240,9 +6747,9 @@ function resolveGeminiThinkingConfig(modelId, thinkingLevel) {
|
|
|
5240
6747
|
}
|
|
5241
6748
|
function decodeInlineDataBuffer(base64) {
|
|
5242
6749
|
try {
|
|
5243
|
-
return
|
|
6750
|
+
return import_node_buffer4.Buffer.from(base64, "base64");
|
|
5244
6751
|
} catch {
|
|
5245
|
-
return
|
|
6752
|
+
return import_node_buffer4.Buffer.from(base64, "base64url");
|
|
5246
6753
|
}
|
|
5247
6754
|
}
|
|
5248
6755
|
function extractImages(content) {
|
|
@@ -5312,7 +6819,7 @@ function parseDataUrlPayload(value) {
|
|
|
5312
6819
|
const isBase64 = /;base64(?:;|$)/iu.test(header);
|
|
5313
6820
|
const mimeType = (header.split(";")[0] ?? "application/octet-stream").trim().toLowerCase();
|
|
5314
6821
|
try {
|
|
5315
|
-
const bytes = isBase64 ?
|
|
6822
|
+
const bytes = isBase64 ? import_node_buffer4.Buffer.from(payload, "base64") : import_node_buffer4.Buffer.from(decodeURIComponent(payload), "utf8");
|
|
5316
6823
|
return {
|
|
5317
6824
|
mimeType,
|
|
5318
6825
|
dataBase64: bytes.toString("base64"),
|
|
@@ -5415,7 +6922,10 @@ function collectLoggedAttachmentsFromLlmParts(parts, prefix) {
|
|
|
5415
6922
|
continue;
|
|
5416
6923
|
}
|
|
5417
6924
|
attachments.push({
|
|
5418
|
-
filename:
|
|
6925
|
+
filename: normaliseAttachmentFilename(
|
|
6926
|
+
part.filename,
|
|
6927
|
+
buildLoggedAttachmentFilename(prefix, index, part.mimeType)
|
|
6928
|
+
),
|
|
5419
6929
|
bytes: decodeInlineDataBuffer(part.data)
|
|
5420
6930
|
});
|
|
5421
6931
|
index += 1;
|
|
@@ -5544,15 +7054,19 @@ function startLlmCallLoggerFromContents(options) {
|
|
|
5544
7054
|
sections.push(part.text);
|
|
5545
7055
|
continue;
|
|
5546
7056
|
}
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
7057
|
+
if (part.type === "inlineData") {
|
|
7058
|
+
const filename = buildLoggedAttachmentFilename("input", attachmentIndex, part.mimeType);
|
|
7059
|
+
attachments.push({
|
|
7060
|
+
filename,
|
|
7061
|
+
bytes: decodeInlineDataBuffer(part.data)
|
|
7062
|
+
});
|
|
7063
|
+
attachmentIndex += 1;
|
|
7064
|
+
sections.push(
|
|
7065
|
+
`[inlineData] file=${filename} mime=${part.mimeType ?? "application/octet-stream"} bytes=${attachments[attachments.length - 1]?.bytes.byteLength ?? 0}`
|
|
7066
|
+
);
|
|
7067
|
+
continue;
|
|
7068
|
+
}
|
|
7069
|
+
sections.push(`[${part.type}] file_id=${"file_id" in part ? part.file_id ?? "" : ""}`);
|
|
5556
7070
|
}
|
|
5557
7071
|
sections.push("");
|
|
5558
7072
|
}
|
|
@@ -5683,307 +7197,317 @@ async function runTextCall(params) {
|
|
|
5683
7197
|
return abortController.signal;
|
|
5684
7198
|
};
|
|
5685
7199
|
const signal = resolveAbortSignal();
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
};
|
|
5695
|
-
const reasoning = {
|
|
5696
|
-
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
5697
|
-
summary: "detailed"
|
|
5698
|
-
};
|
|
5699
|
-
await runOpenAiCall(async (client) => {
|
|
5700
|
-
const stream = client.responses.stream(
|
|
5701
|
-
{
|
|
5702
|
-
model: modelForProvider,
|
|
5703
|
-
input: openAiInput,
|
|
5704
|
-
reasoning,
|
|
5705
|
-
text: openAiTextConfig,
|
|
5706
|
-
...openAiTools ? { tools: openAiTools } : {},
|
|
5707
|
-
include: ["code_interpreter_call.outputs", "reasoning.encrypted_content"]
|
|
5708
|
-
},
|
|
5709
|
-
{ signal }
|
|
7200
|
+
const { result } = await collectFileUploadMetrics(async () => {
|
|
7201
|
+
try {
|
|
7202
|
+
if (provider === "openai") {
|
|
7203
|
+
const openAiInput = await maybePrepareOpenAiPromptInput(toOpenAiInput(contents));
|
|
7204
|
+
const openAiTools = toOpenAiTools(request.tools);
|
|
7205
|
+
const reasoningEffort = resolveOpenAiReasoningEffort(
|
|
7206
|
+
modelForProvider,
|
|
7207
|
+
request.thinkingLevel
|
|
5710
7208
|
);
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
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})` : ""}`
|
|
7209
|
+
const openAiTextConfig = {
|
|
7210
|
+
format: request.openAiTextFormat ?? { type: "text" },
|
|
7211
|
+
verbosity: resolveOpenAiVerbosity(modelForProvider)
|
|
7212
|
+
};
|
|
7213
|
+
const reasoning = {
|
|
7214
|
+
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
7215
|
+
summary: "detailed"
|
|
7216
|
+
};
|
|
7217
|
+
await runOpenAiCall(async (client) => {
|
|
7218
|
+
const stream = client.responses.stream(
|
|
7219
|
+
{
|
|
7220
|
+
model: modelForProvider,
|
|
7221
|
+
input: openAiInput,
|
|
7222
|
+
reasoning,
|
|
7223
|
+
text: openAiTextConfig,
|
|
7224
|
+
...openAiTools ? { tools: openAiTools } : {},
|
|
7225
|
+
include: ["code_interpreter_call.outputs", "reasoning.encrypted_content"]
|
|
7226
|
+
},
|
|
7227
|
+
{ signal }
|
|
5743
7228
|
);
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
7229
|
+
for await (const event of stream) {
|
|
7230
|
+
switch (event.type) {
|
|
7231
|
+
case "response.output_text.delta": {
|
|
7232
|
+
const delta = event.delta ?? "";
|
|
7233
|
+
pushDelta("response", typeof delta === "string" ? delta : "");
|
|
7234
|
+
break;
|
|
7235
|
+
}
|
|
7236
|
+
case "response.reasoning_summary_text.delta": {
|
|
7237
|
+
const delta = event.delta ?? "";
|
|
7238
|
+
pushDelta("thought", typeof delta === "string" ? delta : "");
|
|
7239
|
+
break;
|
|
7240
|
+
}
|
|
7241
|
+
case "response.refusal.delta": {
|
|
7242
|
+
blocked = true;
|
|
7243
|
+
queue.push({ type: "blocked" });
|
|
7244
|
+
break;
|
|
7245
|
+
}
|
|
7246
|
+
default:
|
|
7247
|
+
break;
|
|
5754
7248
|
}
|
|
5755
7249
|
}
|
|
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);
|
|
7250
|
+
const finalResponse = await stream.finalResponse();
|
|
7251
|
+
modelVersion = typeof finalResponse.model === "string" ? finalResponse.model : request.model;
|
|
7252
|
+
queue.push({ type: "model", modelVersion });
|
|
7253
|
+
if (finalResponse.error) {
|
|
7254
|
+
const message = typeof finalResponse.error.message === "string" ? finalResponse.error.message : "OpenAI response failed";
|
|
7255
|
+
throw new Error(message);
|
|
5789
7256
|
}
|
|
5790
|
-
if (
|
|
5791
|
-
|
|
5792
|
-
|
|
7257
|
+
if (finalResponse.status && finalResponse.status !== "completed" && finalResponse.status !== "in_progress") {
|
|
7258
|
+
const detail = finalResponse.incomplete_details?.reason;
|
|
7259
|
+
throw new Error(
|
|
7260
|
+
`OpenAI response status ${finalResponse.status}${detail ? ` (${detail})` : ""}`
|
|
7261
|
+
);
|
|
5793
7262
|
}
|
|
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
|
|
7263
|
+
latestUsage = extractOpenAiUsageTokens(finalResponse.usage);
|
|
7264
|
+
if (responseParts.length === 0) {
|
|
7265
|
+
const fallback = extractOpenAiResponseParts(finalResponse);
|
|
7266
|
+
blocked = blocked || fallback.blocked;
|
|
7267
|
+
for (const part of fallback.parts) {
|
|
7268
|
+
if (part.type === "text") {
|
|
7269
|
+
pushDelta(part.thought === true ? "thought" : "response", part.text);
|
|
7270
|
+
} else if (part.type === "inlineData") {
|
|
7271
|
+
pushInline(part.data, part.mimeType);
|
|
7272
|
+
}
|
|
7273
|
+
}
|
|
5829
7274
|
}
|
|
5830
|
-
}
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
7275
|
+
}, modelForProvider);
|
|
7276
|
+
} else if (provider === "chatgpt") {
|
|
7277
|
+
const chatGptInput = toChatGptInput(contents);
|
|
7278
|
+
const reasoningEffort = resolveOpenAiReasoningEffort(request.model, request.thinkingLevel);
|
|
7279
|
+
const openAiTools = toOpenAiTools(request.tools);
|
|
7280
|
+
const requestPayload = {
|
|
7281
|
+
model: modelForProvider,
|
|
7282
|
+
store: false,
|
|
7283
|
+
stream: true,
|
|
7284
|
+
...providerInfo.serviceTier ? { service_tier: providerInfo.serviceTier } : {},
|
|
7285
|
+
instructions: chatGptInput.instructions ?? "You are a helpful assistant.",
|
|
7286
|
+
input: chatGptInput.input,
|
|
7287
|
+
include: ["reasoning.encrypted_content"],
|
|
7288
|
+
reasoning: {
|
|
7289
|
+
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
7290
|
+
summary: "detailed"
|
|
5836
7291
|
},
|
|
5837
|
-
{
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
7292
|
+
text: {
|
|
7293
|
+
format: request.openAiTextFormat ?? { type: "text" },
|
|
7294
|
+
verbosity: resolveOpenAiVerbosity(request.model)
|
|
7295
|
+
},
|
|
7296
|
+
...openAiTools ? { tools: openAiTools } : {}
|
|
7297
|
+
};
|
|
7298
|
+
let sawResponseDelta = false;
|
|
7299
|
+
let sawThoughtDelta = false;
|
|
7300
|
+
const result2 = await collectChatGptCodexResponseWithRetry({
|
|
7301
|
+
request: requestPayload,
|
|
7302
|
+
signal,
|
|
7303
|
+
onDelta: (delta) => {
|
|
7304
|
+
if (delta.thoughtDelta) {
|
|
7305
|
+
sawThoughtDelta = true;
|
|
7306
|
+
pushDelta("thought", delta.thoughtDelta);
|
|
7307
|
+
}
|
|
7308
|
+
if (delta.textDelta) {
|
|
7309
|
+
sawResponseDelta = true;
|
|
7310
|
+
pushDelta("response", delta.textDelta);
|
|
7311
|
+
}
|
|
7312
|
+
}
|
|
7313
|
+
});
|
|
7314
|
+
blocked = blocked || result2.blocked;
|
|
7315
|
+
if (blocked) {
|
|
5844
7316
|
queue.push({ type: "blocked" });
|
|
5845
7317
|
}
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
if (textOutput.length > 0) {
|
|
5850
|
-
pushDelta("response", textOutput);
|
|
7318
|
+
if (result2.model) {
|
|
7319
|
+
modelVersion = providerInfo.serviceTier ? request.model : `chatgpt-${result2.model}`;
|
|
7320
|
+
queue.push({ type: "model", modelVersion });
|
|
5851
7321
|
}
|
|
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
|
|
7322
|
+
latestUsage = extractChatGptUsageTokens(result2.usage);
|
|
7323
|
+
const fallbackText = typeof result2.text === "string" ? result2.text : "";
|
|
7324
|
+
const fallbackThoughts = typeof result2.reasoningSummaryText === "string" && result2.reasoningSummaryText.length > 0 ? result2.reasoningSummaryText : typeof result2.reasoningText === "string" ? result2.reasoningText : "";
|
|
7325
|
+
if (!sawThoughtDelta && fallbackThoughts.length > 0) {
|
|
7326
|
+
pushDelta("thought", fallbackThoughts);
|
|
7327
|
+
}
|
|
7328
|
+
if (!sawResponseDelta && fallbackText.length > 0) {
|
|
7329
|
+
pushDelta("response", fallbackText);
|
|
7330
|
+
}
|
|
7331
|
+
} else if (provider === "fireworks") {
|
|
7332
|
+
if (request.tools && request.tools.length > 0) {
|
|
7333
|
+
throw new Error(
|
|
7334
|
+
"Fireworks provider does not support provider-native tools in generateText; use runToolLoop for function tools."
|
|
7335
|
+
);
|
|
7336
|
+
}
|
|
7337
|
+
const fireworksMessages = toFireworksMessages(contents, {
|
|
7338
|
+
responseMimeType: request.responseMimeType,
|
|
7339
|
+
responseJsonSchema: request.responseJsonSchema
|
|
5879
7340
|
});
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
7341
|
+
await runFireworksCall(async (client) => {
|
|
7342
|
+
const responseFormat = request.responseJsonSchema ? {
|
|
7343
|
+
type: "json_schema",
|
|
7344
|
+
json_schema: {
|
|
7345
|
+
name: "llm-response",
|
|
7346
|
+
schema: request.responseJsonSchema
|
|
7347
|
+
}
|
|
7348
|
+
} : request.responseMimeType === "application/json" ? { type: "json_object" } : void 0;
|
|
7349
|
+
const response = await client.chat.completions.create(
|
|
7350
|
+
{
|
|
7351
|
+
model: modelForProvider,
|
|
7352
|
+
messages: fireworksMessages,
|
|
7353
|
+
...responseFormat ? { response_format: responseFormat } : {}
|
|
7354
|
+
},
|
|
7355
|
+
{ signal }
|
|
7356
|
+
);
|
|
7357
|
+
modelVersion = typeof response.model === "string" ? response.model : request.model;
|
|
7358
|
+
queue.push({ type: "model", modelVersion });
|
|
7359
|
+
const choice = Array.isArray(response.choices) ? response.choices[0] : void 0;
|
|
7360
|
+
if (choice?.finish_reason === "content_filter") {
|
|
5887
7361
|
blocked = true;
|
|
5888
7362
|
queue.push({ type: "blocked" });
|
|
5889
7363
|
}
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
extractGeminiUsageTokens(chunk.usageMetadata)
|
|
7364
|
+
const textOutput = extractFireworksMessageText(
|
|
7365
|
+
choice?.message
|
|
5893
7366
|
);
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
continue;
|
|
5897
|
-
}
|
|
5898
|
-
const primary = candidates[0];
|
|
5899
|
-
if (primary && isModerationFinish(primary.finishReason)) {
|
|
5900
|
-
blocked = true;
|
|
5901
|
-
queue.push({ type: "blocked" });
|
|
7367
|
+
if (textOutput.length > 0) {
|
|
7368
|
+
pushDelta("response", textOutput);
|
|
5902
7369
|
}
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
7370
|
+
latestUsage = extractFireworksUsageTokens(response.usage);
|
|
7371
|
+
}, modelForProvider);
|
|
7372
|
+
} else {
|
|
7373
|
+
const geminiContents = await maybePrepareGeminiPromptContents(
|
|
7374
|
+
contents.map(convertLlmContentToGeminiContent)
|
|
7375
|
+
);
|
|
7376
|
+
const thinkingConfig = resolveGeminiThinkingConfig(modelForProvider, request.thinkingLevel);
|
|
7377
|
+
const config = {
|
|
7378
|
+
maxOutputTokens: 32e3,
|
|
7379
|
+
...thinkingConfig ? { thinkingConfig } : {},
|
|
7380
|
+
...request.responseMimeType ? { responseMimeType: request.responseMimeType } : {},
|
|
7381
|
+
...request.responseJsonSchema ? { responseJsonSchema: request.responseJsonSchema } : {},
|
|
7382
|
+
...request.responseModalities ? { responseModalities: Array.from(request.responseModalities) } : {},
|
|
7383
|
+
...request.imageAspectRatio || request.imageSize ? {
|
|
7384
|
+
imageConfig: {
|
|
7385
|
+
...request.imageAspectRatio ? { aspectRatio: request.imageAspectRatio } : {},
|
|
7386
|
+
...request.imageSize ? { imageSize: request.imageSize } : {}
|
|
7387
|
+
}
|
|
7388
|
+
} : {}
|
|
7389
|
+
};
|
|
7390
|
+
const geminiTools = toGeminiTools(request.tools);
|
|
7391
|
+
if (geminiTools) {
|
|
7392
|
+
config.tools = geminiTools;
|
|
7393
|
+
}
|
|
7394
|
+
await runGeminiCall(async (client) => {
|
|
7395
|
+
const stream = await client.models.generateContentStream({
|
|
7396
|
+
model: modelForProvider,
|
|
7397
|
+
contents: geminiContents,
|
|
7398
|
+
config
|
|
7399
|
+
});
|
|
7400
|
+
let latestGrounding;
|
|
7401
|
+
for await (const chunk of stream) {
|
|
7402
|
+
if (chunk.modelVersion) {
|
|
7403
|
+
modelVersion = chunk.modelVersion;
|
|
7404
|
+
queue.push({ type: "model", modelVersion });
|
|
5907
7405
|
}
|
|
5908
|
-
if (
|
|
5909
|
-
|
|
7406
|
+
if (chunk.promptFeedback?.blockReason) {
|
|
7407
|
+
blocked = true;
|
|
7408
|
+
queue.push({ type: "blocked" });
|
|
5910
7409
|
}
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
7410
|
+
latestUsage = mergeTokenUpdates(
|
|
7411
|
+
latestUsage,
|
|
7412
|
+
extractGeminiUsageTokens(chunk.usageMetadata)
|
|
7413
|
+
);
|
|
7414
|
+
const candidates = chunk.candidates;
|
|
7415
|
+
if (!candidates || candidates.length === 0) {
|
|
7416
|
+
continue;
|
|
5914
7417
|
}
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
7418
|
+
const primary = candidates[0];
|
|
7419
|
+
if (primary && isModerationFinish(primary.finishReason)) {
|
|
7420
|
+
blocked = true;
|
|
7421
|
+
queue.push({ type: "blocked" });
|
|
7422
|
+
}
|
|
7423
|
+
for (const candidate of candidates) {
|
|
7424
|
+
const candidateContent = candidate.content;
|
|
7425
|
+
if (!candidateContent) {
|
|
7426
|
+
continue;
|
|
7427
|
+
}
|
|
7428
|
+
if (candidate.groundingMetadata) {
|
|
7429
|
+
latestGrounding = candidate.groundingMetadata;
|
|
7430
|
+
}
|
|
7431
|
+
const content2 = convertGeminiContentToLlmContent(candidateContent);
|
|
7432
|
+
if (!responseRole) {
|
|
7433
|
+
responseRole = content2.role;
|
|
7434
|
+
}
|
|
7435
|
+
for (const part of content2.parts) {
|
|
7436
|
+
if (part.type === "text") {
|
|
7437
|
+
pushDelta(part.thought === true ? "thought" : "response", part.text);
|
|
7438
|
+
} else if (part.type === "inlineData") {
|
|
7439
|
+
pushInline(part.data, part.mimeType);
|
|
7440
|
+
}
|
|
5920
7441
|
}
|
|
5921
7442
|
}
|
|
5922
7443
|
}
|
|
7444
|
+
grounding = latestGrounding;
|
|
7445
|
+
}, modelForProvider);
|
|
7446
|
+
}
|
|
7447
|
+
const mergedParts = mergeConsecutiveTextParts(responseParts);
|
|
7448
|
+
const content = mergedParts.length > 0 ? { role: responseRole ?? "assistant", parts: mergedParts } : void 0;
|
|
7449
|
+
const { text, thoughts } = extractTextByChannel(content);
|
|
7450
|
+
const outputAttachments = collectLoggedAttachmentsFromLlmParts(mergedParts, "output");
|
|
7451
|
+
const costUsd = estimateCallCostUsd({
|
|
7452
|
+
modelId: modelVersion,
|
|
7453
|
+
tokens: latestUsage,
|
|
7454
|
+
responseImages,
|
|
7455
|
+
imageSize: request.imageSize
|
|
7456
|
+
});
|
|
7457
|
+
if (latestUsage) {
|
|
7458
|
+
queue.push({ type: "usage", usage: latestUsage, costUsd, modelVersion });
|
|
7459
|
+
}
|
|
7460
|
+
callLogger?.complete({
|
|
7461
|
+
responseText: text,
|
|
7462
|
+
attachments: outputAttachments,
|
|
7463
|
+
metadata: {
|
|
7464
|
+
provider,
|
|
7465
|
+
model: request.model,
|
|
7466
|
+
modelVersion,
|
|
7467
|
+
blocked,
|
|
7468
|
+
costUsd,
|
|
7469
|
+
usage: latestUsage,
|
|
7470
|
+
grounding: grounding ? sanitiseLogValue(grounding) : void 0,
|
|
7471
|
+
responseChars: text.length,
|
|
7472
|
+
thoughtChars: thoughts.length,
|
|
7473
|
+
responseImages,
|
|
7474
|
+
uploads: getCurrentFileUploadMetrics()
|
|
5923
7475
|
}
|
|
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: {
|
|
7476
|
+
});
|
|
7477
|
+
return {
|
|
5976
7478
|
provider,
|
|
5977
7479
|
model: request.model,
|
|
5978
7480
|
modelVersion,
|
|
7481
|
+
content,
|
|
7482
|
+
text,
|
|
7483
|
+
thoughts,
|
|
5979
7484
|
blocked,
|
|
5980
7485
|
usage: latestUsage,
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
}
|
|
5984
|
-
})
|
|
5985
|
-
|
|
5986
|
-
|
|
7486
|
+
costUsd,
|
|
7487
|
+
grounding
|
|
7488
|
+
};
|
|
7489
|
+
} catch (error) {
|
|
7490
|
+
const partialParts = mergeConsecutiveTextParts(responseParts);
|
|
7491
|
+
const partialContent = partialParts.length > 0 ? { role: responseRole ?? "assistant", parts: partialParts } : void 0;
|
|
7492
|
+
const { text: partialText } = extractTextByChannel(partialContent);
|
|
7493
|
+
callLogger?.fail(error, {
|
|
7494
|
+
responseText: partialText,
|
|
7495
|
+
attachments: collectLoggedAttachmentsFromLlmParts(partialParts, "output"),
|
|
7496
|
+
metadata: {
|
|
7497
|
+
provider,
|
|
7498
|
+
model: request.model,
|
|
7499
|
+
modelVersion,
|
|
7500
|
+
blocked,
|
|
7501
|
+
usage: latestUsage,
|
|
7502
|
+
partialResponseParts: responseParts.length,
|
|
7503
|
+
responseImages,
|
|
7504
|
+
uploads: getCurrentFileUploadMetrics()
|
|
7505
|
+
}
|
|
7506
|
+
});
|
|
7507
|
+
throw error;
|
|
7508
|
+
}
|
|
7509
|
+
});
|
|
7510
|
+
return result;
|
|
5987
7511
|
}
|
|
5988
7512
|
function streamText(request) {
|
|
5989
7513
|
const queue = createAsyncQueue();
|
|
@@ -6266,7 +7790,12 @@ function normalizeToolLoopSteeringInput(input) {
|
|
|
6266
7790
|
if (part.type === "text") {
|
|
6267
7791
|
parts.push({ type: "text", text: part.text });
|
|
6268
7792
|
} else {
|
|
6269
|
-
parts.push({
|
|
7793
|
+
parts.push({
|
|
7794
|
+
type: "inlineData",
|
|
7795
|
+
data: part.data,
|
|
7796
|
+
mimeType: part.mimeType,
|
|
7797
|
+
filename: part.filename
|
|
7798
|
+
});
|
|
6270
7799
|
}
|
|
6271
7800
|
}
|
|
6272
7801
|
if (parts.length > 0) {
|
|
@@ -6454,9 +7983,10 @@ async function runToolLoop(request) {
|
|
|
6454
7983
|
let reasoningSummary = "";
|
|
6455
7984
|
let stepToolCallText;
|
|
6456
7985
|
let stepToolCallPayload;
|
|
7986
|
+
const preparedInput = await maybePrepareOpenAiPromptInput(input);
|
|
6457
7987
|
const stepRequestPayload = {
|
|
6458
7988
|
model: providerInfo.model,
|
|
6459
|
-
input,
|
|
7989
|
+
input: preparedInput,
|
|
6460
7990
|
...previousResponseId ? { previous_response_id: previousResponseId } : {},
|
|
6461
7991
|
...openAiTools.length > 0 ? { tools: openAiTools } : {},
|
|
6462
7992
|
...openAiTools.length > 0 ? { parallel_tool_calls: true } : {},
|
|
@@ -6484,7 +8014,7 @@ async function runToolLoop(request) {
|
|
|
6484
8014
|
const stream = client.responses.stream(
|
|
6485
8015
|
{
|
|
6486
8016
|
model: providerInfo.model,
|
|
6487
|
-
input,
|
|
8017
|
+
input: preparedInput,
|
|
6488
8018
|
...previousResponseId ? { previous_response_id: previousResponseId } : {},
|
|
6489
8019
|
...openAiTools.length > 0 ? { tools: openAiTools } : {},
|
|
6490
8020
|
...openAiTools.length > 0 ? { parallel_tool_calls: true } : {},
|
|
@@ -6661,27 +8191,29 @@ async function runToolLoop(request) {
|
|
|
6661
8191
|
input: entry.value
|
|
6662
8192
|
});
|
|
6663
8193
|
}
|
|
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,
|
|
8194
|
+
const callResults = await maybeSpillCombinedToolCallOutputs(
|
|
8195
|
+
await Promise.all(
|
|
8196
|
+
callInputs.map(async (entry) => {
|
|
8197
|
+
return await toolCallContextStorage.run(
|
|
8198
|
+
{
|
|
6676
8199
|
toolName: entry.toolName,
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
}
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
8200
|
+
toolId: entry.toolId,
|
|
8201
|
+
turn: entry.turn,
|
|
8202
|
+
toolIndex: entry.toolIndex
|
|
8203
|
+
},
|
|
8204
|
+
async () => {
|
|
8205
|
+
const { result, outputPayload } = await executeToolCall({
|
|
8206
|
+
callKind: entry.call.kind,
|
|
8207
|
+
toolName: entry.toolName,
|
|
8208
|
+
tool: request.tools[entry.toolName],
|
|
8209
|
+
rawInput: entry.value,
|
|
8210
|
+
parseError: entry.parseError
|
|
8211
|
+
});
|
|
8212
|
+
return { entry, result, outputPayload };
|
|
8213
|
+
}
|
|
8214
|
+
);
|
|
8215
|
+
})
|
|
8216
|
+
)
|
|
6685
8217
|
);
|
|
6686
8218
|
const toolOutputs = [];
|
|
6687
8219
|
let toolExecutionMs = 0;
|
|
@@ -6788,7 +8320,7 @@ async function runToolLoop(request) {
|
|
|
6788
8320
|
const openAiTools = openAiNativeTools ? [...openAiNativeTools, ...openAiAgentTools] : [...openAiAgentTools];
|
|
6789
8321
|
const reasoningEffort = resolveOpenAiReasoningEffort(request.model, request.thinkingLevel);
|
|
6790
8322
|
const toolLoopInput = toChatGptInput(contents);
|
|
6791
|
-
const conversationId = `tool-loop-${(0,
|
|
8323
|
+
const conversationId = `tool-loop-${(0, import_node_crypto2.randomBytes)(8).toString("hex")}`;
|
|
6792
8324
|
const promptCacheKey = conversationId;
|
|
6793
8325
|
let input = [...toolLoopInput.input];
|
|
6794
8326
|
for (let stepIndex = 0; stepIndex < maxSteps; stepIndex += 1) {
|
|
@@ -6962,27 +8494,29 @@ async function runToolLoop(request) {
|
|
|
6962
8494
|
input: entry.value
|
|
6963
8495
|
});
|
|
6964
8496
|
}
|
|
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,
|
|
8497
|
+
const callResults = await maybeSpillCombinedToolCallOutputs(
|
|
8498
|
+
await Promise.all(
|
|
8499
|
+
callInputs.map(async (entry) => {
|
|
8500
|
+
return await toolCallContextStorage.run(
|
|
8501
|
+
{
|
|
6977
8502
|
toolName: entry.toolName,
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
}
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
8503
|
+
toolId: entry.toolId,
|
|
8504
|
+
turn: entry.turn,
|
|
8505
|
+
toolIndex: entry.toolIndex
|
|
8506
|
+
},
|
|
8507
|
+
async () => {
|
|
8508
|
+
const { result, outputPayload } = await executeToolCall({
|
|
8509
|
+
callKind: entry.call.kind,
|
|
8510
|
+
toolName: entry.toolName,
|
|
8511
|
+
tool: request.tools[entry.toolName],
|
|
8512
|
+
rawInput: entry.value,
|
|
8513
|
+
parseError: entry.parseError
|
|
8514
|
+
});
|
|
8515
|
+
return { entry, result, outputPayload };
|
|
8516
|
+
}
|
|
8517
|
+
);
|
|
8518
|
+
})
|
|
8519
|
+
)
|
|
6986
8520
|
);
|
|
6987
8521
|
let toolExecutionMs = 0;
|
|
6988
8522
|
let waitToolMs = 0;
|
|
@@ -7254,27 +8788,29 @@ async function runToolLoop(request) {
|
|
|
7254
8788
|
input: entry.value
|
|
7255
8789
|
});
|
|
7256
8790
|
}
|
|
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",
|
|
8791
|
+
const callResults = await maybeSpillCombinedToolCallOutputs(
|
|
8792
|
+
await Promise.all(
|
|
8793
|
+
callInputs.map(async (entry) => {
|
|
8794
|
+
return await toolCallContextStorage.run(
|
|
8795
|
+
{
|
|
7269
8796
|
toolName: entry.toolName,
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
}
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
|
|
7277
|
-
|
|
8797
|
+
toolId: entry.toolId,
|
|
8798
|
+
turn: entry.turn,
|
|
8799
|
+
toolIndex: entry.toolIndex
|
|
8800
|
+
},
|
|
8801
|
+
async () => {
|
|
8802
|
+
const { result, outputPayload } = await executeToolCall({
|
|
8803
|
+
callKind: "function",
|
|
8804
|
+
toolName: entry.toolName,
|
|
8805
|
+
tool: request.tools[entry.toolName],
|
|
8806
|
+
rawInput: entry.value,
|
|
8807
|
+
parseError: entry.parseError
|
|
8808
|
+
});
|
|
8809
|
+
return { entry, result, outputPayload };
|
|
8810
|
+
}
|
|
8811
|
+
);
|
|
8812
|
+
})
|
|
8813
|
+
)
|
|
7278
8814
|
);
|
|
7279
8815
|
const assistantToolCalls = [];
|
|
7280
8816
|
const toolMessages = [];
|
|
@@ -7413,9 +8949,10 @@ async function runToolLoop(request) {
|
|
|
7413
8949
|
...thinkingConfig ? { thinkingConfig } : {}
|
|
7414
8950
|
};
|
|
7415
8951
|
const onEvent = request.onEvent;
|
|
8952
|
+
const preparedGeminiContents = await maybePrepareGeminiPromptContents(geminiContents);
|
|
7416
8953
|
const stepRequestPayload = {
|
|
7417
8954
|
model: request.model,
|
|
7418
|
-
contents:
|
|
8955
|
+
contents: preparedGeminiContents,
|
|
7419
8956
|
config
|
|
7420
8957
|
};
|
|
7421
8958
|
const stepCallLogger = startLlmCallLoggerFromPayload({
|
|
@@ -7429,7 +8966,7 @@ async function runToolLoop(request) {
|
|
|
7429
8966
|
async (client) => {
|
|
7430
8967
|
const stream = await client.models.generateContentStream({
|
|
7431
8968
|
model: request.model,
|
|
7432
|
-
contents:
|
|
8969
|
+
contents: preparedGeminiContents,
|
|
7433
8970
|
config
|
|
7434
8971
|
});
|
|
7435
8972
|
let responseText2 = "";
|
|
@@ -7605,26 +9142,28 @@ async function runToolLoop(request) {
|
|
|
7605
9142
|
input: entry.rawInput
|
|
7606
9143
|
});
|
|
7607
9144
|
}
|
|
7608
|
-
const callResults = await
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
toolId: entry.toolId,
|
|
7614
|
-
turn: entry.turn,
|
|
7615
|
-
toolIndex: entry.toolIndex
|
|
7616
|
-
},
|
|
7617
|
-
async () => {
|
|
7618
|
-
const { result, outputPayload } = await executeToolCall({
|
|
7619
|
-
callKind: "function",
|
|
9145
|
+
const callResults = await maybeSpillCombinedToolCallOutputs(
|
|
9146
|
+
await Promise.all(
|
|
9147
|
+
callInputs.map(async (entry) => {
|
|
9148
|
+
return await toolCallContextStorage.run(
|
|
9149
|
+
{
|
|
7620
9150
|
toolName: entry.toolName,
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
9151
|
+
toolId: entry.toolId,
|
|
9152
|
+
turn: entry.turn,
|
|
9153
|
+
toolIndex: entry.toolIndex
|
|
9154
|
+
},
|
|
9155
|
+
async () => {
|
|
9156
|
+
const { result, outputPayload } = await executeToolCall({
|
|
9157
|
+
callKind: "function",
|
|
9158
|
+
toolName: entry.toolName,
|
|
9159
|
+
tool: request.tools[entry.toolName],
|
|
9160
|
+
rawInput: entry.rawInput
|
|
9161
|
+
});
|
|
9162
|
+
return { entry, result, outputPayload };
|
|
9163
|
+
}
|
|
9164
|
+
);
|
|
9165
|
+
})
|
|
9166
|
+
)
|
|
7628
9167
|
);
|
|
7629
9168
|
let toolExecutionMs = 0;
|
|
7630
9169
|
let waitToolMs = 0;
|
|
@@ -8028,11 +9567,11 @@ ${lines}`;
|
|
|
8028
9567
|
}
|
|
8029
9568
|
|
|
8030
9569
|
// src/agent.ts
|
|
8031
|
-
var
|
|
8032
|
-
var
|
|
9570
|
+
var import_node_crypto4 = require("crypto");
|
|
9571
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
8033
9572
|
|
|
8034
9573
|
// src/agent/subagents.ts
|
|
8035
|
-
var
|
|
9574
|
+
var import_node_crypto3 = require("crypto");
|
|
8036
9575
|
var import_zod4 = require("zod");
|
|
8037
9576
|
var DEFAULT_SUBAGENT_MAX_AGENTS = 6;
|
|
8038
9577
|
var DEFAULT_SUBAGENT_MAX_DEPTH = 1;
|
|
@@ -8252,7 +9791,7 @@ function createSubagentToolController(options) {
|
|
|
8252
9791
|
}
|
|
8253
9792
|
model = input.model;
|
|
8254
9793
|
}
|
|
8255
|
-
const id = `agent_${(0,
|
|
9794
|
+
const id = `agent_${(0, import_node_crypto3.randomBytes)(6).toString("hex")}`;
|
|
8256
9795
|
const now = Date.now();
|
|
8257
9796
|
const { roleName, roleInstructions } = resolveAgentType(input.agent_type);
|
|
8258
9797
|
const nickname = reserveAgentNickname(roleName, roleNicknameCounts);
|
|
@@ -8504,26 +10043,26 @@ function resolveInputItemsText(items) {
|
|
|
8504
10043
|
}
|
|
8505
10044
|
const itemType = typeof item.type === "string" ? item.type.trim() : "";
|
|
8506
10045
|
const name = typeof item.name === "string" ? item.name.trim() : "";
|
|
8507
|
-
const
|
|
10046
|
+
const path10 = typeof item.path === "string" ? item.path.trim() : "";
|
|
8508
10047
|
const imageUrl = typeof item.image_url === "string" ? item.image_url.trim() : "";
|
|
8509
10048
|
if (itemType === "image") {
|
|
8510
10049
|
lines.push("[image]");
|
|
8511
10050
|
continue;
|
|
8512
10051
|
}
|
|
8513
|
-
if (itemType === "local_image" &&
|
|
8514
|
-
lines.push(`[local_image:${
|
|
10052
|
+
if (itemType === "local_image" && path10) {
|
|
10053
|
+
lines.push(`[local_image:${path10}]`);
|
|
8515
10054
|
continue;
|
|
8516
10055
|
}
|
|
8517
|
-
if (itemType === "skill" && name &&
|
|
8518
|
-
lines.push(`[skill:$${name}](${
|
|
10056
|
+
if (itemType === "skill" && name && path10) {
|
|
10057
|
+
lines.push(`[skill:$${name}](${path10})`);
|
|
8519
10058
|
continue;
|
|
8520
10059
|
}
|
|
8521
|
-
if (itemType === "mention" && name &&
|
|
8522
|
-
lines.push(`[mention:$${name}](${
|
|
10060
|
+
if (itemType === "mention" && name && path10) {
|
|
10061
|
+
lines.push(`[mention:$${name}](${path10})`);
|
|
8523
10062
|
continue;
|
|
8524
10063
|
}
|
|
8525
|
-
if (
|
|
8526
|
-
lines.push(`[${itemType || "input"}:${
|
|
10064
|
+
if (path10 || imageUrl) {
|
|
10065
|
+
lines.push(`[${itemType || "input"}:${path10 || imageUrl}]`);
|
|
8527
10066
|
continue;
|
|
8528
10067
|
}
|
|
8529
10068
|
if (name) {
|
|
@@ -8812,7 +10351,7 @@ function joinInstructionBlocks(...blocks) {
|
|
|
8812
10351
|
return parts.join("\n\n");
|
|
8813
10352
|
}
|
|
8814
10353
|
function randomSubmissionId() {
|
|
8815
|
-
return `sub_${(0,
|
|
10354
|
+
return `sub_${(0, import_node_crypto3.randomBytes)(6).toString("hex")}`;
|
|
8816
10355
|
}
|
|
8817
10356
|
function normalizeInteger(value, fallback, min, max) {
|
|
8818
10357
|
const parsed = Number.isFinite(value) ? Math.floor(value) : fallback;
|
|
@@ -8841,27 +10380,27 @@ function sleep2(ms) {
|
|
|
8841
10380
|
}
|
|
8842
10381
|
|
|
8843
10382
|
// src/tools/filesystemTools.ts
|
|
8844
|
-
var
|
|
8845
|
-
var
|
|
10383
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
10384
|
+
var import_node_buffer5 = require("buffer");
|
|
8846
10385
|
var import_zod6 = require("zod");
|
|
8847
10386
|
|
|
8848
10387
|
// src/tools/applyPatch.ts
|
|
8849
|
-
var
|
|
10388
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
8850
10389
|
var import_zod5 = require("zod");
|
|
8851
10390
|
|
|
8852
10391
|
// src/tools/filesystem.ts
|
|
8853
|
-
var
|
|
8854
|
-
var
|
|
10392
|
+
var import_node_fs4 = require("fs");
|
|
10393
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
8855
10394
|
var InMemoryAgentFilesystem = class {
|
|
8856
10395
|
#files = /* @__PURE__ */ new Map();
|
|
8857
10396
|
#dirs = /* @__PURE__ */ new Map();
|
|
8858
10397
|
#clock = 0;
|
|
8859
10398
|
constructor(initialFiles = {}) {
|
|
8860
|
-
const root =
|
|
10399
|
+
const root = import_node_path6.default.resolve("/");
|
|
8861
10400
|
this.#dirs.set(root, { mtimeMs: this.#nextMtime() });
|
|
8862
10401
|
for (const [filePath, content] of Object.entries(initialFiles)) {
|
|
8863
|
-
const absolutePath =
|
|
8864
|
-
this.#ensureDirSync(
|
|
10402
|
+
const absolutePath = import_node_path6.default.resolve(filePath);
|
|
10403
|
+
this.#ensureDirSync(import_node_path6.default.dirname(absolutePath));
|
|
8865
10404
|
this.#files.set(absolutePath, {
|
|
8866
10405
|
content,
|
|
8867
10406
|
mtimeMs: this.#nextMtime()
|
|
@@ -8869,7 +10408,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
8869
10408
|
}
|
|
8870
10409
|
}
|
|
8871
10410
|
async readTextFile(filePath) {
|
|
8872
|
-
const absolutePath =
|
|
10411
|
+
const absolutePath = import_node_path6.default.resolve(filePath);
|
|
8873
10412
|
const file = this.#files.get(absolutePath);
|
|
8874
10413
|
if (!file) {
|
|
8875
10414
|
throw createNoSuchFileError("open", absolutePath);
|
|
@@ -8881,24 +10420,24 @@ var InMemoryAgentFilesystem = class {
|
|
|
8881
10420
|
return Buffer.from(content, "utf8");
|
|
8882
10421
|
}
|
|
8883
10422
|
async writeTextFile(filePath, content) {
|
|
8884
|
-
const absolutePath =
|
|
8885
|
-
const parentPath =
|
|
10423
|
+
const absolutePath = import_node_path6.default.resolve(filePath);
|
|
10424
|
+
const parentPath = import_node_path6.default.dirname(absolutePath);
|
|
8886
10425
|
if (!this.#dirs.has(parentPath)) {
|
|
8887
10426
|
throw createNoSuchFileError("open", parentPath);
|
|
8888
10427
|
}
|
|
8889
10428
|
this.#files.set(absolutePath, { content, mtimeMs: this.#nextMtime() });
|
|
8890
10429
|
}
|
|
8891
10430
|
async deleteFile(filePath) {
|
|
8892
|
-
const absolutePath =
|
|
10431
|
+
const absolutePath = import_node_path6.default.resolve(filePath);
|
|
8893
10432
|
if (!this.#files.delete(absolutePath)) {
|
|
8894
10433
|
throw createNoSuchFileError("unlink", absolutePath);
|
|
8895
10434
|
}
|
|
8896
10435
|
}
|
|
8897
10436
|
async ensureDir(directoryPath) {
|
|
8898
|
-
this.#ensureDirSync(
|
|
10437
|
+
this.#ensureDirSync(import_node_path6.default.resolve(directoryPath));
|
|
8899
10438
|
}
|
|
8900
10439
|
async readDir(directoryPath) {
|
|
8901
|
-
const absolutePath =
|
|
10440
|
+
const absolutePath = import_node_path6.default.resolve(directoryPath);
|
|
8902
10441
|
const directory = this.#dirs.get(absolutePath);
|
|
8903
10442
|
if (!directory) {
|
|
8904
10443
|
throw createNoSuchFileError("scandir", absolutePath);
|
|
@@ -8909,10 +10448,10 @@ var InMemoryAgentFilesystem = class {
|
|
|
8909
10448
|
if (dirPath === absolutePath) {
|
|
8910
10449
|
continue;
|
|
8911
10450
|
}
|
|
8912
|
-
if (
|
|
10451
|
+
if (import_node_path6.default.dirname(dirPath) !== absolutePath) {
|
|
8913
10452
|
continue;
|
|
8914
10453
|
}
|
|
8915
|
-
const name =
|
|
10454
|
+
const name = import_node_path6.default.basename(dirPath);
|
|
8916
10455
|
if (seenNames.has(name)) {
|
|
8917
10456
|
continue;
|
|
8918
10457
|
}
|
|
@@ -8925,10 +10464,10 @@ var InMemoryAgentFilesystem = class {
|
|
|
8925
10464
|
});
|
|
8926
10465
|
}
|
|
8927
10466
|
for (const [filePath, fileRecord] of this.#files.entries()) {
|
|
8928
|
-
if (
|
|
10467
|
+
if (import_node_path6.default.dirname(filePath) !== absolutePath) {
|
|
8929
10468
|
continue;
|
|
8930
10469
|
}
|
|
8931
|
-
const name =
|
|
10470
|
+
const name = import_node_path6.default.basename(filePath);
|
|
8932
10471
|
if (seenNames.has(name)) {
|
|
8933
10472
|
continue;
|
|
8934
10473
|
}
|
|
@@ -8944,7 +10483,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
8944
10483
|
return entries;
|
|
8945
10484
|
}
|
|
8946
10485
|
async stat(entryPath) {
|
|
8947
|
-
const absolutePath =
|
|
10486
|
+
const absolutePath = import_node_path6.default.resolve(entryPath);
|
|
8948
10487
|
const file = this.#files.get(absolutePath);
|
|
8949
10488
|
if (file) {
|
|
8950
10489
|
return { kind: "file", mtimeMs: file.mtimeMs };
|
|
@@ -8960,7 +10499,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
8960
10499
|
return Object.fromEntries(entries.map(([filePath, record]) => [filePath, record.content]));
|
|
8961
10500
|
}
|
|
8962
10501
|
#ensureDirSync(directoryPath) {
|
|
8963
|
-
const absolutePath =
|
|
10502
|
+
const absolutePath = import_node_path6.default.resolve(directoryPath);
|
|
8964
10503
|
const parts = [];
|
|
8965
10504
|
let cursor = absolutePath;
|
|
8966
10505
|
for (; ; ) {
|
|
@@ -8968,7 +10507,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
8968
10507
|
break;
|
|
8969
10508
|
}
|
|
8970
10509
|
parts.push(cursor);
|
|
8971
|
-
const parent =
|
|
10510
|
+
const parent = import_node_path6.default.dirname(cursor);
|
|
8972
10511
|
if (parent === cursor) {
|
|
8973
10512
|
break;
|
|
8974
10513
|
}
|
|
@@ -8991,19 +10530,19 @@ var InMemoryAgentFilesystem = class {
|
|
|
8991
10530
|
};
|
|
8992
10531
|
function createNodeAgentFilesystem() {
|
|
8993
10532
|
return {
|
|
8994
|
-
readTextFile: async (filePath) =>
|
|
8995
|
-
readBinaryFile: async (filePath) =>
|
|
8996
|
-
writeTextFile: async (filePath, content) =>
|
|
8997
|
-
deleteFile: async (filePath) =>
|
|
10533
|
+
readTextFile: async (filePath) => import_node_fs4.promises.readFile(filePath, "utf8"),
|
|
10534
|
+
readBinaryFile: async (filePath) => import_node_fs4.promises.readFile(filePath),
|
|
10535
|
+
writeTextFile: async (filePath, content) => import_node_fs4.promises.writeFile(filePath, content, "utf8"),
|
|
10536
|
+
deleteFile: async (filePath) => import_node_fs4.promises.unlink(filePath),
|
|
8998
10537
|
ensureDir: async (directoryPath) => {
|
|
8999
|
-
await
|
|
10538
|
+
await import_node_fs4.promises.mkdir(directoryPath, { recursive: true });
|
|
9000
10539
|
},
|
|
9001
10540
|
readDir: async (directoryPath) => {
|
|
9002
|
-
const entries = await
|
|
10541
|
+
const entries = await import_node_fs4.promises.readdir(directoryPath, { withFileTypes: true });
|
|
9003
10542
|
const result = [];
|
|
9004
10543
|
for (const entry of entries) {
|
|
9005
|
-
const entryPath =
|
|
9006
|
-
const stats = await
|
|
10544
|
+
const entryPath = import_node_path6.default.resolve(directoryPath, entry.name);
|
|
10545
|
+
const stats = await import_node_fs4.promises.lstat(entryPath);
|
|
9007
10546
|
result.push({
|
|
9008
10547
|
name: entry.name,
|
|
9009
10548
|
path: entryPath,
|
|
@@ -9014,7 +10553,7 @@ function createNodeAgentFilesystem() {
|
|
|
9014
10553
|
return result;
|
|
9015
10554
|
},
|
|
9016
10555
|
stat: async (entryPath) => {
|
|
9017
|
-
const stats = await
|
|
10556
|
+
const stats = await import_node_fs4.promises.lstat(entryPath);
|
|
9018
10557
|
return {
|
|
9019
10558
|
kind: statsToKind(stats),
|
|
9020
10559
|
mtimeMs: stats.mtimeMs
|
|
@@ -9166,7 +10705,7 @@ function createApplyPatchTool(options = {}) {
|
|
|
9166
10705
|
});
|
|
9167
10706
|
}
|
|
9168
10707
|
async function applyPatch(request) {
|
|
9169
|
-
const cwd =
|
|
10708
|
+
const cwd = import_node_path7.default.resolve(request.cwd ?? process.cwd());
|
|
9170
10709
|
const adapter = request.fs ?? createNodeAgentFilesystem();
|
|
9171
10710
|
const allowOutsideCwd = request.allowOutsideCwd === true;
|
|
9172
10711
|
const patchBytes = Buffer.byteLength(request.patch, "utf8");
|
|
@@ -9188,7 +10727,7 @@ async function applyPatch(request) {
|
|
|
9188
10727
|
kind: "add",
|
|
9189
10728
|
path: absolutePath2
|
|
9190
10729
|
});
|
|
9191
|
-
await adapter.ensureDir(
|
|
10730
|
+
await adapter.ensureDir(import_node_path7.default.dirname(absolutePath2));
|
|
9192
10731
|
await adapter.writeTextFile(absolutePath2, operation.content);
|
|
9193
10732
|
added.push(toDisplayPath(absolutePath2, cwd));
|
|
9194
10733
|
continue;
|
|
@@ -9222,7 +10761,7 @@ async function applyPatch(request) {
|
|
|
9222
10761
|
fromPath: absolutePath,
|
|
9223
10762
|
toPath: destinationPath
|
|
9224
10763
|
});
|
|
9225
|
-
await adapter.ensureDir(
|
|
10764
|
+
await adapter.ensureDir(import_node_path7.default.dirname(destinationPath));
|
|
9226
10765
|
await adapter.writeTextFile(destinationPath, next);
|
|
9227
10766
|
await adapter.deleteFile(absolutePath);
|
|
9228
10767
|
modified.push(toDisplayPath(destinationPath, cwd));
|
|
@@ -9253,22 +10792,22 @@ function resolvePatchPath(rawPath, cwd, allowOutsideCwd) {
|
|
|
9253
10792
|
if (trimmed.length === 0) {
|
|
9254
10793
|
throw new Error("apply_patch failed: empty file path");
|
|
9255
10794
|
}
|
|
9256
|
-
const absolutePath =
|
|
10795
|
+
const absolutePath = import_node_path7.default.isAbsolute(trimmed) ? import_node_path7.default.resolve(trimmed) : import_node_path7.default.resolve(cwd, trimmed);
|
|
9257
10796
|
if (!allowOutsideCwd && !isPathInsideCwd(absolutePath, cwd)) {
|
|
9258
10797
|
throw new Error(`apply_patch failed: path "${trimmed}" resolves outside cwd "${cwd}"`);
|
|
9259
10798
|
}
|
|
9260
10799
|
return absolutePath;
|
|
9261
10800
|
}
|
|
9262
10801
|
function isPathInsideCwd(candidatePath, cwd) {
|
|
9263
|
-
const relative =
|
|
9264
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
10802
|
+
const relative = import_node_path7.default.relative(cwd, candidatePath);
|
|
10803
|
+
return relative === "" || !relative.startsWith("..") && !import_node_path7.default.isAbsolute(relative);
|
|
9265
10804
|
}
|
|
9266
10805
|
function toDisplayPath(absolutePath, cwd) {
|
|
9267
|
-
const relative =
|
|
10806
|
+
const relative = import_node_path7.default.relative(cwd, absolutePath);
|
|
9268
10807
|
if (relative === "") {
|
|
9269
10808
|
return ".";
|
|
9270
10809
|
}
|
|
9271
|
-
if (!relative.startsWith("..") && !
|
|
10810
|
+
if (!relative.startsWith("..") && !import_node_path7.default.isAbsolute(relative)) {
|
|
9272
10811
|
return relative;
|
|
9273
10812
|
}
|
|
9274
10813
|
return absolutePath;
|
|
@@ -10035,7 +11574,7 @@ async function readBinaryFile(filesystem, filePath) {
|
|
|
10035
11574
|
return await filesystem.readBinaryFile(filePath);
|
|
10036
11575
|
}
|
|
10037
11576
|
const text = await filesystem.readTextFile(filePath);
|
|
10038
|
-
return
|
|
11577
|
+
return import_node_buffer5.Buffer.from(text, "utf8");
|
|
10039
11578
|
}
|
|
10040
11579
|
function detectImageMimeType(buffer, filePath) {
|
|
10041
11580
|
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) {
|
|
@@ -10053,7 +11592,7 @@ function detectImageMimeType(buffer, filePath) {
|
|
|
10053
11592
|
if (buffer.length >= 12 && buffer.subarray(0, 4).toString("ascii") === "RIFF" && buffer.subarray(8, 12).toString("ascii") === "WEBP") {
|
|
10054
11593
|
return "image/webp";
|
|
10055
11594
|
}
|
|
10056
|
-
const fromExtension = IMAGE_MIME_BY_EXTENSION[
|
|
11595
|
+
const fromExtension = IMAGE_MIME_BY_EXTENSION[import_node_path8.default.extname(filePath).toLowerCase()];
|
|
10057
11596
|
if (fromExtension && SUPPORTED_IMAGE_MIME_TYPES.has(fromExtension)) {
|
|
10058
11597
|
return fromExtension;
|
|
10059
11598
|
}
|
|
@@ -10063,13 +11602,13 @@ function isPdfFile(buffer, filePath) {
|
|
|
10063
11602
|
if (buffer.length >= 5 && buffer.subarray(0, 5).toString("ascii") === "%PDF-") {
|
|
10064
11603
|
return true;
|
|
10065
11604
|
}
|
|
10066
|
-
return
|
|
11605
|
+
return import_node_path8.default.extname(filePath).toLowerCase() === ".pdf";
|
|
10067
11606
|
}
|
|
10068
11607
|
function isValidUtf8(buffer) {
|
|
10069
11608
|
if (buffer.length === 0) {
|
|
10070
11609
|
return true;
|
|
10071
11610
|
}
|
|
10072
|
-
return
|
|
11611
|
+
return import_node_buffer5.Buffer.from(buffer.toString("utf8"), "utf8").equals(buffer);
|
|
10073
11612
|
}
|
|
10074
11613
|
async function readFileGemini(input, options) {
|
|
10075
11614
|
const runtime = resolveRuntime(options);
|
|
@@ -10101,7 +11640,7 @@ async function writeFileGemini(input, options) {
|
|
|
10101
11640
|
action: "write",
|
|
10102
11641
|
path: filePath
|
|
10103
11642
|
});
|
|
10104
|
-
await runtime.filesystem.ensureDir(
|
|
11643
|
+
await runtime.filesystem.ensureDir(import_node_path8.default.dirname(filePath));
|
|
10105
11644
|
await runtime.filesystem.writeTextFile(filePath, input.content);
|
|
10106
11645
|
return `Successfully wrote file: ${toDisplayPath2(filePath, runtime.cwd)}`;
|
|
10107
11646
|
}
|
|
@@ -10122,7 +11661,7 @@ async function replaceFileContentGemini(input, options) {
|
|
|
10122
11661
|
originalContent = await runtime.filesystem.readTextFile(filePath);
|
|
10123
11662
|
} catch (error) {
|
|
10124
11663
|
if (isNoEntError(error) && oldValue.length === 0) {
|
|
10125
|
-
await runtime.filesystem.ensureDir(
|
|
11664
|
+
await runtime.filesystem.ensureDir(import_node_path8.default.dirname(filePath));
|
|
10126
11665
|
await runtime.filesystem.writeTextFile(filePath, newValue);
|
|
10127
11666
|
return `Successfully wrote new file: ${toDisplayPath2(filePath, runtime.cwd)}`;
|
|
10128
11667
|
}
|
|
@@ -10292,15 +11831,15 @@ async function globFilesGemini(input, options) {
|
|
|
10292
11831
|
throw new Error(`Path is not a directory: ${dirPath}`);
|
|
10293
11832
|
}
|
|
10294
11833
|
const matcher = createGlobMatcher(input.pattern, input.case_sensitive === true);
|
|
10295
|
-
const
|
|
11834
|
+
const files2 = await collectSearchFiles({
|
|
10296
11835
|
filesystem: runtime.filesystem,
|
|
10297
11836
|
searchPath: dirPath,
|
|
10298
11837
|
rootKind: "directory",
|
|
10299
11838
|
maxScannedFiles: runtime.grepMaxScannedFiles
|
|
10300
11839
|
});
|
|
10301
11840
|
const matched = [];
|
|
10302
|
-
for (const filePath of
|
|
10303
|
-
const relativePath = normalizeSlashes(
|
|
11841
|
+
for (const filePath of files2) {
|
|
11842
|
+
const relativePath = normalizeSlashes(import_node_path8.default.relative(dirPath, filePath));
|
|
10304
11843
|
if (!matcher(relativePath)) {
|
|
10305
11844
|
continue;
|
|
10306
11845
|
}
|
|
@@ -10318,7 +11857,7 @@ async function globFilesGemini(input, options) {
|
|
|
10318
11857
|
}
|
|
10319
11858
|
function resolveRuntime(options) {
|
|
10320
11859
|
return {
|
|
10321
|
-
cwd:
|
|
11860
|
+
cwd: import_node_path8.default.resolve(options.cwd ?? process.cwd()),
|
|
10322
11861
|
filesystem: options.fs ?? createNodeAgentFilesystem(),
|
|
10323
11862
|
allowOutsideCwd: options.allowOutsideCwd === true,
|
|
10324
11863
|
checkAccess: options.checkAccess,
|
|
@@ -10349,13 +11888,13 @@ function mapApplyPatchAction(action) {
|
|
|
10349
11888
|
return "move";
|
|
10350
11889
|
}
|
|
10351
11890
|
function resolvePathWithPolicy(inputPath, cwd, allowOutsideCwd) {
|
|
10352
|
-
const absolutePath =
|
|
11891
|
+
const absolutePath = import_node_path8.default.isAbsolute(inputPath) ? import_node_path8.default.resolve(inputPath) : import_node_path8.default.resolve(cwd, inputPath);
|
|
10353
11892
|
if (allowOutsideCwd || isPathInsideCwd2(absolutePath, cwd)) {
|
|
10354
11893
|
return absolutePath;
|
|
10355
11894
|
}
|
|
10356
|
-
if (
|
|
11895
|
+
if (import_node_path8.default.isAbsolute(inputPath)) {
|
|
10357
11896
|
const sandboxRelativePath = inputPath.replace(/^[/\\]+/, "");
|
|
10358
|
-
const sandboxRootedPath =
|
|
11897
|
+
const sandboxRootedPath = import_node_path8.default.resolve(cwd, sandboxRelativePath);
|
|
10359
11898
|
if (isPathInsideCwd2(sandboxRootedPath, cwd)) {
|
|
10360
11899
|
return sandboxRootedPath;
|
|
10361
11900
|
}
|
|
@@ -10363,25 +11902,25 @@ function resolvePathWithPolicy(inputPath, cwd, allowOutsideCwd) {
|
|
|
10363
11902
|
throw new Error(`path "${inputPath}" resolves outside cwd "${cwd}"`);
|
|
10364
11903
|
}
|
|
10365
11904
|
function isPathInsideCwd2(candidatePath, cwd) {
|
|
10366
|
-
const relative =
|
|
10367
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
11905
|
+
const relative = import_node_path8.default.relative(cwd, candidatePath);
|
|
11906
|
+
return relative === "" || !relative.startsWith("..") && !import_node_path8.default.isAbsolute(relative);
|
|
10368
11907
|
}
|
|
10369
11908
|
function toDisplayPath2(absolutePath, cwd) {
|
|
10370
|
-
const relative =
|
|
11909
|
+
const relative = import_node_path8.default.relative(cwd, absolutePath);
|
|
10371
11910
|
if (relative === "") {
|
|
10372
11911
|
return ".";
|
|
10373
11912
|
}
|
|
10374
|
-
if (!relative.startsWith("..") && !
|
|
11913
|
+
if (!relative.startsWith("..") && !import_node_path8.default.isAbsolute(relative)) {
|
|
10375
11914
|
return relative;
|
|
10376
11915
|
}
|
|
10377
11916
|
return absolutePath;
|
|
10378
11917
|
}
|
|
10379
11918
|
function toSandboxDisplayPath(absolutePath, cwd) {
|
|
10380
|
-
const relative =
|
|
11919
|
+
const relative = import_node_path8.default.relative(cwd, absolutePath);
|
|
10381
11920
|
if (relative === "") {
|
|
10382
11921
|
return "/";
|
|
10383
11922
|
}
|
|
10384
|
-
if (!relative.startsWith("..") && !
|
|
11923
|
+
if (!relative.startsWith("..") && !import_node_path8.default.isAbsolute(relative)) {
|
|
10385
11924
|
return `/${normalizeSlashes(relative)}`;
|
|
10386
11925
|
}
|
|
10387
11926
|
return normalizeSlashes(absolutePath);
|
|
@@ -10457,7 +11996,7 @@ async function collectSearchFiles(params) {
|
|
|
10457
11996
|
return [searchPath];
|
|
10458
11997
|
}
|
|
10459
11998
|
const queue = [searchPath];
|
|
10460
|
-
const
|
|
11999
|
+
const files2 = [];
|
|
10461
12000
|
while (queue.length > 0) {
|
|
10462
12001
|
const current = queue.shift();
|
|
10463
12002
|
if (!current) {
|
|
@@ -10472,13 +12011,13 @@ async function collectSearchFiles(params) {
|
|
|
10472
12011
|
if (entry.kind !== "file") {
|
|
10473
12012
|
continue;
|
|
10474
12013
|
}
|
|
10475
|
-
|
|
10476
|
-
if (
|
|
10477
|
-
return
|
|
12014
|
+
files2.push(entry.path);
|
|
12015
|
+
if (files2.length >= maxScannedFiles) {
|
|
12016
|
+
return files2;
|
|
10478
12017
|
}
|
|
10479
12018
|
}
|
|
10480
12019
|
}
|
|
10481
|
-
return
|
|
12020
|
+
return files2;
|
|
10482
12021
|
}
|
|
10483
12022
|
function compileRegex(pattern, flags = "m") {
|
|
10484
12023
|
try {
|
|
@@ -10497,7 +12036,7 @@ function createGlobMatcher(pattern, caseSensitive = false) {
|
|
|
10497
12036
|
}));
|
|
10498
12037
|
return (candidatePath) => {
|
|
10499
12038
|
const normalizedPath = normalizeSlashes(candidatePath);
|
|
10500
|
-
const basename =
|
|
12039
|
+
const basename = import_node_path8.default.posix.basename(normalizedPath);
|
|
10501
12040
|
return compiled.some(
|
|
10502
12041
|
(entry) => entry.regex.test(entry.applyToBasename ? basename : normalizedPath)
|
|
10503
12042
|
);
|
|
@@ -10774,13 +12313,24 @@ async function runAgentLoopInternal(request, context) {
|
|
|
10774
12313
|
}
|
|
10775
12314
|
streamEventLogger?.appendEvent(event);
|
|
10776
12315
|
} : void 0;
|
|
12316
|
+
let uploadMetrics = emptyFileUploadMetrics();
|
|
10777
12317
|
try {
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
12318
|
+
let result;
|
|
12319
|
+
await collectFileUploadMetrics(async () => {
|
|
12320
|
+
try {
|
|
12321
|
+
result = await runToolLoop({
|
|
12322
|
+
...toolLoopRequestWithSteering,
|
|
12323
|
+
...instructions ? { instructions } : {},
|
|
12324
|
+
...wrappedOnEvent ? { onEvent: wrappedOnEvent } : {},
|
|
12325
|
+
tools: mergedTools
|
|
12326
|
+
});
|
|
12327
|
+
} finally {
|
|
12328
|
+
uploadMetrics = getCurrentFileUploadMetrics();
|
|
12329
|
+
}
|
|
10783
12330
|
});
|
|
12331
|
+
if (!result) {
|
|
12332
|
+
throw new Error("runToolLoop returned no result.");
|
|
12333
|
+
}
|
|
10784
12334
|
streamEventLogger?.flush();
|
|
10785
12335
|
emitTelemetry({
|
|
10786
12336
|
type: "agent.run.completed",
|
|
@@ -10789,7 +12339,10 @@ async function runAgentLoopInternal(request, context) {
|
|
|
10789
12339
|
stepCount: result.steps.length,
|
|
10790
12340
|
toolCallCount: countToolCalls(result),
|
|
10791
12341
|
totalCostUsd: result.totalCostUsd,
|
|
10792
|
-
usage: summarizeResultUsage(result)
|
|
12342
|
+
usage: summarizeResultUsage(result),
|
|
12343
|
+
uploadCount: uploadMetrics.count,
|
|
12344
|
+
uploadBytes: uploadMetrics.totalBytes,
|
|
12345
|
+
uploadLatencyMs: uploadMetrics.totalLatencyMs
|
|
10793
12346
|
});
|
|
10794
12347
|
loggingSession?.logLine(
|
|
10795
12348
|
[
|
|
@@ -10798,7 +12351,10 @@ async function runAgentLoopInternal(request, context) {
|
|
|
10798
12351
|
`durationMs=${Math.max(0, Date.now() - startedAtMs).toString()}`,
|
|
10799
12352
|
`steps=${result.steps.length.toString()}`,
|
|
10800
12353
|
`toolCalls=${countToolCalls(result).toString()}`,
|
|
10801
|
-
`totalCostUsd=${(result.totalCostUsd ?? 0).toFixed(6)}
|
|
12354
|
+
`totalCostUsd=${(result.totalCostUsd ?? 0).toFixed(6)}`,
|
|
12355
|
+
`uploadCount=${uploadMetrics.count.toString()}`,
|
|
12356
|
+
`uploadBytes=${uploadMetrics.totalBytes.toString()}`,
|
|
12357
|
+
`uploadLatencyMs=${uploadMetrics.totalLatencyMs.toString()}`
|
|
10802
12358
|
].join(" ")
|
|
10803
12359
|
);
|
|
10804
12360
|
for (const step of result.steps) {
|
|
@@ -10819,6 +12375,9 @@ async function runAgentLoopInternal(request, context) {
|
|
|
10819
12375
|
type: "agent.run.completed",
|
|
10820
12376
|
success: false,
|
|
10821
12377
|
durationMs: Math.max(0, Date.now() - startedAtMs),
|
|
12378
|
+
uploadCount: uploadMetrics.count,
|
|
12379
|
+
uploadBytes: uploadMetrics.totalBytes,
|
|
12380
|
+
uploadLatencyMs: uploadMetrics.totalLatencyMs,
|
|
10822
12381
|
error: toErrorMessage3(error)
|
|
10823
12382
|
});
|
|
10824
12383
|
loggingSession?.logLine(
|
|
@@ -10826,6 +12385,9 @@ async function runAgentLoopInternal(request, context) {
|
|
|
10826
12385
|
`[agent:${runId}] run_completed`,
|
|
10827
12386
|
`status=error`,
|
|
10828
12387
|
`durationMs=${Math.max(0, Date.now() - startedAtMs).toString()}`,
|
|
12388
|
+
`uploadCount=${uploadMetrics.count.toString()}`,
|
|
12389
|
+
`uploadBytes=${uploadMetrics.totalBytes.toString()}`,
|
|
12390
|
+
`uploadLatencyMs=${uploadMetrics.totalLatencyMs.toString()}`,
|
|
10829
12391
|
`error=${toErrorMessage3(error)}`
|
|
10830
12392
|
].join(" ")
|
|
10831
12393
|
);
|
|
@@ -10963,7 +12525,7 @@ function trimToUndefined2(value) {
|
|
|
10963
12525
|
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
10964
12526
|
}
|
|
10965
12527
|
function randomRunId() {
|
|
10966
|
-
return (0,
|
|
12528
|
+
return (0, import_node_crypto4.randomBytes)(8).toString("hex");
|
|
10967
12529
|
}
|
|
10968
12530
|
function toIsoNow2() {
|
|
10969
12531
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -11032,7 +12594,7 @@ function resolveWorkspaceDirForLogging(request) {
|
|
|
11032
12594
|
if (explicitSelection && typeof explicitSelection === "object" && !Array.isArray(explicitSelection)) {
|
|
11033
12595
|
const cwd = explicitSelection.options?.cwd;
|
|
11034
12596
|
if (typeof cwd === "string" && cwd.trim().length > 0) {
|
|
11035
|
-
return
|
|
12597
|
+
return import_node_path9.default.resolve(cwd);
|
|
11036
12598
|
}
|
|
11037
12599
|
}
|
|
11038
12600
|
return process.cwd();
|
|
@@ -11042,7 +12604,7 @@ function createRootAgentLoggingSession(request) {
|
|
|
11042
12604
|
if (!selected) {
|
|
11043
12605
|
return void 0;
|
|
11044
12606
|
}
|
|
11045
|
-
const workspaceDir = typeof selected.workspaceDir === "string" && selected.workspaceDir.trim().length > 0 ?
|
|
12607
|
+
const workspaceDir = typeof selected.workspaceDir === "string" && selected.workspaceDir.trim().length > 0 ? import_node_path9.default.resolve(selected.workspaceDir) : resolveWorkspaceDirForLogging(request);
|
|
11046
12608
|
return createAgentLoggingSession({
|
|
11047
12609
|
...selected,
|
|
11048
12610
|
workspaceDir,
|
|
@@ -11120,7 +12682,7 @@ function createAgentTelemetryEmitter(params) {
|
|
|
11120
12682
|
}
|
|
11121
12683
|
|
|
11122
12684
|
// src/agent/candidateEvolution.ts
|
|
11123
|
-
var
|
|
12685
|
+
var import_node_crypto5 = require("crypto");
|
|
11124
12686
|
var DEFAULT_BATCH_SIZE = 1;
|
|
11125
12687
|
var DEFAULT_GENERATION_CONCURRENCY = 8;
|
|
11126
12688
|
var DEFAULT_ASSESSMENT_CONCURRENCY = 8;
|
|
@@ -11152,7 +12714,7 @@ function addStats(left, right) {
|
|
|
11152
12714
|
};
|
|
11153
12715
|
}
|
|
11154
12716
|
function randomId(prefix) {
|
|
11155
|
-
return `${prefix}_${(0,
|
|
12717
|
+
return `${prefix}_${(0, import_node_crypto5.randomBytes)(8).toString("hex")}`;
|
|
11156
12718
|
}
|
|
11157
12719
|
function toFiniteNumber(value, fallback) {
|
|
11158
12720
|
if (!Number.isFinite(value)) {
|
|
@@ -11777,6 +13339,7 @@ async function runCandidateEvolution(options) {
|
|
|
11777
13339
|
CODEX_APPLY_PATCH_FREEFORM_TOOL_DESCRIPTION,
|
|
11778
13340
|
CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION,
|
|
11779
13341
|
CODEX_APPLY_PATCH_LARK_GRAMMAR,
|
|
13342
|
+
DEFAULT_FILE_TTL_SECONDS,
|
|
11780
13343
|
FIREWORKS_DEFAULT_GLM_MODEL,
|
|
11781
13344
|
FIREWORKS_DEFAULT_GPT_OSS_120B_MODEL,
|
|
11782
13345
|
FIREWORKS_DEFAULT_KIMI_MODEL,
|
|
@@ -11817,10 +13380,12 @@ async function runCandidateEvolution(options) {
|
|
|
11817
13380
|
createViewImageTool,
|
|
11818
13381
|
createWriteFileTool,
|
|
11819
13382
|
customTool,
|
|
13383
|
+
emptyFileUploadMetrics,
|
|
11820
13384
|
encodeChatGptAuthJson,
|
|
11821
13385
|
encodeChatGptAuthJsonB64,
|
|
11822
13386
|
estimateCallCostUsd,
|
|
11823
13387
|
exchangeChatGptOauthCode,
|
|
13388
|
+
files,
|
|
11824
13389
|
generateImageInBatches,
|
|
11825
13390
|
generateImages,
|
|
11826
13391
|
generateJson,
|