@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 CHANGED
@@ -4700,6 +4700,144 @@ 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.createPartFromBase64)(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.createPartFromBase64)(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.createPartFromBase64)(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.createPartFromUri)(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 buildGeminiFunctionResponseParts(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
+ {
4820
+ functionResponse: {
4821
+ name: options.toolName,
4822
+ response: responsePayload2
4823
+ }
4824
+ }
4825
+ ];
4826
+ }
4827
+ const responseOutput = outputItems.map((item) => toGeminiToolOutputPlaceholder(item));
4828
+ const responseParts = outputItems.flatMap((item) => {
4829
+ const mediaPart = buildGeminiToolOutputMediaPart(item);
4830
+ return mediaPart ? [mediaPart] : [];
4831
+ });
4832
+ const responsePayload = { output: responseOutput };
4833
+ const functionResponsePart = options.callId ? (0, import_genai2.createPartFromFunctionResponse)(options.callId, options.toolName, responsePayload) : {
4834
+ functionResponse: {
4835
+ name: options.toolName,
4836
+ response: responsePayload
4837
+ }
4838
+ };
4839
+ return [functionResponsePart, ...responseParts];
4840
+ }
4703
4841
  function parseOpenAiToolArguments(raw) {
4704
4842
  const trimmed = raw.trim();
4705
4843
  if (trimmed.length === 0) {
@@ -5160,7 +5298,7 @@ function resolveAttachmentExtension(mimeType) {
5160
5298
  function buildLoggedAttachmentFilename(prefix, index, mimeType) {
5161
5299
  return `${prefix}-${index.toString()}.${resolveAttachmentExtension(mimeType)}`;
5162
5300
  }
5163
- function decodeDataUrlAttachment(value, options) {
5301
+ function parseDataUrlPayload(value) {
5164
5302
  const trimmed = value.trim();
5165
5303
  if (!trimmed.toLowerCase().startsWith("data:")) {
5166
5304
  return null;
@@ -5176,13 +5314,24 @@ function decodeDataUrlAttachment(value, options) {
5176
5314
  try {
5177
5315
  const bytes = isBase64 ? import_node_buffer3.Buffer.from(payload, "base64") : import_node_buffer3.Buffer.from(decodeURIComponent(payload), "utf8");
5178
5316
  return {
5179
- filename: buildLoggedAttachmentFilename(options.prefix, options.index, mimeType),
5317
+ mimeType,
5318
+ dataBase64: bytes.toString("base64"),
5180
5319
  bytes
5181
5320
  };
5182
5321
  } catch {
5183
5322
  return null;
5184
5323
  }
5185
5324
  }
5325
+ function decodeDataUrlAttachment(value, options) {
5326
+ const parsed = parseDataUrlPayload(value);
5327
+ if (!parsed) {
5328
+ return null;
5329
+ }
5330
+ return {
5331
+ filename: buildLoggedAttachmentFilename(options.prefix, options.index, parsed.mimeType),
5332
+ bytes: parsed.bytes
5333
+ };
5334
+ }
5186
5335
  function collectPayloadAttachments(value, options) {
5187
5336
  if (typeof value === "string") {
5188
5337
  const attachment = decodeDataUrlAttachment(value, {
@@ -7514,14 +7663,13 @@ async function runToolLoop(request) {
7514
7663
  error: result.error,
7515
7664
  durationMs: result.durationMs
7516
7665
  });
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
- });
7666
+ responseParts.push(
7667
+ ...buildGeminiFunctionResponseParts({
7668
+ toolName: entry.toolName,
7669
+ callId: entry.call.id,
7670
+ outputPayload
7671
+ })
7672
+ );
7525
7673
  }
7526
7674
  const stepCompletedAtMs = Date.now();
7527
7675
  const timing = buildStepTiming({