@langchain/openai 0.2.5 → 0.2.7
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/azure/chat_models.cjs +412 -0
- package/dist/azure/chat_models.d.ts +412 -0
- package/dist/azure/chat_models.js +412 -0
- package/dist/chat_models.cjs +546 -39
- package/dist/chat_models.d.ts +465 -40
- package/dist/chat_models.js +546 -39
- package/dist/types.d.ts +17 -0
- package/dist/utils/tools.cjs +54 -0
- package/dist/utils/tools.d.ts +20 -0
- package/dist/utils/tools.js +50 -0
- package/package.json +7 -7
- package/dist/tools/tests/dalle.int.test.d.ts +0 -1
- package/dist/tools/tests/dalle.int.test.js +0 -57
package/dist/chat_models.cjs
CHANGED
|
@@ -6,14 +6,16 @@ const messages_1 = require("@langchain/core/messages");
|
|
|
6
6
|
const outputs_1 = require("@langchain/core/outputs");
|
|
7
7
|
const env_1 = require("@langchain/core/utils/env");
|
|
8
8
|
const chat_models_1 = require("@langchain/core/language_models/chat_models");
|
|
9
|
-
const
|
|
9
|
+
const base_1 = require("@langchain/core/language_models/base");
|
|
10
10
|
const runnables_1 = require("@langchain/core/runnables");
|
|
11
11
|
const output_parsers_1 = require("@langchain/core/output_parsers");
|
|
12
12
|
const openai_tools_1 = require("@langchain/core/output_parsers/openai_tools");
|
|
13
13
|
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
14
|
+
const zod_1 = require("openai/helpers/zod");
|
|
14
15
|
const azure_js_1 = require("./utils/azure.cjs");
|
|
15
16
|
const openai_js_1 = require("./utils/openai.cjs");
|
|
16
17
|
const openai_format_fndef_js_1 = require("./utils/openai-format-fndef.cjs");
|
|
18
|
+
const tools_js_1 = require("./utils/tools.cjs");
|
|
17
19
|
function extractGenericMessageCustomRole(message) {
|
|
18
20
|
if (message.role !== "system" &&
|
|
19
21
|
message.role !== "assistant" &&
|
|
@@ -184,38 +186,434 @@ function convertMessagesToOpenAIParams(messages) {
|
|
|
184
186
|
return completionParam;
|
|
185
187
|
});
|
|
186
188
|
}
|
|
189
|
+
function _convertChatOpenAIToolTypeToOpenAITool(tool, fields) {
|
|
190
|
+
if ((0, base_1.isOpenAITool)(tool)) {
|
|
191
|
+
if (fields?.strict !== undefined) {
|
|
192
|
+
return {
|
|
193
|
+
...tool,
|
|
194
|
+
function: {
|
|
195
|
+
...tool.function,
|
|
196
|
+
strict: fields.strict,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
return tool;
|
|
201
|
+
}
|
|
202
|
+
return (0, tools_js_1._convertToOpenAITool)(tool, fields);
|
|
203
|
+
}
|
|
187
204
|
/**
|
|
188
|
-
*
|
|
205
|
+
* OpenAI chat model integration.
|
|
206
|
+
*
|
|
207
|
+
* Setup:
|
|
208
|
+
* Install `@langchain/openai` and set an environment variable named `OPENAI_API_KEY`.
|
|
209
|
+
*
|
|
210
|
+
* ```bash
|
|
211
|
+
* npm install @langchain/openai
|
|
212
|
+
* export OPENAI_API_KEY="your-api-key"
|
|
213
|
+
* ```
|
|
214
|
+
*
|
|
215
|
+
* ## [Constructor args](https://api.js.langchain.com/classes/langchain_openai.ChatOpenAI.html#constructor)
|
|
216
|
+
*
|
|
217
|
+
* ## [Runtime args](https://api.js.langchain.com/interfaces/langchain_openai.ChatOpenAICallOptions.html)
|
|
218
|
+
*
|
|
219
|
+
* Runtime args can be passed as the second argument to any of the base runnable methods `.invoke`. `.stream`, `.batch`, etc.
|
|
220
|
+
* They can also be passed via `.bind`, or the second arg in `.bindTools`, like shown in the examples below:
|
|
221
|
+
*
|
|
222
|
+
* ```typescript
|
|
223
|
+
* // When calling `.bind`, call options should be passed via the first argument
|
|
224
|
+
* const llmWithArgsBound = llm.bind({
|
|
225
|
+
* stop: ["\n"],
|
|
226
|
+
* tools: [...],
|
|
227
|
+
* });
|
|
228
|
+
*
|
|
229
|
+
* // When calling `.bindTools`, call options should be passed via the second argument
|
|
230
|
+
* const llmWithTools = llm.bindTools(
|
|
231
|
+
* [...],
|
|
232
|
+
* {
|
|
233
|
+
* tool_choice: "auto",
|
|
234
|
+
* }
|
|
235
|
+
* );
|
|
236
|
+
* ```
|
|
237
|
+
*
|
|
238
|
+
* ## Examples
|
|
239
|
+
*
|
|
240
|
+
* <details open>
|
|
241
|
+
* <summary><strong>Instantiate</strong></summary>
|
|
242
|
+
*
|
|
243
|
+
* ```typescript
|
|
244
|
+
* import { ChatOpenAI } from '@langchain/openai';
|
|
245
|
+
*
|
|
246
|
+
* const llm = new ChatOpenAI({
|
|
247
|
+
* model: "gpt-4o",
|
|
248
|
+
* temperature: 0,
|
|
249
|
+
* maxTokens: undefined,
|
|
250
|
+
* timeout: undefined,
|
|
251
|
+
* maxRetries: 2,
|
|
252
|
+
* // apiKey: "...",
|
|
253
|
+
* // baseUrl: "...",
|
|
254
|
+
* // organization: "...",
|
|
255
|
+
* // other params...
|
|
256
|
+
* });
|
|
257
|
+
* ```
|
|
258
|
+
* </details>
|
|
259
|
+
*
|
|
260
|
+
* <br />
|
|
261
|
+
*
|
|
262
|
+
* <details>
|
|
263
|
+
* <summary><strong>Invoking</strong></summary>
|
|
264
|
+
*
|
|
265
|
+
* ```typescript
|
|
266
|
+
* const input = `Translate "I love programming" into French.`;
|
|
267
|
+
*
|
|
268
|
+
* // Models also accept a list of chat messages or a formatted prompt
|
|
269
|
+
* const result = await llm.invoke(input);
|
|
270
|
+
* console.log(result);
|
|
271
|
+
* ```
|
|
272
|
+
*
|
|
273
|
+
* ```txt
|
|
274
|
+
* AIMessage {
|
|
275
|
+
* "id": "chatcmpl-9u4Mpu44CbPjwYFkTbeoZgvzB00Tz",
|
|
276
|
+
* "content": "J'adore la programmation.",
|
|
277
|
+
* "response_metadata": {
|
|
278
|
+
* "tokenUsage": {
|
|
279
|
+
* "completionTokens": 5,
|
|
280
|
+
* "promptTokens": 28,
|
|
281
|
+
* "totalTokens": 33
|
|
282
|
+
* },
|
|
283
|
+
* "finish_reason": "stop",
|
|
284
|
+
* "system_fingerprint": "fp_3aa7262c27"
|
|
285
|
+
* },
|
|
286
|
+
* "usage_metadata": {
|
|
287
|
+
* "input_tokens": 28,
|
|
288
|
+
* "output_tokens": 5,
|
|
289
|
+
* "total_tokens": 33
|
|
290
|
+
* }
|
|
291
|
+
* }
|
|
292
|
+
* ```
|
|
293
|
+
* </details>
|
|
294
|
+
*
|
|
295
|
+
* <br />
|
|
296
|
+
*
|
|
297
|
+
* <details>
|
|
298
|
+
* <summary><strong>Streaming Chunks</strong></summary>
|
|
299
|
+
*
|
|
300
|
+
* ```typescript
|
|
301
|
+
* for await (const chunk of await llm.stream(input)) {
|
|
302
|
+
* console.log(chunk);
|
|
303
|
+
* }
|
|
304
|
+
* ```
|
|
305
|
+
*
|
|
306
|
+
* ```txt
|
|
307
|
+
* AIMessageChunk {
|
|
308
|
+
* "id": "chatcmpl-9u4NWB7yUeHCKdLr6jP3HpaOYHTqs",
|
|
309
|
+
* "content": ""
|
|
310
|
+
* }
|
|
311
|
+
* AIMessageChunk {
|
|
312
|
+
* "content": "J"
|
|
313
|
+
* }
|
|
314
|
+
* AIMessageChunk {
|
|
315
|
+
* "content": "'adore"
|
|
316
|
+
* }
|
|
317
|
+
* AIMessageChunk {
|
|
318
|
+
* "content": " la"
|
|
319
|
+
* }
|
|
320
|
+
* AIMessageChunk {
|
|
321
|
+
* "content": " programmation",,
|
|
322
|
+
* }
|
|
323
|
+
* AIMessageChunk {
|
|
324
|
+
* "content": ".",,
|
|
325
|
+
* }
|
|
326
|
+
* AIMessageChunk {
|
|
327
|
+
* "content": "",
|
|
328
|
+
* "response_metadata": {
|
|
329
|
+
* "finish_reason": "stop",
|
|
330
|
+
* "system_fingerprint": "fp_c9aa9c0491"
|
|
331
|
+
* },
|
|
332
|
+
* }
|
|
333
|
+
* AIMessageChunk {
|
|
334
|
+
* "content": "",
|
|
335
|
+
* "usage_metadata": {
|
|
336
|
+
* "input_tokens": 28,
|
|
337
|
+
* "output_tokens": 5,
|
|
338
|
+
* "total_tokens": 33
|
|
339
|
+
* }
|
|
340
|
+
* }
|
|
341
|
+
* ```
|
|
342
|
+
* </details>
|
|
343
|
+
*
|
|
344
|
+
* <br />
|
|
345
|
+
*
|
|
346
|
+
* <details>
|
|
347
|
+
* <summary><strong>Aggregate Streamed Chunks</strong></summary>
|
|
348
|
+
*
|
|
349
|
+
* ```typescript
|
|
350
|
+
* import { AIMessageChunk } from '@langchain/core/messages';
|
|
351
|
+
* import { concat } from '@langchain/core/utils/stream';
|
|
352
|
+
*
|
|
353
|
+
* const stream = await llm.stream(input);
|
|
354
|
+
* let full: AIMessageChunk | undefined;
|
|
355
|
+
* for await (const chunk of stream) {
|
|
356
|
+
* full = !full ? chunk : concat(full, chunk);
|
|
357
|
+
* }
|
|
358
|
+
* console.log(full);
|
|
359
|
+
* ```
|
|
360
|
+
*
|
|
361
|
+
* ```txt
|
|
362
|
+
* AIMessageChunk {
|
|
363
|
+
* "id": "chatcmpl-9u4PnX6Fy7OmK46DASy0bH6cxn5Xu",
|
|
364
|
+
* "content": "J'adore la programmation.",
|
|
365
|
+
* "response_metadata": {
|
|
366
|
+
* "prompt": 0,
|
|
367
|
+
* "completion": 0,
|
|
368
|
+
* "finish_reason": "stop",
|
|
369
|
+
* },
|
|
370
|
+
* "usage_metadata": {
|
|
371
|
+
* "input_tokens": 28,
|
|
372
|
+
* "output_tokens": 5,
|
|
373
|
+
* "total_tokens": 33
|
|
374
|
+
* }
|
|
375
|
+
* }
|
|
376
|
+
* ```
|
|
377
|
+
* </details>
|
|
378
|
+
*
|
|
379
|
+
* <br />
|
|
380
|
+
*
|
|
381
|
+
* <details>
|
|
382
|
+
* <summary><strong>Bind tools</strong></summary>
|
|
383
|
+
*
|
|
384
|
+
* ```typescript
|
|
385
|
+
* import { z } from 'zod';
|
|
386
|
+
*
|
|
387
|
+
* const GetWeather = {
|
|
388
|
+
* name: "GetWeather",
|
|
389
|
+
* description: "Get the current weather in a given location",
|
|
390
|
+
* schema: z.object({
|
|
391
|
+
* location: z.string().describe("The city and state, e.g. San Francisco, CA")
|
|
392
|
+
* }),
|
|
393
|
+
* }
|
|
394
|
+
*
|
|
395
|
+
* const GetPopulation = {
|
|
396
|
+
* name: "GetPopulation",
|
|
397
|
+
* description: "Get the current population in a given location",
|
|
398
|
+
* schema: z.object({
|
|
399
|
+
* location: z.string().describe("The city and state, e.g. San Francisco, CA")
|
|
400
|
+
* }),
|
|
401
|
+
* }
|
|
402
|
+
*
|
|
403
|
+
* const llmWithTools = llm.bindTools(
|
|
404
|
+
* [GetWeather, GetPopulation],
|
|
405
|
+
* {
|
|
406
|
+
* // strict: true // enforce tool args schema is respected
|
|
407
|
+
* }
|
|
408
|
+
* );
|
|
409
|
+
* const aiMsg = await llmWithTools.invoke(
|
|
410
|
+
* "Which city is hotter today and which is bigger: LA or NY?"
|
|
411
|
+
* );
|
|
412
|
+
* console.log(aiMsg.tool_calls);
|
|
413
|
+
* ```
|
|
414
|
+
*
|
|
415
|
+
* ```txt
|
|
416
|
+
* [
|
|
417
|
+
* {
|
|
418
|
+
* name: 'GetWeather',
|
|
419
|
+
* args: { location: 'Los Angeles, CA' },
|
|
420
|
+
* type: 'tool_call',
|
|
421
|
+
* id: 'call_uPU4FiFzoKAtMxfmPnfQL6UK'
|
|
422
|
+
* },
|
|
423
|
+
* {
|
|
424
|
+
* name: 'GetWeather',
|
|
425
|
+
* args: { location: 'New York, NY' },
|
|
426
|
+
* type: 'tool_call',
|
|
427
|
+
* id: 'call_UNkEwuQsHrGYqgDQuH9nPAtX'
|
|
428
|
+
* },
|
|
429
|
+
* {
|
|
430
|
+
* name: 'GetPopulation',
|
|
431
|
+
* args: { location: 'Los Angeles, CA' },
|
|
432
|
+
* type: 'tool_call',
|
|
433
|
+
* id: 'call_kL3OXxaq9OjIKqRTpvjaCH14'
|
|
434
|
+
* },
|
|
435
|
+
* {
|
|
436
|
+
* name: 'GetPopulation',
|
|
437
|
+
* args: { location: 'New York, NY' },
|
|
438
|
+
* type: 'tool_call',
|
|
439
|
+
* id: 'call_s9KQB1UWj45LLGaEnjz0179q'
|
|
440
|
+
* }
|
|
441
|
+
* ]
|
|
442
|
+
* ```
|
|
443
|
+
* </details>
|
|
444
|
+
*
|
|
445
|
+
* <br />
|
|
446
|
+
*
|
|
447
|
+
* <details>
|
|
448
|
+
* <summary><strong>Structured Output</strong></summary>
|
|
449
|
+
*
|
|
450
|
+
* ```typescript
|
|
451
|
+
* import { z } from 'zod';
|
|
452
|
+
*
|
|
453
|
+
* const Joke = z.object({
|
|
454
|
+
* setup: z.string().describe("The setup of the joke"),
|
|
455
|
+
* punchline: z.string().describe("The punchline to the joke"),
|
|
456
|
+
* rating: z.number().optional().describe("How funny the joke is, from 1 to 10")
|
|
457
|
+
* }).describe('Joke to tell user.');
|
|
458
|
+
*
|
|
459
|
+
* const structuredLlm = llm.withStructuredOutput(Joke);
|
|
460
|
+
* const jokeResult = await structuredLlm.invoke("Tell me a joke about cats", { name: "Joke" });
|
|
461
|
+
* console.log(jokeResult);
|
|
462
|
+
* ```
|
|
463
|
+
*
|
|
464
|
+
* ```txt
|
|
465
|
+
* {
|
|
466
|
+
* setup: 'Why was the cat sitting on the computer?',
|
|
467
|
+
* punchline: 'Because it wanted to keep an eye on the mouse!',
|
|
468
|
+
* rating: 7
|
|
469
|
+
* }
|
|
470
|
+
* ```
|
|
471
|
+
* </details>
|
|
472
|
+
*
|
|
473
|
+
* <br />
|
|
474
|
+
*
|
|
475
|
+
* <details>
|
|
476
|
+
* <summary><strong>JSON Object Response Format</strong></summary>
|
|
477
|
+
*
|
|
478
|
+
* ```typescript
|
|
479
|
+
* const jsonLlm = llm.bind({ response_format: { type: "json_object" } });
|
|
480
|
+
* const jsonLlmAiMsg = await jsonLlm.invoke(
|
|
481
|
+
* "Return a JSON object with key 'randomInts' and a value of 10 random ints in [0-99]"
|
|
482
|
+
* );
|
|
483
|
+
* console.log(jsonLlmAiMsg.content);
|
|
484
|
+
* ```
|
|
485
|
+
*
|
|
486
|
+
* ```txt
|
|
487
|
+
* {
|
|
488
|
+
* "randomInts": [23, 87, 45, 12, 78, 34, 56, 90, 11, 67]
|
|
489
|
+
* }
|
|
490
|
+
* ```
|
|
491
|
+
* </details>
|
|
189
492
|
*
|
|
190
|
-
*
|
|
493
|
+
* <br />
|
|
191
494
|
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
* `AZURE_OPENAI_API_INSTANCE_NAME`,
|
|
195
|
-
* `AZURE_OPENAI_API_DEPLOYMENT_NAME`
|
|
196
|
-
* and `AZURE_OPENAI_API_VERSION` environment variables set.
|
|
197
|
-
* `AZURE_OPENAI_BASE_PATH` is optional and will override `AZURE_OPENAI_API_INSTANCE_NAME` if you need to use a custom endpoint.
|
|
495
|
+
* <details>
|
|
496
|
+
* <summary><strong>Multimodal</strong></summary>
|
|
198
497
|
*
|
|
199
|
-
* @remarks
|
|
200
|
-
* Any parameters that are valid to be passed to {@link
|
|
201
|
-
* https://platform.openai.com/docs/api-reference/chat/create |
|
|
202
|
-
* `openai.createChatCompletion`} can be passed through {@link modelKwargs}, even
|
|
203
|
-
* if not explicitly available on this class.
|
|
204
|
-
* @example
|
|
205
498
|
* ```typescript
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
499
|
+
* import { HumanMessage } from '@langchain/core/messages';
|
|
500
|
+
*
|
|
501
|
+
* const imageUrl = "https://example.com/image.jpg";
|
|
502
|
+
* const imageData = await fetch(imageUrl).then(res => res.arrayBuffer());
|
|
503
|
+
* const base64Image = Buffer.from(imageData).toString('base64');
|
|
504
|
+
*
|
|
505
|
+
* const message = new HumanMessage({
|
|
506
|
+
* content: [
|
|
507
|
+
* { type: "text", text: "describe the weather in this image" },
|
|
508
|
+
* {
|
|
509
|
+
* type: "image_url",
|
|
510
|
+
* image_url: { url: `data:image/jpeg;base64,${base64Image}` },
|
|
511
|
+
* },
|
|
512
|
+
* ]
|
|
210
513
|
* });
|
|
211
514
|
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
515
|
+
* const imageDescriptionAiMsg = await llm.invoke([message]);
|
|
516
|
+
* console.log(imageDescriptionAiMsg.content);
|
|
517
|
+
* ```
|
|
518
|
+
*
|
|
519
|
+
* ```txt
|
|
520
|
+
* The weather in the image appears to be clear and sunny. The sky is mostly blue with a few scattered white clouds, indicating fair weather. The bright sunlight is casting shadows on the green, grassy hill, suggesting it is a pleasant day with good visibility. There are no signs of rain or stormy conditions.
|
|
521
|
+
* ```
|
|
522
|
+
* </details>
|
|
523
|
+
*
|
|
524
|
+
* <br />
|
|
525
|
+
*
|
|
526
|
+
* <details>
|
|
527
|
+
* <summary><strong>Usage Metadata</strong></summary>
|
|
528
|
+
*
|
|
529
|
+
* ```typescript
|
|
530
|
+
* const aiMsgForMetadata = await llm.invoke(input);
|
|
531
|
+
* console.log(aiMsgForMetadata.usage_metadata);
|
|
532
|
+
* ```
|
|
533
|
+
*
|
|
534
|
+
* ```txt
|
|
535
|
+
* { input_tokens: 28, output_tokens: 5, total_tokens: 33 }
|
|
536
|
+
* ```
|
|
537
|
+
* </details>
|
|
538
|
+
*
|
|
539
|
+
* <br />
|
|
540
|
+
*
|
|
541
|
+
* <details>
|
|
542
|
+
* <summary><strong>Logprobs</strong></summary>
|
|
543
|
+
*
|
|
544
|
+
* ```typescript
|
|
545
|
+
* const logprobsLlm = new ChatOpenAI({ logprobs: true });
|
|
546
|
+
* const aiMsgForLogprobs = await logprobsLlm.invoke(input);
|
|
547
|
+
* console.log(aiMsgForLogprobs.response_metadata.logprobs);
|
|
548
|
+
* ```
|
|
549
|
+
*
|
|
550
|
+
* ```txt
|
|
551
|
+
* {
|
|
552
|
+
* content: [
|
|
553
|
+
* {
|
|
554
|
+
* token: 'J',
|
|
555
|
+
* logprob: -0.000050616763,
|
|
556
|
+
* bytes: [Array],
|
|
557
|
+
* top_logprobs: []
|
|
558
|
+
* },
|
|
559
|
+
* {
|
|
560
|
+
* token: "'",
|
|
561
|
+
* logprob: -0.01868736,
|
|
562
|
+
* bytes: [Array],
|
|
563
|
+
* top_logprobs: []
|
|
564
|
+
* },
|
|
565
|
+
* {
|
|
566
|
+
* token: 'ad',
|
|
567
|
+
* logprob: -0.0000030545007,
|
|
568
|
+
* bytes: [Array],
|
|
569
|
+
* top_logprobs: []
|
|
570
|
+
* },
|
|
571
|
+
* { token: 'ore', logprob: 0, bytes: [Array], top_logprobs: [] },
|
|
572
|
+
* {
|
|
573
|
+
* token: ' la',
|
|
574
|
+
* logprob: -0.515404,
|
|
575
|
+
* bytes: [Array],
|
|
576
|
+
* top_logprobs: []
|
|
577
|
+
* },
|
|
578
|
+
* {
|
|
579
|
+
* token: ' programm',
|
|
580
|
+
* logprob: -0.0000118755715,
|
|
581
|
+
* bytes: [Array],
|
|
582
|
+
* top_logprobs: []
|
|
583
|
+
* },
|
|
584
|
+
* { token: 'ation', logprob: 0, bytes: [Array], top_logprobs: [] },
|
|
585
|
+
* {
|
|
586
|
+
* token: '.',
|
|
587
|
+
* logprob: -0.0000037697225,
|
|
588
|
+
* bytes: [Array],
|
|
589
|
+
* top_logprobs: []
|
|
590
|
+
* }
|
|
591
|
+
* ],
|
|
592
|
+
* refusal: null
|
|
593
|
+
* }
|
|
594
|
+
* ```
|
|
595
|
+
* </details>
|
|
596
|
+
*
|
|
597
|
+
* <br />
|
|
214
598
|
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
599
|
+
* <details>
|
|
600
|
+
* <summary><strong>Response Metadata</strong></summary>
|
|
217
601
|
*
|
|
602
|
+
* ```typescript
|
|
603
|
+
* const aiMsgForResponseMetadata = await llm.invoke(input);
|
|
604
|
+
* console.log(aiMsgForResponseMetadata.response_metadata);
|
|
218
605
|
* ```
|
|
606
|
+
*
|
|
607
|
+
* ```txt
|
|
608
|
+
* {
|
|
609
|
+
* tokenUsage: { completionTokens: 5, promptTokens: 28, totalTokens: 33 },
|
|
610
|
+
* finish_reason: 'stop',
|
|
611
|
+
* system_fingerprint: 'fp_3aa7262c27'
|
|
612
|
+
* }
|
|
613
|
+
* ```
|
|
614
|
+
* </details>
|
|
615
|
+
*
|
|
616
|
+
* <br />
|
|
219
617
|
*/
|
|
220
618
|
class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
221
619
|
static lc_name() {
|
|
@@ -443,6 +841,16 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
443
841
|
writable: true,
|
|
444
842
|
value: void 0
|
|
445
843
|
});
|
|
844
|
+
/**
|
|
845
|
+
* Whether the model supports the `strict` argument when passing in tools.
|
|
846
|
+
* If `undefined` the `strict` argument will not be passed to OpenAI.
|
|
847
|
+
*/
|
|
848
|
+
Object.defineProperty(this, "supportsStrictToolCalling", {
|
|
849
|
+
enumerable: true,
|
|
850
|
+
configurable: true,
|
|
851
|
+
writable: true,
|
|
852
|
+
value: void 0
|
|
853
|
+
});
|
|
446
854
|
this.openAIApiKey =
|
|
447
855
|
fields?.apiKey ??
|
|
448
856
|
fields?.openAIApiKey ??
|
|
@@ -515,6 +923,11 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
515
923
|
...configuration,
|
|
516
924
|
...fields?.configuration,
|
|
517
925
|
};
|
|
926
|
+
// If `supportsStrictToolCalling` is explicitly set, use that value.
|
|
927
|
+
// Else leave undefined so it's not passed to OpenAI.
|
|
928
|
+
if (fields?.supportsStrictToolCalling !== undefined) {
|
|
929
|
+
this.supportsStrictToolCalling = fields.supportsStrictToolCalling;
|
|
930
|
+
}
|
|
518
931
|
}
|
|
519
932
|
getLsParams(options) {
|
|
520
933
|
const params = this.invocationParams(options);
|
|
@@ -528,18 +941,39 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
528
941
|
};
|
|
529
942
|
}
|
|
530
943
|
bindTools(tools, kwargs) {
|
|
944
|
+
let strict;
|
|
945
|
+
if (kwargs?.strict !== undefined) {
|
|
946
|
+
strict = kwargs.strict;
|
|
947
|
+
}
|
|
948
|
+
else if (this.supportsStrictToolCalling !== undefined) {
|
|
949
|
+
strict = this.supportsStrictToolCalling;
|
|
950
|
+
}
|
|
531
951
|
return this.bind({
|
|
532
|
-
tools: tools.map(
|
|
952
|
+
tools: tools.map((tool) => _convertChatOpenAIToolTypeToOpenAITool(tool, { strict })),
|
|
533
953
|
...kwargs,
|
|
534
954
|
});
|
|
535
955
|
}
|
|
956
|
+
createResponseFormat(resFormat) {
|
|
957
|
+
if (resFormat &&
|
|
958
|
+
resFormat.type === "json_schema" &&
|
|
959
|
+
resFormat.json_schema.schema &&
|
|
960
|
+
isZodSchema(resFormat.json_schema.schema)) {
|
|
961
|
+
return (0, zod_1.zodResponseFormat)(resFormat.json_schema.schema, resFormat.json_schema.name, {
|
|
962
|
+
description: resFormat.json_schema.description,
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
return resFormat;
|
|
966
|
+
}
|
|
536
967
|
/**
|
|
537
968
|
* Get the parameters used to invoke the model
|
|
538
969
|
*/
|
|
539
970
|
invocationParams(options, extra) {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
971
|
+
let strict;
|
|
972
|
+
if (options?.strict !== undefined) {
|
|
973
|
+
strict = options.strict;
|
|
974
|
+
}
|
|
975
|
+
else if (this.supportsStrictToolCalling !== undefined) {
|
|
976
|
+
strict = this.supportsStrictToolCalling;
|
|
543
977
|
}
|
|
544
978
|
let streamOptionsConfig = {};
|
|
545
979
|
if (options?.stream_options !== undefined) {
|
|
@@ -565,11 +999,11 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
565
999
|
stream: this.streaming,
|
|
566
1000
|
functions: options?.functions,
|
|
567
1001
|
function_call: options?.function_call,
|
|
568
|
-
tools:
|
|
569
|
-
? options
|
|
570
|
-
:
|
|
1002
|
+
tools: options?.tools?.length
|
|
1003
|
+
? options.tools.map((tool) => _convertChatOpenAIToolTypeToOpenAITool(tool, { strict }))
|
|
1004
|
+
: undefined,
|
|
571
1005
|
tool_choice: (0, openai_js_1.formatToOpenAIToolChoice)(options?.tool_choice),
|
|
572
|
-
response_format: options?.response_format,
|
|
1006
|
+
response_format: this.createResponseFormat(options?.response_format),
|
|
573
1007
|
seed: options?.seed,
|
|
574
1008
|
...streamOptionsConfig,
|
|
575
1009
|
parallel_tool_calls: options?.parallel_tool_calls,
|
|
@@ -595,6 +1029,20 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
595
1029
|
stream: true,
|
|
596
1030
|
};
|
|
597
1031
|
let defaultRole;
|
|
1032
|
+
if (params.response_format &&
|
|
1033
|
+
params.response_format.type === "json_schema") {
|
|
1034
|
+
console.warn(`OpenAI does not yet support streaming with "response_format" set to "json_schema". Falling back to non-streaming mode.`);
|
|
1035
|
+
const res = await this._generate(messages, options, runManager);
|
|
1036
|
+
const chunk = new outputs_1.ChatGenerationChunk({
|
|
1037
|
+
message: new messages_1.AIMessageChunk({
|
|
1038
|
+
...res.generations[0].message,
|
|
1039
|
+
}),
|
|
1040
|
+
text: res.generations[0].text,
|
|
1041
|
+
generationInfo: res.generations[0].generationInfo,
|
|
1042
|
+
});
|
|
1043
|
+
yield chunk;
|
|
1044
|
+
return runManager?.handleLLMNewToken(res.generations[0].text ?? "", undefined, undefined, undefined, undefined, { chunk });
|
|
1045
|
+
}
|
|
598
1046
|
const streamIterable = await this.completionWithRetry(params, options);
|
|
599
1047
|
let usage;
|
|
600
1048
|
for await (const data of streamIterable) {
|
|
@@ -698,14 +1146,28 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
698
1146
|
return { generations, llmOutput: { estimatedTokenUsage: tokenUsage } };
|
|
699
1147
|
}
|
|
700
1148
|
else {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
1149
|
+
let data;
|
|
1150
|
+
if (options.response_format &&
|
|
1151
|
+
options.response_format.type === "json_schema") {
|
|
1152
|
+
data = await this.betaParsedCompletionWithRetry({
|
|
1153
|
+
...params,
|
|
1154
|
+
stream: false,
|
|
1155
|
+
messages: messagesMapped,
|
|
1156
|
+
}, {
|
|
1157
|
+
signal: options?.signal,
|
|
1158
|
+
...options?.options,
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
else {
|
|
1162
|
+
data = await this.completionWithRetry({
|
|
1163
|
+
...params,
|
|
1164
|
+
stream: false,
|
|
1165
|
+
messages: messagesMapped,
|
|
1166
|
+
}, {
|
|
1167
|
+
signal: options?.signal,
|
|
1168
|
+
...options?.options,
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
709
1171
|
const { completion_tokens: completionTokens, prompt_tokens: promptTokens, total_tokens: totalTokens, } = data?.usage ?? {};
|
|
710
1172
|
if (completionTokens) {
|
|
711
1173
|
tokenUsage.completionTokens =
|
|
@@ -850,6 +1312,25 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
850
1312
|
}
|
|
851
1313
|
});
|
|
852
1314
|
}
|
|
1315
|
+
/**
|
|
1316
|
+
* Call the beta chat completions parse endpoint. This should only be called if
|
|
1317
|
+
* response_format is set to "json_object".
|
|
1318
|
+
* @param {OpenAIClient.Chat.ChatCompletionCreateParamsNonStreaming} request
|
|
1319
|
+
* @param {OpenAICoreRequestOptions | undefined} options
|
|
1320
|
+
*/
|
|
1321
|
+
async betaParsedCompletionWithRetry(request, options) {
|
|
1322
|
+
const requestOptions = this._getClientOptions(options);
|
|
1323
|
+
return this.caller.call(async () => {
|
|
1324
|
+
try {
|
|
1325
|
+
const res = await this.client.beta.chat.completions.parse(request, requestOptions);
|
|
1326
|
+
return res;
|
|
1327
|
+
}
|
|
1328
|
+
catch (e) {
|
|
1329
|
+
const error = (0, openai_js_1.wrapOpenAIClientError)(e);
|
|
1330
|
+
throw error;
|
|
1331
|
+
}
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
853
1334
|
_getClientOptions(options) {
|
|
854
1335
|
if (!this.client) {
|
|
855
1336
|
const openAIEndpointConfig = {
|
|
@@ -928,6 +1409,9 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
928
1409
|
}
|
|
929
1410
|
let llm;
|
|
930
1411
|
let outputParser;
|
|
1412
|
+
if (config?.strict !== undefined && method === "jsonMode") {
|
|
1413
|
+
throw new Error("Argument `strict` is only supported for `method` = 'function_calling'");
|
|
1414
|
+
}
|
|
931
1415
|
if (method === "jsonMode") {
|
|
932
1416
|
llm = this.bind({
|
|
933
1417
|
response_format: { type: "json_object" },
|
|
@@ -939,6 +1423,25 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
939
1423
|
outputParser = new output_parsers_1.JsonOutputParser();
|
|
940
1424
|
}
|
|
941
1425
|
}
|
|
1426
|
+
else if (method === "jsonSchema") {
|
|
1427
|
+
llm = this.bind({
|
|
1428
|
+
response_format: {
|
|
1429
|
+
type: "json_schema",
|
|
1430
|
+
json_schema: {
|
|
1431
|
+
name: name ?? "extract",
|
|
1432
|
+
description: schema.description,
|
|
1433
|
+
schema,
|
|
1434
|
+
strict: config?.strict,
|
|
1435
|
+
},
|
|
1436
|
+
},
|
|
1437
|
+
});
|
|
1438
|
+
if (isZodSchema(schema)) {
|
|
1439
|
+
outputParser = output_parsers_1.StructuredOutputParser.fromZodSchema(schema);
|
|
1440
|
+
}
|
|
1441
|
+
else {
|
|
1442
|
+
outputParser = new output_parsers_1.JsonOutputParser();
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
942
1445
|
else {
|
|
943
1446
|
let functionName = name ?? "extract";
|
|
944
1447
|
// Is function calling
|
|
@@ -961,6 +1464,8 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
961
1464
|
name: functionName,
|
|
962
1465
|
},
|
|
963
1466
|
},
|
|
1467
|
+
// Do not pass `strict` argument to OpenAI if `config.strict` is undefined
|
|
1468
|
+
...(config?.strict !== undefined ? { strict: config.strict } : {}),
|
|
964
1469
|
});
|
|
965
1470
|
outputParser = new openai_tools_1.JsonOutputKeyToolsParser({
|
|
966
1471
|
returnSingle: true,
|
|
@@ -997,6 +1502,8 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
997
1502
|
name: functionName,
|
|
998
1503
|
},
|
|
999
1504
|
},
|
|
1505
|
+
// Do not pass `strict` argument to OpenAI if `config.strict` is undefined
|
|
1506
|
+
...(config?.strict !== undefined ? { strict: config.strict } : {}),
|
|
1000
1507
|
});
|
|
1001
1508
|
outputParser = new openai_tools_1.JsonOutputKeyToolsParser({
|
|
1002
1509
|
returnSingle: true,
|