@langchain/openai 0.1.3 → 0.2.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.
@@ -47,7 +47,7 @@ function messageToOpenAIRole(message) {
47
47
  }
48
48
  }
49
49
  exports.messageToOpenAIRole = messageToOpenAIRole;
50
- function openAIResponseToChatMessage(message) {
50
+ function openAIResponseToChatMessage(message, messageId) {
51
51
  const rawToolCalls = message.tool_calls;
52
52
  switch (message.role) {
53
53
  case "assistant": {
@@ -70,6 +70,7 @@ function openAIResponseToChatMessage(message) {
70
70
  function_call: message.function_call,
71
71
  tool_calls: rawToolCalls,
72
72
  },
73
+ id: messageId,
73
74
  });
74
75
  }
75
76
  default:
@@ -78,7 +79,7 @@ function openAIResponseToChatMessage(message) {
78
79
  }
79
80
  function _convertDeltaToMessageChunk(
80
81
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
81
- delta, defaultRole) {
82
+ delta, messageId, defaultRole) {
82
83
  const role = delta.role ?? defaultRole;
83
84
  const content = delta.content ?? "";
84
85
  let additional_kwargs;
@@ -114,6 +115,7 @@ delta, defaultRole) {
114
115
  content,
115
116
  tool_call_chunks: toolCallChunks,
116
117
  additional_kwargs,
118
+ id: messageId,
117
119
  });
118
120
  }
119
121
  else if (role === "system") {
@@ -150,9 +152,11 @@ function convertMessagesToOpenAIParams(messages) {
150
152
  }
151
153
  if (message.additional_kwargs.function_call != null) {
152
154
  completionParam.function_call = message.additional_kwargs.function_call;
155
+ completionParam.content = null;
153
156
  }
154
157
  if ((0, messages_1.isAIMessage)(message) && !!message.tool_calls?.length) {
155
158
  completionParam.tool_calls = message.tool_calls.map(openai_tools_1.convertLangChainToolCallToOpenAI);
159
+ completionParam.content = null;
156
160
  }
157
161
  else {
158
162
  if (message.additional_kwargs.tool_calls != null) {
@@ -168,14 +172,13 @@ function convertMessagesToOpenAIParams(messages) {
168
172
  /**
169
173
  * Wrapper around OpenAI large language models that use the Chat endpoint.
170
174
  *
171
- * To use you should have the `openai` package installed, with the
172
- * `OPENAI_API_KEY` environment variable set.
175
+ * To use you should have the `OPENAI_API_KEY` environment variable set.
173
176
  *
174
- * To use with Azure you should have the `openai` package installed, with the
177
+ * To use with Azure you should have the:
175
178
  * `AZURE_OPENAI_API_KEY`,
176
179
  * `AZURE_OPENAI_API_INSTANCE_NAME`,
177
180
  * `AZURE_OPENAI_API_DEPLOYMENT_NAME`
178
- * and `AZURE_OPENAI_API_VERSION` environment variable set.
181
+ * and `AZURE_OPENAI_API_VERSION` environment variables set.
179
182
  * `AZURE_OPENAI_BASE_PATH` is optional and will override `AZURE_OPENAI_API_INSTANCE_NAME` if you need to use a custom endpoint.
180
183
  *
181
184
  * @remarks
@@ -329,6 +332,12 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
329
332
  writable: true,
330
333
  value: false
331
334
  });
335
+ Object.defineProperty(this, "streamUsage", {
336
+ enumerable: true,
337
+ configurable: true,
338
+ writable: true,
339
+ value: true
340
+ });
332
341
  Object.defineProperty(this, "maxTokens", {
333
342
  enumerable: true,
334
343
  configurable: true,
@@ -456,7 +465,6 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
456
465
  this.stop = fields?.stopSequences ?? fields?.stop;
457
466
  this.stopSequences = this?.stop;
458
467
  this.user = fields?.user;
459
- this.streaming = fields?.streaming ?? false;
460
468
  if (this.azureOpenAIApiKey || this.azureADTokenProvider) {
461
469
  if (!this.azureOpenAIApiInstanceName && !this.azureOpenAIBasePath) {
462
470
  throw new Error("Azure OpenAI API instance name not found");
@@ -468,7 +476,11 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
468
476
  throw new Error("Azure OpenAI API version not found");
469
477
  }
470
478
  this.apiKey = this.apiKey ?? "";
479
+ // Streaming usage is not supported by Azure deployments, so default to false
480
+ this.streamUsage = false;
471
481
  }
482
+ this.streaming = fields?.streaming ?? false;
483
+ this.streamUsage = fields?.streamUsage ?? this.streamUsage;
472
484
  this.clientConfig = {
473
485
  apiKey: this.apiKey,
474
486
  organization: this.organization,
@@ -507,6 +519,13 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
507
519
  return (tools !== undefined &&
508
520
  tools.every((tool) => Array.isArray(tool.lc_namespace)));
509
521
  }
522
+ let streamOptionsConfig = {};
523
+ if (options?.stream_options !== undefined) {
524
+ streamOptionsConfig = { stream_options: options.stream_options };
525
+ }
526
+ else if (this.streamUsage && this.streaming) {
527
+ streamOptionsConfig = { stream_options: { include_usage: true } };
528
+ }
510
529
  const params = {
511
530
  model: this.model,
512
531
  temperature: this.temperature,
@@ -520,6 +539,7 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
520
539
  logit_bias: this.logitBias,
521
540
  stop: options?.stop ?? this.stopSequences,
522
541
  user: this.user,
542
+ // if include_usage is set or streamUsage then stream must be set to true.
523
543
  stream: this.streaming,
524
544
  functions: options?.functions,
525
545
  function_call: options?.function_call,
@@ -529,9 +549,7 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
529
549
  tool_choice: options?.tool_choice,
530
550
  response_format: options?.response_format,
531
551
  seed: options?.seed,
532
- ...(options?.stream_options !== undefined
533
- ? { stream_options: options.stream_options }
534
- : {}),
552
+ ...streamOptionsConfig,
535
553
  parallel_tool_calls: options?.parallel_tool_calls,
536
554
  ...this.modelKwargs,
537
555
  };
@@ -567,7 +585,7 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
567
585
  if (!delta) {
568
586
  continue;
569
587
  }
570
- const chunk = _convertDeltaToMessageChunk(delta, defaultRole);
588
+ const chunk = _convertDeltaToMessageChunk(delta, data.id, defaultRole);
571
589
  defaultRole = delta.role ?? defaultRole;
572
590
  const newTokenIndices = {
573
591
  prompt: options.promptIndex ?? 0,
@@ -678,7 +696,7 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
678
696
  const text = part.message?.content ?? "";
679
697
  const generation = {
680
698
  text,
681
- message: openAIResponseToChatMessage(part.message ?? { role: "assistant" }),
699
+ message: openAIResponseToChatMessage(part.message ?? { role: "assistant" }, data.id),
682
700
  };
683
701
  generation.generationInfo = {
684
702
  ...(part.finish_reason ? { finish_reason: part.finish_reason } : {}),
@@ -29,6 +29,7 @@ export interface ChatOpenAICallOptions extends OpenAICallOptions, BaseFunctionCa
29
29
  seed?: number;
30
30
  /**
31
31
  * Additional options to pass to streamed completions.
32
+ * If provided takes precedence over "streamUsage" set at initialization time.
32
33
  */
33
34
  stream_options?: {
34
35
  /**
@@ -47,14 +48,13 @@ export interface ChatOpenAICallOptions extends OpenAICallOptions, BaseFunctionCa
47
48
  /**
48
49
  * Wrapper around OpenAI large language models that use the Chat endpoint.
49
50
  *
50
- * To use you should have the `openai` package installed, with the
51
- * `OPENAI_API_KEY` environment variable set.
51
+ * To use you should have the `OPENAI_API_KEY` environment variable set.
52
52
  *
53
- * To use with Azure you should have the `openai` package installed, with the
53
+ * To use with Azure you should have the:
54
54
  * `AZURE_OPENAI_API_KEY`,
55
55
  * `AZURE_OPENAI_API_INSTANCE_NAME`,
56
56
  * `AZURE_OPENAI_API_DEPLOYMENT_NAME`
57
- * and `AZURE_OPENAI_API_VERSION` environment variable set.
57
+ * and `AZURE_OPENAI_API_VERSION` environment variables set.
58
58
  * `AZURE_OPENAI_BASE_PATH` is optional and will override `AZURE_OPENAI_API_INSTANCE_NAME` if you need to use a custom endpoint.
59
59
  *
60
60
  * @remarks
@@ -100,6 +100,7 @@ export declare class ChatOpenAI<CallOptions extends ChatOpenAICallOptions = Chat
100
100
  user?: string;
101
101
  timeout?: number;
102
102
  streaming: boolean;
103
+ streamUsage: boolean;
103
104
  maxTokens?: number;
104
105
  logprobs?: boolean;
105
106
  topLogprobs?: number;
@@ -43,7 +43,7 @@ export function messageToOpenAIRole(message) {
43
43
  throw new Error(`Unknown message type: ${type}`);
44
44
  }
45
45
  }
46
- function openAIResponseToChatMessage(message) {
46
+ function openAIResponseToChatMessage(message, messageId) {
47
47
  const rawToolCalls = message.tool_calls;
48
48
  switch (message.role) {
49
49
  case "assistant": {
@@ -66,6 +66,7 @@ function openAIResponseToChatMessage(message) {
66
66
  function_call: message.function_call,
67
67
  tool_calls: rawToolCalls,
68
68
  },
69
+ id: messageId,
69
70
  });
70
71
  }
71
72
  default:
@@ -74,7 +75,7 @@ function openAIResponseToChatMessage(message) {
74
75
  }
75
76
  function _convertDeltaToMessageChunk(
76
77
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
77
- delta, defaultRole) {
78
+ delta, messageId, defaultRole) {
78
79
  const role = delta.role ?? defaultRole;
79
80
  const content = delta.content ?? "";
80
81
  let additional_kwargs;
@@ -110,6 +111,7 @@ delta, defaultRole) {
110
111
  content,
111
112
  tool_call_chunks: toolCallChunks,
112
113
  additional_kwargs,
114
+ id: messageId,
113
115
  });
114
116
  }
115
117
  else if (role === "system") {
@@ -146,9 +148,11 @@ function convertMessagesToOpenAIParams(messages) {
146
148
  }
147
149
  if (message.additional_kwargs.function_call != null) {
148
150
  completionParam.function_call = message.additional_kwargs.function_call;
151
+ completionParam.content = null;
149
152
  }
150
153
  if (isAIMessage(message) && !!message.tool_calls?.length) {
151
154
  completionParam.tool_calls = message.tool_calls.map(convertLangChainToolCallToOpenAI);
155
+ completionParam.content = null;
152
156
  }
153
157
  else {
154
158
  if (message.additional_kwargs.tool_calls != null) {
@@ -164,14 +168,13 @@ function convertMessagesToOpenAIParams(messages) {
164
168
  /**
165
169
  * Wrapper around OpenAI large language models that use the Chat endpoint.
166
170
  *
167
- * To use you should have the `openai` package installed, with the
168
- * `OPENAI_API_KEY` environment variable set.
171
+ * To use you should have the `OPENAI_API_KEY` environment variable set.
169
172
  *
170
- * To use with Azure you should have the `openai` package installed, with the
173
+ * To use with Azure you should have the:
171
174
  * `AZURE_OPENAI_API_KEY`,
172
175
  * `AZURE_OPENAI_API_INSTANCE_NAME`,
173
176
  * `AZURE_OPENAI_API_DEPLOYMENT_NAME`
174
- * and `AZURE_OPENAI_API_VERSION` environment variable set.
177
+ * and `AZURE_OPENAI_API_VERSION` environment variables set.
175
178
  * `AZURE_OPENAI_BASE_PATH` is optional and will override `AZURE_OPENAI_API_INSTANCE_NAME` if you need to use a custom endpoint.
176
179
  *
177
180
  * @remarks
@@ -325,6 +328,12 @@ export class ChatOpenAI extends BaseChatModel {
325
328
  writable: true,
326
329
  value: false
327
330
  });
331
+ Object.defineProperty(this, "streamUsage", {
332
+ enumerable: true,
333
+ configurable: true,
334
+ writable: true,
335
+ value: true
336
+ });
328
337
  Object.defineProperty(this, "maxTokens", {
329
338
  enumerable: true,
330
339
  configurable: true,
@@ -452,7 +461,6 @@ export class ChatOpenAI extends BaseChatModel {
452
461
  this.stop = fields?.stopSequences ?? fields?.stop;
453
462
  this.stopSequences = this?.stop;
454
463
  this.user = fields?.user;
455
- this.streaming = fields?.streaming ?? false;
456
464
  if (this.azureOpenAIApiKey || this.azureADTokenProvider) {
457
465
  if (!this.azureOpenAIApiInstanceName && !this.azureOpenAIBasePath) {
458
466
  throw new Error("Azure OpenAI API instance name not found");
@@ -464,7 +472,11 @@ export class ChatOpenAI extends BaseChatModel {
464
472
  throw new Error("Azure OpenAI API version not found");
465
473
  }
466
474
  this.apiKey = this.apiKey ?? "";
475
+ // Streaming usage is not supported by Azure deployments, so default to false
476
+ this.streamUsage = false;
467
477
  }
478
+ this.streaming = fields?.streaming ?? false;
479
+ this.streamUsage = fields?.streamUsage ?? this.streamUsage;
468
480
  this.clientConfig = {
469
481
  apiKey: this.apiKey,
470
482
  organization: this.organization,
@@ -503,6 +515,13 @@ export class ChatOpenAI extends BaseChatModel {
503
515
  return (tools !== undefined &&
504
516
  tools.every((tool) => Array.isArray(tool.lc_namespace)));
505
517
  }
518
+ let streamOptionsConfig = {};
519
+ if (options?.stream_options !== undefined) {
520
+ streamOptionsConfig = { stream_options: options.stream_options };
521
+ }
522
+ else if (this.streamUsage && this.streaming) {
523
+ streamOptionsConfig = { stream_options: { include_usage: true } };
524
+ }
506
525
  const params = {
507
526
  model: this.model,
508
527
  temperature: this.temperature,
@@ -516,6 +535,7 @@ export class ChatOpenAI extends BaseChatModel {
516
535
  logit_bias: this.logitBias,
517
536
  stop: options?.stop ?? this.stopSequences,
518
537
  user: this.user,
538
+ // if include_usage is set or streamUsage then stream must be set to true.
519
539
  stream: this.streaming,
520
540
  functions: options?.functions,
521
541
  function_call: options?.function_call,
@@ -525,9 +545,7 @@ export class ChatOpenAI extends BaseChatModel {
525
545
  tool_choice: options?.tool_choice,
526
546
  response_format: options?.response_format,
527
547
  seed: options?.seed,
528
- ...(options?.stream_options !== undefined
529
- ? { stream_options: options.stream_options }
530
- : {}),
548
+ ...streamOptionsConfig,
531
549
  parallel_tool_calls: options?.parallel_tool_calls,
532
550
  ...this.modelKwargs,
533
551
  };
@@ -563,7 +581,7 @@ export class ChatOpenAI extends BaseChatModel {
563
581
  if (!delta) {
564
582
  continue;
565
583
  }
566
- const chunk = _convertDeltaToMessageChunk(delta, defaultRole);
584
+ const chunk = _convertDeltaToMessageChunk(delta, data.id, defaultRole);
567
585
  defaultRole = delta.role ?? defaultRole;
568
586
  const newTokenIndices = {
569
587
  prompt: options.promptIndex ?? 0,
@@ -674,7 +692,7 @@ export class ChatOpenAI extends BaseChatModel {
674
692
  const text = part.message?.content ?? "";
675
693
  const generation = {
676
694
  text,
677
- message: openAIResponseToChatMessage(part.message ?? { role: "assistant" }),
695
+ message: openAIResponseToChatMessage(part.message ?? { role: "assistant" }, data.id),
678
696
  };
679
697
  generation.generationInfo = {
680
698
  ...(part.finish_reason ? { finish_reason: part.finish_reason } : {}),
package/dist/types.d.ts CHANGED
@@ -24,6 +24,11 @@ export declare interface OpenAIBaseInput {
24
24
  user?: string;
25
25
  /** Whether to stream the results or not. Enabling disables tokenUsage reporting */
26
26
  streaming: boolean;
27
+ /**
28
+ * Whether or not to include token usage data in streamed chunks.
29
+ * @default true
30
+ */
31
+ streamUsage?: boolean;
27
32
  /**
28
33
  * Model name to use
29
34
  * Alias for `model`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/openai",
3
- "version": "0.1.3",
3
+ "version": "0.2.1",
4
4
  "description": "OpenAI integrations for LangChain.js",
5
5
  "type": "module",
6
6
  "engines": {
@@ -35,7 +35,7 @@
35
35
  "author": "LangChain",
36
36
  "license": "MIT",
37
37
  "dependencies": {
38
- "@langchain/core": ">=0.2.5 <0.3.0",
38
+ "@langchain/core": ">=0.2.8 <0.3.0",
39
39
  "js-tiktoken": "^1.0.12",
40
40
  "openai": "^4.49.1",
41
41
  "zod": "^3.22.4",