@ljoukov/llm 4.0.9 → 4.0.11
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 +158 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +162 -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
|
+
createPartFromBase64,
|
|
10
|
+
createPartFromFunctionResponse,
|
|
11
|
+
createPartFromUri
|
|
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,144 @@ 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 createPartFromBase64(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 = createPartFromBase64(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 = createPartFromBase64(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 = createPartFromUri(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 buildGeminiFunctionResponseParts(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
|
+
{
|
|
4711
|
+
functionResponse: {
|
|
4712
|
+
name: options.toolName,
|
|
4713
|
+
response: responsePayload2
|
|
4714
|
+
}
|
|
4715
|
+
}
|
|
4716
|
+
];
|
|
4717
|
+
}
|
|
4718
|
+
const responseOutput = outputItems.map((item) => toGeminiToolOutputPlaceholder(item));
|
|
4719
|
+
const responseParts = outputItems.flatMap((item) => {
|
|
4720
|
+
const mediaPart = buildGeminiToolOutputMediaPart(item);
|
|
4721
|
+
return mediaPart ? [mediaPart] : [];
|
|
4722
|
+
});
|
|
4723
|
+
const responsePayload = { output: responseOutput };
|
|
4724
|
+
const functionResponsePart = options.callId ? createPartFromFunctionResponse(options.callId, options.toolName, responsePayload) : {
|
|
4725
|
+
functionResponse: {
|
|
4726
|
+
name: options.toolName,
|
|
4727
|
+
response: responsePayload
|
|
4728
|
+
}
|
|
4729
|
+
};
|
|
4730
|
+
return [functionResponsePart, ...responseParts];
|
|
4731
|
+
}
|
|
4591
4732
|
function parseOpenAiToolArguments(raw) {
|
|
4592
4733
|
const trimmed = raw.trim();
|
|
4593
4734
|
if (trimmed.length === 0) {
|
|
@@ -5048,7 +5189,7 @@ function resolveAttachmentExtension(mimeType) {
|
|
|
5048
5189
|
function buildLoggedAttachmentFilename(prefix, index, mimeType) {
|
|
5049
5190
|
return `${prefix}-${index.toString()}.${resolveAttachmentExtension(mimeType)}`;
|
|
5050
5191
|
}
|
|
5051
|
-
function
|
|
5192
|
+
function parseDataUrlPayload(value) {
|
|
5052
5193
|
const trimmed = value.trim();
|
|
5053
5194
|
if (!trimmed.toLowerCase().startsWith("data:")) {
|
|
5054
5195
|
return null;
|
|
@@ -5064,13 +5205,24 @@ function decodeDataUrlAttachment(value, options) {
|
|
|
5064
5205
|
try {
|
|
5065
5206
|
const bytes = isBase64 ? Buffer4.from(payload, "base64") : Buffer4.from(decodeURIComponent(payload), "utf8");
|
|
5066
5207
|
return {
|
|
5067
|
-
|
|
5208
|
+
mimeType,
|
|
5209
|
+
dataBase64: bytes.toString("base64"),
|
|
5068
5210
|
bytes
|
|
5069
5211
|
};
|
|
5070
5212
|
} catch {
|
|
5071
5213
|
return null;
|
|
5072
5214
|
}
|
|
5073
5215
|
}
|
|
5216
|
+
function decodeDataUrlAttachment(value, options) {
|
|
5217
|
+
const parsed = parseDataUrlPayload(value);
|
|
5218
|
+
if (!parsed) {
|
|
5219
|
+
return null;
|
|
5220
|
+
}
|
|
5221
|
+
return {
|
|
5222
|
+
filename: buildLoggedAttachmentFilename(options.prefix, options.index, parsed.mimeType),
|
|
5223
|
+
bytes: parsed.bytes
|
|
5224
|
+
};
|
|
5225
|
+
}
|
|
5074
5226
|
function collectPayloadAttachments(value, options) {
|
|
5075
5227
|
if (typeof value === "string") {
|
|
5076
5228
|
const attachment = decodeDataUrlAttachment(value, {
|
|
@@ -7402,14 +7554,13 @@ async function runToolLoop(request) {
|
|
|
7402
7554
|
error: result.error,
|
|
7403
7555
|
durationMs: result.durationMs
|
|
7404
7556
|
});
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
});
|
|
7557
|
+
responseParts.push(
|
|
7558
|
+
...buildGeminiFunctionResponseParts({
|
|
7559
|
+
toolName: entry.toolName,
|
|
7560
|
+
callId: entry.call.id,
|
|
7561
|
+
outputPayload
|
|
7562
|
+
})
|
|
7563
|
+
);
|
|
7413
7564
|
}
|
|
7414
7565
|
const stepCompletedAtMs = Date.now();
|
|
7415
7566
|
const timing = buildStepTiming({
|