@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/README.md CHANGED
@@ -687,9 +687,9 @@ See `docs/agent-telemetry.md` for event schema, design rationale, and backend ad
687
687
 
688
688
  Each LLM call writes:
689
689
 
690
- - `request.txt`, `request.metadata.json`, `tool_call_response.txt` (when the request includes tool outputs), and `input-<n>.<ext>` attachments immediately,
690
+ - `request.txt`, `request.metadata.json`, `tool_call_response.txt` plus `tool_call_response.json` (when the request includes tool outputs), and `input-<n>.<ext>` attachments immediately,
691
691
  - streamed `thoughts.txt` deltas during generation,
692
- - `response.txt` for assistant text responses, `tool_call.txt` when the model asks to call tools, `output-<n>.<ext>` for inline output media, and `response.metadata.json` at completion,
692
+ - `response.txt` for assistant text responses, `tool_call.txt` plus `tool_call.json` when the model asks to call tools, `output-<n>.<ext>` for inline output media, and `response.metadata.json` at completion,
693
693
  - `error.txt` plus `response.metadata.json` on failure.
694
694
 
695
695
  `image_url` data URLs are redacted in text/metadata logs (`data:...,...`) so base64 payloads are not printed inline.
package/dist/index.cjs CHANGED
@@ -2881,6 +2881,33 @@ function ensureTrailingNewline(value) {
2881
2881
  function hasNonEmptyText(value) {
2882
2882
  return typeof value === "string" && value.length > 0;
2883
2883
  }
2884
+ function hasLogArtifactValue(value) {
2885
+ if (value === null || value === void 0) {
2886
+ return false;
2887
+ }
2888
+ if (typeof value === "string") {
2889
+ return value.length > 0;
2890
+ }
2891
+ if (Array.isArray(value)) {
2892
+ return value.length > 0;
2893
+ }
2894
+ if (typeof value === "object") {
2895
+ return Object.keys(value).length > 0;
2896
+ }
2897
+ return true;
2898
+ }
2899
+ function serialiseJsonArtifact(value) {
2900
+ if (!hasLogArtifactValue(value)) {
2901
+ return void 0;
2902
+ }
2903
+ try {
2904
+ return `${JSON.stringify(sanitiseLogValue(value), null, 2)}
2905
+ `;
2906
+ } catch {
2907
+ return `${JSON.stringify(String(value), null, 2)}
2908
+ `;
2909
+ }
2910
+ }
2884
2911
  function redactDataUrlPayload(value) {
2885
2912
  if (!value.toLowerCase().startsWith("data:")) {
2886
2913
  return value;
@@ -3161,7 +3188,9 @@ var AgentLoggingSessionImpl = class {
3161
3188
  const responsePath = import_node_path3.default.join(baseDir, "response.txt");
3162
3189
  const thoughtsPath = import_node_path3.default.join(baseDir, "thoughts.txt");
3163
3190
  const toolCallPath = import_node_path3.default.join(baseDir, "tool_call.txt");
3191
+ const toolCallJsonPath = import_node_path3.default.join(baseDir, "tool_call.json");
3164
3192
  const toolCallResponsePath = import_node_path3.default.join(baseDir, "tool_call_response.txt");
3193
+ const toolCallResponseJsonPath = import_node_path3.default.join(baseDir, "tool_call_response.json");
3165
3194
  const errorPath = import_node_path3.default.join(baseDir, "error.txt");
3166
3195
  const responseMetadataPath = import_node_path3.default.join(baseDir, "response.metadata.json");
3167
3196
  let chain = this.ensureReady.then(async () => {
@@ -3192,6 +3221,10 @@ var AgentLoggingSessionImpl = class {
3192
3221
  "utf8"
3193
3222
  );
3194
3223
  }
3224
+ const toolCallResponseJson = serialiseJsonArtifact(input.toolCallResponsePayload);
3225
+ if (toolCallResponseJson) {
3226
+ await (0, import_promises.writeFile)(toolCallResponseJsonPath, toolCallResponseJson, "utf8");
3227
+ }
3195
3228
  }).catch(() => void 0);
3196
3229
  this.track(chain);
3197
3230
  let closed = false;
@@ -3230,6 +3263,10 @@ var AgentLoggingSessionImpl = class {
3230
3263
  if (hasNonEmptyText(options?.toolCallText)) {
3231
3264
  await (0, import_promises.writeFile)(toolCallPath, ensureTrailingNewline(options.toolCallText), "utf8");
3232
3265
  }
3266
+ const toolCallJson = serialiseJsonArtifact(options?.toolCallPayload);
3267
+ if (toolCallJson) {
3268
+ await (0, import_promises.writeFile)(toolCallJsonPath, toolCallJson, "utf8");
3269
+ }
3233
3270
  await this.writeAttachments(baseDir, options?.attachments);
3234
3271
  const payload = {
3235
3272
  capturedAt: toIsoNow(),
@@ -3259,6 +3296,10 @@ var AgentLoggingSessionImpl = class {
3259
3296
  if (hasNonEmptyText(options?.toolCallText)) {
3260
3297
  await (0, import_promises.writeFile)(toolCallPath, ensureTrailingNewline(options.toolCallText), "utf8");
3261
3298
  }
3299
+ const toolCallJson = serialiseJsonArtifact(options?.toolCallPayload);
3300
+ if (toolCallJson) {
3301
+ await (0, import_promises.writeFile)(toolCallJsonPath, toolCallJson, "utf8");
3302
+ }
3262
3303
  await this.writeAttachments(baseDir, options?.attachments);
3263
3304
  await (0, import_promises.writeFile)(errorPath, ensureTrailingNewline(toErrorMessage(error)), "utf8");
3264
3305
  const payload = {
@@ -4659,6 +4700,150 @@ function toOpenAiToolOutput(value) {
4659
4700
  }
4660
4701
  return mergeToolOutput(value);
4661
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
+ }
4662
4847
  function parseOpenAiToolArguments(raw) {
4663
4848
  const trimmed = raw.trim();
4664
4849
  if (trimmed.length === 0) {
@@ -5119,7 +5304,7 @@ function resolveAttachmentExtension(mimeType) {
5119
5304
  function buildLoggedAttachmentFilename(prefix, index, mimeType) {
5120
5305
  return `${prefix}-${index.toString()}.${resolveAttachmentExtension(mimeType)}`;
5121
5306
  }
5122
- function decodeDataUrlAttachment(value, options) {
5307
+ function parseDataUrlPayload(value) {
5123
5308
  const trimmed = value.trim();
5124
5309
  if (!trimmed.toLowerCase().startsWith("data:")) {
5125
5310
  return null;
@@ -5135,13 +5320,24 @@ function decodeDataUrlAttachment(value, options) {
5135
5320
  try {
5136
5321
  const bytes = isBase64 ? import_node_buffer3.Buffer.from(payload, "base64") : import_node_buffer3.Buffer.from(decodeURIComponent(payload), "utf8");
5137
5322
  return {
5138
- filename: buildLoggedAttachmentFilename(options.prefix, options.index, mimeType),
5323
+ mimeType,
5324
+ dataBase64: bytes.toString("base64"),
5139
5325
  bytes
5140
5326
  };
5141
5327
  } catch {
5142
5328
  return null;
5143
5329
  }
5144
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
+ }
5145
5341
  function collectPayloadAttachments(value, options) {
5146
5342
  if (typeof value === "string") {
5147
5343
  const attachment = decodeDataUrlAttachment(value, {
@@ -5236,6 +5432,10 @@ function collectLoggedAttachmentsFromGeminiParts(parts, prefix) {
5236
5432
  return collectLoggedAttachmentsFromLlmParts(convertGooglePartsToLlmParts(parts), prefix);
5237
5433
  }
5238
5434
  function extractToolCallResponseTextFromOpenAiInput(input) {
5435
+ const responses = extractToolCallResponsePayloadFromOpenAiInput(input);
5436
+ return serialiseLogArtifactText(responses);
5437
+ }
5438
+ function extractToolCallResponsePayloadFromOpenAiInput(input) {
5239
5439
  if (!Array.isArray(input)) {
5240
5440
  return void 0;
5241
5441
  }
@@ -5252,9 +5452,13 @@ function extractToolCallResponseTextFromOpenAiInput(input) {
5252
5452
  }
5253
5453
  ];
5254
5454
  });
5255
- return serialiseLogArtifactText(responses);
5455
+ return responses.length > 0 ? responses : void 0;
5256
5456
  }
5257
5457
  function extractToolCallResponseTextFromFireworksMessages(messages) {
5458
+ const responses = extractToolCallResponsePayloadFromFireworksMessages(messages);
5459
+ return serialiseLogArtifactText(responses);
5460
+ }
5461
+ function extractToolCallResponsePayloadFromFireworksMessages(messages) {
5258
5462
  if (!Array.isArray(messages)) {
5259
5463
  return void 0;
5260
5464
  }
@@ -5269,9 +5473,13 @@ function extractToolCallResponseTextFromFireworksMessages(messages) {
5269
5473
  }
5270
5474
  ];
5271
5475
  });
5272
- return serialiseLogArtifactText(responses);
5476
+ return responses.length > 0 ? responses : void 0;
5273
5477
  }
5274
5478
  function extractToolCallResponseTextFromGeminiContents(contents) {
5479
+ const responses = extractToolCallResponsePayloadFromGeminiContents(contents);
5480
+ return serialiseLogArtifactText(responses);
5481
+ }
5482
+ function extractToolCallResponsePayloadFromGeminiContents(contents) {
5275
5483
  if (!Array.isArray(contents)) {
5276
5484
  return void 0;
5277
5485
  }
@@ -5294,40 +5502,36 @@ function extractToolCallResponseTextFromGeminiContents(contents) {
5294
5502
  }
5295
5503
  }
5296
5504
  }
5297
- return serialiseLogArtifactText(responses);
5505
+ return responses.length > 0 ? responses : void 0;
5298
5506
  }
5299
- function serialiseOpenAiStyleToolCallsForLogging(calls) {
5300
- return serialiseLogArtifactText(
5301
- calls.map((call) => {
5302
- if (call.kind === "custom") {
5303
- return {
5304
- kind: call.kind,
5305
- name: call.name,
5306
- callId: call.callId,
5307
- itemId: call.itemId,
5308
- input: call.input
5309
- };
5310
- }
5311
- const { value, error } = parseOpenAiToolArguments(call.arguments);
5507
+ function toLoggedOpenAiStyleToolCalls(calls) {
5508
+ return calls.map((call) => {
5509
+ if (call.kind === "custom") {
5312
5510
  return {
5313
5511
  kind: call.kind,
5314
5512
  name: call.name,
5315
5513
  callId: call.callId,
5316
5514
  itemId: call.itemId,
5317
- arguments: value,
5318
- ...error ? { parseError: error, rawArguments: call.arguments } : {}
5515
+ input: call.input
5319
5516
  };
5320
- })
5321
- );
5517
+ }
5518
+ const { value, error } = parseOpenAiToolArguments(call.arguments);
5519
+ return {
5520
+ kind: call.kind,
5521
+ name: call.name,
5522
+ callId: call.callId,
5523
+ itemId: call.itemId,
5524
+ arguments: value,
5525
+ ...error ? { parseError: error, rawArguments: call.arguments } : {}
5526
+ };
5527
+ });
5322
5528
  }
5323
- function serialiseGeminiToolCallsForLogging(calls) {
5324
- return serialiseLogArtifactText(
5325
- calls.map((call) => ({
5326
- name: call.name ?? "unknown",
5327
- callId: typeof call.id === "string" ? call.id : void 0,
5328
- arguments: sanitiseLogValue(call.args ?? {})
5329
- }))
5330
- );
5529
+ function toLoggedGeminiToolCalls(calls) {
5530
+ return calls.map((call) => ({
5531
+ name: call.name ?? "unknown",
5532
+ callId: typeof call.id === "string" ? call.id : void 0,
5533
+ arguments: sanitiseLogValue(call.args ?? {})
5534
+ }));
5331
5535
  }
5332
5536
  function startLlmCallLoggerFromContents(options) {
5333
5537
  const session = getCurrentAgentLoggingSession();
@@ -5407,6 +5611,13 @@ function startLlmCallLoggerFromPayload(options) {
5407
5611
  ) : extractToolCallResponseTextFromGeminiContents(
5408
5612
  options.requestPayload.contents
5409
5613
  );
5614
+ const toolCallResponsePayload = options.provider === "openai" || options.provider === "chatgpt" ? extractToolCallResponsePayloadFromOpenAiInput(
5615
+ options.requestPayload.input
5616
+ ) : options.provider === "fireworks" ? extractToolCallResponsePayloadFromFireworksMessages(
5617
+ options.requestPayload.messages
5618
+ ) : extractToolCallResponsePayloadFromGeminiContents(
5619
+ options.requestPayload.contents
5620
+ );
5410
5621
  return session.startLlmCall({
5411
5622
  provider: options.provider,
5412
5623
  modelId: options.modelId,
@@ -5416,7 +5627,8 @@ function startLlmCallLoggerFromPayload(options) {
5416
5627
  ...getCurrentToolCallContext() ? { toolContext: getCurrentToolCallContext() } : {}
5417
5628
  },
5418
5629
  attachments,
5419
- toolCallResponseText
5630
+ toolCallResponseText,
5631
+ toolCallResponsePayload
5420
5632
  });
5421
5633
  }
5422
5634
  async function runTextCall(params) {
@@ -6247,6 +6459,7 @@ async function runToolLoop(request) {
6247
6459
  let responseText = "";
6248
6460
  let reasoningSummary = "";
6249
6461
  let stepToolCallText;
6462
+ let stepToolCallPayload;
6250
6463
  const stepRequestPayload = {
6251
6464
  model: providerInfo.model,
6252
6465
  input,
@@ -6356,7 +6569,7 @@ async function runToolLoop(request) {
6356
6569
  emitEvent({ type: "usage", usage: usageTokens, costUsd: stepCostUsd, modelVersion });
6357
6570
  }
6358
6571
  const responseToolCalls = extractOpenAiToolCalls(finalResponse.output);
6359
- stepToolCallText = serialiseOpenAiStyleToolCallsForLogging(
6572
+ stepToolCallPayload = toLoggedOpenAiStyleToolCalls(
6360
6573
  responseToolCalls.map(
6361
6574
  (call) => call.kind === "custom" ? {
6362
6575
  kind: call.kind,
@@ -6373,6 +6586,7 @@ async function runToolLoop(request) {
6373
6586
  }
6374
6587
  )
6375
6588
  );
6589
+ stepToolCallText = serialiseLogArtifactText(stepToolCallPayload);
6376
6590
  const stepToolCalls = [];
6377
6591
  if (responseToolCalls.length === 0) {
6378
6592
  const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
@@ -6538,6 +6752,7 @@ async function runToolLoop(request) {
6538
6752
  stepCallLogger?.complete({
6539
6753
  responseText,
6540
6754
  toolCallText: stepToolCallText,
6755
+ toolCallPayload: stepToolCallPayload,
6541
6756
  metadata: {
6542
6757
  provider: "openai",
6543
6758
  model: request.model,
@@ -6558,6 +6773,7 @@ async function runToolLoop(request) {
6558
6773
  stepCallLogger?.fail(error, {
6559
6774
  responseText,
6560
6775
  toolCallText: stepToolCallText,
6776
+ toolCallPayload: stepToolCallPayload,
6561
6777
  metadata: {
6562
6778
  provider: "openai",
6563
6779
  model: request.model,
@@ -6592,6 +6808,7 @@ async function runToolLoop(request) {
6592
6808
  let responseText = "";
6593
6809
  let reasoningSummaryText = "";
6594
6810
  let stepToolCallText;
6811
+ let stepToolCallPayload;
6595
6812
  const markFirstModelEvent = () => {
6596
6813
  if (firstModelEventAtMs === void 0) {
6597
6814
  firstModelEventAtMs = Date.now();
@@ -6660,7 +6877,7 @@ async function runToolLoop(request) {
6660
6877
  stepCallLogger?.appendResponseDelta(responseText);
6661
6878
  }
6662
6879
  const responseToolCalls = response.toolCalls ?? [];
6663
- stepToolCallText = serialiseOpenAiStyleToolCallsForLogging(
6880
+ stepToolCallPayload = toLoggedOpenAiStyleToolCalls(
6664
6881
  responseToolCalls.map(
6665
6882
  (call) => call.kind === "custom" ? {
6666
6883
  kind: call.kind,
@@ -6677,6 +6894,7 @@ async function runToolLoop(request) {
6677
6894
  }
6678
6895
  )
6679
6896
  );
6897
+ stepToolCallText = serialiseLogArtifactText(stepToolCallPayload);
6680
6898
  if (responseToolCalls.length === 0) {
6681
6899
  const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
6682
6900
  const steeringItems2 = steeringInput2.length > 0 ? toChatGptInput(steeringInput2).input : [];
@@ -6849,6 +7067,7 @@ async function runToolLoop(request) {
6849
7067
  stepCallLogger?.complete({
6850
7068
  responseText,
6851
7069
  toolCallText: stepToolCallText,
7070
+ toolCallPayload: stepToolCallPayload,
6852
7071
  metadata: {
6853
7072
  provider: "chatgpt",
6854
7073
  model: request.model,
@@ -6867,6 +7086,7 @@ async function runToolLoop(request) {
6867
7086
  stepCallLogger?.fail(error, {
6868
7087
  responseText,
6869
7088
  toolCallText: stepToolCallText,
7089
+ toolCallPayload: stepToolCallPayload,
6870
7090
  metadata: {
6871
7091
  provider: "chatgpt",
6872
7092
  model: request.model,
@@ -6897,6 +7117,7 @@ async function runToolLoop(request) {
6897
7117
  let responseText = "";
6898
7118
  let blocked = false;
6899
7119
  let stepToolCallText;
7120
+ let stepToolCallPayload;
6900
7121
  const stepRequestPayload = {
6901
7122
  model: providerInfo.model,
6902
7123
  messages,
@@ -6961,7 +7182,7 @@ async function runToolLoop(request) {
6961
7182
  });
6962
7183
  }
6963
7184
  const responseToolCalls = extractFireworksToolCalls(message);
6964
- stepToolCallText = serialiseOpenAiStyleToolCallsForLogging(
7185
+ stepToolCallPayload = toLoggedOpenAiStyleToolCalls(
6965
7186
  responseToolCalls.map((call) => ({
6966
7187
  kind: "function",
6967
7188
  name: call.name,
@@ -6969,6 +7190,7 @@ async function runToolLoop(request) {
6969
7190
  callId: call.id
6970
7191
  }))
6971
7192
  );
7193
+ stepToolCallText = serialiseLogArtifactText(stepToolCallPayload);
6972
7194
  if (responseToolCalls.length === 0) {
6973
7195
  const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
6974
7196
  const steeringMessages = steeringInput2.length > 0 ? toFireworksMessages(steeringInput2) : [];
@@ -7121,6 +7343,7 @@ async function runToolLoop(request) {
7121
7343
  stepCallLogger?.complete({
7122
7344
  responseText,
7123
7345
  toolCallText: stepToolCallText,
7346
+ toolCallPayload: stepToolCallPayload,
7124
7347
  metadata: {
7125
7348
  provider: "fireworks",
7126
7349
  model: request.model,
@@ -7149,6 +7372,7 @@ async function runToolLoop(request) {
7149
7372
  stepCallLogger?.fail(error, {
7150
7373
  responseText,
7151
7374
  toolCallText: stepToolCallText,
7375
+ toolCallPayload: stepToolCallPayload,
7152
7376
  metadata: {
7153
7377
  provider: "fireworks",
7154
7378
  model: request.model,
@@ -7177,6 +7401,7 @@ async function runToolLoop(request) {
7177
7401
  let responseText = "";
7178
7402
  let thoughtsText = "";
7179
7403
  let stepToolCallText;
7404
+ let stepToolCallPayload;
7180
7405
  const markFirstModelEvent = () => {
7181
7406
  if (firstModelEventAtMs === void 0) {
7182
7407
  firstModelEventAtMs = Date.now();
@@ -7307,7 +7532,8 @@ async function runToolLoop(request) {
7307
7532
  responseImages: 0
7308
7533
  });
7309
7534
  totalCostUsd += stepCostUsd;
7310
- stepToolCallText = serialiseGeminiToolCallsForLogging(response.functionCalls);
7535
+ stepToolCallPayload = toLoggedGeminiToolCalls(response.functionCalls);
7536
+ stepToolCallText = serialiseLogArtifactText(stepToolCallPayload);
7311
7537
  if (response.functionCalls.length === 0) {
7312
7538
  const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
7313
7539
  finalText = responseText;
@@ -7443,14 +7669,13 @@ async function runToolLoop(request) {
7443
7669
  error: result.error,
7444
7670
  durationMs: result.durationMs
7445
7671
  });
7446
- const responsePayload = isPlainRecord(outputPayload) ? outputPayload : { output: outputPayload };
7447
- responseParts.push({
7448
- functionResponse: {
7449
- name: entry.toolName,
7450
- response: responsePayload,
7451
- ...entry.call.id ? { id: entry.call.id } : {}
7452
- }
7453
- });
7672
+ responseParts.push(
7673
+ buildGeminiFunctionResponsePart({
7674
+ toolName: entry.toolName,
7675
+ callId: entry.call.id,
7676
+ outputPayload
7677
+ })
7678
+ );
7454
7679
  }
7455
7680
  const stepCompletedAtMs = Date.now();
7456
7681
  const timing = buildStepTiming({
@@ -7476,6 +7701,7 @@ async function runToolLoop(request) {
7476
7701
  responseText,
7477
7702
  attachments: responseOutputAttachments,
7478
7703
  toolCallText: stepToolCallText,
7704
+ toolCallPayload: stepToolCallPayload,
7479
7705
  metadata: {
7480
7706
  provider: "gemini",
7481
7707
  model: request.model,
@@ -7498,6 +7724,7 @@ async function runToolLoop(request) {
7498
7724
  stepCallLogger?.fail(error, {
7499
7725
  responseText,
7500
7726
  toolCallText: stepToolCallText,
7727
+ toolCallPayload: stepToolCallPayload,
7501
7728
  metadata: {
7502
7729
  provider: "gemini",
7503
7730
  model: request.model,