@tanstack/openai-base 0.10.16 → 0.12.1

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.
@@ -1,9 +1,10 @@
1
- import { makeStructuredOutputCompatibleWithMap } from "../utils/schema-converter.js";
1
+ import { makeStructuredOutputCompatibleWithMap, warnStrictFallback } from "../utils/schema-converter.js";
2
2
  import { buildResponsesUsage } from "../usage.js";
3
3
  import { extractRequestOptions } from "../utils/request-options.js";
4
4
  import { createToolInputNormalizer } from "../utils/tool-input-normalizer.js";
5
5
  import { convertToolsToResponsesFormat } from "./responses-tool-converter.js";
6
- import { EventType, normalizeSystemPrompts } from "@tanstack/ai";
6
+ import { hostedShellCallIds, readUserExecutedCall, userToolRequestItem, userToolResultItem } from "./responses-user-tools.js";
7
+ import { EventType, fileReferenceFor, isFileSource, normalizeSystemPrompts, unsupportedFileSourceError } from "@tanstack/ai";
7
8
  import { toRunErrorPayload, toRunErrorRawEvent } from "@tanstack/ai/adapter-internals";
8
9
  import { BaseTextAdapter } from "@tanstack/ai/adapters";
9
10
  import { generateId } from "@tanstack/ai-utils";
@@ -12,6 +13,40 @@ var PDF_BASE64_MAGIC = "JVBERi";
12
13
  function isRecord(value) {
13
14
  return typeof value === "object" && value !== null;
14
15
  }
16
+ function readURLCitation(value) {
17
+ if (!isRecord(value) || value.type !== "url_citation") return void 0;
18
+ if (typeof value.url !== "string" || typeof value.title !== "string" || typeof value.start_index !== "number" || typeof value.end_index !== "number") return;
19
+ return {
20
+ type: "url_citation",
21
+ url: value.url,
22
+ title: value.title,
23
+ start_index: value.start_index,
24
+ end_index: value.end_index
25
+ };
26
+ }
27
+ function readWebSearchCall(value) {
28
+ if (!isRecord(value) || value.type !== "web_search_call") return void 0;
29
+ if (typeof value.id !== "string" || typeof value.status !== "string" || !isRecord(value.action) || typeof value.action.type !== "string") return;
30
+ return value;
31
+ }
32
+ function collectWebSearchSources(item, citations) {
33
+ const sources = /* @__PURE__ */ new Map();
34
+ const add = (url, title) => {
35
+ if (typeof url !== "string" || url.length === 0) return;
36
+ const existing = sources.get(url);
37
+ if (existing) {
38
+ if (!existing.title && typeof title === "string" && title.length > 0) existing.title = title;
39
+ return;
40
+ }
41
+ sources.set(url, {
42
+ url,
43
+ ...typeof title === "string" && title.length > 0 ? { title } : {}
44
+ });
45
+ };
46
+ if (item.action.type === "search") for (const source of item.action.sources ?? []) add(source.url);
47
+ for (const citation of citations) add(citation.url, citation.title);
48
+ return [...sources.values()];
49
+ }
15
50
  function packResponsesReasoningSignature(id, encryptedContent) {
16
51
  if (!id && !encryptedContent) return void 0;
17
52
  return JSON.stringify({
@@ -54,10 +89,13 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
54
89
  kind = "text";
55
90
  name;
56
91
  client;
57
- constructor(model, name, client) {
92
+ /** See {@link OpenAIBaseTextAdapterOptions.strictFallbackWarning}. */
93
+ strictFallbackWarning;
94
+ constructor(model, name, client, options = {}) {
58
95
  super({}, model);
59
96
  this.name = name;
60
97
  this.client = client;
98
+ this.strictFallbackWarning = options.strictFallbackWarning ?? true;
61
99
  }
62
100
  async *chatStream(options) {
63
101
  const toolCallMetadata = /* @__PURE__ */ new Map();
@@ -197,6 +235,7 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
197
235
  let hasClosedReasoning = false;
198
236
  let model = chatOptions.model;
199
237
  let usage;
238
+ let responseCompleted = false;
200
239
  const closeReasoning = function* () {
201
240
  if (reasoningMessageId && !hasClosedReasoning) {
202
241
  hasClosedReasoning = true;
@@ -347,10 +386,11 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
347
386
  continue;
348
387
  }
349
388
  if (chunk.type === "response.completed") {
389
+ responseCompleted = true;
350
390
  const response = chunk.response;
351
391
  if (response.usage) usage = response.usage;
352
392
  if (response.model) model = response.model;
353
- continue;
393
+ break;
354
394
  }
355
395
  if (chunk.type === "response.failed") {
356
396
  const response = chunk.response;
@@ -378,6 +418,22 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
378
418
  model,
379
419
  timestamp: Date.now()
380
420
  };
421
+ if (!responseCompleted) {
422
+ const message = "Response stream ended before response.completed";
423
+ yield {
424
+ type: EventType.RUN_ERROR,
425
+ runId: aguiState.runId,
426
+ model,
427
+ timestamp: Date.now(),
428
+ message,
429
+ code: "incomplete-stream",
430
+ error: {
431
+ message,
432
+ code: "incomplete-stream"
433
+ }
434
+ };
435
+ return;
436
+ }
381
437
  if (accumulatedContent.length === 0) {
382
438
  yield {
383
439
  type: EventType.RUN_ERROR,
@@ -566,8 +622,61 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
566
622
  let closedReasoningStepId;
567
623
  let hasClosedReasoning = false;
568
624
  let runFinishedEmitted = false;
625
+ const providerWebSearchCalls = /* @__PURE__ */ new Map();
626
+ const webSearchCitations = [];
569
627
  const adapterName = this.name;
570
628
  const emitModel = () => model || options.model;
629
+ const recordProviderWebSearchCall = (value, index) => {
630
+ const item = readWebSearchCall(value);
631
+ if (!item) return;
632
+ const existing = providerWebSearchCalls.get(item.id);
633
+ if (existing) {
634
+ existing.item = item;
635
+ existing.index = index;
636
+ } else providerWebSearchCalls.set(item.id, {
637
+ item,
638
+ index,
639
+ started: false
640
+ });
641
+ };
642
+ const emitProviderWebSearchCalls = function* (assistantMessage, completedOnly = false) {
643
+ for (const entry of providerWebSearchCalls.values()) {
644
+ if (entry.started || completedOnly && entry.item.status !== "completed") continue;
645
+ const callUrls = new Set(entry.item.action.type === "search" ? (entry.item.action.sources ?? []).map((source) => source.url) : []);
646
+ const citations = webSearchCitations.filter((citation) => callUrls.has(citation.url));
647
+ const metadata = {
648
+ itemId: entry.item.id,
649
+ providerExecuted: true,
650
+ sources: collectWebSearchSources(entry.item, citations),
651
+ openai: {
652
+ webSearchCall: entry.item,
653
+ urlCitations: citations,
654
+ ...assistantMessage ? { assistantMessage } : {}
655
+ }
656
+ };
657
+ entry.started = true;
658
+ yield {
659
+ type: EventType.TOOL_CALL_START,
660
+ toolCallId: entry.item.id,
661
+ toolCallName: "web_search",
662
+ toolName: "web_search",
663
+ parentMessageId: aguiState.messageId,
664
+ model: emitModel(),
665
+ timestamp: Date.now(),
666
+ index: entry.index,
667
+ metadata
668
+ };
669
+ yield {
670
+ type: EventType.TOOL_CALL_END,
671
+ toolCallId: entry.item.id,
672
+ toolCallName: "web_search",
673
+ toolName: "web_search",
674
+ model: emitModel(),
675
+ timestamp: Date.now(),
676
+ input: entry.item.action
677
+ };
678
+ }
679
+ };
571
680
  const openReasoning = function* () {
572
681
  if (reasoningMessageId) return;
573
682
  reasoningMessageId = generateId(adapterName);
@@ -639,6 +748,46 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
639
748
  hasClosedReasoning = false;
640
749
  accumulatedReasoning = "";
641
750
  };
751
+ const userToolChunks = (item, outputIndex, bareShell) => {
752
+ const call = readUserExecutedCall(item, { bareShell });
753
+ if (!call || toolCallMetadata.get(call.callId)?.ended) return [];
754
+ const tracked = toolCallMetadata.get(call.callId) ?? {
755
+ callId: call.callId,
756
+ index: outputIndex,
757
+ name: call.name,
758
+ started: false
759
+ };
760
+ toolCallMetadata.set(call.callId, tracked);
761
+ tracked.started = true;
762
+ tracked.ended = true;
763
+ tracked.name = call.name;
764
+ const timestamp = Date.now();
765
+ const modelName = model || options.model;
766
+ const metadata = {
767
+ openaiUserTool: call.name,
768
+ ...call.itemId ? { itemId: call.itemId } : {},
769
+ ...call.maxOutputLength !== void 0 ? { maxOutputLength: call.maxOutputLength } : {}
770
+ };
771
+ return [{
772
+ type: EventType.TOOL_CALL_START,
773
+ toolCallId: call.callId,
774
+ toolCallName: call.name,
775
+ toolName: call.name,
776
+ parentMessageId: aguiState.messageId,
777
+ model: modelName,
778
+ timestamp,
779
+ index: outputIndex,
780
+ metadata
781
+ }, {
782
+ type: EventType.TOOL_CALL_END,
783
+ toolCallId: call.callId,
784
+ toolCallName: call.name,
785
+ toolName: call.name,
786
+ model: modelName,
787
+ timestamp,
788
+ input: call.input
789
+ }];
790
+ };
642
791
  const emitReasoningDelta = function* (text) {
643
792
  if (!text) return;
644
793
  yield* openReasoning();
@@ -709,6 +858,10 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
709
858
  accumulatedReasoning = "";
710
859
  }
711
860
  if (chunk.type === "response.failed" || chunk.type === "response.incomplete") {
861
+ if (chunk.type === "response.incomplete") {
862
+ for (const [index, item] of (chunk.response.output ?? []).entries()) recordProviderWebSearchCall(item, index);
863
+ yield* emitProviderWebSearchCalls(void 0, true);
864
+ }
712
865
  yield* closeReasoning();
713
866
  if (hasEmittedTextMessageStart) {
714
867
  yield {
@@ -817,6 +970,7 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
817
970
  }
818
971
  if (chunk.type === "response.output_item.added") {
819
972
  const item = chunk.item;
973
+ if (item.type === "web_search_call") recordProviderWebSearchCall(item, chunk.output_index);
820
974
  if (item.type === "reasoning") {
821
975
  captureReasoningItem(item);
822
976
  yield* openReasoning();
@@ -850,6 +1004,7 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
850
1004
  metadata.started = true;
851
1005
  }
852
1006
  }
1007
+ yield* userToolChunks(item, chunk.output_index, false);
853
1008
  }
854
1009
  if (chunk.type === "response.function_call_arguments.delta" && chunk.delta) {
855
1010
  const metadata = toolCallMetadata.get(chunk.item_id);
@@ -912,6 +1067,7 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
912
1067
  }
913
1068
  if (chunk.type === "response.output_item.done") {
914
1069
  const item = chunk.item;
1070
+ if (item.type === "web_search_call") recordProviderWebSearchCall(item, chunk.output_index);
915
1071
  if (item.type === "reasoning") {
916
1072
  captureReasoningItem(item);
917
1073
  yield* openReasoning();
@@ -973,9 +1129,17 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
973
1129
  metadata.pendingArguments = void 0;
974
1130
  }
975
1131
  }
1132
+ yield* userToolChunks(item, chunk.output_index, false);
1133
+ }
1134
+ if (chunk.type === "response.output_text.annotation.added") {
1135
+ const citation = readURLCitation(chunk.annotation);
1136
+ if (citation) webSearchCitations.push(citation);
976
1137
  }
977
1138
  if (chunk.type === "response.completed") {
978
- const completedText = chunk.response.output.flatMap((item) => item.type === "message" ? item.content : []).filter((part) => part.type === "output_text").map((part) => part.text).join("");
1139
+ const responseOutput = Array.isArray(chunk.response.output) ? chunk.response.output : [];
1140
+ const assistantMessage = responseOutput.find((item) => item.type === "message");
1141
+ for (const [index, item] of responseOutput.entries()) if (item.type === "web_search_call") recordProviderWebSearchCall(item, index);
1142
+ const completedText = responseOutput.flatMap((item) => item.type === "message" ? item.content : []).filter((part) => part.type === "output_text").map((part) => part.text).join("");
979
1143
  if (accumulatedContent.length === 0 && completedText.length > 0) {
980
1144
  if (!hasEmittedTextMessageStart) {
981
1145
  hasEmittedTextMessageStart = true;
@@ -998,7 +1162,7 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
998
1162
  content: accumulatedContent
999
1163
  };
1000
1164
  }
1001
- if (Array.isArray(chunk.response.output)) for (const item of chunk.response.output) captureReasoningItem(item);
1165
+ for (const item of responseOutput) captureReasoningItem(item);
1002
1166
  if (!reasoningMessageId && (reasoningItemId || reasoningEncryptedContent)) {
1003
1167
  const signature = packResponsesReasoningSignature(reasoningItemId, reasoningEncryptedContent);
1004
1168
  if (closedReasoningStepId && signature) yield {
@@ -1012,11 +1176,11 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1012
1176
  };
1013
1177
  else if (!closedReasoningStepId) yield* openReasoning();
1014
1178
  }
1015
- for (const item of chunk.response.output) {
1179
+ for (const [outputIndex, item] of responseOutput.entries()) {
1016
1180
  if (item.type !== "function_call" || !item.id) continue;
1017
1181
  const metadata = toolCallMetadata.get(item.id) ?? {
1018
1182
  callId: item.call_id || item.id,
1019
- index: 0,
1183
+ index: outputIndex,
1020
1184
  name: item.name || "",
1021
1185
  started: false
1022
1186
  };
@@ -1070,6 +1234,12 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1070
1234
  metadata.pendingArguments = void 0;
1071
1235
  }
1072
1236
  }
1237
+ yield* emitProviderWebSearchCalls(assistantMessage);
1238
+ const shellOutputs = hostedShellCallIds(responseOutput);
1239
+ for (const [outputIndex, item] of responseOutput.entries()) {
1240
+ if (isRecord(item) && item.type === "shell_call" && typeof item.call_id === "string" && shellOutputs.has(item.call_id)) continue;
1241
+ yield* userToolChunks(item, outputIndex, true);
1242
+ }
1073
1243
  yield* closeReasoning();
1074
1244
  if (hasEmittedTextMessageStart) {
1075
1245
  yield {
@@ -1080,7 +1250,12 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1080
1250
  };
1081
1251
  hasEmittedTextMessageStart = false;
1082
1252
  }
1083
- const hasFunctionCalls = chunk.response.output.some((item) => item.type === "function_call");
1253
+ const hasFunctionCalls = responseOutput.some((item) => {
1254
+ if (!isRecord(item)) return false;
1255
+ if (item.type === "function_call") return true;
1256
+ if (item.type === "shell_call" && typeof item.call_id === "string" && shellOutputs.has(item.call_id)) return false;
1257
+ return readUserExecutedCall(item, { bareShell: true }) !== null;
1258
+ });
1084
1259
  const incompleteReason = chunk.response.incomplete_details?.reason;
1085
1260
  const finishReason = hasFunctionCalls ? "tool_calls" : incompleteReason === "max_output_tokens" ? "length" : incompleteReason === "content_filter" ? "content_filter" : "stop";
1086
1261
  yield {
@@ -1093,6 +1268,7 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1093
1268
  finishReason
1094
1269
  };
1095
1270
  runFinishedEmitted = true;
1271
+ return;
1096
1272
  }
1097
1273
  if (chunk.type === "error") {
1098
1274
  const code = chunk.code ?? void 0;
@@ -1112,6 +1288,7 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1112
1288
  }
1113
1289
  }
1114
1290
  if (!runFinishedEmitted && aguiState.hasEmittedRunStarted) {
1291
+ yield* emitProviderWebSearchCalls(void 0, true);
1115
1292
  yield* closeReasoning();
1116
1293
  if (hasEmittedTextMessageStart) yield {
1117
1294
  type: EventType.TEXT_MESSAGE_END,
@@ -1119,13 +1296,17 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1119
1296
  model: model || options.model,
1120
1297
  timestamp: Date.now()
1121
1298
  };
1299
+ const message = "Response stream ended before response.completed";
1122
1300
  yield {
1123
- type: EventType.RUN_FINISHED,
1124
- runId: aguiState.runId,
1125
- threadId: aguiState.threadId,
1301
+ type: EventType.RUN_ERROR,
1126
1302
  model: model || options.model,
1127
1303
  timestamp: Date.now(),
1128
- finishReason: toolCallMetadata.size > 0 ? "tool_calls" : "stop"
1304
+ message,
1305
+ code: "incomplete-stream",
1306
+ error: {
1307
+ message,
1308
+ code: "incomplete-stream"
1309
+ }
1129
1310
  };
1130
1311
  }
1131
1312
  } catch (error) {
@@ -1155,6 +1336,7 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1155
1336
  */
1156
1337
  mapOptionsToRequest(options) {
1157
1338
  const input = this.convertMessagesToInput(options.messages);
1339
+ if (this.strictFallbackWarning) warnStrictFallback(options.tools, options.logger);
1158
1340
  const tools = options.tools ? convertToolsToResponsesFormat(options.tools, this.makeStructuredOutputCompatible.bind(this)) : void 0;
1159
1341
  const modelOptions = options.modelOptions;
1160
1342
  const combinedSchema = options.outputSchema;
@@ -1198,8 +1380,16 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1198
1380
  */
1199
1381
  convertMessagesToInput(messages) {
1200
1382
  const result = [];
1383
+ const seenReasoningIds = /* @__PURE__ */ new Set();
1384
+ const userToolCalls = /* @__PURE__ */ new Map();
1201
1385
  for (const message of messages) {
1202
1386
  if (message.role === "tool") {
1387
+ const owner = message.toolCallId ? userToolCalls.get(message.toolCallId) : void 0;
1388
+ const userOutput = owner ? userToolResultItem(owner, message.content) : null;
1389
+ if (userOutput) {
1390
+ result.push(userOutput);
1391
+ continue;
1392
+ }
1203
1393
  const toolContent = message.content;
1204
1394
  const output = Array.isArray(toolContent) ? toolContent.map((part) => this.convertContentPartToInput(part)) : typeof toolContent === "string" ? toolContent : JSON.stringify(toolContent);
1205
1395
  result.push({
@@ -1210,10 +1400,16 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1210
1400
  continue;
1211
1401
  }
1212
1402
  if (message.role === "assistant") {
1403
+ let reasoningCandidates = 0;
1404
+ let emittedReasoning = 0;
1213
1405
  if (message.thinking) for (const thinking of message.thinking) {
1214
1406
  if (!thinking.signature) continue;
1215
1407
  const packed = unpackResponsesReasoningSignature(thinking.signature);
1216
1408
  if (!packed?.id) continue;
1409
+ reasoningCandidates++;
1410
+ if (seenReasoningIds.has(packed.id)) continue;
1411
+ seenReasoningIds.add(packed.id);
1412
+ emittedReasoning++;
1217
1413
  result.push({
1218
1414
  type: "reasoning",
1219
1415
  id: packed.id,
@@ -1224,18 +1420,44 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1224
1420
  }] : []
1225
1421
  });
1226
1422
  }
1423
+ const canPairReasoning = reasoningCandidates === 0 || reasoningCandidates === 1 && emittedReasoning === 1;
1424
+ let rawAssistantMessage;
1227
1425
  if (message.toolCalls && message.toolCalls.length > 0) for (const toolCall of message.toolCalls) {
1426
+ const metadata = toolCall.metadata;
1427
+ if (metadata?.providerExecuted) {
1428
+ const webSearchCall = metadata.openai?.webSearchCall;
1429
+ if (webSearchCall && canPairReasoning) {
1430
+ result.push(webSearchCall);
1431
+ rawAssistantMessage ??= metadata.openai?.assistantMessage;
1432
+ }
1433
+ continue;
1434
+ }
1228
1435
  const argumentsString = typeof toolCall.function.arguments === "string" ? toolCall.function.arguments : JSON.stringify(toolCall.function.arguments);
1229
- const itemId = toolCall.metadata?.itemId;
1436
+ const replayCall = {
1437
+ id: toolCall.id,
1438
+ function: {
1439
+ name: toolCall.function.name,
1440
+ arguments: argumentsString
1441
+ },
1442
+ ...toolCall.metadata !== void 0 ? { metadata: toolCall.metadata } : {}
1443
+ };
1444
+ const userItem = userToolRequestItem(replayCall);
1445
+ if (userItem) {
1446
+ userToolCalls.set(toolCall.id, replayCall);
1447
+ result.push(userItem);
1448
+ continue;
1449
+ }
1450
+ const itemId = metadata?.itemId;
1230
1451
  result.push({
1231
1452
  type: "function_call",
1232
1453
  call_id: toolCall.id,
1233
- ...itemId && { id: itemId },
1454
+ ...itemId && canPairReasoning && { id: itemId },
1234
1455
  name: toolCall.function.name,
1235
1456
  arguments: argumentsString
1236
1457
  });
1237
1458
  }
1238
- if (message.content) {
1459
+ if (rawAssistantMessage) result.push(rawAssistantMessage);
1460
+ else if (message.content) {
1239
1461
  const contentStr = this.extractTextContent(message.content);
1240
1462
  if (contentStr) result.push({
1241
1463
  type: "message",
@@ -1270,6 +1492,14 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1270
1492
  };
1271
1493
  case "image": {
1272
1494
  const imageMetadata = part.metadata;
1495
+ if (isFileSource(part.source)) {
1496
+ if (this.supportsFileSources !== true) throw unsupportedFileSourceError(this.name);
1497
+ return {
1498
+ type: "input_image",
1499
+ file_id: fileReferenceFor(part.source, this.name),
1500
+ detail: imageMetadata?.detail || "auto"
1501
+ };
1502
+ }
1273
1503
  if (part.source.type === "url") return {
1274
1504
  type: "input_image",
1275
1505
  image_url: part.source.value,
@@ -1284,6 +1514,13 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1284
1514
  };
1285
1515
  }
1286
1516
  case "audio": {
1517
+ if (isFileSource(part.source)) {
1518
+ if (this.supportsFileSources !== true) throw unsupportedFileSourceError(this.name);
1519
+ return {
1520
+ type: "input_file",
1521
+ file_id: fileReferenceFor(part.source, this.name)
1522
+ };
1523
+ }
1287
1524
  if (part.source.type === "url") return {
1288
1525
  type: "input_file",
1289
1526
  file_url: part.source.value
@@ -1298,6 +1535,14 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
1298
1535
  case "document": {
1299
1536
  const documentMetadata = part.metadata;
1300
1537
  const documentDetail = documentMetadata?.detail !== void 0 ? { detail: documentMetadata.detail } : {};
1538
+ if (isFileSource(part.source)) {
1539
+ if (this.supportsFileSources !== true) throw unsupportedFileSourceError(this.name);
1540
+ return {
1541
+ type: "input_file",
1542
+ file_id: fileReferenceFor(part.source, this.name),
1543
+ ...documentDetail
1544
+ };
1545
+ }
1301
1546
  if (part.source.type === "url") return {
1302
1547
  type: "input_file",
1303
1548
  file_url: part.source.value,