@langchain/openai 0.5.12 → 0.5.14
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 +5 -2
- package/dist/azure/chat_models.d.ts +4 -4
- package/dist/azure/chat_models.js +5 -2
- package/dist/azure/embeddings.cjs +5 -8
- package/dist/azure/embeddings.d.ts +1 -1
- package/dist/azure/embeddings.js +5 -8
- package/dist/azure/llms.cjs +4 -2
- package/dist/azure/llms.js +4 -2
- package/dist/chat_models.cjs +209 -101
- package/dist/chat_models.d.ts +5 -5
- package/dist/chat_models.js +173 -98
- package/dist/embeddings.d.ts +7 -3
- package/dist/tools/dalle.d.ts +7 -2
- package/dist/types.d.ts +8 -5
- package/dist/utils/azure.cjs +1 -2
- package/dist/utils/errors.cjs +1 -2
- package/dist/utils/headers.cjs +39 -0
- package/dist/utils/headers.d.ts +8 -0
- package/dist/utils/headers.js +35 -0
- package/dist/utils/openai-format-fndef.cjs +1 -2
- package/dist/utils/openai.cjs +7 -7
- package/dist/utils/openai.js +4 -4
- package/dist/utils/prompts.cjs +1 -2
- package/dist/utils/tools.cjs +18 -3
- package/dist/utils/tools.js +17 -1
- package/package.json +10 -11
package/dist/chat_models.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as z4 from "zod/v4/core";
|
|
1
2
|
import { OpenAI as OpenAIClient } from "openai";
|
|
2
3
|
import { AIMessage, AIMessageChunk, ChatMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, SystemMessageChunk, ToolMessageChunk, isAIMessage, parseBase64DataUrl, parseMimeType, convertToProviderContentBlock, isDataContentBlock, } from "@langchain/core/messages";
|
|
3
4
|
import { ChatGenerationChunk, } from "@langchain/core/outputs";
|
|
@@ -7,8 +8,9 @@ import { isOpenAITool, } from "@langchain/core/language_models/base";
|
|
|
7
8
|
import { RunnableLambda, RunnablePassthrough, RunnableSequence, } from "@langchain/core/runnables";
|
|
8
9
|
import { JsonOutputParser, StructuredOutputParser, } from "@langchain/core/output_parsers";
|
|
9
10
|
import { JsonOutputKeyToolsParser, convertLangChainToolCallToOpenAI, makeInvalidToolCall, parseToolCall, } from "@langchain/core/output_parsers/openai_tools";
|
|
10
|
-
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
11
11
|
import { zodResponseFormat } from "openai/helpers/zod";
|
|
12
|
+
import { getSchemaDescription, isInteropZodSchema, isZodSchemaV3, isZodSchemaV4, } from "@langchain/core/utils/types";
|
|
13
|
+
import { toJsonSchema, } from "@langchain/core/utils/json_schema";
|
|
12
14
|
import { getEndpoint } from "./utils/azure.js";
|
|
13
15
|
import { formatToOpenAIToolChoice, wrapOpenAIClientError, } from "./utils/openai.js";
|
|
14
16
|
import { formatFunctionDefinitions, } from "./utils/openai-format-fndef.js";
|
|
@@ -134,7 +136,7 @@ const completionsApiContentBlockConverter = {
|
|
|
134
136
|
return {
|
|
135
137
|
type: "file",
|
|
136
138
|
file: {
|
|
137
|
-
file_data: block.url,
|
|
139
|
+
file_data: block.url, // formatted as base64 data URL
|
|
138
140
|
...(block.metadata?.filename || block.metadata?.name
|
|
139
141
|
? {
|
|
140
142
|
filename: (block.metadata?.filename ||
|
|
@@ -247,12 +249,8 @@ function _convertReasoningSummaryToOpenAIResponsesParams(reasoning) {
|
|
|
247
249
|
};
|
|
248
250
|
}
|
|
249
251
|
function _convertMessagesToOpenAIResponsesParams(messages, model, zdrEnabled) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const newMessages = lastAIMessageId && lastAIMessageId.startsWith("resp_") && !zdrEnabled
|
|
253
|
-
? messages.slice(messages.indexOf(lastAIMessage) + 1)
|
|
254
|
-
: messages;
|
|
255
|
-
return newMessages.flatMap((lcMsg) => {
|
|
252
|
+
return messages.flatMap((lcMsg) => {
|
|
253
|
+
const additional_kwargs = lcMsg.additional_kwargs;
|
|
256
254
|
let role = messageToOpenAIRole(lcMsg);
|
|
257
255
|
if (role === "system" && isReasoningModel(model))
|
|
258
256
|
role = "developer";
|
|
@@ -262,7 +260,7 @@ function _convertMessagesToOpenAIResponsesParams(messages, model, zdrEnabled) {
|
|
|
262
260
|
if (role === "tool") {
|
|
263
261
|
const toolMessage = lcMsg;
|
|
264
262
|
// Handle computer call output
|
|
265
|
-
if (
|
|
263
|
+
if (additional_kwargs?.type === "computer_call_output") {
|
|
266
264
|
const output = (() => {
|
|
267
265
|
if (typeof toolMessage.content === "string") {
|
|
268
266
|
return {
|
|
@@ -313,25 +311,19 @@ function _convertMessagesToOpenAIResponsesParams(messages, model, zdrEnabled) {
|
|
|
313
311
|
// otherwise, try to reconstruct the response from what we have
|
|
314
312
|
const input = [];
|
|
315
313
|
// reasoning items
|
|
316
|
-
if (
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
"type" in item &&
|
|
320
|
-
item.type === "reasoning";
|
|
321
|
-
if (isReasoningItem(lcMsg.additional_kwargs.reasoning)) {
|
|
322
|
-
const reasoningItem = _convertReasoningSummaryToOpenAIResponsesParams(lcMsg.additional_kwargs.reasoning);
|
|
323
|
-
input.push(reasoningItem);
|
|
324
|
-
}
|
|
314
|
+
if (additional_kwargs?.reasoning && !zdrEnabled) {
|
|
315
|
+
const reasoningItem = _convertReasoningSummaryToOpenAIResponsesParams(additional_kwargs.reasoning);
|
|
316
|
+
input.push(reasoningItem);
|
|
325
317
|
}
|
|
326
318
|
// ai content
|
|
327
319
|
let { content } = lcMsg;
|
|
328
|
-
if (
|
|
320
|
+
if (additional_kwargs?.refusal) {
|
|
329
321
|
if (typeof content === "string") {
|
|
330
322
|
content = [{ type: "output_text", text: content, annotations: [] }];
|
|
331
323
|
}
|
|
332
324
|
content = [
|
|
333
325
|
...content,
|
|
334
|
-
{ type: "refusal", refusal:
|
|
326
|
+
{ type: "refusal", refusal: additional_kwargs.refusal },
|
|
335
327
|
];
|
|
336
328
|
}
|
|
337
329
|
input.push({
|
|
@@ -355,10 +347,7 @@ function _convertMessagesToOpenAIResponsesParams(messages, model, zdrEnabled) {
|
|
|
355
347
|
return [];
|
|
356
348
|
}),
|
|
357
349
|
});
|
|
358
|
-
|
|
359
|
-
const functionCallIds =
|
|
360
|
-
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
361
|
-
lcMsg.additional_kwargs[_FUNCTION_CALL_IDS_MAP_KEY];
|
|
350
|
+
const functionCallIds = additional_kwargs?.[_FUNCTION_CALL_IDS_MAP_KEY];
|
|
362
351
|
if (isAIMessage(lcMsg) && !!lcMsg.tool_calls?.length) {
|
|
363
352
|
input.push(...lcMsg.tool_calls.map((toolCall) => ({
|
|
364
353
|
type: "function_call",
|
|
@@ -368,44 +357,64 @@ function _convertMessagesToOpenAIResponsesParams(messages, model, zdrEnabled) {
|
|
|
368
357
|
...(zdrEnabled ? { id: functionCallIds?.[toolCall.id] } : {}),
|
|
369
358
|
})));
|
|
370
359
|
}
|
|
371
|
-
else if (
|
|
372
|
-
input.push(...
|
|
360
|
+
else if (additional_kwargs?.tool_calls) {
|
|
361
|
+
input.push(...additional_kwargs.tool_calls.map((toolCall) => ({
|
|
373
362
|
type: "function_call",
|
|
374
363
|
name: toolCall.function.name,
|
|
375
364
|
call_id: toolCall.id,
|
|
376
|
-
...(zdrEnabled ? { id: functionCallIds?.[toolCall.id] } : {}),
|
|
377
365
|
arguments: toolCall.function.arguments,
|
|
366
|
+
...(zdrEnabled ? { id: functionCallIds?.[toolCall.id] } : {}),
|
|
378
367
|
})));
|
|
379
368
|
}
|
|
380
369
|
const toolOutputs = lcMsg.response_metadata.output?.length
|
|
381
370
|
? lcMsg.response_metadata.output
|
|
382
|
-
:
|
|
383
|
-
|
|
371
|
+
: additional_kwargs.tool_outputs;
|
|
372
|
+
const fallthroughCallTypes = [
|
|
373
|
+
"computer_call",
|
|
374
|
+
"mcp_call",
|
|
375
|
+
"code_interpreter_call",
|
|
376
|
+
"image_generation_call",
|
|
377
|
+
];
|
|
384
378
|
if (toolOutputs != null) {
|
|
385
379
|
const castToolOutputs = toolOutputs;
|
|
386
|
-
|
|
387
|
-
if (
|
|
388
|
-
input.push(...
|
|
380
|
+
const fallthroughCalls = castToolOutputs?.filter((item) => fallthroughCallTypes.includes(item.type));
|
|
381
|
+
if (fallthroughCalls.length > 0)
|
|
382
|
+
input.push(...fallthroughCalls);
|
|
389
383
|
}
|
|
390
384
|
return input;
|
|
391
385
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
386
|
+
if (role === "user" || role === "system" || role === "developer") {
|
|
387
|
+
if (typeof lcMsg.content === "string") {
|
|
388
|
+
return { type: "message", role, content: lcMsg.content };
|
|
389
|
+
}
|
|
390
|
+
const messages = [];
|
|
391
|
+
const content = lcMsg.content.flatMap((item) => {
|
|
392
|
+
if (item.type === "mcp_approval_response") {
|
|
393
|
+
messages.push({
|
|
394
|
+
type: "mcp_approval_response",
|
|
395
|
+
approval_request_id: item.approval_request_id,
|
|
396
|
+
approve: item.approve,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
395
399
|
if (isDataContentBlock(item)) {
|
|
396
400
|
return convertToProviderContentBlock(item, completionsApiContentBlockConverter);
|
|
397
401
|
}
|
|
398
402
|
if (item.type === "text") {
|
|
399
|
-
return {
|
|
403
|
+
return {
|
|
404
|
+
type: "input_text",
|
|
405
|
+
text: item.text,
|
|
406
|
+
};
|
|
400
407
|
}
|
|
401
408
|
if (item.type === "image_url") {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
: item.image_url
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
: item.image_url
|
|
408
|
-
|
|
409
|
+
return {
|
|
410
|
+
type: "input_image",
|
|
411
|
+
image_url: typeof item.image_url === "string"
|
|
412
|
+
? item.image_url
|
|
413
|
+
: item.image_url.url,
|
|
414
|
+
detail: typeof item.image_url === "string"
|
|
415
|
+
? "auto"
|
|
416
|
+
: item.image_url.detail,
|
|
417
|
+
};
|
|
409
418
|
}
|
|
410
419
|
if (item.type === "input_text" ||
|
|
411
420
|
item.type === "input_image" ||
|
|
@@ -414,8 +423,10 @@ function _convertMessagesToOpenAIResponsesParams(messages, model, zdrEnabled) {
|
|
|
414
423
|
}
|
|
415
424
|
return [];
|
|
416
425
|
});
|
|
417
|
-
|
|
418
|
-
|
|
426
|
+
if (content.length > 0) {
|
|
427
|
+
messages.push({ type: "message", role, content });
|
|
428
|
+
}
|
|
429
|
+
return messages;
|
|
419
430
|
}
|
|
420
431
|
console.warn(`Unsupported role found when converting to OpenAI Responses API: ${role}`);
|
|
421
432
|
return [];
|
|
@@ -522,7 +533,7 @@ function _convertOpenAIResponsesDeltaToBaseMessageChunk(chunk) {
|
|
|
522
533
|
index: chunk.content_index,
|
|
523
534
|
});
|
|
524
535
|
}
|
|
525
|
-
else if (chunk.type === "response.
|
|
536
|
+
else if (chunk.type === "response.output_text_annotation.added") {
|
|
526
537
|
content.push({
|
|
527
538
|
type: "text",
|
|
528
539
|
text: "",
|
|
@@ -548,9 +559,16 @@ function _convertOpenAIResponsesDeltaToBaseMessageChunk(chunk) {
|
|
|
548
559
|
};
|
|
549
560
|
}
|
|
550
561
|
else if (chunk.type === "response.output_item.done" &&
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
562
|
+
[
|
|
563
|
+
"web_search_call",
|
|
564
|
+
"file_search_call",
|
|
565
|
+
"computer_call",
|
|
566
|
+
"code_interpreter_call",
|
|
567
|
+
"mcp_call",
|
|
568
|
+
"mcp_list_tools",
|
|
569
|
+
"mcp_approval_request",
|
|
570
|
+
"image_generation_call",
|
|
571
|
+
].includes(chunk.item.type)) {
|
|
554
572
|
additional_kwargs.tool_outputs = [chunk.item];
|
|
555
573
|
}
|
|
556
574
|
else if (chunk.type === "response.created") {
|
|
@@ -622,6 +640,11 @@ function _convertOpenAIResponsesDeltaToBaseMessageChunk(chunk) {
|
|
|
622
640
|
],
|
|
623
641
|
};
|
|
624
642
|
}
|
|
643
|
+
else if (chunk.type === "response.image_generation_call.partial_image") {
|
|
644
|
+
// noop/fixme: retaining partial images in a message chunk means that _all_
|
|
645
|
+
// partial images get kept in history, so we don't do anything here.
|
|
646
|
+
return null;
|
|
647
|
+
}
|
|
625
648
|
else {
|
|
626
649
|
return null;
|
|
627
650
|
}
|
|
@@ -648,6 +671,29 @@ function isBuiltInToolChoice(tool_choice) {
|
|
|
648
671
|
"type" in tool_choice &&
|
|
649
672
|
tool_choice.type !== "function");
|
|
650
673
|
}
|
|
674
|
+
function _reduceChatOpenAIToolsForResponses(tools, fields) {
|
|
675
|
+
const reducedTools = [];
|
|
676
|
+
for (const tool of tools) {
|
|
677
|
+
if (isBuiltInTool(tool)) {
|
|
678
|
+
if (tool.type === "image_generation" && fields?.stream) {
|
|
679
|
+
// OpenAI sends a 400 error if partial_images is not set and we want to stream.
|
|
680
|
+
// We also set it to 1 since we don't support partial images yet.
|
|
681
|
+
tool.partial_images = 1;
|
|
682
|
+
}
|
|
683
|
+
reducedTools.push(tool);
|
|
684
|
+
}
|
|
685
|
+
else if (isOpenAITool(tool)) {
|
|
686
|
+
reducedTools.push({
|
|
687
|
+
type: "function",
|
|
688
|
+
name: tool.function.name,
|
|
689
|
+
parameters: tool.function.parameters,
|
|
690
|
+
description: tool.function.description,
|
|
691
|
+
strict: fields?.strict ?? null,
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return reducedTools;
|
|
696
|
+
}
|
|
651
697
|
function _convertChatOpenAIToolTypeToOpenAITool(tool, fields) {
|
|
652
698
|
if (isOpenAITool(tool)) {
|
|
653
699
|
if (fields?.strict !== undefined) {
|
|
@@ -1582,8 +1628,8 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
1582
1628
|
if (resFormat &&
|
|
1583
1629
|
resFormat.type === "json_schema" &&
|
|
1584
1630
|
resFormat.json_schema.schema &&
|
|
1585
|
-
|
|
1586
|
-
return
|
|
1631
|
+
isInteropZodSchema(resFormat.json_schema.schema)) {
|
|
1632
|
+
return interopZodResponseFormat(resFormat.json_schema.schema, resFormat.json_schema.name, {
|
|
1587
1633
|
description: resFormat.json_schema.description,
|
|
1588
1634
|
});
|
|
1589
1635
|
}
|
|
@@ -1641,25 +1687,10 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
1641
1687
|
truncation: options?.truncation,
|
|
1642
1688
|
include: options?.include,
|
|
1643
1689
|
tools: options?.tools?.length
|
|
1644
|
-
? options.tools
|
|
1645
|
-
.
|
|
1646
|
-
|
|
1647
|
-
return tool;
|
|
1648
|
-
}
|
|
1649
|
-
else if (isOpenAITool(tool)) {
|
|
1650
|
-
return {
|
|
1651
|
-
type: "function",
|
|
1652
|
-
name: tool.function.name,
|
|
1653
|
-
parameters: tool.function.parameters,
|
|
1654
|
-
description: tool.function.description,
|
|
1655
|
-
strict,
|
|
1656
|
-
};
|
|
1657
|
-
}
|
|
1658
|
-
else {
|
|
1659
|
-
return null;
|
|
1660
|
-
}
|
|
1690
|
+
? _reduceChatOpenAIToolsForResponses(options.tools, {
|
|
1691
|
+
stream: this.streaming,
|
|
1692
|
+
strict,
|
|
1661
1693
|
})
|
|
1662
|
-
.filter((tool) => tool !== null)
|
|
1663
1694
|
: undefined,
|
|
1664
1695
|
tool_choice: isBuiltInToolChoice(options?.tool_choice)
|
|
1665
1696
|
? options?.tool_choice
|
|
@@ -1902,17 +1933,10 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
1902
1933
|
}
|
|
1903
1934
|
async *_streamResponseChunks(messages, options, runManager) {
|
|
1904
1935
|
if (this._useResponseApi(options)) {
|
|
1905
|
-
const lastAIMessage = messages.filter((m) => isAIMessage(m)).pop();
|
|
1906
|
-
const lastAIMessageId = lastAIMessage?.response_metadata?.id;
|
|
1907
1936
|
const streamIterable = await this.responseApiWithRetry({
|
|
1908
1937
|
...this.invocationParams(options, { streaming: true }),
|
|
1909
1938
|
input: _convertMessagesToOpenAIResponsesParams(messages, this.model, this.zdrEnabled),
|
|
1910
1939
|
stream: true,
|
|
1911
|
-
...(lastAIMessageId &&
|
|
1912
|
-
lastAIMessageId.startsWith("resp_") &&
|
|
1913
|
-
!this.zdrEnabled
|
|
1914
|
-
? { previous_response_id: lastAIMessageId }
|
|
1915
|
-
: {}),
|
|
1916
1940
|
}, options);
|
|
1917
1941
|
for await (const data of streamIterable) {
|
|
1918
1942
|
const chunk = _convertOpenAIResponsesDeltaToBaseMessageChunk(data);
|
|
@@ -2046,17 +2070,10 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
2046
2070
|
},
|
|
2047
2071
|
};
|
|
2048
2072
|
}
|
|
2049
|
-
const lastAIMessage = messages.filter((m) => isAIMessage(m)).pop();
|
|
2050
|
-
const lastAIMessageId = lastAIMessage?.response_metadata?.id;
|
|
2051
2073
|
const input = _convertMessagesToOpenAIResponsesParams(messages, this.model, this.zdrEnabled);
|
|
2052
2074
|
const data = await this.responseApiWithRetry({
|
|
2053
2075
|
input,
|
|
2054
2076
|
...invocationParams,
|
|
2055
|
-
...(lastAIMessageId &&
|
|
2056
|
-
lastAIMessageId.startsWith("resp_") &&
|
|
2057
|
-
!this.zdrEnabled
|
|
2058
|
-
? { previous_response_id: lastAIMessageId }
|
|
2059
|
-
: {}),
|
|
2060
2077
|
}, { signal: options?.signal, ...options?.options });
|
|
2061
2078
|
return {
|
|
2062
2079
|
generations: [
|
|
@@ -2366,7 +2383,7 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
2366
2383
|
const requestOptions = this._getClientOptions(options);
|
|
2367
2384
|
return this.caller.call(async () => {
|
|
2368
2385
|
try {
|
|
2369
|
-
const res = await this.client.
|
|
2386
|
+
const res = await this.client.chat.completions.parse(request, requestOptions);
|
|
2370
2387
|
return res;
|
|
2371
2388
|
}
|
|
2372
2389
|
catch (e) {
|
|
@@ -2453,15 +2470,21 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
2453
2470
|
console.warn(`[WARNING]: JSON Schema is not supported for model "${this.model}". Falling back to tool calling.`);
|
|
2454
2471
|
}
|
|
2455
2472
|
if (method === "jsonMode") {
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
});
|
|
2459
|
-
if (isZodSchema(schema)) {
|
|
2473
|
+
let outputFormatSchema;
|
|
2474
|
+
if (isInteropZodSchema(schema)) {
|
|
2460
2475
|
outputParser = StructuredOutputParser.fromZodSchema(schema);
|
|
2476
|
+
outputFormatSchema = toJsonSchema(schema);
|
|
2461
2477
|
}
|
|
2462
2478
|
else {
|
|
2463
2479
|
outputParser = new JsonOutputParser();
|
|
2464
2480
|
}
|
|
2481
|
+
llm = this.withConfig({
|
|
2482
|
+
response_format: { type: "json_object" },
|
|
2483
|
+
ls_structured_output_format: {
|
|
2484
|
+
kwargs: { method: "jsonMode" },
|
|
2485
|
+
schema: outputFormatSchema,
|
|
2486
|
+
},
|
|
2487
|
+
});
|
|
2465
2488
|
}
|
|
2466
2489
|
else if (method === "jsonSchema") {
|
|
2467
2490
|
llm = this.withConfig({
|
|
@@ -2469,13 +2492,17 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
2469
2492
|
type: "json_schema",
|
|
2470
2493
|
json_schema: {
|
|
2471
2494
|
name: name ?? "extract",
|
|
2472
|
-
description: schema
|
|
2495
|
+
description: getSchemaDescription(schema),
|
|
2473
2496
|
schema,
|
|
2474
2497
|
strict: config?.strict,
|
|
2475
2498
|
},
|
|
2476
2499
|
},
|
|
2500
|
+
ls_structured_output_format: {
|
|
2501
|
+
kwargs: { method: "jsonSchema" },
|
|
2502
|
+
schema: toJsonSchema(schema),
|
|
2503
|
+
},
|
|
2477
2504
|
});
|
|
2478
|
-
if (
|
|
2505
|
+
if (isInteropZodSchema(schema)) {
|
|
2479
2506
|
const altParser = StructuredOutputParser.fromZodSchema(schema);
|
|
2480
2507
|
outputParser = RunnableLambda.from((aiMessage) => {
|
|
2481
2508
|
if ("parsed" in aiMessage.additional_kwargs) {
|
|
@@ -2491,8 +2518,8 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
2491
2518
|
else {
|
|
2492
2519
|
let functionName = name ?? "extract";
|
|
2493
2520
|
// Is function calling
|
|
2494
|
-
if (
|
|
2495
|
-
const asJsonSchema =
|
|
2521
|
+
if (isInteropZodSchema(schema)) {
|
|
2522
|
+
const asJsonSchema = toJsonSchema(schema);
|
|
2496
2523
|
llm = this.withConfig({
|
|
2497
2524
|
tools: [
|
|
2498
2525
|
{
|
|
@@ -2510,6 +2537,10 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
2510
2537
|
name: functionName,
|
|
2511
2538
|
},
|
|
2512
2539
|
},
|
|
2540
|
+
ls_structured_output_format: {
|
|
2541
|
+
kwargs: { method: "functionCalling" },
|
|
2542
|
+
schema: asJsonSchema,
|
|
2543
|
+
},
|
|
2513
2544
|
// Do not pass `strict` argument to OpenAI if `config.strict` is undefined
|
|
2514
2545
|
...(config?.strict !== undefined ? { strict: config.strict } : {}),
|
|
2515
2546
|
});
|
|
@@ -2548,6 +2579,10 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
2548
2579
|
name: functionName,
|
|
2549
2580
|
},
|
|
2550
2581
|
},
|
|
2582
|
+
ls_structured_output_format: {
|
|
2583
|
+
kwargs: { method: "functionCalling" },
|
|
2584
|
+
schema: toJsonSchema(schema),
|
|
2585
|
+
},
|
|
2551
2586
|
// Do not pass `strict` argument to OpenAI if `config.strict` is undefined
|
|
2552
2587
|
...(config?.strict !== undefined ? { strict: config.strict } : {}),
|
|
2553
2588
|
});
|
|
@@ -2573,12 +2608,6 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
2573
2608
|
return RunnableSequence.from([{ raw: llm }, parsedWithFallback]);
|
|
2574
2609
|
}
|
|
2575
2610
|
}
|
|
2576
|
-
function isZodSchema(
|
|
2577
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2578
|
-
input) {
|
|
2579
|
-
// Check for a characteristic method of Zod schemas
|
|
2580
|
-
return typeof input?.parse === "function";
|
|
2581
|
-
}
|
|
2582
2611
|
function isStructuredOutputMethodParams(x
|
|
2583
2612
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2584
2613
|
) {
|
|
@@ -2587,3 +2616,49 @@ function isStructuredOutputMethodParams(x
|
|
|
2587
2616
|
typeof x.schema ===
|
|
2588
2617
|
"object");
|
|
2589
2618
|
}
|
|
2619
|
+
// inlined from openai/lib/parser.ts
|
|
2620
|
+
function makeParseableResponseFormat(response_format, parser) {
|
|
2621
|
+
const obj = { ...response_format };
|
|
2622
|
+
Object.defineProperties(obj, {
|
|
2623
|
+
$brand: {
|
|
2624
|
+
value: "auto-parseable-response-format",
|
|
2625
|
+
enumerable: false,
|
|
2626
|
+
},
|
|
2627
|
+
$parseRaw: {
|
|
2628
|
+
value: parser,
|
|
2629
|
+
enumerable: false,
|
|
2630
|
+
},
|
|
2631
|
+
});
|
|
2632
|
+
return obj;
|
|
2633
|
+
}
|
|
2634
|
+
function interopZodResponseFormat(zodSchema, name, props) {
|
|
2635
|
+
if (isZodSchemaV3(zodSchema)) {
|
|
2636
|
+
return zodResponseFormat(zodSchema, name, props);
|
|
2637
|
+
}
|
|
2638
|
+
if (isZodSchemaV4(zodSchema)) {
|
|
2639
|
+
return makeParseableResponseFormat({
|
|
2640
|
+
type: "json_schema",
|
|
2641
|
+
json_schema: {
|
|
2642
|
+
...props,
|
|
2643
|
+
name,
|
|
2644
|
+
strict: true,
|
|
2645
|
+
schema: z4.toJSONSchema(zodSchema, {
|
|
2646
|
+
cycles: "ref", // equivalent to nameStrategy: 'duplicate-ref'
|
|
2647
|
+
reused: "ref", // equivalent to $refStrategy: 'extract-to-root'
|
|
2648
|
+
override(ctx) {
|
|
2649
|
+
ctx.jsonSchema.title = name; // equivalent to `name` property
|
|
2650
|
+
// TODO: implement `nullableStrategy` patch-fix (zod doesn't support openApi3 json schema target)
|
|
2651
|
+
// TODO: implement `openaiStrictMode` patch-fix (where optional properties without `nullable` are not supported)
|
|
2652
|
+
},
|
|
2653
|
+
/// property equivalents from native `zodResponseFormat` fn
|
|
2654
|
+
// openaiStrictMode: true,
|
|
2655
|
+
// name,
|
|
2656
|
+
// nameStrategy: 'duplicate-ref',
|
|
2657
|
+
// $refStrategy: 'extract-to-root',
|
|
2658
|
+
// nullableStrategy: 'property',
|
|
2659
|
+
}),
|
|
2660
|
+
},
|
|
2661
|
+
}, (content) => z4.parse(zodSchema, JSON.parse(content)));
|
|
2662
|
+
}
|
|
2663
|
+
throw new Error("Unsupported schema response format");
|
|
2664
|
+
}
|
package/dist/embeddings.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { type ClientOptions, OpenAI as OpenAIClient } from "openai";
|
|
2
2
|
import { Embeddings, type EmbeddingsParams } from "@langchain/core/embeddings";
|
|
3
|
+
/**
|
|
4
|
+
* @see https://platform.openai.com/docs/guides/embeddings#embedding-models
|
|
5
|
+
*/
|
|
6
|
+
export type OpenAIEmbeddingModelId = OpenAIClient.EmbeddingModel | (string & NonNullable<unknown>);
|
|
3
7
|
/**
|
|
4
8
|
* Interface for OpenAIEmbeddings parameters. Extends EmbeddingsParams and
|
|
5
9
|
* defines additional parameters specific to the OpenAIEmbeddings class.
|
|
@@ -10,9 +14,9 @@ export interface OpenAIEmbeddingsParams extends EmbeddingsParams {
|
|
|
10
14
|
* Alias for `model`
|
|
11
15
|
* @deprecated Use "model" instead.
|
|
12
16
|
*/
|
|
13
|
-
modelName:
|
|
17
|
+
modelName: OpenAIEmbeddingModelId;
|
|
14
18
|
/** Model name to use */
|
|
15
|
-
model:
|
|
19
|
+
model: OpenAIEmbeddingModelId;
|
|
16
20
|
/**
|
|
17
21
|
* The number of dimensions the resulting output embeddings should have.
|
|
18
22
|
* Only supported in `text-embedding-3` and later models.
|
|
@@ -99,6 +103,6 @@ export declare class OpenAIEmbeddings extends Embeddings implements Partial<Open
|
|
|
99
103
|
* @returns Promise that resolves to the response from the API.
|
|
100
104
|
*/
|
|
101
105
|
protected embeddingWithRetry(request: OpenAIClient.EmbeddingCreateParams): Promise<OpenAIClient.Embeddings.CreateEmbeddingResponse & {
|
|
102
|
-
_request_id?: string | null
|
|
106
|
+
_request_id?: string | null;
|
|
103
107
|
}>;
|
|
104
108
|
}
|
package/dist/tools/dalle.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { OpenAI as OpenAIClient } from "openai";
|
|
2
2
|
import { Tool, ToolParams } from "@langchain/core/tools";
|
|
3
3
|
import { MessageContentComplex } from "@langchain/core/messages";
|
|
4
|
+
/**
|
|
5
|
+
* @see https://platform.openai.com/docs/api-reference/images/create
|
|
6
|
+
*/
|
|
7
|
+
export type OpenAIImageModelId = OpenAIClient.ImageModel | (string & NonNullable<unknown>);
|
|
4
8
|
/**
|
|
5
9
|
* An interface for the Dall-E API Wrapper.
|
|
6
10
|
*/
|
|
@@ -19,14 +23,15 @@ export interface DallEAPIWrapperParams extends ToolParams {
|
|
|
19
23
|
* Alias for `model`
|
|
20
24
|
* @params "dall-e-2" | "dall-e-3"
|
|
21
25
|
* @default "dall-e-3"
|
|
26
|
+
* @deprecated Use `model` instead.
|
|
22
27
|
*/
|
|
23
|
-
modelName?:
|
|
28
|
+
modelName?: OpenAIImageModelId;
|
|
24
29
|
/**
|
|
25
30
|
* The model to use.
|
|
26
31
|
* @params "dall-e-2" | "dall-e-3"
|
|
27
32
|
* @default "dall-e-3"
|
|
28
33
|
*/
|
|
29
|
-
model?:
|
|
34
|
+
model?: OpenAIImageModelId;
|
|
30
35
|
/**
|
|
31
36
|
* The style of the generated images. Must be one of vivid or natural.
|
|
32
37
|
* Vivid causes the model to lean towards generating hyper-real and dramatic images.
|
package/dist/types.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { OpenAI as OpenAIClient } from "openai";
|
|
2
|
-
import type { RequestOptions as _OpenAICoreRequestOptions } from "openai/core";
|
|
3
2
|
import type { ResponseFormatText, ResponseFormatJSONObject, ResponseFormatJSONSchema } from "openai/resources/shared";
|
|
4
3
|
import { TiktokenModel } from "js-tiktoken/lite";
|
|
5
4
|
import type { BaseLanguageModelCallOptions } from "@langchain/core/language_models/base";
|
|
6
|
-
import
|
|
5
|
+
import { InteropZodObject } from "@langchain/core/utils/types";
|
|
7
6
|
export type { TiktokenModel };
|
|
7
|
+
/**
|
|
8
|
+
* @see https://platform.openai.com/docs/models
|
|
9
|
+
*/
|
|
10
|
+
export type OpenAIChatModelId = OpenAIClient.ChatModel | (string & NonNullable<unknown>);
|
|
8
11
|
export declare interface OpenAIBaseInput {
|
|
9
12
|
/** Sampling temperature to use */
|
|
10
13
|
temperature: number;
|
|
@@ -45,7 +48,7 @@ export declare interface OpenAIBaseInput {
|
|
|
45
48
|
*/
|
|
46
49
|
modelName: string;
|
|
47
50
|
/** Model name to use */
|
|
48
|
-
model:
|
|
51
|
+
model: OpenAIChatModelId;
|
|
49
52
|
/** Holds any additional parameters that are valid to pass to {@link
|
|
50
53
|
* https://platform.openai.com/docs/api-reference/completions/create |
|
|
51
54
|
* `openai.createCompletion`} that are not explicitly specified on this class.
|
|
@@ -74,7 +77,7 @@ export declare interface OpenAIBaseInput {
|
|
|
74
77
|
*/
|
|
75
78
|
apiKey?: string;
|
|
76
79
|
}
|
|
77
|
-
export type OpenAICoreRequestOptions
|
|
80
|
+
export type OpenAICoreRequestOptions = OpenAIClient.RequestOptions;
|
|
78
81
|
export interface OpenAICallOptions extends BaseLanguageModelCallOptions {
|
|
79
82
|
/**
|
|
80
83
|
* Additional options to pass to the underlying axios request.
|
|
@@ -218,7 +221,7 @@ type ChatOpenAIResponseFormatJSONSchema = Omit<ResponseFormatJSONSchema, "json_s
|
|
|
218
221
|
* The schema for the response format, described as a JSON Schema object
|
|
219
222
|
* or a Zod object.
|
|
220
223
|
*/
|
|
221
|
-
schema: Record<string, any> |
|
|
224
|
+
schema: Record<string, any> | InteropZodObject;
|
|
222
225
|
};
|
|
223
226
|
};
|
|
224
227
|
/**
|
package/dist/utils/azure.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getEndpoint =
|
|
3
|
+
exports.getEndpoint = getEndpoint;
|
|
4
4
|
/**
|
|
5
5
|
* This function generates an endpoint URL for (Azure) OpenAI
|
|
6
6
|
* based on the configuration parameters provided.
|
|
@@ -48,4 +48,3 @@ function getEndpoint(config) {
|
|
|
48
48
|
}
|
|
49
49
|
return baseURL;
|
|
50
50
|
}
|
|
51
|
-
exports.getEndpoint = getEndpoint;
|
package/dist/utils/errors.cjs
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
3
|
/* eslint-disable no-param-reassign */
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.addLangChainErrorFields =
|
|
5
|
+
exports.addLangChainErrorFields = addLangChainErrorFields;
|
|
6
6
|
function addLangChainErrorFields(error, lc_error_code) {
|
|
7
7
|
error.lc_error_code = lc_error_code;
|
|
8
8
|
error.message = `${error.message}\n\nTroubleshooting URL: https://js.langchain.com/docs/troubleshooting/errors/${lc_error_code}/\n`;
|
|
9
9
|
return error;
|
|
10
10
|
}
|
|
11
|
-
exports.addLangChainErrorFields = addLangChainErrorFields;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isHeaders = isHeaders;
|
|
4
|
+
exports.normalizeHeaders = normalizeHeaders;
|
|
5
|
+
const iife = (fn) => fn();
|
|
6
|
+
function isHeaders(headers) {
|
|
7
|
+
return (typeof Headers !== "undefined" &&
|
|
8
|
+
headers !== null &&
|
|
9
|
+
typeof headers === "object" &&
|
|
10
|
+
Object.prototype.toString.call(headers) === "[object Headers]");
|
|
11
|
+
}
|
|
12
|
+
function normalizeHeaders(headers) {
|
|
13
|
+
const output = iife(() => {
|
|
14
|
+
// If headers is a Headers instance
|
|
15
|
+
if (isHeaders(headers)) {
|
|
16
|
+
return headers;
|
|
17
|
+
}
|
|
18
|
+
// If headers is an array of [key, value] pairs
|
|
19
|
+
else if (Array.isArray(headers)) {
|
|
20
|
+
return new Headers(headers);
|
|
21
|
+
}
|
|
22
|
+
// If headers is a NullableHeaders-like object (has 'values' property that is a Headers)
|
|
23
|
+
else if (typeof headers === "object" &&
|
|
24
|
+
headers !== null &&
|
|
25
|
+
"values" in headers &&
|
|
26
|
+
isHeaders(headers.values)) {
|
|
27
|
+
return headers.values;
|
|
28
|
+
}
|
|
29
|
+
// If headers is a plain object
|
|
30
|
+
else if (typeof headers === "object" && headers !== null) {
|
|
31
|
+
const entries = Object.entries(headers)
|
|
32
|
+
.filter(([, v]) => typeof v === "string")
|
|
33
|
+
.map(([k, v]) => [k, v]);
|
|
34
|
+
return new Headers(entries);
|
|
35
|
+
}
|
|
36
|
+
return new Headers();
|
|
37
|
+
});
|
|
38
|
+
return Object.fromEntries(output.entries());
|
|
39
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type HeaderValue = string | undefined | null;
|
|
2
|
+
export type HeadersLike = Headers | readonly HeaderValue[][] | Record<string, HeaderValue | readonly HeaderValue[]> | undefined | null | {
|
|
3
|
+
values: Headers;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
};
|
|
6
|
+
export declare function isHeaders(headers: unknown): headers is Headers;
|
|
7
|
+
export declare function normalizeHeaders(headers: HeadersLike): Record<string, HeaderValue | readonly HeaderValue[]>;
|
|
8
|
+
export {};
|