@langchain/openai 0.3.13 → 0.3.15

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 openai_format_fndef_js_1 = require("./utils/openai-format-fndef.cjs");
18
18
  const tools_js_1 = require("./utils/tools.cjs");
19
19
  function extractGenericMessageCustomRole(message) {
20
20
  if (message.role !== "system" &&
21
+ message.role !== "developer" &&
21
22
  message.role !== "assistant" &&
22
23
  message.role !== "user" &&
23
24
  message.role !== "function" &&
@@ -150,6 +151,15 @@ delta, rawResponse, defaultRole, includeRawResponse) {
150
151
  else if (role === "system") {
151
152
  return new messages_1.SystemMessageChunk({ content, response_metadata });
152
153
  }
154
+ else if (role === "developer") {
155
+ return new messages_1.SystemMessageChunk({
156
+ content,
157
+ response_metadata,
158
+ additional_kwargs: {
159
+ __openai_role__: "developer",
160
+ },
161
+ });
162
+ }
153
163
  else if (role === "function") {
154
164
  return new messages_1.FunctionMessageChunk({
155
165
  content,
@@ -171,12 +181,16 @@ delta, rawResponse, defaultRole, includeRawResponse) {
171
181
  }
172
182
  }
173
183
  // Used in LangSmith, export is important here
174
- function _convertMessagesToOpenAIParams(messages) {
184
+ function _convertMessagesToOpenAIParams(messages, model) {
175
185
  // TODO: Function messages do not support array content, fix cast
176
186
  return messages.flatMap((message) => {
187
+ let role = messageToOpenAIRole(message);
188
+ if (role === "system" && model?.startsWith("o1")) {
189
+ role = "developer";
190
+ }
177
191
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
178
192
  const completionParam = {
179
- role: messageToOpenAIRole(message),
193
+ role,
180
194
  content: message.content,
181
195
  };
182
196
  if (message.name != null) {
@@ -779,6 +793,7 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
779
793
  "promptIndex",
780
794
  "response_format",
781
795
  "seed",
796
+ "reasoning_effort",
782
797
  ];
783
798
  }
784
799
  get lc_secrets() {
@@ -1018,6 +1033,12 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
1018
1033
  writable: true,
1019
1034
  value: void 0
1020
1035
  });
1036
+ Object.defineProperty(this, "reasoningEffort", {
1037
+ enumerable: true,
1038
+ configurable: true,
1039
+ writable: true,
1040
+ value: void 0
1041
+ });
1021
1042
  this.openAIApiKey =
1022
1043
  fields?.apiKey ??
1023
1044
  fields?.openAIApiKey ??
@@ -1068,6 +1089,7 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
1068
1089
  this.__includeRawResponse = fields?.__includeRawResponse;
1069
1090
  this.audio = fields?.audio;
1070
1091
  this.modalities = fields?.modalities;
1092
+ this.reasoningEffort = fields?.reasoningEffort;
1071
1093
  if (this.azureOpenAIApiKey || this.azureADTokenProvider) {
1072
1094
  if (!this.azureOpenAIApiInstanceName &&
1073
1095
  !this.azureOpenAIBasePath &&
@@ -1200,6 +1222,10 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
1200
1222
  if (options?.prediction !== undefined) {
1201
1223
  params.prediction = options.prediction;
1202
1224
  }
1225
+ const reasoningEffort = options?.reasoning_effort ?? this.reasoningEffort;
1226
+ if (reasoningEffort !== undefined) {
1227
+ params.reasoning_effort = reasoningEffort;
1228
+ }
1203
1229
  return params;
1204
1230
  }
1205
1231
  /** @ignore */
@@ -1211,17 +1237,7 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
1211
1237
  };
1212
1238
  }
1213
1239
  async *_streamResponseChunks(messages, options, runManager) {
1214
- if (this.model.includes("o1-")) {
1215
- console.warn("[WARNING]: OpenAI o1 models do not yet support token-level streaming. Streaming will yield single chunk.");
1216
- const result = await this._generate(messages, options, runManager);
1217
- const messageChunk = (0, messages_1.convertToChunk)(result.generations[0].message);
1218
- yield new outputs_1.ChatGenerationChunk({
1219
- message: messageChunk,
1220
- text: typeof messageChunk.content === "string" ? messageChunk.content : "",
1221
- });
1222
- return;
1223
- }
1224
- const messagesMapped = _convertMessagesToOpenAIParams(messages);
1240
+ const messagesMapped = _convertMessagesToOpenAIParams(messages, this.model);
1225
1241
  const params = {
1226
1242
  ...this.invocationParams(options, {
1227
1243
  streaming: true,
@@ -1327,7 +1343,7 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
1327
1343
  async _generate(messages, options, runManager) {
1328
1344
  const usageMetadata = {};
1329
1345
  const params = this.invocationParams(options);
1330
- const messagesMapped = _convertMessagesToOpenAIParams(messages);
1346
+ const messagesMapped = _convertMessagesToOpenAIParams(messages, this.model);
1331
1347
  if (params.stream) {
1332
1348
  const stream = this._streamResponseChunks(messages, options, runManager);
1333
1349
  const finalChunks = {};
@@ -17,10 +17,10 @@ interface TokenUsage {
17
17
  interface OpenAILLMOutput {
18
18
  tokenUsage: TokenUsage;
19
19
  }
20
- type OpenAIRoleEnum = "system" | "assistant" | "user" | "function" | "tool";
20
+ type OpenAIRoleEnum = "system" | "developer" | "assistant" | "user" | "function" | "tool";
21
21
  type OpenAICompletionParam = OpenAIClient.Chat.Completions.ChatCompletionMessageParam;
22
22
  export declare function messageToOpenAIRole(message: BaseMessage): OpenAIRoleEnum;
23
- export declare function _convertMessagesToOpenAIParams(messages: BaseMessage[]): OpenAICompletionParam[];
23
+ export declare function _convertMessagesToOpenAIParams(messages: BaseMessage[], model?: string): OpenAICompletionParam[];
24
24
  type ChatOpenAIToolType = BindToolsInput | OpenAIClient.ChatCompletionTool;
25
25
  export interface ChatOpenAIStructuredOutputMethodOptions<IncludeRaw extends boolean> extends StructuredOutputMethodOptions<IncludeRaw> {
26
26
  /**
@@ -100,6 +100,11 @@ export interface ChatOpenAICallOptions extends OpenAICallOptions, BaseFunctionCa
100
100
  * [Learn more](https://platform.openai.com/docs/guides/latency-optimization#use-predicted-outputs).
101
101
  */
102
102
  prediction?: OpenAIClient.ChatCompletionPredictionContent;
103
+ /**
104
+ * Constrains effort on reasoning for reasoning models. Currently supported values are low, medium, and high.
105
+ * Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response.
106
+ */
107
+ reasoning_effort?: OpenAIClient.Chat.ChatCompletionReasoningEffort;
103
108
  }
104
109
  export interface ChatOpenAIFields extends Partial<OpenAIChatInput>, Partial<AzureOpenAIInput>, BaseChatModelParams {
105
110
  configuration?: ClientOptions & LegacyOpenAIInput;
@@ -686,6 +691,7 @@ export declare class ChatOpenAI<CallOptions extends ChatOpenAICallOptions = Chat
686
691
  supportsStrictToolCalling?: boolean;
687
692
  audio?: OpenAIClient.Chat.ChatCompletionAudioParam;
688
693
  modalities?: Array<OpenAIClient.Chat.ChatCompletionModality>;
694
+ reasoningEffort?: OpenAIClient.Chat.ChatCompletionReasoningEffort;
689
695
  constructor(fields?: ChatOpenAIFields,
690
696
  /** @deprecated */
691
697
  configuration?: ClientOptions & LegacyOpenAIInput);
@@ -1,5 +1,5 @@
1
1
  import { OpenAI as OpenAIClient } from "openai";
2
- import { AIMessage, AIMessageChunk, ChatMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, SystemMessageChunk, ToolMessageChunk, isAIMessage, convertToChunk, } from "@langchain/core/messages";
2
+ import { AIMessage, AIMessageChunk, ChatMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, SystemMessageChunk, ToolMessageChunk, isAIMessage, } 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";
@@ -15,6 +15,7 @@ import { formatFunctionDefinitions, } from "./utils/openai-format-fndef.js";
15
15
  import { _convertToOpenAITool } from "./utils/tools.js";
16
16
  function extractGenericMessageCustomRole(message) {
17
17
  if (message.role !== "system" &&
18
+ message.role !== "developer" &&
18
19
  message.role !== "assistant" &&
19
20
  message.role !== "user" &&
20
21
  message.role !== "function" &&
@@ -146,6 +147,15 @@ delta, rawResponse, defaultRole, includeRawResponse) {
146
147
  else if (role === "system") {
147
148
  return new SystemMessageChunk({ content, response_metadata });
148
149
  }
150
+ else if (role === "developer") {
151
+ return new SystemMessageChunk({
152
+ content,
153
+ response_metadata,
154
+ additional_kwargs: {
155
+ __openai_role__: "developer",
156
+ },
157
+ });
158
+ }
149
159
  else if (role === "function") {
150
160
  return new FunctionMessageChunk({
151
161
  content,
@@ -167,12 +177,16 @@ delta, rawResponse, defaultRole, includeRawResponse) {
167
177
  }
168
178
  }
169
179
  // Used in LangSmith, export is important here
170
- export function _convertMessagesToOpenAIParams(messages) {
180
+ export function _convertMessagesToOpenAIParams(messages, model) {
171
181
  // TODO: Function messages do not support array content, fix cast
172
182
  return messages.flatMap((message) => {
183
+ let role = messageToOpenAIRole(message);
184
+ if (role === "system" && model?.startsWith("o1")) {
185
+ role = "developer";
186
+ }
173
187
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
174
188
  const completionParam = {
175
- role: messageToOpenAIRole(message),
189
+ role,
176
190
  content: message.content,
177
191
  };
178
192
  if (message.name != null) {
@@ -774,6 +788,7 @@ export class ChatOpenAI extends BaseChatModel {
774
788
  "promptIndex",
775
789
  "response_format",
776
790
  "seed",
791
+ "reasoning_effort",
777
792
  ];
778
793
  }
779
794
  get lc_secrets() {
@@ -1013,6 +1028,12 @@ export class ChatOpenAI extends BaseChatModel {
1013
1028
  writable: true,
1014
1029
  value: void 0
1015
1030
  });
1031
+ Object.defineProperty(this, "reasoningEffort", {
1032
+ enumerable: true,
1033
+ configurable: true,
1034
+ writable: true,
1035
+ value: void 0
1036
+ });
1016
1037
  this.openAIApiKey =
1017
1038
  fields?.apiKey ??
1018
1039
  fields?.openAIApiKey ??
@@ -1063,6 +1084,7 @@ export class ChatOpenAI extends BaseChatModel {
1063
1084
  this.__includeRawResponse = fields?.__includeRawResponse;
1064
1085
  this.audio = fields?.audio;
1065
1086
  this.modalities = fields?.modalities;
1087
+ this.reasoningEffort = fields?.reasoningEffort;
1066
1088
  if (this.azureOpenAIApiKey || this.azureADTokenProvider) {
1067
1089
  if (!this.azureOpenAIApiInstanceName &&
1068
1090
  !this.azureOpenAIBasePath &&
@@ -1195,6 +1217,10 @@ export class ChatOpenAI extends BaseChatModel {
1195
1217
  if (options?.prediction !== undefined) {
1196
1218
  params.prediction = options.prediction;
1197
1219
  }
1220
+ const reasoningEffort = options?.reasoning_effort ?? this.reasoningEffort;
1221
+ if (reasoningEffort !== undefined) {
1222
+ params.reasoning_effort = reasoningEffort;
1223
+ }
1198
1224
  return params;
1199
1225
  }
1200
1226
  /** @ignore */
@@ -1206,17 +1232,7 @@ export class ChatOpenAI extends BaseChatModel {
1206
1232
  };
1207
1233
  }
1208
1234
  async *_streamResponseChunks(messages, options, runManager) {
1209
- if (this.model.includes("o1-")) {
1210
- console.warn("[WARNING]: OpenAI o1 models do not yet support token-level streaming. Streaming will yield single chunk.");
1211
- const result = await this._generate(messages, options, runManager);
1212
- const messageChunk = convertToChunk(result.generations[0].message);
1213
- yield new ChatGenerationChunk({
1214
- message: messageChunk,
1215
- text: typeof messageChunk.content === "string" ? messageChunk.content : "",
1216
- });
1217
- return;
1218
- }
1219
- const messagesMapped = _convertMessagesToOpenAIParams(messages);
1235
+ const messagesMapped = _convertMessagesToOpenAIParams(messages, this.model);
1220
1236
  const params = {
1221
1237
  ...this.invocationParams(options, {
1222
1238
  streaming: true,
@@ -1322,7 +1338,7 @@ export class ChatOpenAI extends BaseChatModel {
1322
1338
  async _generate(messages, options, runManager) {
1323
1339
  const usageMetadata = {};
1324
1340
  const params = this.invocationParams(options);
1325
- const messagesMapped = _convertMessagesToOpenAIParams(messages);
1341
+ const messagesMapped = _convertMessagesToOpenAIParams(messages, this.model);
1326
1342
  if (params.stream) {
1327
1343
  const stream = this._streamResponseChunks(messages, options, runManager);
1328
1344
  const finalChunks = {};
package/dist/types.d.ts CHANGED
@@ -147,6 +147,11 @@ export interface OpenAIChatInput extends OpenAIBaseInput {
147
147
  * [Learn more](https://platform.openai.com/docs/guides/audio).
148
148
  */
149
149
  audio?: OpenAIClient.Chat.ChatCompletionAudioParam;
150
+ /**
151
+ * Constrains effort on reasoning for reasoning models. Currently supported values are low, medium, and high.
152
+ * Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response.
153
+ */
154
+ reasoningEffort?: OpenAIClient.ChatCompletionReasoningEffort;
150
155
  }
151
156
  export declare interface AzureOpenAIInput {
152
157
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/openai",
3
- "version": "0.3.13",
3
+ "version": "0.3.15",
4
4
  "description": "OpenAI integrations for LangChain.js",
5
5
  "type": "module",
6
6
  "engines": {
@@ -36,7 +36,7 @@
36
36
  "license": "MIT",
37
37
  "dependencies": {
38
38
  "js-tiktoken": "^1.0.12",
39
- "openai": "^4.71.0",
39
+ "openai": "^4.77.0",
40
40
  "zod": "^3.22.4",
41
41
  "zod-to-json-schema": "^3.22.3"
42
42
  },