@langchain/openai 0.3.9 → 0.3.11
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.
- package/dist/chat_models.cjs +67 -17
- package/dist/chat_models.d.ts +39 -1
- package/dist/chat_models.js +67 -17
- package/package.json +1 -1
package/dist/chat_models.cjs
CHANGED
|
@@ -78,9 +78,11 @@ function openAIResponseToChatMessage(message, rawResponse, includeRawResponse) {
|
|
|
78
78
|
system_fingerprint: rawResponse.system_fingerprint,
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
|
-
|
|
81
|
+
if (message.audio) {
|
|
82
|
+
additional_kwargs.audio = message.audio;
|
|
83
|
+
}
|
|
82
84
|
return new messages_1.AIMessage({
|
|
83
|
-
content: content || "",
|
|
85
|
+
content: message.content || "",
|
|
84
86
|
tool_calls: toolCalls,
|
|
85
87
|
invalid_tool_calls: invalidToolCalls,
|
|
86
88
|
additional_kwargs,
|
|
@@ -96,18 +98,7 @@ function _convertDeltaToMessageChunk(
|
|
|
96
98
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
97
99
|
delta, rawResponse, defaultRole, includeRawResponse) {
|
|
98
100
|
const role = delta.role ?? defaultRole;
|
|
99
|
-
|
|
100
|
-
if (delta.audio) {
|
|
101
|
-
content = [
|
|
102
|
-
{
|
|
103
|
-
...delta.audio,
|
|
104
|
-
index: rawResponse.choices[0].index,
|
|
105
|
-
},
|
|
106
|
-
];
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
content = delta.content ?? "";
|
|
110
|
-
}
|
|
101
|
+
const content = delta.content ?? "";
|
|
111
102
|
let additional_kwargs;
|
|
112
103
|
if (delta.function_call) {
|
|
113
104
|
additional_kwargs = {
|
|
@@ -125,6 +116,12 @@ delta, rawResponse, defaultRole, includeRawResponse) {
|
|
|
125
116
|
if (includeRawResponse) {
|
|
126
117
|
additional_kwargs.__raw_response = rawResponse;
|
|
127
118
|
}
|
|
119
|
+
if (delta.audio) {
|
|
120
|
+
additional_kwargs.audio = {
|
|
121
|
+
...delta.audio,
|
|
122
|
+
index: rawResponse.choices[0].index,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
128
125
|
const response_metadata = { usage: { ...rawResponse.usage } };
|
|
129
126
|
if (role === "user") {
|
|
130
127
|
return new messages_1.HumanMessageChunk({ content, response_metadata });
|
|
@@ -176,7 +173,7 @@ delta, rawResponse, defaultRole, includeRawResponse) {
|
|
|
176
173
|
// Used in LangSmith, export is important here
|
|
177
174
|
function _convertMessagesToOpenAIParams(messages) {
|
|
178
175
|
// TODO: Function messages do not support array content, fix cast
|
|
179
|
-
return messages.
|
|
176
|
+
return messages.flatMap((message) => {
|
|
180
177
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
181
178
|
const completionParam = {
|
|
182
179
|
role: messageToOpenAIRole(message),
|
|
@@ -201,6 +198,17 @@ function _convertMessagesToOpenAIParams(messages) {
|
|
|
201
198
|
completionParam.tool_call_id = message.tool_call_id;
|
|
202
199
|
}
|
|
203
200
|
}
|
|
201
|
+
if (message.additional_kwargs.audio &&
|
|
202
|
+
typeof message.additional_kwargs.audio === "object" &&
|
|
203
|
+
"id" in message.additional_kwargs.audio) {
|
|
204
|
+
const audioMessage = {
|
|
205
|
+
role: "assistant",
|
|
206
|
+
audio: {
|
|
207
|
+
id: message.additional_kwargs.audio.id,
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
return [completionParam, audioMessage];
|
|
211
|
+
}
|
|
204
212
|
return completionParam;
|
|
205
213
|
});
|
|
206
214
|
}
|
|
@@ -718,6 +726,43 @@ function _convertChatOpenAIToolTypeToOpenAITool(tool, fields) {
|
|
|
718
726
|
* </details>
|
|
719
727
|
*
|
|
720
728
|
* <br />
|
|
729
|
+
*
|
|
730
|
+
* <details>
|
|
731
|
+
* <summary><strong>Audio Outputs</strong></summary>
|
|
732
|
+
*
|
|
733
|
+
* ```typescript
|
|
734
|
+
* import { ChatOpenAI } from "@langchain/openai";
|
|
735
|
+
*
|
|
736
|
+
* const modelWithAudioOutput = new ChatOpenAI({
|
|
737
|
+
* model: "gpt-4o-audio-preview",
|
|
738
|
+
* // You may also pass these fields to `.bind` as a call argument.
|
|
739
|
+
* modalities: ["text", "audio"], // Specifies that the model should output audio.
|
|
740
|
+
* audio: {
|
|
741
|
+
* voice: "alloy",
|
|
742
|
+
* format: "wav",
|
|
743
|
+
* },
|
|
744
|
+
* });
|
|
745
|
+
*
|
|
746
|
+
* const audioOutputResult = await modelWithAudioOutput.invoke("Tell me a joke about cats.");
|
|
747
|
+
* const castAudioContent = audioOutputResult.additional_kwargs.audio as Record<string, any>;
|
|
748
|
+
*
|
|
749
|
+
* console.log({
|
|
750
|
+
* ...castAudioContent,
|
|
751
|
+
* data: castAudioContent.data.slice(0, 100) // Sliced for brevity
|
|
752
|
+
* })
|
|
753
|
+
* ```
|
|
754
|
+
*
|
|
755
|
+
* ```txt
|
|
756
|
+
* {
|
|
757
|
+
* id: 'audio_67117718c6008190a3afad3e3054b9b6',
|
|
758
|
+
* data: 'UklGRqYwBgBXQVZFZm10IBAAAAABAAEAwF0AAIC7AAACABAATElTVBoAAABJTkZPSVNGVA4AAABMYXZmNTguMjkuMTAwAGRhdGFg',
|
|
759
|
+
* expires_at: 1729201448,
|
|
760
|
+
* transcript: 'Sure! Why did the cat sit on the computer? Because it wanted to keep an eye on the mouse!'
|
|
761
|
+
* }
|
|
762
|
+
* ```
|
|
763
|
+
* </details>
|
|
764
|
+
*
|
|
765
|
+
* <br />
|
|
721
766
|
*/
|
|
722
767
|
class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
723
768
|
static lc_name() {
|
|
@@ -1202,6 +1247,10 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
1202
1247
|
prompt: options.promptIndex ?? 0,
|
|
1203
1248
|
completion: choice.index ?? 0,
|
|
1204
1249
|
};
|
|
1250
|
+
if (typeof chunk.content !== "string") {
|
|
1251
|
+
console.log("[WARNING]: Received non-string content from OpenAI. This is currently not supported.");
|
|
1252
|
+
continue;
|
|
1253
|
+
}
|
|
1205
1254
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1206
1255
|
const generationInfo = { ...newTokenIndices };
|
|
1207
1256
|
if (choice.finish_reason != null) {
|
|
@@ -1215,7 +1264,7 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
1215
1264
|
}
|
|
1216
1265
|
const generationChunk = new outputs_1.ChatGenerationChunk({
|
|
1217
1266
|
message: chunk,
|
|
1218
|
-
text:
|
|
1267
|
+
text: chunk.content,
|
|
1219
1268
|
generationInfo,
|
|
1220
1269
|
});
|
|
1221
1270
|
yield generationChunk;
|
|
@@ -1374,8 +1423,9 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
1374
1423
|
}
|
|
1375
1424
|
const generations = [];
|
|
1376
1425
|
for (const part of data?.choices ?? []) {
|
|
1426
|
+
const text = part.message?.content ?? "";
|
|
1377
1427
|
const generation = {
|
|
1378
|
-
text
|
|
1428
|
+
text,
|
|
1379
1429
|
message: openAIResponseToChatMessage(part.message ?? { role: "assistant" }, data, this.__includeRawResponse),
|
|
1380
1430
|
};
|
|
1381
1431
|
generation.generationInfo = {
|
package/dist/chat_models.d.ts
CHANGED
|
@@ -18,8 +18,9 @@ interface OpenAILLMOutput {
|
|
|
18
18
|
tokenUsage: TokenUsage;
|
|
19
19
|
}
|
|
20
20
|
type OpenAIRoleEnum = "system" | "assistant" | "user" | "function" | "tool";
|
|
21
|
+
type OpenAICompletionParam = OpenAIClient.Chat.Completions.ChatCompletionMessageParam;
|
|
21
22
|
export declare function messageToOpenAIRole(message: BaseMessage): OpenAIRoleEnum;
|
|
22
|
-
export declare function _convertMessagesToOpenAIParams(messages: BaseMessage[]):
|
|
23
|
+
export declare function _convertMessagesToOpenAIParams(messages: BaseMessage[]): OpenAICompletionParam[];
|
|
23
24
|
type ChatOpenAIToolType = BindToolsInput | OpenAIClient.ChatCompletionTool;
|
|
24
25
|
export interface ChatOpenAIStructuredOutputMethodOptions<IncludeRaw extends boolean> extends StructuredOutputMethodOptions<IncludeRaw> {
|
|
25
26
|
/**
|
|
@@ -596,6 +597,43 @@ export interface ChatOpenAIFields extends Partial<OpenAIChatInput>, Partial<Azur
|
|
|
596
597
|
* </details>
|
|
597
598
|
*
|
|
598
599
|
* <br />
|
|
600
|
+
*
|
|
601
|
+
* <details>
|
|
602
|
+
* <summary><strong>Audio Outputs</strong></summary>
|
|
603
|
+
*
|
|
604
|
+
* ```typescript
|
|
605
|
+
* import { ChatOpenAI } from "@langchain/openai";
|
|
606
|
+
*
|
|
607
|
+
* const modelWithAudioOutput = new ChatOpenAI({
|
|
608
|
+
* model: "gpt-4o-audio-preview",
|
|
609
|
+
* // You may also pass these fields to `.bind` as a call argument.
|
|
610
|
+
* modalities: ["text", "audio"], // Specifies that the model should output audio.
|
|
611
|
+
* audio: {
|
|
612
|
+
* voice: "alloy",
|
|
613
|
+
* format: "wav",
|
|
614
|
+
* },
|
|
615
|
+
* });
|
|
616
|
+
*
|
|
617
|
+
* const audioOutputResult = await modelWithAudioOutput.invoke("Tell me a joke about cats.");
|
|
618
|
+
* const castAudioContent = audioOutputResult.additional_kwargs.audio as Record<string, any>;
|
|
619
|
+
*
|
|
620
|
+
* console.log({
|
|
621
|
+
* ...castAudioContent,
|
|
622
|
+
* data: castAudioContent.data.slice(0, 100) // Sliced for brevity
|
|
623
|
+
* })
|
|
624
|
+
* ```
|
|
625
|
+
*
|
|
626
|
+
* ```txt
|
|
627
|
+
* {
|
|
628
|
+
* id: 'audio_67117718c6008190a3afad3e3054b9b6',
|
|
629
|
+
* data: 'UklGRqYwBgBXQVZFZm10IBAAAAABAAEAwF0AAIC7AAACABAATElTVBoAAABJTkZPSVNGVA4AAABMYXZmNTguMjkuMTAwAGRhdGFg',
|
|
630
|
+
* expires_at: 1729201448,
|
|
631
|
+
* transcript: 'Sure! Why did the cat sit on the computer? Because it wanted to keep an eye on the mouse!'
|
|
632
|
+
* }
|
|
633
|
+
* ```
|
|
634
|
+
* </details>
|
|
635
|
+
*
|
|
636
|
+
* <br />
|
|
599
637
|
*/
|
|
600
638
|
export declare class ChatOpenAI<CallOptions extends ChatOpenAICallOptions = ChatOpenAICallOptions> extends BaseChatModel<CallOptions, AIMessageChunk> implements OpenAIChatInput, AzureOpenAIInput {
|
|
601
639
|
static lc_name(): string;
|
package/dist/chat_models.js
CHANGED
|
@@ -74,9 +74,11 @@ function openAIResponseToChatMessage(message, rawResponse, includeRawResponse) {
|
|
|
74
74
|
system_fingerprint: rawResponse.system_fingerprint,
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
|
-
|
|
77
|
+
if (message.audio) {
|
|
78
|
+
additional_kwargs.audio = message.audio;
|
|
79
|
+
}
|
|
78
80
|
return new AIMessage({
|
|
79
|
-
content: content || "",
|
|
81
|
+
content: message.content || "",
|
|
80
82
|
tool_calls: toolCalls,
|
|
81
83
|
invalid_tool_calls: invalidToolCalls,
|
|
82
84
|
additional_kwargs,
|
|
@@ -92,18 +94,7 @@ function _convertDeltaToMessageChunk(
|
|
|
92
94
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
95
|
delta, rawResponse, defaultRole, includeRawResponse) {
|
|
94
96
|
const role = delta.role ?? defaultRole;
|
|
95
|
-
|
|
96
|
-
if (delta.audio) {
|
|
97
|
-
content = [
|
|
98
|
-
{
|
|
99
|
-
...delta.audio,
|
|
100
|
-
index: rawResponse.choices[0].index,
|
|
101
|
-
},
|
|
102
|
-
];
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
content = delta.content ?? "";
|
|
106
|
-
}
|
|
97
|
+
const content = delta.content ?? "";
|
|
107
98
|
let additional_kwargs;
|
|
108
99
|
if (delta.function_call) {
|
|
109
100
|
additional_kwargs = {
|
|
@@ -121,6 +112,12 @@ delta, rawResponse, defaultRole, includeRawResponse) {
|
|
|
121
112
|
if (includeRawResponse) {
|
|
122
113
|
additional_kwargs.__raw_response = rawResponse;
|
|
123
114
|
}
|
|
115
|
+
if (delta.audio) {
|
|
116
|
+
additional_kwargs.audio = {
|
|
117
|
+
...delta.audio,
|
|
118
|
+
index: rawResponse.choices[0].index,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
124
121
|
const response_metadata = { usage: { ...rawResponse.usage } };
|
|
125
122
|
if (role === "user") {
|
|
126
123
|
return new HumanMessageChunk({ content, response_metadata });
|
|
@@ -172,7 +169,7 @@ delta, rawResponse, defaultRole, includeRawResponse) {
|
|
|
172
169
|
// Used in LangSmith, export is important here
|
|
173
170
|
export function _convertMessagesToOpenAIParams(messages) {
|
|
174
171
|
// TODO: Function messages do not support array content, fix cast
|
|
175
|
-
return messages.
|
|
172
|
+
return messages.flatMap((message) => {
|
|
176
173
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
177
174
|
const completionParam = {
|
|
178
175
|
role: messageToOpenAIRole(message),
|
|
@@ -197,6 +194,17 @@ export function _convertMessagesToOpenAIParams(messages) {
|
|
|
197
194
|
completionParam.tool_call_id = message.tool_call_id;
|
|
198
195
|
}
|
|
199
196
|
}
|
|
197
|
+
if (message.additional_kwargs.audio &&
|
|
198
|
+
typeof message.additional_kwargs.audio === "object" &&
|
|
199
|
+
"id" in message.additional_kwargs.audio) {
|
|
200
|
+
const audioMessage = {
|
|
201
|
+
role: "assistant",
|
|
202
|
+
audio: {
|
|
203
|
+
id: message.additional_kwargs.audio.id,
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
return [completionParam, audioMessage];
|
|
207
|
+
}
|
|
200
208
|
return completionParam;
|
|
201
209
|
});
|
|
202
210
|
}
|
|
@@ -713,6 +721,43 @@ function _convertChatOpenAIToolTypeToOpenAITool(tool, fields) {
|
|
|
713
721
|
* </details>
|
|
714
722
|
*
|
|
715
723
|
* <br />
|
|
724
|
+
*
|
|
725
|
+
* <details>
|
|
726
|
+
* <summary><strong>Audio Outputs</strong></summary>
|
|
727
|
+
*
|
|
728
|
+
* ```typescript
|
|
729
|
+
* import { ChatOpenAI } from "@langchain/openai";
|
|
730
|
+
*
|
|
731
|
+
* const modelWithAudioOutput = new ChatOpenAI({
|
|
732
|
+
* model: "gpt-4o-audio-preview",
|
|
733
|
+
* // You may also pass these fields to `.bind` as a call argument.
|
|
734
|
+
* modalities: ["text", "audio"], // Specifies that the model should output audio.
|
|
735
|
+
* audio: {
|
|
736
|
+
* voice: "alloy",
|
|
737
|
+
* format: "wav",
|
|
738
|
+
* },
|
|
739
|
+
* });
|
|
740
|
+
*
|
|
741
|
+
* const audioOutputResult = await modelWithAudioOutput.invoke("Tell me a joke about cats.");
|
|
742
|
+
* const castAudioContent = audioOutputResult.additional_kwargs.audio as Record<string, any>;
|
|
743
|
+
*
|
|
744
|
+
* console.log({
|
|
745
|
+
* ...castAudioContent,
|
|
746
|
+
* data: castAudioContent.data.slice(0, 100) // Sliced for brevity
|
|
747
|
+
* })
|
|
748
|
+
* ```
|
|
749
|
+
*
|
|
750
|
+
* ```txt
|
|
751
|
+
* {
|
|
752
|
+
* id: 'audio_67117718c6008190a3afad3e3054b9b6',
|
|
753
|
+
* data: 'UklGRqYwBgBXQVZFZm10IBAAAAABAAEAwF0AAIC7AAACABAATElTVBoAAABJTkZPSVNGVA4AAABMYXZmNTguMjkuMTAwAGRhdGFg',
|
|
754
|
+
* expires_at: 1729201448,
|
|
755
|
+
* transcript: 'Sure! Why did the cat sit on the computer? Because it wanted to keep an eye on the mouse!'
|
|
756
|
+
* }
|
|
757
|
+
* ```
|
|
758
|
+
* </details>
|
|
759
|
+
*
|
|
760
|
+
* <br />
|
|
716
761
|
*/
|
|
717
762
|
export class ChatOpenAI extends BaseChatModel {
|
|
718
763
|
static lc_name() {
|
|
@@ -1197,6 +1242,10 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
1197
1242
|
prompt: options.promptIndex ?? 0,
|
|
1198
1243
|
completion: choice.index ?? 0,
|
|
1199
1244
|
};
|
|
1245
|
+
if (typeof chunk.content !== "string") {
|
|
1246
|
+
console.log("[WARNING]: Received non-string content from OpenAI. This is currently not supported.");
|
|
1247
|
+
continue;
|
|
1248
|
+
}
|
|
1200
1249
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1201
1250
|
const generationInfo = { ...newTokenIndices };
|
|
1202
1251
|
if (choice.finish_reason != null) {
|
|
@@ -1210,7 +1259,7 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
1210
1259
|
}
|
|
1211
1260
|
const generationChunk = new ChatGenerationChunk({
|
|
1212
1261
|
message: chunk,
|
|
1213
|
-
text:
|
|
1262
|
+
text: chunk.content,
|
|
1214
1263
|
generationInfo,
|
|
1215
1264
|
});
|
|
1216
1265
|
yield generationChunk;
|
|
@@ -1369,8 +1418,9 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
1369
1418
|
}
|
|
1370
1419
|
const generations = [];
|
|
1371
1420
|
for (const part of data?.choices ?? []) {
|
|
1421
|
+
const text = part.message?.content ?? "";
|
|
1372
1422
|
const generation = {
|
|
1373
|
-
text
|
|
1423
|
+
text,
|
|
1374
1424
|
message: openAIResponseToChatMessage(part.message ?? { role: "assistant" }, data, this.__includeRawResponse),
|
|
1375
1425
|
};
|
|
1376
1426
|
generation.generationInfo = {
|