@ljoukov/llm 4.0.8 → 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.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";
@@ -2769,6 +2772,33 @@ function ensureTrailingNewline(value) {
2769
2772
  function hasNonEmptyText(value) {
2770
2773
  return typeof value === "string" && value.length > 0;
2771
2774
  }
2775
+ function hasLogArtifactValue(value) {
2776
+ if (value === null || value === void 0) {
2777
+ return false;
2778
+ }
2779
+ if (typeof value === "string") {
2780
+ return value.length > 0;
2781
+ }
2782
+ if (Array.isArray(value)) {
2783
+ return value.length > 0;
2784
+ }
2785
+ if (typeof value === "object") {
2786
+ return Object.keys(value).length > 0;
2787
+ }
2788
+ return true;
2789
+ }
2790
+ function serialiseJsonArtifact(value) {
2791
+ if (!hasLogArtifactValue(value)) {
2792
+ return void 0;
2793
+ }
2794
+ try {
2795
+ return `${JSON.stringify(sanitiseLogValue(value), null, 2)}
2796
+ `;
2797
+ } catch {
2798
+ return `${JSON.stringify(String(value), null, 2)}
2799
+ `;
2800
+ }
2801
+ }
2772
2802
  function redactDataUrlPayload(value) {
2773
2803
  if (!value.toLowerCase().startsWith("data:")) {
2774
2804
  return value;
@@ -3049,7 +3079,9 @@ var AgentLoggingSessionImpl = class {
3049
3079
  const responsePath = path3.join(baseDir, "response.txt");
3050
3080
  const thoughtsPath = path3.join(baseDir, "thoughts.txt");
3051
3081
  const toolCallPath = path3.join(baseDir, "tool_call.txt");
3082
+ const toolCallJsonPath = path3.join(baseDir, "tool_call.json");
3052
3083
  const toolCallResponsePath = path3.join(baseDir, "tool_call_response.txt");
3084
+ const toolCallResponseJsonPath = path3.join(baseDir, "tool_call_response.json");
3053
3085
  const errorPath = path3.join(baseDir, "error.txt");
3054
3086
  const responseMetadataPath = path3.join(baseDir, "response.metadata.json");
3055
3087
  let chain = this.ensureReady.then(async () => {
@@ -3080,6 +3112,10 @@ var AgentLoggingSessionImpl = class {
3080
3112
  "utf8"
3081
3113
  );
3082
3114
  }
3115
+ const toolCallResponseJson = serialiseJsonArtifact(input.toolCallResponsePayload);
3116
+ if (toolCallResponseJson) {
3117
+ await writeFile(toolCallResponseJsonPath, toolCallResponseJson, "utf8");
3118
+ }
3083
3119
  }).catch(() => void 0);
3084
3120
  this.track(chain);
3085
3121
  let closed = false;
@@ -3118,6 +3154,10 @@ var AgentLoggingSessionImpl = class {
3118
3154
  if (hasNonEmptyText(options?.toolCallText)) {
3119
3155
  await writeFile(toolCallPath, ensureTrailingNewline(options.toolCallText), "utf8");
3120
3156
  }
3157
+ const toolCallJson = serialiseJsonArtifact(options?.toolCallPayload);
3158
+ if (toolCallJson) {
3159
+ await writeFile(toolCallJsonPath, toolCallJson, "utf8");
3160
+ }
3121
3161
  await this.writeAttachments(baseDir, options?.attachments);
3122
3162
  const payload = {
3123
3163
  capturedAt: toIsoNow(),
@@ -3147,6 +3187,10 @@ var AgentLoggingSessionImpl = class {
3147
3187
  if (hasNonEmptyText(options?.toolCallText)) {
3148
3188
  await writeFile(toolCallPath, ensureTrailingNewline(options.toolCallText), "utf8");
3149
3189
  }
3190
+ const toolCallJson = serialiseJsonArtifact(options?.toolCallPayload);
3191
+ if (toolCallJson) {
3192
+ await writeFile(toolCallJsonPath, toolCallJson, "utf8");
3193
+ }
3150
3194
  await this.writeAttachments(baseDir, options?.attachments);
3151
3195
  await writeFile(errorPath, ensureTrailingNewline(toErrorMessage(error)), "utf8");
3152
3196
  const payload = {
@@ -4547,6 +4591,150 @@ function toOpenAiToolOutput(value) {
4547
4591
  }
4548
4592
  return mergeToolOutput(value);
4549
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
+ }
4550
4738
  function parseOpenAiToolArguments(raw) {
4551
4739
  const trimmed = raw.trim();
4552
4740
  if (trimmed.length === 0) {
@@ -5007,7 +5195,7 @@ function resolveAttachmentExtension(mimeType) {
5007
5195
  function buildLoggedAttachmentFilename(prefix, index, mimeType) {
5008
5196
  return `${prefix}-${index.toString()}.${resolveAttachmentExtension(mimeType)}`;
5009
5197
  }
5010
- function decodeDataUrlAttachment(value, options) {
5198
+ function parseDataUrlPayload(value) {
5011
5199
  const trimmed = value.trim();
5012
5200
  if (!trimmed.toLowerCase().startsWith("data:")) {
5013
5201
  return null;
@@ -5023,13 +5211,24 @@ function decodeDataUrlAttachment(value, options) {
5023
5211
  try {
5024
5212
  const bytes = isBase64 ? Buffer4.from(payload, "base64") : Buffer4.from(decodeURIComponent(payload), "utf8");
5025
5213
  return {
5026
- filename: buildLoggedAttachmentFilename(options.prefix, options.index, mimeType),
5214
+ mimeType,
5215
+ dataBase64: bytes.toString("base64"),
5027
5216
  bytes
5028
5217
  };
5029
5218
  } catch {
5030
5219
  return null;
5031
5220
  }
5032
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
+ }
5033
5232
  function collectPayloadAttachments(value, options) {
5034
5233
  if (typeof value === "string") {
5035
5234
  const attachment = decodeDataUrlAttachment(value, {
@@ -5124,6 +5323,10 @@ function collectLoggedAttachmentsFromGeminiParts(parts, prefix) {
5124
5323
  return collectLoggedAttachmentsFromLlmParts(convertGooglePartsToLlmParts(parts), prefix);
5125
5324
  }
5126
5325
  function extractToolCallResponseTextFromOpenAiInput(input) {
5326
+ const responses = extractToolCallResponsePayloadFromOpenAiInput(input);
5327
+ return serialiseLogArtifactText(responses);
5328
+ }
5329
+ function extractToolCallResponsePayloadFromOpenAiInput(input) {
5127
5330
  if (!Array.isArray(input)) {
5128
5331
  return void 0;
5129
5332
  }
@@ -5140,9 +5343,13 @@ function extractToolCallResponseTextFromOpenAiInput(input) {
5140
5343
  }
5141
5344
  ];
5142
5345
  });
5143
- return serialiseLogArtifactText(responses);
5346
+ return responses.length > 0 ? responses : void 0;
5144
5347
  }
5145
5348
  function extractToolCallResponseTextFromFireworksMessages(messages) {
5349
+ const responses = extractToolCallResponsePayloadFromFireworksMessages(messages);
5350
+ return serialiseLogArtifactText(responses);
5351
+ }
5352
+ function extractToolCallResponsePayloadFromFireworksMessages(messages) {
5146
5353
  if (!Array.isArray(messages)) {
5147
5354
  return void 0;
5148
5355
  }
@@ -5157,9 +5364,13 @@ function extractToolCallResponseTextFromFireworksMessages(messages) {
5157
5364
  }
5158
5365
  ];
5159
5366
  });
5160
- return serialiseLogArtifactText(responses);
5367
+ return responses.length > 0 ? responses : void 0;
5161
5368
  }
5162
5369
  function extractToolCallResponseTextFromGeminiContents(contents) {
5370
+ const responses = extractToolCallResponsePayloadFromGeminiContents(contents);
5371
+ return serialiseLogArtifactText(responses);
5372
+ }
5373
+ function extractToolCallResponsePayloadFromGeminiContents(contents) {
5163
5374
  if (!Array.isArray(contents)) {
5164
5375
  return void 0;
5165
5376
  }
@@ -5182,40 +5393,36 @@ function extractToolCallResponseTextFromGeminiContents(contents) {
5182
5393
  }
5183
5394
  }
5184
5395
  }
5185
- return serialiseLogArtifactText(responses);
5396
+ return responses.length > 0 ? responses : void 0;
5186
5397
  }
5187
- function serialiseOpenAiStyleToolCallsForLogging(calls) {
5188
- return serialiseLogArtifactText(
5189
- calls.map((call) => {
5190
- if (call.kind === "custom") {
5191
- return {
5192
- kind: call.kind,
5193
- name: call.name,
5194
- callId: call.callId,
5195
- itemId: call.itemId,
5196
- input: call.input
5197
- };
5198
- }
5199
- const { value, error } = parseOpenAiToolArguments(call.arguments);
5398
+ function toLoggedOpenAiStyleToolCalls(calls) {
5399
+ return calls.map((call) => {
5400
+ if (call.kind === "custom") {
5200
5401
  return {
5201
5402
  kind: call.kind,
5202
5403
  name: call.name,
5203
5404
  callId: call.callId,
5204
5405
  itemId: call.itemId,
5205
- arguments: value,
5206
- ...error ? { parseError: error, rawArguments: call.arguments } : {}
5406
+ input: call.input
5207
5407
  };
5208
- })
5209
- );
5408
+ }
5409
+ const { value, error } = parseOpenAiToolArguments(call.arguments);
5410
+ return {
5411
+ kind: call.kind,
5412
+ name: call.name,
5413
+ callId: call.callId,
5414
+ itemId: call.itemId,
5415
+ arguments: value,
5416
+ ...error ? { parseError: error, rawArguments: call.arguments } : {}
5417
+ };
5418
+ });
5210
5419
  }
5211
- function serialiseGeminiToolCallsForLogging(calls) {
5212
- return serialiseLogArtifactText(
5213
- calls.map((call) => ({
5214
- name: call.name ?? "unknown",
5215
- callId: typeof call.id === "string" ? call.id : void 0,
5216
- arguments: sanitiseLogValue(call.args ?? {})
5217
- }))
5218
- );
5420
+ function toLoggedGeminiToolCalls(calls) {
5421
+ return calls.map((call) => ({
5422
+ name: call.name ?? "unknown",
5423
+ callId: typeof call.id === "string" ? call.id : void 0,
5424
+ arguments: sanitiseLogValue(call.args ?? {})
5425
+ }));
5219
5426
  }
5220
5427
  function startLlmCallLoggerFromContents(options) {
5221
5428
  const session = getCurrentAgentLoggingSession();
@@ -5295,6 +5502,13 @@ function startLlmCallLoggerFromPayload(options) {
5295
5502
  ) : extractToolCallResponseTextFromGeminiContents(
5296
5503
  options.requestPayload.contents
5297
5504
  );
5505
+ const toolCallResponsePayload = options.provider === "openai" || options.provider === "chatgpt" ? extractToolCallResponsePayloadFromOpenAiInput(
5506
+ options.requestPayload.input
5507
+ ) : options.provider === "fireworks" ? extractToolCallResponsePayloadFromFireworksMessages(
5508
+ options.requestPayload.messages
5509
+ ) : extractToolCallResponsePayloadFromGeminiContents(
5510
+ options.requestPayload.contents
5511
+ );
5298
5512
  return session.startLlmCall({
5299
5513
  provider: options.provider,
5300
5514
  modelId: options.modelId,
@@ -5304,7 +5518,8 @@ function startLlmCallLoggerFromPayload(options) {
5304
5518
  ...getCurrentToolCallContext() ? { toolContext: getCurrentToolCallContext() } : {}
5305
5519
  },
5306
5520
  attachments,
5307
- toolCallResponseText
5521
+ toolCallResponseText,
5522
+ toolCallResponsePayload
5308
5523
  });
5309
5524
  }
5310
5525
  async function runTextCall(params) {
@@ -6135,6 +6350,7 @@ async function runToolLoop(request) {
6135
6350
  let responseText = "";
6136
6351
  let reasoningSummary = "";
6137
6352
  let stepToolCallText;
6353
+ let stepToolCallPayload;
6138
6354
  const stepRequestPayload = {
6139
6355
  model: providerInfo.model,
6140
6356
  input,
@@ -6244,7 +6460,7 @@ async function runToolLoop(request) {
6244
6460
  emitEvent({ type: "usage", usage: usageTokens, costUsd: stepCostUsd, modelVersion });
6245
6461
  }
6246
6462
  const responseToolCalls = extractOpenAiToolCalls(finalResponse.output);
6247
- stepToolCallText = serialiseOpenAiStyleToolCallsForLogging(
6463
+ stepToolCallPayload = toLoggedOpenAiStyleToolCalls(
6248
6464
  responseToolCalls.map(
6249
6465
  (call) => call.kind === "custom" ? {
6250
6466
  kind: call.kind,
@@ -6261,6 +6477,7 @@ async function runToolLoop(request) {
6261
6477
  }
6262
6478
  )
6263
6479
  );
6480
+ stepToolCallText = serialiseLogArtifactText(stepToolCallPayload);
6264
6481
  const stepToolCalls = [];
6265
6482
  if (responseToolCalls.length === 0) {
6266
6483
  const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
@@ -6426,6 +6643,7 @@ async function runToolLoop(request) {
6426
6643
  stepCallLogger?.complete({
6427
6644
  responseText,
6428
6645
  toolCallText: stepToolCallText,
6646
+ toolCallPayload: stepToolCallPayload,
6429
6647
  metadata: {
6430
6648
  provider: "openai",
6431
6649
  model: request.model,
@@ -6446,6 +6664,7 @@ async function runToolLoop(request) {
6446
6664
  stepCallLogger?.fail(error, {
6447
6665
  responseText,
6448
6666
  toolCallText: stepToolCallText,
6667
+ toolCallPayload: stepToolCallPayload,
6449
6668
  metadata: {
6450
6669
  provider: "openai",
6451
6670
  model: request.model,
@@ -6480,6 +6699,7 @@ async function runToolLoop(request) {
6480
6699
  let responseText = "";
6481
6700
  let reasoningSummaryText = "";
6482
6701
  let stepToolCallText;
6702
+ let stepToolCallPayload;
6483
6703
  const markFirstModelEvent = () => {
6484
6704
  if (firstModelEventAtMs === void 0) {
6485
6705
  firstModelEventAtMs = Date.now();
@@ -6548,7 +6768,7 @@ async function runToolLoop(request) {
6548
6768
  stepCallLogger?.appendResponseDelta(responseText);
6549
6769
  }
6550
6770
  const responseToolCalls = response.toolCalls ?? [];
6551
- stepToolCallText = serialiseOpenAiStyleToolCallsForLogging(
6771
+ stepToolCallPayload = toLoggedOpenAiStyleToolCalls(
6552
6772
  responseToolCalls.map(
6553
6773
  (call) => call.kind === "custom" ? {
6554
6774
  kind: call.kind,
@@ -6565,6 +6785,7 @@ async function runToolLoop(request) {
6565
6785
  }
6566
6786
  )
6567
6787
  );
6788
+ stepToolCallText = serialiseLogArtifactText(stepToolCallPayload);
6568
6789
  if (responseToolCalls.length === 0) {
6569
6790
  const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
6570
6791
  const steeringItems2 = steeringInput2.length > 0 ? toChatGptInput(steeringInput2).input : [];
@@ -6737,6 +6958,7 @@ async function runToolLoop(request) {
6737
6958
  stepCallLogger?.complete({
6738
6959
  responseText,
6739
6960
  toolCallText: stepToolCallText,
6961
+ toolCallPayload: stepToolCallPayload,
6740
6962
  metadata: {
6741
6963
  provider: "chatgpt",
6742
6964
  model: request.model,
@@ -6755,6 +6977,7 @@ async function runToolLoop(request) {
6755
6977
  stepCallLogger?.fail(error, {
6756
6978
  responseText,
6757
6979
  toolCallText: stepToolCallText,
6980
+ toolCallPayload: stepToolCallPayload,
6758
6981
  metadata: {
6759
6982
  provider: "chatgpt",
6760
6983
  model: request.model,
@@ -6785,6 +7008,7 @@ async function runToolLoop(request) {
6785
7008
  let responseText = "";
6786
7009
  let blocked = false;
6787
7010
  let stepToolCallText;
7011
+ let stepToolCallPayload;
6788
7012
  const stepRequestPayload = {
6789
7013
  model: providerInfo.model,
6790
7014
  messages,
@@ -6849,7 +7073,7 @@ async function runToolLoop(request) {
6849
7073
  });
6850
7074
  }
6851
7075
  const responseToolCalls = extractFireworksToolCalls(message);
6852
- stepToolCallText = serialiseOpenAiStyleToolCallsForLogging(
7076
+ stepToolCallPayload = toLoggedOpenAiStyleToolCalls(
6853
7077
  responseToolCalls.map((call) => ({
6854
7078
  kind: "function",
6855
7079
  name: call.name,
@@ -6857,6 +7081,7 @@ async function runToolLoop(request) {
6857
7081
  callId: call.id
6858
7082
  }))
6859
7083
  );
7084
+ stepToolCallText = serialiseLogArtifactText(stepToolCallPayload);
6860
7085
  if (responseToolCalls.length === 0) {
6861
7086
  const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
6862
7087
  const steeringMessages = steeringInput2.length > 0 ? toFireworksMessages(steeringInput2) : [];
@@ -7009,6 +7234,7 @@ async function runToolLoop(request) {
7009
7234
  stepCallLogger?.complete({
7010
7235
  responseText,
7011
7236
  toolCallText: stepToolCallText,
7237
+ toolCallPayload: stepToolCallPayload,
7012
7238
  metadata: {
7013
7239
  provider: "fireworks",
7014
7240
  model: request.model,
@@ -7037,6 +7263,7 @@ async function runToolLoop(request) {
7037
7263
  stepCallLogger?.fail(error, {
7038
7264
  responseText,
7039
7265
  toolCallText: stepToolCallText,
7266
+ toolCallPayload: stepToolCallPayload,
7040
7267
  metadata: {
7041
7268
  provider: "fireworks",
7042
7269
  model: request.model,
@@ -7065,6 +7292,7 @@ async function runToolLoop(request) {
7065
7292
  let responseText = "";
7066
7293
  let thoughtsText = "";
7067
7294
  let stepToolCallText;
7295
+ let stepToolCallPayload;
7068
7296
  const markFirstModelEvent = () => {
7069
7297
  if (firstModelEventAtMs === void 0) {
7070
7298
  firstModelEventAtMs = Date.now();
@@ -7195,7 +7423,8 @@ async function runToolLoop(request) {
7195
7423
  responseImages: 0
7196
7424
  });
7197
7425
  totalCostUsd += stepCostUsd;
7198
- stepToolCallText = serialiseGeminiToolCallsForLogging(response.functionCalls);
7426
+ stepToolCallPayload = toLoggedGeminiToolCalls(response.functionCalls);
7427
+ stepToolCallText = serialiseLogArtifactText(stepToolCallPayload);
7199
7428
  if (response.functionCalls.length === 0) {
7200
7429
  const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
7201
7430
  finalText = responseText;
@@ -7331,14 +7560,13 @@ async function runToolLoop(request) {
7331
7560
  error: result.error,
7332
7561
  durationMs: result.durationMs
7333
7562
  });
7334
- const responsePayload = isPlainRecord(outputPayload) ? outputPayload : { output: outputPayload };
7335
- responseParts.push({
7336
- functionResponse: {
7337
- name: entry.toolName,
7338
- response: responsePayload,
7339
- ...entry.call.id ? { id: entry.call.id } : {}
7340
- }
7341
- });
7563
+ responseParts.push(
7564
+ buildGeminiFunctionResponsePart({
7565
+ toolName: entry.toolName,
7566
+ callId: entry.call.id,
7567
+ outputPayload
7568
+ })
7569
+ );
7342
7570
  }
7343
7571
  const stepCompletedAtMs = Date.now();
7344
7572
  const timing = buildStepTiming({
@@ -7364,6 +7592,7 @@ async function runToolLoop(request) {
7364
7592
  responseText,
7365
7593
  attachments: responseOutputAttachments,
7366
7594
  toolCallText: stepToolCallText,
7595
+ toolCallPayload: stepToolCallPayload,
7367
7596
  metadata: {
7368
7597
  provider: "gemini",
7369
7598
  model: request.model,
@@ -7386,6 +7615,7 @@ async function runToolLoop(request) {
7386
7615
  stepCallLogger?.fail(error, {
7387
7616
  responseText,
7388
7617
  toolCallText: stepToolCallText,
7618
+ toolCallPayload: stepToolCallPayload,
7389
7619
  metadata: {
7390
7620
  provider: "gemini",
7391
7621
  model: request.model,