@langchain/openai 0.6.10 → 0.6.12

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.
@@ -18,6 +18,7 @@ const azure_js_1 = require("./utils/azure.cjs");
18
18
  const openai_js_1 = require("./utils/openai.cjs");
19
19
  const openai_format_fndef_js_1 = require("./utils/openai-format-fndef.cjs");
20
20
  const tools_js_1 = require("./utils/tools.cjs");
21
+ const output_js_1 = require("./utils/output.cjs");
21
22
  const _FUNCTION_CALL_IDS_MAP_KEY = "__openai_function_call_ids__";
22
23
  function isReasoningModel(model) {
23
24
  if (!model)
@@ -273,7 +274,7 @@ class BaseChatOpenAI extends chat_models_1.BaseChatModel {
273
274
  "response_format",
274
275
  "seed",
275
276
  "reasoning",
276
- "reasoning_effort",
277
+ "reasoningEffort",
277
278
  "service_tier",
278
279
  ];
279
280
  }
@@ -287,6 +288,7 @@ class BaseChatOpenAI extends chat_models_1.BaseChatModel {
287
288
  return {
288
289
  apiKey: "openai_api_key",
289
290
  modelName: "model",
291
+ reasoningEffort: "reasoning_effort",
290
292
  };
291
293
  }
292
294
  get lc_serializable_keys() {
@@ -325,7 +327,7 @@ class BaseChatOpenAI extends chat_models_1.BaseChatModel {
325
327
  "disableStreaming",
326
328
  "zdrEnabled",
327
329
  "reasoning",
328
- "reasoning_effort",
330
+ "reasoningEffort",
329
331
  "promptCacheKey",
330
332
  "verbosity",
331
333
  ];
@@ -603,18 +605,18 @@ class BaseChatOpenAI extends chat_models_1.BaseChatModel {
603
605
  this.audio = fields?.audio;
604
606
  this.modalities = fields?.modalities;
605
607
  this.reasoning =
606
- fields?.reasoning ?? fields?.reasoning_effort
607
- ? { effort: fields.reasoning_effort }
608
+ fields?.reasoning ?? fields?.reasoningEffort
609
+ ? { effort: fields.reasoningEffort }
608
610
  : undefined;
609
611
  this.maxTokens = fields?.maxCompletionTokens ?? fields?.maxTokens;
610
- this.disableStreaming = fields?.disableStreaming ?? this.disableStreaming;
612
+ this.disableStreaming = fields?.disableStreaming === true;
613
+ this.streaming = fields?.streaming === true;
611
614
  this.promptCacheKey = fields?.promptCacheKey ?? this.promptCacheKey;
612
615
  this.verbosity = fields?.verbosity ?? this.verbosity;
613
- this.streaming = fields?.streaming ?? false;
614
616
  // disable streaming in BaseChatModel if explicitly disabled
615
617
  if (this.streaming === false)
616
618
  this.disableStreaming = true;
617
- if (this.disableStreaming)
619
+ if (this.disableStreaming === true)
618
620
  this.streaming = false;
619
621
  this.streamUsage = fields?.streamUsage ?? this.streamUsage;
620
622
  if (this.disableStreaming)
@@ -1373,7 +1375,8 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
1373
1375
  response_metadata[key] = value;
1374
1376
  }
1375
1377
  }
1376
- else if (chunk.type === "response.function_call_arguments.delta") {
1378
+ else if (chunk.type === "response.function_call_arguments.delta" ||
1379
+ chunk.type === "response.custom_tool_call_input.delta") {
1377
1380
  tool_call_chunks.push({
1378
1381
  type: "tool_call_chunk",
1379
1382
  args: chunk.delta,
@@ -2061,8 +2064,9 @@ class ChatOpenAICompletions extends BaseChatOpenAI {
2061
2064
  if (message.audio) {
2062
2065
  additional_kwargs.audio = message.audio;
2063
2066
  }
2067
+ const content = (0, output_js_1.handleMultiModalOutput)(message.content || "", rawResponse.choices?.[0]?.message);
2064
2068
  return new messages_1.AIMessage({
2065
- content: message.content || "",
2069
+ content,
2066
2070
  tool_calls: toolCalls,
2067
2071
  invalid_tool_calls: invalidToolCalls,
2068
2072
  additional_kwargs,
@@ -13,6 +13,7 @@ import { getEndpoint } from "./utils/azure.js";
13
13
  import { formatToOpenAIToolChoice, interopZodResponseFormat, wrapOpenAIClientError, } from "./utils/openai.js";
14
14
  import { formatFunctionDefinitions, } from "./utils/openai-format-fndef.js";
15
15
  import { _convertToOpenAITool, convertCompletionsCustomTool, convertResponsesCustomTool, isBuiltInTool, isBuiltInToolChoice, isCustomTool, isCustomToolCall, isOpenAICustomTool, parseCustomToolCall, } from "./utils/tools.js";
16
+ import { handleMultiModalOutput } from "./utils/output.js";
16
17
  const _FUNCTION_CALL_IDS_MAP_KEY = "__openai_function_call_ids__";
17
18
  function isReasoningModel(model) {
18
19
  if (!model)
@@ -268,7 +269,7 @@ export class BaseChatOpenAI extends BaseChatModel {
268
269
  "response_format",
269
270
  "seed",
270
271
  "reasoning",
271
- "reasoning_effort",
272
+ "reasoningEffort",
272
273
  "service_tier",
273
274
  ];
274
275
  }
@@ -282,6 +283,7 @@ export class BaseChatOpenAI extends BaseChatModel {
282
283
  return {
283
284
  apiKey: "openai_api_key",
284
285
  modelName: "model",
286
+ reasoningEffort: "reasoning_effort",
285
287
  };
286
288
  }
287
289
  get lc_serializable_keys() {
@@ -320,7 +322,7 @@ export class BaseChatOpenAI extends BaseChatModel {
320
322
  "disableStreaming",
321
323
  "zdrEnabled",
322
324
  "reasoning",
323
- "reasoning_effort",
325
+ "reasoningEffort",
324
326
  "promptCacheKey",
325
327
  "verbosity",
326
328
  ];
@@ -598,18 +600,18 @@ export class BaseChatOpenAI extends BaseChatModel {
598
600
  this.audio = fields?.audio;
599
601
  this.modalities = fields?.modalities;
600
602
  this.reasoning =
601
- fields?.reasoning ?? fields?.reasoning_effort
602
- ? { effort: fields.reasoning_effort }
603
+ fields?.reasoning ?? fields?.reasoningEffort
604
+ ? { effort: fields.reasoningEffort }
603
605
  : undefined;
604
606
  this.maxTokens = fields?.maxCompletionTokens ?? fields?.maxTokens;
605
- this.disableStreaming = fields?.disableStreaming ?? this.disableStreaming;
607
+ this.disableStreaming = fields?.disableStreaming === true;
608
+ this.streaming = fields?.streaming === true;
606
609
  this.promptCacheKey = fields?.promptCacheKey ?? this.promptCacheKey;
607
610
  this.verbosity = fields?.verbosity ?? this.verbosity;
608
- this.streaming = fields?.streaming ?? false;
609
611
  // disable streaming in BaseChatModel if explicitly disabled
610
612
  if (this.streaming === false)
611
613
  this.disableStreaming = true;
612
- if (this.disableStreaming)
614
+ if (this.disableStreaming === true)
613
615
  this.streaming = false;
614
616
  this.streamUsage = fields?.streamUsage ?? this.streamUsage;
615
617
  if (this.disableStreaming)
@@ -1367,7 +1369,8 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
1367
1369
  response_metadata[key] = value;
1368
1370
  }
1369
1371
  }
1370
- else if (chunk.type === "response.function_call_arguments.delta") {
1372
+ else if (chunk.type === "response.function_call_arguments.delta" ||
1373
+ chunk.type === "response.custom_tool_call_input.delta") {
1371
1374
  tool_call_chunks.push({
1372
1375
  type: "tool_call_chunk",
1373
1376
  args: chunk.delta,
@@ -2054,8 +2057,9 @@ export class ChatOpenAICompletions extends BaseChatOpenAI {
2054
2057
  if (message.audio) {
2055
2058
  additional_kwargs.audio = message.audio;
2056
2059
  }
2060
+ const content = handleMultiModalOutput(message.content || "", rawResponse.choices?.[0]?.message);
2057
2061
  return new AIMessage({
2058
- content: message.content || "",
2062
+ content,
2059
2063
  tool_calls: toolCalls,
2060
2064
  invalid_tool_calls: invalidToolCalls,
2061
2065
  additional_kwargs,
@@ -75,6 +75,12 @@ class OpenAIEmbeddings extends embeddings_1.Embeddings {
75
75
  writable: true,
76
76
  value: void 0
77
77
  });
78
+ Object.defineProperty(this, "encodingFormat", {
79
+ enumerable: true,
80
+ configurable: true,
81
+ writable: true,
82
+ value: void 0
83
+ });
78
84
  Object.defineProperty(this, "client", {
79
85
  enumerable: true,
80
86
  configurable: true,
@@ -101,6 +107,7 @@ class OpenAIEmbeddings extends embeddings_1.Embeddings {
101
107
  fieldsWithDefaults?.stripNewLines ?? this.stripNewLines;
102
108
  this.timeout = fieldsWithDefaults?.timeout;
103
109
  this.dimensions = fieldsWithDefaults?.dimensions;
110
+ this.encodingFormat = fieldsWithDefaults?.encodingFormat;
104
111
  this.clientConfig = {
105
112
  apiKey,
106
113
  organization: this.organization,
@@ -125,6 +132,9 @@ class OpenAIEmbeddings extends embeddings_1.Embeddings {
125
132
  if (this.dimensions) {
126
133
  params.dimensions = this.dimensions;
127
134
  }
135
+ if (this.encodingFormat) {
136
+ params.encoding_format = this.encodingFormat;
137
+ }
128
138
  return this.embeddingWithRetry(params);
129
139
  });
130
140
  const batchResponses = await Promise.all(batchRequests);
@@ -152,6 +162,9 @@ class OpenAIEmbeddings extends embeddings_1.Embeddings {
152
162
  if (this.dimensions) {
153
163
  params.dimensions = this.dimensions;
154
164
  }
165
+ if (this.encodingFormat) {
166
+ params.encoding_format = this.encodingFormat;
167
+ }
155
168
  const { data } = await this.embeddingWithRetry(params);
156
169
  return data[0].embedding;
157
170
  }
@@ -37,6 +37,10 @@ export interface OpenAIEmbeddingsParams extends EmbeddingsParams {
37
37
  * See: https://github.com/openai/openai-python/issues/418#issuecomment-1525939500
38
38
  */
39
39
  stripNewLines?: boolean;
40
+ /**
41
+ * The format to return the embeddings in. Can be either 'float' or 'base64'.
42
+ */
43
+ encodingFormat?: "float" | "base64";
40
44
  }
41
45
  /**
42
46
  * Class for generating embeddings using the OpenAI API.
@@ -54,7 +58,7 @@ export interface OpenAIEmbeddingsParams extends EmbeddingsParams {
54
58
  *
55
59
  * ```
56
60
  */
57
- export declare class OpenAIEmbeddings extends Embeddings implements Partial<OpenAIEmbeddingsParams> {
61
+ export declare class OpenAIEmbeddings<TOutput = number[]> extends Embeddings<TOutput> implements Partial<OpenAIEmbeddingsParams> {
58
62
  model: string;
59
63
  /** @deprecated Use "model" instead */
60
64
  modelName: string;
@@ -67,6 +71,7 @@ export declare class OpenAIEmbeddings extends Embeddings implements Partial<Open
67
71
  dimensions?: number;
68
72
  timeout?: number;
69
73
  organization?: string;
74
+ encodingFormat?: "float" | "base64";
70
75
  protected client: OpenAIClient;
71
76
  protected clientConfig: ClientOptions;
72
77
  constructor(fields?: Partial<OpenAIEmbeddingsParams> & {
@@ -87,14 +92,14 @@ export declare class OpenAIEmbeddings extends Embeddings implements Partial<Open
87
92
  * @param texts Array of documents to generate embeddings for.
88
93
  * @returns Promise that resolves to a 2D array of embeddings for each document.
89
94
  */
90
- embedDocuments(texts: string[]): Promise<number[][]>;
95
+ embedDocuments(texts: string[]): Promise<TOutput[]>;
91
96
  /**
92
97
  * Method to generate an embedding for a single document. Calls the
93
98
  * embeddingWithRetry method with the document as the input.
94
99
  * @param text Document to generate an embedding for.
95
100
  * @returns Promise that resolves to an embedding for the document.
96
101
  */
97
- embedQuery(text: string): Promise<number[]>;
102
+ embedQuery(text: string): Promise<TOutput>;
98
103
  /**
99
104
  * Private method to make a request to the OpenAI API to generate
100
105
  * embeddings. Handles the retry logic and returns the response from the
@@ -72,6 +72,12 @@ export class OpenAIEmbeddings extends Embeddings {
72
72
  writable: true,
73
73
  value: void 0
74
74
  });
75
+ Object.defineProperty(this, "encodingFormat", {
76
+ enumerable: true,
77
+ configurable: true,
78
+ writable: true,
79
+ value: void 0
80
+ });
75
81
  Object.defineProperty(this, "client", {
76
82
  enumerable: true,
77
83
  configurable: true,
@@ -98,6 +104,7 @@ export class OpenAIEmbeddings extends Embeddings {
98
104
  fieldsWithDefaults?.stripNewLines ?? this.stripNewLines;
99
105
  this.timeout = fieldsWithDefaults?.timeout;
100
106
  this.dimensions = fieldsWithDefaults?.dimensions;
107
+ this.encodingFormat = fieldsWithDefaults?.encodingFormat;
101
108
  this.clientConfig = {
102
109
  apiKey,
103
110
  organization: this.organization,
@@ -122,6 +129,9 @@ export class OpenAIEmbeddings extends Embeddings {
122
129
  if (this.dimensions) {
123
130
  params.dimensions = this.dimensions;
124
131
  }
132
+ if (this.encodingFormat) {
133
+ params.encoding_format = this.encodingFormat;
134
+ }
125
135
  return this.embeddingWithRetry(params);
126
136
  });
127
137
  const batchResponses = await Promise.all(batchRequests);
@@ -149,6 +159,9 @@ export class OpenAIEmbeddings extends Embeddings {
149
159
  if (this.dimensions) {
150
160
  params.dimensions = this.dimensions;
151
161
  }
162
+ if (this.encodingFormat) {
163
+ params.encoding_format = this.encodingFormat;
164
+ }
152
165
  const { data } = await this.embeddingWithRetry(params);
153
166
  return data[0].embedding;
154
167
  }
package/dist/types.d.ts CHANGED
@@ -155,7 +155,7 @@ export interface OpenAIChatInput extends OpenAIBaseInput {
155
155
  *
156
156
  * @deprecated Use `reasoning` instead.
157
157
  */
158
- reasoning_effort?: OpenAIClient.ReasoningEffort;
158
+ reasoningEffort?: OpenAIClient.ReasoningEffort;
159
159
  /**
160
160
  * Should be set to `true` in tenancies with Zero Data Retention
161
161
  * @see https://platform.openai.com/docs/guides/your-data
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleMultiModalOutput = handleMultiModalOutput;
4
+ /**
5
+ * Handle multi modal response content.
6
+ *
7
+ * @param content The content of the message.
8
+ * @param messages The messages of the response.
9
+ * @returns The new content of the message.
10
+ */
11
+ function handleMultiModalOutput(content, messages) {
12
+ /**
13
+ * Handle OpenRouter image responses
14
+ * @see https://openrouter.ai/docs/features/multimodal/image-generation#api-usage
15
+ */
16
+ if (messages &&
17
+ typeof messages === "object" &&
18
+ "images" in messages &&
19
+ Array.isArray(messages.images)) {
20
+ const images = messages.images
21
+ .filter((image) => typeof image?.image_url?.url === "string")
22
+ .map((image) => ({
23
+ type: "image",
24
+ url: image.image_url.url,
25
+ source_type: "url",
26
+ }));
27
+ return [{ type: "text", text: content, source_type: "text" }, ...images];
28
+ }
29
+ return content;
30
+ }
@@ -0,0 +1,9 @@
1
+ import { StandardImageBlock, StandardTextBlock } from "@langchain/core/messages";
2
+ /**
3
+ * Handle multi modal response content.
4
+ *
5
+ * @param content The content of the message.
6
+ * @param messages The messages of the response.
7
+ * @returns The new content of the message.
8
+ */
9
+ export declare function handleMultiModalOutput(content: string, messages: unknown): (StandardImageBlock | StandardTextBlock)[] | string;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Handle multi modal response content.
3
+ *
4
+ * @param content The content of the message.
5
+ * @param messages The messages of the response.
6
+ * @returns The new content of the message.
7
+ */
8
+ export function handleMultiModalOutput(content, messages) {
9
+ /**
10
+ * Handle OpenRouter image responses
11
+ * @see https://openrouter.ai/docs/features/multimodal/image-generation#api-usage
12
+ */
13
+ if (messages &&
14
+ typeof messages === "object" &&
15
+ "images" in messages &&
16
+ Array.isArray(messages.images)) {
17
+ const images = messages.images
18
+ .filter((image) => typeof image?.image_url?.url === "string")
19
+ .map((image) => ({
20
+ type: "image",
21
+ url: image.image_url.url,
22
+ source_type: "url",
23
+ }));
24
+ return [{ type: "text", text: content, source_type: "text" }, ...images];
25
+ }
26
+ return content;
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/openai",
3
- "version": "0.6.10",
3
+ "version": "0.6.12",
4
4
  "description": "OpenAI integrations for LangChain.js",
5
5
  "type": "module",
6
6
  "engines": {