@ljoukov/llm 4.0.9 → 4.0.10
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 +164 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +168 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,10 @@ import { randomBytes } from "crypto";
|
|
|
5
5
|
import {
|
|
6
6
|
FinishReason,
|
|
7
7
|
FunctionCallingConfigMode,
|
|
8
|
-
ThinkingLevel
|
|
8
|
+
ThinkingLevel,
|
|
9
|
+
createFunctionResponsePartFromBase64,
|
|
10
|
+
createFunctionResponsePartFromUri,
|
|
11
|
+
createPartFromFunctionResponse
|
|
9
12
|
} from "@google/genai";
|
|
10
13
|
import { zodToJsonSchema } from "@alcyone-labs/zod-to-json-schema";
|
|
11
14
|
import { z as z3 } from "zod";
|
|
@@ -4588,6 +4591,150 @@ function toOpenAiToolOutput(value) {
|
|
|
4588
4591
|
}
|
|
4589
4592
|
return mergeToolOutput(value);
|
|
4590
4593
|
}
|
|
4594
|
+
function toGeminiToolOutputItems(value) {
|
|
4595
|
+
if (isLlmToolOutputContentItem(value)) {
|
|
4596
|
+
return [value];
|
|
4597
|
+
}
|
|
4598
|
+
if (Array.isArray(value) && value.every((item) => isLlmToolOutputContentItem(item))) {
|
|
4599
|
+
return value;
|
|
4600
|
+
}
|
|
4601
|
+
return null;
|
|
4602
|
+
}
|
|
4603
|
+
function inferToolOutputMimeTypeFromFilename(filename) {
|
|
4604
|
+
const normalized = filename?.trim().toLowerCase() ?? "";
|
|
4605
|
+
if (normalized.length === 0) {
|
|
4606
|
+
return void 0;
|
|
4607
|
+
}
|
|
4608
|
+
if (normalized.endsWith(".png")) {
|
|
4609
|
+
return "image/png";
|
|
4610
|
+
}
|
|
4611
|
+
if (normalized.endsWith(".jpg") || normalized.endsWith(".jpeg")) {
|
|
4612
|
+
return "image/jpeg";
|
|
4613
|
+
}
|
|
4614
|
+
if (normalized.endsWith(".webp")) {
|
|
4615
|
+
return "image/webp";
|
|
4616
|
+
}
|
|
4617
|
+
if (normalized.endsWith(".gif")) {
|
|
4618
|
+
return "image/gif";
|
|
4619
|
+
}
|
|
4620
|
+
if (normalized.endsWith(".heic")) {
|
|
4621
|
+
return "image/heic";
|
|
4622
|
+
}
|
|
4623
|
+
if (normalized.endsWith(".heif")) {
|
|
4624
|
+
return "image/heif";
|
|
4625
|
+
}
|
|
4626
|
+
if (normalized.endsWith(".pdf")) {
|
|
4627
|
+
return "application/pdf";
|
|
4628
|
+
}
|
|
4629
|
+
if (normalized.endsWith(".json")) {
|
|
4630
|
+
return "application/json";
|
|
4631
|
+
}
|
|
4632
|
+
if (normalized.endsWith(".md")) {
|
|
4633
|
+
return "text/markdown";
|
|
4634
|
+
}
|
|
4635
|
+
if (normalized.endsWith(".txt")) {
|
|
4636
|
+
return "text/plain";
|
|
4637
|
+
}
|
|
4638
|
+
return void 0;
|
|
4639
|
+
}
|
|
4640
|
+
function buildGeminiToolOutputMediaPart(item) {
|
|
4641
|
+
if (item.type === "input_image") {
|
|
4642
|
+
const parsed = parseDataUrlPayload(item.image_url);
|
|
4643
|
+
if (!parsed) {
|
|
4644
|
+
return null;
|
|
4645
|
+
}
|
|
4646
|
+
return createFunctionResponsePartFromBase64(parsed.dataBase64, parsed.mimeType);
|
|
4647
|
+
}
|
|
4648
|
+
if (item.type === "input_file") {
|
|
4649
|
+
const dataUrl = typeof item.file_url === "string" ? parseDataUrlPayload(item.file_url) : null;
|
|
4650
|
+
if (dataUrl) {
|
|
4651
|
+
const part = createFunctionResponsePartFromBase64(dataUrl.dataBase64, dataUrl.mimeType);
|
|
4652
|
+
const displayName = item.filename?.trim();
|
|
4653
|
+
if (displayName && part.inlineData) {
|
|
4654
|
+
part.inlineData.displayName = displayName;
|
|
4655
|
+
}
|
|
4656
|
+
return part;
|
|
4657
|
+
}
|
|
4658
|
+
const inferredMimeType = inferToolOutputMimeTypeFromFilename(item.filename);
|
|
4659
|
+
if (typeof item.file_data === "string" && item.file_data.trim().length > 0 && inferredMimeType) {
|
|
4660
|
+
const part = createFunctionResponsePartFromBase64(item.file_data, inferredMimeType);
|
|
4661
|
+
const displayName = item.filename?.trim();
|
|
4662
|
+
if (displayName && part.inlineData) {
|
|
4663
|
+
part.inlineData.displayName = displayName;
|
|
4664
|
+
}
|
|
4665
|
+
return part;
|
|
4666
|
+
}
|
|
4667
|
+
if (typeof item.file_url === "string" && item.file_url.trim().length > 0 && inferredMimeType) {
|
|
4668
|
+
const part = createFunctionResponsePartFromUri(item.file_url, inferredMimeType);
|
|
4669
|
+
const displayName = item.filename?.trim();
|
|
4670
|
+
if (displayName && part.fileData) {
|
|
4671
|
+
part.fileData.displayName = displayName;
|
|
4672
|
+
}
|
|
4673
|
+
return part;
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
return null;
|
|
4677
|
+
}
|
|
4678
|
+
function toGeminiToolOutputPlaceholder(item) {
|
|
4679
|
+
if (item.type === "input_text") {
|
|
4680
|
+
return {
|
|
4681
|
+
type: item.type,
|
|
4682
|
+
text: item.text
|
|
4683
|
+
};
|
|
4684
|
+
}
|
|
4685
|
+
if (item.type === "input_image") {
|
|
4686
|
+
const parsed = parseDataUrlPayload(item.image_url);
|
|
4687
|
+
return {
|
|
4688
|
+
type: item.type,
|
|
4689
|
+
mimeType: parsed?.mimeType ?? void 0,
|
|
4690
|
+
media: "attached-inline-data"
|
|
4691
|
+
};
|
|
4692
|
+
}
|
|
4693
|
+
const dataUrl = typeof item.file_url === "string" ? parseDataUrlPayload(item.file_url) : null;
|
|
4694
|
+
return {
|
|
4695
|
+
type: item.type,
|
|
4696
|
+
filename: item.filename ?? void 0,
|
|
4697
|
+
fileId: item.file_id ?? void 0,
|
|
4698
|
+
mimeType: dataUrl?.mimeType ?? inferToolOutputMimeTypeFromFilename(item.filename) ?? void 0,
|
|
4699
|
+
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
|
|
4700
|
+
};
|
|
4701
|
+
}
|
|
4702
|
+
function buildGeminiFunctionResponsePart(options) {
|
|
4703
|
+
const outputItems = toGeminiToolOutputItems(options.outputPayload);
|
|
4704
|
+
if (!outputItems) {
|
|
4705
|
+
const responsePayload2 = isPlainRecord(options.outputPayload) ? sanitiseLogValue(options.outputPayload) : { output: sanitiseLogValue(options.outputPayload) };
|
|
4706
|
+
if (options.callId) {
|
|
4707
|
+
return createPartFromFunctionResponse(options.callId, options.toolName, responsePayload2);
|
|
4708
|
+
}
|
|
4709
|
+
return {
|
|
4710
|
+
functionResponse: {
|
|
4711
|
+
name: options.toolName,
|
|
4712
|
+
response: responsePayload2
|
|
4713
|
+
}
|
|
4714
|
+
};
|
|
4715
|
+
}
|
|
4716
|
+
const responseOutput = outputItems.map((item) => toGeminiToolOutputPlaceholder(item));
|
|
4717
|
+
const responseMediaParts = outputItems.flatMap((item) => {
|
|
4718
|
+
const mediaPart = buildGeminiToolOutputMediaPart(item);
|
|
4719
|
+
return mediaPart ? [mediaPart] : [];
|
|
4720
|
+
});
|
|
4721
|
+
const responsePayload = { output: responseOutput };
|
|
4722
|
+
if (options.callId) {
|
|
4723
|
+
return createPartFromFunctionResponse(
|
|
4724
|
+
options.callId,
|
|
4725
|
+
options.toolName,
|
|
4726
|
+
responsePayload,
|
|
4727
|
+
responseMediaParts
|
|
4728
|
+
);
|
|
4729
|
+
}
|
|
4730
|
+
return {
|
|
4731
|
+
functionResponse: {
|
|
4732
|
+
name: options.toolName,
|
|
4733
|
+
response: { output: responseOutput },
|
|
4734
|
+
...responseMediaParts.length > 0 ? { parts: responseMediaParts } : {}
|
|
4735
|
+
}
|
|
4736
|
+
};
|
|
4737
|
+
}
|
|
4591
4738
|
function parseOpenAiToolArguments(raw) {
|
|
4592
4739
|
const trimmed = raw.trim();
|
|
4593
4740
|
if (trimmed.length === 0) {
|
|
@@ -5048,7 +5195,7 @@ function resolveAttachmentExtension(mimeType) {
|
|
|
5048
5195
|
function buildLoggedAttachmentFilename(prefix, index, mimeType) {
|
|
5049
5196
|
return `${prefix}-${index.toString()}.${resolveAttachmentExtension(mimeType)}`;
|
|
5050
5197
|
}
|
|
5051
|
-
function
|
|
5198
|
+
function parseDataUrlPayload(value) {
|
|
5052
5199
|
const trimmed = value.trim();
|
|
5053
5200
|
if (!trimmed.toLowerCase().startsWith("data:")) {
|
|
5054
5201
|
return null;
|
|
@@ -5064,13 +5211,24 @@ function decodeDataUrlAttachment(value, options) {
|
|
|
5064
5211
|
try {
|
|
5065
5212
|
const bytes = isBase64 ? Buffer4.from(payload, "base64") : Buffer4.from(decodeURIComponent(payload), "utf8");
|
|
5066
5213
|
return {
|
|
5067
|
-
|
|
5214
|
+
mimeType,
|
|
5215
|
+
dataBase64: bytes.toString("base64"),
|
|
5068
5216
|
bytes
|
|
5069
5217
|
};
|
|
5070
5218
|
} catch {
|
|
5071
5219
|
return null;
|
|
5072
5220
|
}
|
|
5073
5221
|
}
|
|
5222
|
+
function decodeDataUrlAttachment(value, options) {
|
|
5223
|
+
const parsed = parseDataUrlPayload(value);
|
|
5224
|
+
if (!parsed) {
|
|
5225
|
+
return null;
|
|
5226
|
+
}
|
|
5227
|
+
return {
|
|
5228
|
+
filename: buildLoggedAttachmentFilename(options.prefix, options.index, parsed.mimeType),
|
|
5229
|
+
bytes: parsed.bytes
|
|
5230
|
+
};
|
|
5231
|
+
}
|
|
5074
5232
|
function collectPayloadAttachments(value, options) {
|
|
5075
5233
|
if (typeof value === "string") {
|
|
5076
5234
|
const attachment = decodeDataUrlAttachment(value, {
|
|
@@ -7402,14 +7560,13 @@ async function runToolLoop(request) {
|
|
|
7402
7560
|
error: result.error,
|
|
7403
7561
|
durationMs: result.durationMs
|
|
7404
7562
|
});
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
});
|
|
7563
|
+
responseParts.push(
|
|
7564
|
+
buildGeminiFunctionResponsePart({
|
|
7565
|
+
toolName: entry.toolName,
|
|
7566
|
+
callId: entry.call.id,
|
|
7567
|
+
outputPayload
|
|
7568
|
+
})
|
|
7569
|
+
);
|
|
7413
7570
|
}
|
|
7414
7571
|
const stepCompletedAtMs = Date.now();
|
|
7415
7572
|
const timing = buildStepTiming({
|