@langchain/openai 0.5.6 → 0.5.8

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,5 +1,5 @@
1
1
  import { OpenAI as OpenAIClient } from "openai";
2
- import { AIMessage, AIMessageChunk, ChatMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, SystemMessageChunk, ToolMessageChunk, isAIMessage, } from "@langchain/core/messages";
2
+ import { AIMessage, AIMessageChunk, ChatMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, SystemMessageChunk, ToolMessageChunk, isAIMessage, parseBase64DataUrl, parseMimeType, convertToProviderContentBlock, isDataContentBlock, } from "@langchain/core/messages";
3
3
  import { ChatGenerationChunk, } from "@langchain/core/outputs";
4
4
  import { getEnvironmentVariable } from "@langchain/core/utils/env";
5
5
  import { BaseChatModel, } from "@langchain/core/language_models/chat_models";
@@ -46,6 +46,132 @@ export function messageToOpenAIRole(message) {
46
46
  throw new Error(`Unknown message type: ${type}`);
47
47
  }
48
48
  }
49
+ const completionsApiContentBlockConverter = {
50
+ providerName: "ChatOpenAI",
51
+ fromStandardTextBlock(block) {
52
+ return { type: "text", text: block.text };
53
+ },
54
+ fromStandardImageBlock(block) {
55
+ if (block.source_type === "url") {
56
+ return {
57
+ type: "image_url",
58
+ image_url: {
59
+ url: block.url,
60
+ ...(block.metadata?.detail
61
+ ? { detail: block.metadata.detail }
62
+ : {}),
63
+ },
64
+ };
65
+ }
66
+ if (block.source_type === "base64") {
67
+ const url = `data:${block.mime_type ?? ""};base64,${block.data}`;
68
+ return {
69
+ type: "image_url",
70
+ image_url: {
71
+ url,
72
+ ...(block.metadata?.detail
73
+ ? { detail: block.metadata.detail }
74
+ : {}),
75
+ },
76
+ };
77
+ }
78
+ throw new Error(`Image content blocks with source_type ${block.source_type} are not supported for ChatOpenAI`);
79
+ },
80
+ fromStandardAudioBlock(block) {
81
+ if (block.source_type === "url") {
82
+ const data = parseBase64DataUrl({ dataUrl: block.url });
83
+ if (!data) {
84
+ throw new Error(`URL audio blocks with source_type ${block.source_type} must be formatted as a data URL for ChatOpenAI`);
85
+ }
86
+ const rawMimeType = data.mime_type || block.mime_type || "";
87
+ let mimeType;
88
+ try {
89
+ mimeType = parseMimeType(rawMimeType);
90
+ }
91
+ catch {
92
+ throw new Error(`Audio blocks with source_type ${block.source_type} must have mime type of audio/wav or audio/mp3`);
93
+ }
94
+ if (mimeType.type !== "audio" ||
95
+ (mimeType.subtype !== "wav" && mimeType.subtype !== "mp3")) {
96
+ throw new Error(`Audio blocks with source_type ${block.source_type} must have mime type of audio/wav or audio/mp3`);
97
+ }
98
+ return {
99
+ type: "input_audio",
100
+ input_audio: {
101
+ format: mimeType.subtype,
102
+ data: data.data,
103
+ },
104
+ };
105
+ }
106
+ if (block.source_type === "base64") {
107
+ let mimeType;
108
+ try {
109
+ mimeType = parseMimeType(block.mime_type ?? "");
110
+ }
111
+ catch {
112
+ throw new Error(`Audio blocks with source_type ${block.source_type} must have mime type of audio/wav or audio/mp3`);
113
+ }
114
+ if (mimeType.type !== "audio" ||
115
+ (mimeType.subtype !== "wav" && mimeType.subtype !== "mp3")) {
116
+ throw new Error(`Audio blocks with source_type ${block.source_type} must have mime type of audio/wav or audio/mp3`);
117
+ }
118
+ return {
119
+ type: "input_audio",
120
+ input_audio: {
121
+ format: mimeType.subtype,
122
+ data: block.data,
123
+ },
124
+ };
125
+ }
126
+ throw new Error(`Audio content blocks with source_type ${block.source_type} are not supported for ChatOpenAI`);
127
+ },
128
+ fromStandardFileBlock(block) {
129
+ if (block.source_type === "url") {
130
+ const data = parseBase64DataUrl({ dataUrl: block.url });
131
+ if (!data) {
132
+ throw new Error(`URL file blocks with source_type ${block.source_type} must be formatted as a data URL for ChatOpenAI`);
133
+ }
134
+ return {
135
+ type: "file",
136
+ file: {
137
+ file_data: block.url,
138
+ ...(block.metadata?.filename || block.metadata?.name
139
+ ? {
140
+ filename: (block.metadata?.filename ||
141
+ block.metadata?.name),
142
+ }
143
+ : {}),
144
+ },
145
+ };
146
+ }
147
+ if (block.source_type === "base64") {
148
+ return {
149
+ type: "file",
150
+ file: {
151
+ file_data: `data:${block.mime_type ?? ""};base64,${block.data}`,
152
+ ...(block.metadata?.filename ||
153
+ block.metadata?.name ||
154
+ block.metadata?.title
155
+ ? {
156
+ filename: (block.metadata?.filename ||
157
+ block.metadata?.name ||
158
+ block.metadata?.title),
159
+ }
160
+ : {}),
161
+ },
162
+ };
163
+ }
164
+ if (block.source_type === "id") {
165
+ return {
166
+ type: "file",
167
+ file: {
168
+ file_id: block.id,
169
+ },
170
+ };
171
+ }
172
+ throw new Error(`File content blocks with source_type ${block.source_type} are not supported for ChatOpenAI`);
173
+ },
174
+ };
49
175
  // Used in LangSmith, export is important here
50
176
  export function _convertMessagesToOpenAIParams(messages, model) {
51
177
  // TODO: Function messages do not support array content, fix cast
@@ -54,10 +180,18 @@ export function _convertMessagesToOpenAIParams(messages, model) {
54
180
  if (role === "system" && isReasoningModel(model)) {
55
181
  role = "developer";
56
182
  }
183
+ const content = typeof message.content === "string"
184
+ ? message.content
185
+ : message.content.map((m) => {
186
+ if (isDataContentBlock(m)) {
187
+ return convertToProviderContentBlock(m, completionsApiContentBlockConverter);
188
+ }
189
+ return m;
190
+ });
57
191
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
192
  const completionParam = {
59
193
  role,
60
- content: message.content,
194
+ content,
61
195
  };
62
196
  if (message.name != null) {
63
197
  completionParam.name = message.name;
@@ -93,8 +227,32 @@ export function _convertMessagesToOpenAIParams(messages, model) {
93
227
  });
94
228
  }
95
229
  const _FUNCTION_CALL_IDS_MAP_KEY = "__openai_function_call_ids__";
96
- function _convertMessagesToOpenAIResponsesParams(messages, model) {
97
- return messages.flatMap((lcMsg) => {
230
+ function _convertReasoningSummaryToOpenAIResponsesParams(reasoning) {
231
+ // combine summary parts that have the the same index and then remove the indexes
232
+ const summary = (reasoning.summary.length > 1
233
+ ? reasoning.summary.reduce((acc, curr) => {
234
+ const last = acc.at(-1);
235
+ if (last.index === curr.index) {
236
+ last.text += curr.text;
237
+ }
238
+ else {
239
+ acc.push(curr);
240
+ }
241
+ return acc;
242
+ }, [{ ...reasoning.summary[0] }])
243
+ : reasoning.summary).map((s) => Object.fromEntries(Object.entries(s).filter(([k]) => k !== "index")));
244
+ return {
245
+ ...reasoning,
246
+ summary,
247
+ };
248
+ }
249
+ function _convertMessagesToOpenAIResponsesParams(messages, model, zdrEnabled) {
250
+ const lastAIMessage = messages.filter((m) => isAIMessage(m)).pop();
251
+ const lastAIMessageId = lastAIMessage?.response_metadata?.id;
252
+ const newMessages = lastAIMessageId && lastAIMessageId.startsWith("resp_") && !zdrEnabled
253
+ ? messages.slice(messages.indexOf(lastAIMessage) + 1)
254
+ : messages;
255
+ return newMessages.flatMap((lcMsg) => {
98
256
  let role = messageToOpenAIRole(lcMsg);
99
257
  if (role === "system" && isReasoningModel(model))
100
258
  role = "developer";
@@ -144,15 +302,25 @@ function _convertMessagesToOpenAIResponsesParams(messages, model) {
144
302
  };
145
303
  }
146
304
  if (role === "assistant") {
305
+ // if we have the original response items, just reuse them
306
+ if (!zdrEnabled &&
307
+ lcMsg.response_metadata.output != null &&
308
+ Array.isArray(lcMsg.response_metadata.output) &&
309
+ lcMsg.response_metadata.output.length > 0 &&
310
+ lcMsg.response_metadata.output.every((item) => "type" in item)) {
311
+ return lcMsg.response_metadata.output;
312
+ }
313
+ // otherwise, try to reconstruct the response from what we have
147
314
  const input = [];
148
315
  // reasoning items
149
- if (lcMsg.additional_kwargs.reasoning != null) {
316
+ if (!zdrEnabled && lcMsg.additional_kwargs.reasoning != null) {
150
317
  const isReasoningItem = (item) => typeof item === "object" &&
151
318
  item != null &&
152
319
  "type" in item &&
153
320
  item.type === "reasoning";
154
321
  if (isReasoningItem(lcMsg.additional_kwargs.reasoning)) {
155
- input.push(lcMsg.additional_kwargs.reasoning);
322
+ const reasoningItem = _convertReasoningSummaryToOpenAIResponsesParams(lcMsg.additional_kwargs.reasoning);
323
+ input.push(reasoningItem);
156
324
  }
157
325
  }
158
326
  // ai content
@@ -169,6 +337,7 @@ function _convertMessagesToOpenAIResponsesParams(messages, model) {
169
337
  input.push({
170
338
  type: "message",
171
339
  role: "assistant",
340
+ ...(lcMsg.id && !zdrEnabled ? { id: lcMsg.id } : {}),
172
341
  content: typeof content === "string"
173
342
  ? content
174
343
  : content.flatMap((item) => {
@@ -196,7 +365,7 @@ function _convertMessagesToOpenAIResponsesParams(messages, model) {
196
365
  name: toolCall.name,
197
366
  arguments: JSON.stringify(toolCall.args),
198
367
  call_id: toolCall.id,
199
- id: functionCallIds?.[toolCall.id],
368
+ ...(zdrEnabled ? { id: functionCallIds?.[toolCall.id] } : {}),
200
369
  })));
201
370
  }
202
371
  else if (lcMsg.additional_kwargs.tool_calls != null) {
@@ -204,21 +373,17 @@ function _convertMessagesToOpenAIResponsesParams(messages, model) {
204
373
  type: "function_call",
205
374
  name: toolCall.function.name,
206
375
  call_id: toolCall.id,
207
- id: functionCallIds?.[toolCall.id],
376
+ ...(zdrEnabled ? { id: functionCallIds?.[toolCall.id] } : {}),
208
377
  arguments: toolCall.function.arguments,
209
378
  })));
210
379
  }
211
380
  const toolOutputs = lcMsg.response_metadata.output?.length
212
381
  ? lcMsg.response_metadata.output
213
382
  : lcMsg.additional_kwargs.tool_outputs;
383
+ let computerCalls = [];
214
384
  if (toolOutputs != null) {
215
385
  const castToolOutputs = toolOutputs;
216
- const reasoningCalls = castToolOutputs?.filter((item) => item.type === "reasoning");
217
- const computerCalls = castToolOutputs?.filter((item) => item.type === "computer_call");
218
- // NOTE: Reasoning outputs must be passed to the model BEFORE computer calls.
219
- if (reasoningCalls.length > 0 && computerCalls.length > 0) {
220
- input.push(...reasoningCalls);
221
- }
386
+ computerCalls = castToolOutputs?.filter((item) => item.type === "computer_call");
222
387
  if (computerCalls.length > 0)
223
388
  input.push(...computerCalls);
224
389
  }
@@ -227,6 +392,9 @@ function _convertMessagesToOpenAIResponsesParams(messages, model) {
227
392
  const content = typeof lcMsg.content === "string"
228
393
  ? lcMsg.content
229
394
  : lcMsg.content.flatMap((item) => {
395
+ if (isDataContentBlock(item)) {
396
+ return convertToProviderContentBlock(item, completionsApiContentBlockConverter);
397
+ }
230
398
  if (item.type === "text") {
231
399
  return { type: "input_text", text: item.text };
232
400
  }
@@ -419,6 +587,39 @@ function _convertOpenAIResponsesDeltaToBaseMessageChunk(chunk) {
419
587
  else if (chunk.type === "response.refusal.done") {
420
588
  additional_kwargs.refusal = chunk.refusal;
421
589
  }
590
+ else if (chunk.type === "response.output_item.added" &&
591
+ "item" in chunk &&
592
+ chunk.item.type === "reasoning") {
593
+ const summary = chunk
594
+ .item.summary
595
+ ? chunk.item.summary.map((s, index) => ({
596
+ ...s,
597
+ index,
598
+ }))
599
+ : undefined;
600
+ additional_kwargs.reasoning = {
601
+ // We only capture ID in the first chunk or else the concatenated result of all chunks will
602
+ // have an ID field that is repeated once per chunk. There is special handling for the `type`
603
+ // field that prevents this, however.
604
+ id: chunk.item.id,
605
+ type: chunk.item.type,
606
+ ...(summary ? { summary } : {}),
607
+ };
608
+ }
609
+ else if (chunk.type === "response.reasoning_summary_part.added") {
610
+ additional_kwargs.reasoning = {
611
+ type: "reasoning",
612
+ summary: [{ ...chunk.part, index: chunk.summary_index }],
613
+ };
614
+ }
615
+ else if (chunk.type === "response.reasoning_summary_text.delta") {
616
+ additional_kwargs.reasoning = {
617
+ type: "reasoning",
618
+ summary: [
619
+ { text: chunk.delta, type: "summary_text", index: chunk.summary_index },
620
+ ],
621
+ };
622
+ }
422
623
  else {
423
624
  return null;
424
625
  }
@@ -461,9 +662,7 @@ function _convertChatOpenAIToolTypeToOpenAITool(tool, fields) {
461
662
  return _convertToOpenAITool(tool, fields);
462
663
  }
463
664
  function isReasoningModel(model) {
464
- return (model?.startsWith("o1") ||
465
- model?.startsWith("o3") ||
466
- model?.startsWith("o4"));
665
+ return model && /^o\d/.test(model);
467
666
  }
468
667
  /**
469
668
  * OpenAI chat model integration.
@@ -1071,6 +1270,9 @@ export class ChatOpenAI extends BaseChatModel {
1071
1270
  "tags",
1072
1271
  "metadata",
1073
1272
  "disableStreaming",
1273
+ "useResponsesApi",
1274
+ "zdrEnabled",
1275
+ "reasoning",
1074
1276
  ];
1075
1277
  }
1076
1278
  constructor(fields) {
@@ -1248,18 +1450,51 @@ export class ChatOpenAI extends BaseChatModel {
1248
1450
  writable: true,
1249
1451
  value: void 0
1250
1452
  });
1453
+ /**
1454
+ * @deprecated Use {@link reasoning} object instead.
1455
+ */
1251
1456
  Object.defineProperty(this, "reasoningEffort", {
1252
1457
  enumerable: true,
1253
1458
  configurable: true,
1254
1459
  writable: true,
1255
1460
  value: void 0
1256
1461
  });
1462
+ /**
1463
+ * Options for reasoning models.
1464
+ */
1465
+ Object.defineProperty(this, "reasoning", {
1466
+ enumerable: true,
1467
+ configurable: true,
1468
+ writable: true,
1469
+ value: void 0
1470
+ });
1471
+ /**
1472
+ * Whether to use the responses API for all requests. If `false` the responses API will be used
1473
+ * only when required in order to fulfill the request.
1474
+ */
1257
1475
  Object.defineProperty(this, "useResponsesApi", {
1258
1476
  enumerable: true,
1259
1477
  configurable: true,
1260
1478
  writable: true,
1261
1479
  value: false
1262
1480
  });
1481
+ /**
1482
+ * Must be set to `true` in tenancies with Zero Data Retention. Setting to `true` will disable
1483
+ * output storage in the Responses API, but this DOES NOT enable Zero Data Retention in your
1484
+ * OpenAI organization or project. This must be configured directly with OpenAI.
1485
+ *
1486
+ * See:
1487
+ * https://help.openai.com/en/articles/10503543-data-residency-for-the-openai-api
1488
+ * https://platform.openai.com/docs/api-reference/responses/create#responses-create-store
1489
+ *
1490
+ * @default false
1491
+ */
1492
+ Object.defineProperty(this, "zdrEnabled", {
1493
+ enumerable: true,
1494
+ configurable: true,
1495
+ writable: true,
1496
+ value: void 0
1497
+ });
1263
1498
  this.openAIApiKey =
1264
1499
  fields?.apiKey ??
1265
1500
  fields?.openAIApiKey ??
@@ -1287,7 +1522,12 @@ export class ChatOpenAI extends BaseChatModel {
1287
1522
  this.__includeRawResponse = fields?.__includeRawResponse;
1288
1523
  this.audio = fields?.audio;
1289
1524
  this.modalities = fields?.modalities;
1290
- this.reasoningEffort = fields?.reasoningEffort;
1525
+ this.reasoningEffort = fields?.reasoningEffort ?? fields?.reasoning?.effort;
1526
+ this.reasoning =
1527
+ fields?.reasoning ??
1528
+ (fields?.reasoningEffort
1529
+ ? { effort: fields.reasoningEffort }
1530
+ : undefined);
1291
1531
  this.maxTokens = fields?.maxCompletionTokens ?? fields?.maxTokens;
1292
1532
  this.useResponsesApi = fields?.useResponsesApi ?? this.useResponsesApi;
1293
1533
  this.disableStreaming = fields?.disableStreaming ?? this.disableStreaming;
@@ -1310,6 +1550,7 @@ export class ChatOpenAI extends BaseChatModel {
1310
1550
  if (fields?.supportsStrictToolCalling !== undefined) {
1311
1551
  this.supportsStrictToolCalling = fields.supportsStrictToolCalling;
1312
1552
  }
1553
+ this.zdrEnabled = fields?.zdrEnabled ?? false;
1313
1554
  }
1314
1555
  getLsParams(options) {
1315
1556
  const params = this.invocationParams(options);
@@ -1348,6 +1589,35 @@ export class ChatOpenAI extends BaseChatModel {
1348
1589
  }
1349
1590
  return resFormat;
1350
1591
  }
1592
+ getReasoningParams(options) {
1593
+ if (!isReasoningModel(this.model)) {
1594
+ return;
1595
+ }
1596
+ let reasoning;
1597
+ // apply reasoning options in reverse order of priority without else blocks so that highest priority overrides lowest priority
1598
+ if (this.reasoningEffort !== undefined) {
1599
+ reasoning = { effort: this.reasoningEffort };
1600
+ }
1601
+ if (this.reasoning !== undefined) {
1602
+ reasoning = {
1603
+ ...reasoning,
1604
+ ...this.reasoning,
1605
+ };
1606
+ }
1607
+ if (options?.reasoning_effort !== undefined) {
1608
+ reasoning = {
1609
+ ...reasoning,
1610
+ effort: options.reasoning_effort,
1611
+ };
1612
+ }
1613
+ if (options?.reasoning !== undefined) {
1614
+ reasoning = {
1615
+ ...reasoning,
1616
+ ...options.reasoning,
1617
+ };
1618
+ }
1619
+ return reasoning;
1620
+ }
1351
1621
  /**
1352
1622
  * Get the parameters used to invoke the model
1353
1623
  */
@@ -1424,11 +1694,12 @@ export class ChatOpenAI extends BaseChatModel {
1424
1694
  })(),
1425
1695
  parallel_tool_calls: options?.parallel_tool_calls,
1426
1696
  max_output_tokens: this.maxTokens === -1 ? undefined : this.maxTokens,
1697
+ ...(this.zdrEnabled ? { store: false } : {}),
1427
1698
  ...this.modelKwargs,
1428
1699
  };
1429
- const reasoningEffort = options?.reasoning_effort ?? this.reasoningEffort;
1430
- if (reasoningEffort !== undefined) {
1431
- params.reasoning = { effort: reasoningEffort };
1700
+ const reasoning = this.getReasoningParams(options);
1701
+ if (reasoning !== undefined) {
1702
+ params.reasoning = reasoning;
1432
1703
  }
1433
1704
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1434
1705
  return params;
@@ -1475,9 +1746,9 @@ export class ChatOpenAI extends BaseChatModel {
1475
1746
  if (options?.prediction !== undefined) {
1476
1747
  params.prediction = options.prediction;
1477
1748
  }
1478
- const reasoningEffort = options?.reasoning_effort ?? this.reasoningEffort;
1479
- if (reasoningEffort !== undefined) {
1480
- params.reasoning_effort = reasoningEffort;
1749
+ const reasoning = this.getReasoningParams(options);
1750
+ if (reasoning !== undefined && reasoning.effort !== undefined) {
1751
+ params.reasoning_effort = reasoning.effort;
1481
1752
  }
1482
1753
  if (isReasoningModel(params.model)) {
1483
1754
  params.max_completion_tokens =
@@ -1631,10 +1902,17 @@ export class ChatOpenAI extends BaseChatModel {
1631
1902
  }
1632
1903
  async *_streamResponseChunks(messages, options, runManager) {
1633
1904
  if (this._useResponseApi(options)) {
1905
+ const lastAIMessage = messages.filter((m) => isAIMessage(m)).pop();
1906
+ const lastAIMessageId = lastAIMessage?.response_metadata?.id;
1634
1907
  const streamIterable = await this.responseApiWithRetry({
1635
1908
  ...this.invocationParams(options, { streaming: true }),
1636
- input: _convertMessagesToOpenAIResponsesParams(messages, this.model),
1909
+ input: _convertMessagesToOpenAIResponsesParams(messages, this.model, this.zdrEnabled),
1637
1910
  stream: true,
1911
+ ...(lastAIMessageId &&
1912
+ lastAIMessageId.startsWith("resp_") &&
1913
+ !this.zdrEnabled
1914
+ ? { previous_response_id: lastAIMessageId }
1915
+ : {}),
1638
1916
  }, options);
1639
1917
  for await (const data of streamIterable) {
1640
1918
  const chunk = _convertOpenAIResponsesDeltaToBaseMessageChunk(data);
@@ -1768,8 +2046,18 @@ export class ChatOpenAI extends BaseChatModel {
1768
2046
  },
1769
2047
  };
1770
2048
  }
1771
- const input = _convertMessagesToOpenAIResponsesParams(messages, this.model);
1772
- const data = await this.responseApiWithRetry({ input, ...invocationParams }, { signal: options?.signal, ...options?.options });
2049
+ const lastAIMessage = messages.filter((m) => isAIMessage(m)).pop();
2050
+ const lastAIMessageId = lastAIMessage?.response_metadata?.id;
2051
+ const input = _convertMessagesToOpenAIResponsesParams(messages, this.model, this.zdrEnabled);
2052
+ const data = await this.responseApiWithRetry({
2053
+ input,
2054
+ ...invocationParams,
2055
+ ...(lastAIMessageId &&
2056
+ lastAIMessageId.startsWith("resp_") &&
2057
+ !this.zdrEnabled
2058
+ ? { previous_response_id: lastAIMessageId }
2059
+ : {}),
2060
+ }, { signal: options?.signal, ...options?.options });
1773
2061
  return {
1774
2062
  generations: [
1775
2063
  {
@@ -1789,12 +2077,23 @@ export class ChatOpenAI extends BaseChatModel {
1789
2077
  },
1790
2078
  };
1791
2079
  }
2080
+ /**
2081
+ * Determines whether the responses API should be used for the given request.
2082
+ *
2083
+ * @internal
2084
+ *
2085
+ * @param options The parsed call options for the request.
2086
+ * @returns `true` if the responses API should be used, either because it is explicitly enabled,
2087
+ * or because the request requires it.
2088
+ */
1792
2089
  _useResponseApi(options) {
1793
2090
  const usesBuiltInTools = options?.tools?.some(isBuiltInTool);
1794
2091
  const hasResponsesOnlyKwargs = options?.previous_response_id != null ||
1795
2092
  options?.text != null ||
1796
2093
  options?.truncation != null ||
1797
- options?.include != null;
2094
+ options?.include != null ||
2095
+ options?.reasoning?.summary != null ||
2096
+ this.reasoning?.summary != null;
1798
2097
  return this.useResponsesApi || usesBuiltInTools || hasResponsesOnlyKwargs;
1799
2098
  }
1800
2099
  /** @ignore */
@@ -115,7 +115,7 @@ class DallEAPIWrapper extends tools_1.Tool {
115
115
  if (this.dallEResponseFormat === "url") {
116
116
  return response.flatMap((res) => {
117
117
  const imageUrlContent = res.data
118
- .flatMap((item) => {
118
+ ?.flatMap((item) => {
119
119
  if (!item.url)
120
120
  return [];
121
121
  return {
@@ -126,14 +126,14 @@ class DallEAPIWrapper extends tools_1.Tool {
126
126
  .filter((item) => item !== undefined &&
127
127
  item.type === "image_url" &&
128
128
  typeof item.image_url === "string" &&
129
- item.image_url !== undefined);
129
+ item.image_url !== undefined) ?? [];
130
130
  return imageUrlContent;
131
131
  });
132
132
  }
133
133
  else {
134
134
  return response.flatMap((res) => {
135
135
  const b64Content = res.data
136
- .flatMap((item) => {
136
+ ?.flatMap((item) => {
137
137
  if (!item.b64_json)
138
138
  return [];
139
139
  return {
@@ -148,7 +148,7 @@ class DallEAPIWrapper extends tools_1.Tool {
148
148
  typeof item.image_url === "object" &&
149
149
  "url" in item.image_url &&
150
150
  typeof item.image_url.url === "string" &&
151
- item.image_url.url !== undefined);
151
+ item.image_url.url !== undefined) ?? [];
152
152
  return b64Content;
153
153
  });
154
154
  }
@@ -172,14 +172,17 @@ class DallEAPIWrapper extends tools_1.Tool {
172
172
  const response = await this.client.images.generate(generateImageFields);
173
173
  let data = "";
174
174
  if (this.dallEResponseFormat === "url") {
175
- [data] = response.data
176
- .map((item) => item.url)
177
- .filter((url) => url !== "undefined");
175
+ [data] =
176
+ response.data
177
+ ?.map((item) => item.url)
178
+ .filter((url) => url !== "undefined") ?? [];
178
179
  }
179
180
  else {
180
- [data] = response.data
181
- .map((item) => item.b64_json)
182
- .filter((b64_json) => b64_json !== "undefined");
181
+ [data] =
182
+ response.data
183
+ ?.map((item) => item.b64_json)
184
+ .filter((b64_json) => b64_json !== "undefined") ??
185
+ [];
183
186
  }
184
187
  return data;
185
188
  }
@@ -112,7 +112,7 @@ export class DallEAPIWrapper extends Tool {
112
112
  if (this.dallEResponseFormat === "url") {
113
113
  return response.flatMap((res) => {
114
114
  const imageUrlContent = res.data
115
- .flatMap((item) => {
115
+ ?.flatMap((item) => {
116
116
  if (!item.url)
117
117
  return [];
118
118
  return {
@@ -123,14 +123,14 @@ export class DallEAPIWrapper extends Tool {
123
123
  .filter((item) => item !== undefined &&
124
124
  item.type === "image_url" &&
125
125
  typeof item.image_url === "string" &&
126
- item.image_url !== undefined);
126
+ item.image_url !== undefined) ?? [];
127
127
  return imageUrlContent;
128
128
  });
129
129
  }
130
130
  else {
131
131
  return response.flatMap((res) => {
132
132
  const b64Content = res.data
133
- .flatMap((item) => {
133
+ ?.flatMap((item) => {
134
134
  if (!item.b64_json)
135
135
  return [];
136
136
  return {
@@ -145,7 +145,7 @@ export class DallEAPIWrapper extends Tool {
145
145
  typeof item.image_url === "object" &&
146
146
  "url" in item.image_url &&
147
147
  typeof item.image_url.url === "string" &&
148
- item.image_url.url !== undefined);
148
+ item.image_url.url !== undefined) ?? [];
149
149
  return b64Content;
150
150
  });
151
151
  }
@@ -169,14 +169,17 @@ export class DallEAPIWrapper extends Tool {
169
169
  const response = await this.client.images.generate(generateImageFields);
170
170
  let data = "";
171
171
  if (this.dallEResponseFormat === "url") {
172
- [data] = response.data
173
- .map((item) => item.url)
174
- .filter((url) => url !== "undefined");
172
+ [data] =
173
+ response.data
174
+ ?.map((item) => item.url)
175
+ .filter((url) => url !== "undefined") ?? [];
175
176
  }
176
177
  else {
177
- [data] = response.data
178
- .map((item) => item.b64_json)
179
- .filter((b64_json) => b64_json !== "undefined");
178
+ [data] =
179
+ response.data
180
+ ?.map((item) => item.b64_json)
181
+ .filter((b64_json) => b64_json !== "undefined") ??
182
+ [];
180
183
  }
181
184
  return data;
182
185
  }