@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 CHANGED
@@ -4700,6 +4700,150 @@ function toOpenAiToolOutput(value) {
4700
4700
  }
4701
4701
  return mergeToolOutput(value);
4702
4702
  }
4703
+ function toGeminiToolOutputItems(value) {
4704
+ if (isLlmToolOutputContentItem(value)) {
4705
+ return [value];
4706
+ }
4707
+ if (Array.isArray(value) && value.every((item) => isLlmToolOutputContentItem(item))) {
4708
+ return value;
4709
+ }
4710
+ return null;
4711
+ }
4712
+ function inferToolOutputMimeTypeFromFilename(filename) {
4713
+ const normalized = filename?.trim().toLowerCase() ?? "";
4714
+ if (normalized.length === 0) {
4715
+ return void 0;
4716
+ }
4717
+ if (normalized.endsWith(".png")) {
4718
+ return "image/png";
4719
+ }
4720
+ if (normalized.endsWith(".jpg") || normalized.endsWith(".jpeg")) {
4721
+ return "image/jpeg";
4722
+ }
4723
+ if (normalized.endsWith(".webp")) {
4724
+ return "image/webp";
4725
+ }
4726
+ if (normalized.endsWith(".gif")) {
4727
+ return "image/gif";
4728
+ }
4729
+ if (normalized.endsWith(".heic")) {
4730
+ return "image/heic";
4731
+ }
4732
+ if (normalized.endsWith(".heif")) {
4733
+ return "image/heif";
4734
+ }
4735
+ if (normalized.endsWith(".pdf")) {
4736
+ return "application/pdf";
4737
+ }
4738
+ if (normalized.endsWith(".json")) {
4739
+ return "application/json";
4740
+ }
4741
+ if (normalized.endsWith(".md")) {
4742
+ return "text/markdown";
4743
+ }
4744
+ if (normalized.endsWith(".txt")) {
4745
+ return "text/plain";
4746
+ }
4747
+ return void 0;
4748
+ }
4749
+ function buildGeminiToolOutputMediaPart(item) {
4750
+ if (item.type === "input_image") {
4751
+ const parsed = parseDataUrlPayload(item.image_url);
4752
+ if (!parsed) {
4753
+ return null;
4754
+ }
4755
+ return (0, import_genai2.createFunctionResponsePartFromBase64)(parsed.dataBase64, parsed.mimeType);
4756
+ }
4757
+ if (item.type === "input_file") {
4758
+ const dataUrl = typeof item.file_url === "string" ? parseDataUrlPayload(item.file_url) : null;
4759
+ if (dataUrl) {
4760
+ const part = (0, import_genai2.createFunctionResponsePartFromBase64)(dataUrl.dataBase64, dataUrl.mimeType);
4761
+ const displayName = item.filename?.trim();
4762
+ if (displayName && part.inlineData) {
4763
+ part.inlineData.displayName = displayName;
4764
+ }
4765
+ return part;
4766
+ }
4767
+ const inferredMimeType = inferToolOutputMimeTypeFromFilename(item.filename);
4768
+ if (typeof item.file_data === "string" && item.file_data.trim().length > 0 && inferredMimeType) {
4769
+ const part = (0, import_genai2.createFunctionResponsePartFromBase64)(item.file_data, inferredMimeType);
4770
+ const displayName = item.filename?.trim();
4771
+ if (displayName && part.inlineData) {
4772
+ part.inlineData.displayName = displayName;
4773
+ }
4774
+ return part;
4775
+ }
4776
+ if (typeof item.file_url === "string" && item.file_url.trim().length > 0 && inferredMimeType) {
4777
+ const part = (0, import_genai2.createFunctionResponsePartFromUri)(item.file_url, inferredMimeType);
4778
+ const displayName = item.filename?.trim();
4779
+ if (displayName && part.fileData) {
4780
+ part.fileData.displayName = displayName;
4781
+ }
4782
+ return part;
4783
+ }
4784
+ }
4785
+ return null;
4786
+ }
4787
+ function toGeminiToolOutputPlaceholder(item) {
4788
+ if (item.type === "input_text") {
4789
+ return {
4790
+ type: item.type,
4791
+ text: item.text
4792
+ };
4793
+ }
4794
+ if (item.type === "input_image") {
4795
+ const parsed = parseDataUrlPayload(item.image_url);
4796
+ return {
4797
+ type: item.type,
4798
+ mimeType: parsed?.mimeType ?? void 0,
4799
+ media: "attached-inline-data"
4800
+ };
4801
+ }
4802
+ const dataUrl = typeof item.file_url === "string" ? parseDataUrlPayload(item.file_url) : null;
4803
+ return {
4804
+ type: item.type,
4805
+ filename: item.filename ?? void 0,
4806
+ fileId: item.file_id ?? void 0,
4807
+ 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
4809
+ };
4810
+ }
4811
+ function buildGeminiFunctionResponsePart(options) {
4812
+ const outputItems = toGeminiToolOutputItems(options.outputPayload);
4813
+ if (!outputItems) {
4814
+ const responsePayload2 = isPlainRecord(options.outputPayload) ? sanitiseLogValue(options.outputPayload) : { output: sanitiseLogValue(options.outputPayload) };
4815
+ if (options.callId) {
4816
+ return (0, import_genai2.createPartFromFunctionResponse)(options.callId, options.toolName, responsePayload2);
4817
+ }
4818
+ return {
4819
+ functionResponse: {
4820
+ name: options.toolName,
4821
+ response: responsePayload2
4822
+ }
4823
+ };
4824
+ }
4825
+ const responseOutput = outputItems.map((item) => toGeminiToolOutputPlaceholder(item));
4826
+ const responseMediaParts = outputItems.flatMap((item) => {
4827
+ const mediaPart = buildGeminiToolOutputMediaPart(item);
4828
+ return mediaPart ? [mediaPart] : [];
4829
+ });
4830
+ const responsePayload = { output: responseOutput };
4831
+ if (options.callId) {
4832
+ return (0, import_genai2.createPartFromFunctionResponse)(
4833
+ options.callId,
4834
+ options.toolName,
4835
+ responsePayload,
4836
+ responseMediaParts
4837
+ );
4838
+ }
4839
+ return {
4840
+ functionResponse: {
4841
+ name: options.toolName,
4842
+ response: { output: responseOutput },
4843
+ ...responseMediaParts.length > 0 ? { parts: responseMediaParts } : {}
4844
+ }
4845
+ };
4846
+ }
4703
4847
  function parseOpenAiToolArguments(raw) {
4704
4848
  const trimmed = raw.trim();
4705
4849
  if (trimmed.length === 0) {
@@ -5160,7 +5304,7 @@ function resolveAttachmentExtension(mimeType) {
5160
5304
  function buildLoggedAttachmentFilename(prefix, index, mimeType) {
5161
5305
  return `${prefix}-${index.toString()}.${resolveAttachmentExtension(mimeType)}`;
5162
5306
  }
5163
- function decodeDataUrlAttachment(value, options) {
5307
+ function parseDataUrlPayload(value) {
5164
5308
  const trimmed = value.trim();
5165
5309
  if (!trimmed.toLowerCase().startsWith("data:")) {
5166
5310
  return null;
@@ -5176,13 +5320,24 @@ function decodeDataUrlAttachment(value, options) {
5176
5320
  try {
5177
5321
  const bytes = isBase64 ? import_node_buffer3.Buffer.from(payload, "base64") : import_node_buffer3.Buffer.from(decodeURIComponent(payload), "utf8");
5178
5322
  return {
5179
- filename: buildLoggedAttachmentFilename(options.prefix, options.index, mimeType),
5323
+ mimeType,
5324
+ dataBase64: bytes.toString("base64"),
5180
5325
  bytes
5181
5326
  };
5182
5327
  } catch {
5183
5328
  return null;
5184
5329
  }
5185
5330
  }
5331
+ function decodeDataUrlAttachment(value, options) {
5332
+ const parsed = parseDataUrlPayload(value);
5333
+ if (!parsed) {
5334
+ return null;
5335
+ }
5336
+ return {
5337
+ filename: buildLoggedAttachmentFilename(options.prefix, options.index, parsed.mimeType),
5338
+ bytes: parsed.bytes
5339
+ };
5340
+ }
5186
5341
  function collectPayloadAttachments(value, options) {
5187
5342
  if (typeof value === "string") {
5188
5343
  const attachment = decodeDataUrlAttachment(value, {
@@ -7514,14 +7669,13 @@ async function runToolLoop(request) {
7514
7669
  error: result.error,
7515
7670
  durationMs: result.durationMs
7516
7671
  });
7517
- const responsePayload = isPlainRecord(outputPayload) ? outputPayload : { output: outputPayload };
7518
- responseParts.push({
7519
- functionResponse: {
7520
- name: entry.toolName,
7521
- response: responsePayload,
7522
- ...entry.call.id ? { id: entry.call.id } : {}
7523
- }
7524
- });
7672
+ responseParts.push(
7673
+ buildGeminiFunctionResponsePart({
7674
+ toolName: entry.toolName,
7675
+ callId: entry.call.id,
7676
+ outputPayload
7677
+ })
7678
+ );
7525
7679
  }
7526
7680
  const stepCompletedAtMs = Date.now();
7527
7681
  const timing = buildStepTiming({