@ljoukov/llm 4.1.0 → 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/dist/index.cjs +132 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +134 -48
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2674,7 +2674,7 @@ function getOpenAiFetch() {
|
|
|
2674
2674
|
headersTimeout: timeoutMs
|
|
2675
2675
|
});
|
|
2676
2676
|
openAiClientState.cachedFetch = ((input, init) => {
|
|
2677
|
-
return
|
|
2677
|
+
return fetch(input, {
|
|
2678
2678
|
...init ?? {},
|
|
2679
2679
|
dispatcher
|
|
2680
2680
|
});
|
|
@@ -3384,6 +3384,9 @@ var OPENAI_UPLOAD_PART_MAX_BYTES = 64 * 1024 * 1024;
|
|
|
3384
3384
|
var GEMINI_FILE_POLL_INTERVAL_MS = 1e3;
|
|
3385
3385
|
var GEMINI_FILE_POLL_TIMEOUT_MS = 6e4;
|
|
3386
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");
|
|
3387
3390
|
var filesState = getRuntimeSingleton(/* @__PURE__ */ Symbol.for("@ljoukov/llm.filesState"), () => ({
|
|
3388
3391
|
metadataById: /* @__PURE__ */ new Map(),
|
|
3389
3392
|
openAiUploadCacheByKey: /* @__PURE__ */ new Map(),
|
|
@@ -3529,6 +3532,12 @@ function toStoredFile(file) {
|
|
|
3529
3532
|
function buildCacheKey(filename, mimeType, sha256Hex) {
|
|
3530
3533
|
return `${sha256Hex}\0${filename}\0${mimeType}`;
|
|
3531
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
|
+
}
|
|
3532
3541
|
function isFresh(file) {
|
|
3533
3542
|
if (!file.expires_at) {
|
|
3534
3543
|
return true;
|
|
@@ -3549,6 +3558,82 @@ function recordMetadata(metadata) {
|
|
|
3549
3558
|
}
|
|
3550
3559
|
return metadata;
|
|
3551
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
|
+
}
|
|
3552
3637
|
async function uploadOpenAiFileFromBytes(params) {
|
|
3553
3638
|
const cacheKey = buildCacheKey(params.filename, params.mimeType, params.sha256Hex);
|
|
3554
3639
|
const cached = filesState.openAiUploadCacheByKey.get(cacheKey);
|
|
@@ -3697,17 +3782,23 @@ async function retrieveOpenAiFile(fileId) {
|
|
|
3697
3782
|
if (cached && isFresh(cached.file)) {
|
|
3698
3783
|
return cached;
|
|
3699
3784
|
}
|
|
3785
|
+
const persisted = await loadPersistedMetadata(fileId);
|
|
3786
|
+
if (persisted && isFresh(persisted.file)) {
|
|
3787
|
+
return persisted;
|
|
3788
|
+
}
|
|
3700
3789
|
const client = getOpenAiClient();
|
|
3701
3790
|
const retrieved = await client.files.retrieve(fileId);
|
|
3702
3791
|
const file = toStoredFile(retrieved);
|
|
3703
|
-
|
|
3792
|
+
const metadata = recordMetadata({
|
|
3704
3793
|
file,
|
|
3705
3794
|
filename: file.filename,
|
|
3706
3795
|
bytes: file.bytes,
|
|
3707
|
-
mimeType: cached?.mimeType ?? resolveMimeType(file.filename, void 0),
|
|
3708
|
-
sha256Hex: cached?.sha256Hex,
|
|
3709
|
-
localPath: cached?.localPath
|
|
3796
|
+
mimeType: cached?.mimeType ?? persisted?.mimeType ?? resolveMimeType(file.filename, void 0),
|
|
3797
|
+
sha256Hex: cached?.sha256Hex ?? persisted?.sha256Hex,
|
|
3798
|
+
localPath: cached?.localPath ?? persisted?.localPath
|
|
3710
3799
|
});
|
|
3800
|
+
await persistMetadataToDisk(metadata);
|
|
3801
|
+
return metadata;
|
|
3711
3802
|
}
|
|
3712
3803
|
function buildGeminiMirrorName(sha256Hex) {
|
|
3713
3804
|
return `files/${sha256Hex.slice(0, 40)}`;
|
|
@@ -3819,6 +3910,7 @@ async function materializeOpenAiFile(fileId) {
|
|
|
3819
3910
|
sha256Hex,
|
|
3820
3911
|
localPath
|
|
3821
3912
|
});
|
|
3913
|
+
await persistMetadataToDisk(updated);
|
|
3822
3914
|
return {
|
|
3823
3915
|
file: updated.file,
|
|
3824
3916
|
filename: updated.filename,
|
|
@@ -3982,7 +4074,13 @@ async function filesCreate(params) {
|
|
|
3982
4074
|
sha256Hex: sha256Hex2,
|
|
3983
4075
|
bytes: info.size
|
|
3984
4076
|
});
|
|
3985
|
-
|
|
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;
|
|
3986
4084
|
}
|
|
3987
4085
|
const filename = normaliseFilename(params.filename);
|
|
3988
4086
|
const bytes = toBuffer(params.data);
|
|
@@ -3996,7 +4094,13 @@ async function filesCreate(params) {
|
|
|
3996
4094
|
expiresAfterSeconds,
|
|
3997
4095
|
sha256Hex
|
|
3998
4096
|
});
|
|
3999
|
-
|
|
4097
|
+
const localPath = await cacheBufferLocally(bytes, sha256Hex);
|
|
4098
|
+
const cached = recordMetadata({
|
|
4099
|
+
...uploaded,
|
|
4100
|
+
localPath
|
|
4101
|
+
});
|
|
4102
|
+
await persistMetadataToDisk(cached);
|
|
4103
|
+
return cached.file;
|
|
4000
4104
|
}
|
|
4001
4105
|
async function filesRetrieve(fileId) {
|
|
4002
4106
|
return (await retrieveOpenAiFile(fileId)).file;
|
|
@@ -4029,6 +4133,10 @@ async function filesDelete(fileId) {
|
|
|
4029
4133
|
const response = await getOpenAiClient().files.delete(fileId);
|
|
4030
4134
|
filesState.metadataById.delete(fileId);
|
|
4031
4135
|
filesState.materializedById.delete(fileId);
|
|
4136
|
+
try {
|
|
4137
|
+
await (0, import_promises2.unlink)(buildCachedMetadataPath(fileId));
|
|
4138
|
+
} catch {
|
|
4139
|
+
}
|
|
4032
4140
|
return {
|
|
4033
4141
|
id: response.id,
|
|
4034
4142
|
deleted: response.deleted,
|
|
@@ -4508,8 +4616,7 @@ function toGeminiPart(part) {
|
|
|
4508
4616
|
return {
|
|
4509
4617
|
fileData: {
|
|
4510
4618
|
fileUri: buildCanonicalGeminiFileUri(part.file_id),
|
|
4511
|
-
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4512
|
-
displayName: part.filename ?? void 0
|
|
4619
|
+
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4513
4620
|
}
|
|
4514
4621
|
};
|
|
4515
4622
|
}
|
|
@@ -4527,8 +4634,7 @@ function toGeminiPart(part) {
|
|
|
4527
4634
|
return {
|
|
4528
4635
|
fileData: {
|
|
4529
4636
|
fileUri: part.image_url,
|
|
4530
|
-
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4531
|
-
displayName: part.filename ?? void 0
|
|
4637
|
+
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4532
4638
|
}
|
|
4533
4639
|
};
|
|
4534
4640
|
}
|
|
@@ -4537,8 +4643,7 @@ function toGeminiPart(part) {
|
|
|
4537
4643
|
return {
|
|
4538
4644
|
fileData: {
|
|
4539
4645
|
fileUri: buildCanonicalGeminiFileUri(part.file_id),
|
|
4540
|
-
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4541
|
-
displayName: part.filename ?? void 0
|
|
4646
|
+
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4542
4647
|
}
|
|
4543
4648
|
};
|
|
4544
4649
|
}
|
|
@@ -4564,8 +4669,7 @@ function toGeminiPart(part) {
|
|
|
4564
4669
|
return {
|
|
4565
4670
|
fileData: {
|
|
4566
4671
|
fileUri: part.file_url,
|
|
4567
|
-
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4568
|
-
displayName: part.filename ?? void 0
|
|
4672
|
+
mimeType: inferToolOutputMimeTypeFromFilename(part.filename) ?? "application/octet-stream"
|
|
4569
4673
|
}
|
|
4570
4674
|
};
|
|
4571
4675
|
}
|
|
@@ -4797,7 +4901,7 @@ async function prepareOpenAiPromptContentItem(item) {
|
|
|
4797
4901
|
mimeType,
|
|
4798
4902
|
filename
|
|
4799
4903
|
});
|
|
4800
|
-
return { type: "input_file", file_id: uploaded.fileId
|
|
4904
|
+
return { type: "input_file", file_id: uploaded.fileId };
|
|
4801
4905
|
}
|
|
4802
4906
|
if (typeof item.file_url === "string" && item.file_url.trim().toLowerCase().startsWith("data:")) {
|
|
4803
4907
|
const parsed = parseDataUrlPayload(item.file_url);
|
|
@@ -4812,7 +4916,7 @@ async function prepareOpenAiPromptContentItem(item) {
|
|
|
4812
4916
|
guessInlineDataFilename(parsed.mimeType)
|
|
4813
4917
|
)
|
|
4814
4918
|
});
|
|
4815
|
-
return { type: "input_file", file_id: uploaded.fileId
|
|
4919
|
+
return { type: "input_file", file_id: uploaded.fileId };
|
|
4816
4920
|
}
|
|
4817
4921
|
return item;
|
|
4818
4922
|
}
|
|
@@ -4877,21 +4981,16 @@ async function prepareGeminiPromptContents(contents) {
|
|
|
4877
4981
|
for (const part of content.parts ?? []) {
|
|
4878
4982
|
const canonicalFileId = parseCanonicalGeminiFileId(part.fileData?.fileUri);
|
|
4879
4983
|
if (canonicalFileId) {
|
|
4880
|
-
|
|
4984
|
+
await getCanonicalFileMetadata(canonicalFileId);
|
|
4881
4985
|
if (backend === "api") {
|
|
4882
4986
|
const mirrored = await ensureGeminiFileMirror(canonicalFileId);
|
|
4883
|
-
|
|
4884
|
-
if (metadata.filename && mirroredPart.fileData) {
|
|
4885
|
-
mirroredPart.fileData.displayName = metadata.filename;
|
|
4886
|
-
}
|
|
4887
|
-
parts.push(mirroredPart);
|
|
4987
|
+
parts.push((0, import_genai2.createPartFromUri)(mirrored.uri, mirrored.mimeType));
|
|
4888
4988
|
} else {
|
|
4889
4989
|
const mirrored = await ensureVertexFileMirror(canonicalFileId);
|
|
4890
4990
|
parts.push({
|
|
4891
4991
|
fileData: {
|
|
4892
4992
|
fileUri: mirrored.fileUri,
|
|
4893
|
-
mimeType: mirrored.mimeType
|
|
4894
|
-
displayName: metadata.filename
|
|
4993
|
+
mimeType: mirrored.mimeType
|
|
4895
4994
|
}
|
|
4896
4995
|
});
|
|
4897
4996
|
}
|
|
@@ -4910,18 +5009,13 @@ async function prepareGeminiPromptContents(contents) {
|
|
|
4910
5009
|
});
|
|
4911
5010
|
if (backend === "api") {
|
|
4912
5011
|
const mirrored = await ensureGeminiFileMirror(stored.fileId);
|
|
4913
|
-
|
|
4914
|
-
if (filename && mirroredPart.fileData) {
|
|
4915
|
-
mirroredPart.fileData.displayName = filename;
|
|
4916
|
-
}
|
|
4917
|
-
parts.push(mirroredPart);
|
|
5012
|
+
parts.push((0, import_genai2.createPartFromUri)(mirrored.uri, mirrored.mimeType));
|
|
4918
5013
|
} else {
|
|
4919
5014
|
const mirrored = await ensureVertexFileMirror(stored.fileId);
|
|
4920
5015
|
parts.push({
|
|
4921
5016
|
fileData: {
|
|
4922
5017
|
fileUri: mirrored.fileUri,
|
|
4923
|
-
mimeType: mirrored.mimeType
|
|
4924
|
-
displayName: filename
|
|
5018
|
+
mimeType: mirrored.mimeType
|
|
4925
5019
|
}
|
|
4926
5020
|
});
|
|
4927
5021
|
}
|
|
@@ -5442,7 +5536,7 @@ function toOpenAiInput(contents) {
|
|
|
5442
5536
|
...part.file_id ? { file_id: part.file_id } : {},
|
|
5443
5537
|
...part.file_data ? { file_data: part.file_data } : {},
|
|
5444
5538
|
...part.file_url ? { file_url: part.file_url } : {},
|
|
5445
|
-
|
|
5539
|
+
...!part.file_id && part.filename ? { filename: part.filename } : {}
|
|
5446
5540
|
});
|
|
5447
5541
|
break;
|
|
5448
5542
|
default:
|
|
@@ -5527,7 +5621,7 @@ function toChatGptInput(contents) {
|
|
|
5527
5621
|
...part.file_id ? { file_id: part.file_id } : {},
|
|
5528
5622
|
...part.file_data ? { file_data: part.file_data } : {},
|
|
5529
5623
|
...part.file_url ? { file_url: part.file_url } : {},
|
|
5530
|
-
|
|
5624
|
+
...!part.file_id && part.filename ? { filename: part.filename } : {}
|
|
5531
5625
|
});
|
|
5532
5626
|
break;
|
|
5533
5627
|
default:
|
|
@@ -6134,8 +6228,7 @@ function buildGeminiToolOutputMediaPart(item) {
|
|
|
6134
6228
|
return {
|
|
6135
6229
|
fileData: {
|
|
6136
6230
|
fileUri: buildCanonicalGeminiFileUri(item.file_id),
|
|
6137
|
-
mimeType: inferToolOutputMimeTypeFromFilename(item.filename) ?? "application/octet-stream"
|
|
6138
|
-
displayName: item.filename ?? void 0
|
|
6231
|
+
mimeType: inferToolOutputMimeTypeFromFilename(item.filename) ?? "application/octet-stream"
|
|
6139
6232
|
}
|
|
6140
6233
|
};
|
|
6141
6234
|
}
|
|
@@ -6154,8 +6247,7 @@ function buildGeminiToolOutputMediaPart(item) {
|
|
|
6154
6247
|
return {
|
|
6155
6248
|
fileData: {
|
|
6156
6249
|
fileUri: item.image_url,
|
|
6157
|
-
mimeType: inferToolOutputMimeTypeFromFilename(item.filename) ?? "application/octet-stream"
|
|
6158
|
-
displayName: item.filename ?? void 0
|
|
6250
|
+
mimeType: inferToolOutputMimeTypeFromFilename(item.filename) ?? "application/octet-stream"
|
|
6159
6251
|
}
|
|
6160
6252
|
};
|
|
6161
6253
|
}
|
|
@@ -6164,8 +6256,7 @@ function buildGeminiToolOutputMediaPart(item) {
|
|
|
6164
6256
|
return {
|
|
6165
6257
|
fileData: {
|
|
6166
6258
|
fileUri: buildCanonicalGeminiFileUri(item.file_id),
|
|
6167
|
-
mimeType: inferToolOutputMimeTypeFromFilename(item.filename) ?? "application/octet-stream"
|
|
6168
|
-
displayName: item.filename ?? void 0
|
|
6259
|
+
mimeType: inferToolOutputMimeTypeFromFilename(item.filename) ?? "application/octet-stream"
|
|
6169
6260
|
}
|
|
6170
6261
|
};
|
|
6171
6262
|
}
|
|
@@ -6188,12 +6279,7 @@ function buildGeminiToolOutputMediaPart(item) {
|
|
|
6188
6279
|
return part;
|
|
6189
6280
|
}
|
|
6190
6281
|
if (typeof item.file_url === "string" && item.file_url.trim().length > 0 && inferredMimeType) {
|
|
6191
|
-
|
|
6192
|
-
const displayName = item.filename?.trim();
|
|
6193
|
-
if (displayName && part.fileData) {
|
|
6194
|
-
part.fileData.displayName = displayName;
|
|
6195
|
-
}
|
|
6196
|
-
return part;
|
|
6282
|
+
return (0, import_genai2.createPartFromUri)(item.file_url, inferredMimeType);
|
|
6197
6283
|
}
|
|
6198
6284
|
}
|
|
6199
6285
|
return null;
|