@langchain/openai 0.6.4 → 0.6.6
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 +115 -53
- package/dist/chat_models.d.ts +18 -9
- package/dist/chat_models.js +115 -53
- package/dist/index.cjs +3 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/tools/custom.cjs +28 -0
- package/dist/tools/custom.d.ts +5 -0
- package/dist/tools/custom.js +25 -0
- package/dist/types.d.ts +11 -2
- package/dist/utils/tools.cjs +114 -1
- package/dist/utils/tools.d.ts +24 -0
- package/dist/utils/tools.js +106 -1
- package/package.json +3 -3
package/dist/chat_models.cjs
CHANGED
|
@@ -19,17 +19,8 @@ const openai_js_1 = require("./utils/openai.cjs");
|
|
|
19
19
|
const openai_format_fndef_js_1 = require("./utils/openai-format-fndef.cjs");
|
|
20
20
|
const tools_js_1 = require("./utils/tools.cjs");
|
|
21
21
|
const _FUNCTION_CALL_IDS_MAP_KEY = "__openai_function_call_ids__";
|
|
22
|
-
function isBuiltInTool(tool) {
|
|
23
|
-
return "type" in tool && tool.type !== "function";
|
|
24
|
-
}
|
|
25
|
-
function isBuiltInToolChoice(tool_choice) {
|
|
26
|
-
return (tool_choice != null &&
|
|
27
|
-
typeof tool_choice === "object" &&
|
|
28
|
-
"type" in tool_choice &&
|
|
29
|
-
tool_choice.type !== "function");
|
|
30
|
-
}
|
|
31
22
|
function isReasoningModel(model) {
|
|
32
|
-
return model && /^o\d/.test(model);
|
|
23
|
+
return model && (/^o\d/.test(model) || model.startsWith("gpt-5"));
|
|
33
24
|
}
|
|
34
25
|
function isStructuredOutputMethodParams(x
|
|
35
26
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -327,6 +318,8 @@ class BaseChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
327
318
|
"disableStreaming",
|
|
328
319
|
"zdrEnabled",
|
|
329
320
|
"reasoning",
|
|
321
|
+
"verbosity",
|
|
322
|
+
"promptCacheKey",
|
|
330
323
|
];
|
|
331
324
|
}
|
|
332
325
|
getLsParams(options) {
|
|
@@ -545,6 +538,17 @@ class BaseChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
545
538
|
writable: true,
|
|
546
539
|
value: void 0
|
|
547
540
|
});
|
|
541
|
+
/**
|
|
542
|
+
* Used by OpenAI to cache responses for similar requests to optimize your cache
|
|
543
|
+
* hit rates.
|
|
544
|
+
* [Learn more](https://platform.openai.com/docs/guides/prompt-caching).
|
|
545
|
+
*/
|
|
546
|
+
Object.defineProperty(this, "promptCacheKey", {
|
|
547
|
+
enumerable: true,
|
|
548
|
+
configurable: true,
|
|
549
|
+
writable: true,
|
|
550
|
+
value: void 0
|
|
551
|
+
});
|
|
548
552
|
Object.defineProperty(this, "defaultOptions", {
|
|
549
553
|
enumerable: true,
|
|
550
554
|
configurable: true,
|
|
@@ -584,6 +588,7 @@ class BaseChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
584
588
|
this.reasoning = fields?.reasoning;
|
|
585
589
|
this.maxTokens = fields?.maxCompletionTokens ?? fields?.maxTokens;
|
|
586
590
|
this.disableStreaming = fields?.disableStreaming ?? this.disableStreaming;
|
|
591
|
+
this.promptCacheKey = fields?.promptCacheKey ?? this.promptCacheKey;
|
|
587
592
|
this.streaming = fields?.streaming ?? false;
|
|
588
593
|
if (this.disableStreaming)
|
|
589
594
|
this.streaming = false;
|
|
@@ -677,6 +682,9 @@ class BaseChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
677
682
|
}
|
|
678
683
|
// TODO: move to completions class
|
|
679
684
|
_convertChatOpenAIToolToCompletionsTool(tool, fields) {
|
|
685
|
+
if ((0, tools_js_1.isCustomTool)(tool)) {
|
|
686
|
+
return (0, tools_js_1.convertResponsesCustomTool)(tool.metadata.customTool);
|
|
687
|
+
}
|
|
680
688
|
if ((0, base_1.isOpenAITool)(tool)) {
|
|
681
689
|
if (fields?.strict !== undefined) {
|
|
682
690
|
return {
|
|
@@ -700,7 +708,7 @@ class BaseChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
700
708
|
strict = this.supportsStrictToolCalling;
|
|
701
709
|
}
|
|
702
710
|
return this.withConfig({
|
|
703
|
-
tools: tools.map((tool) => isBuiltInTool(tool)
|
|
711
|
+
tools: tools.map((tool) => (0, tools_js_1.isBuiltInTool)(tool)
|
|
704
712
|
? tool
|
|
705
713
|
: this._convertChatOpenAIToolToCompletionsTool(tool, { strict })),
|
|
706
714
|
...kwargs,
|
|
@@ -1036,16 +1044,29 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1036
1044
|
strict,
|
|
1037
1045
|
})
|
|
1038
1046
|
: undefined,
|
|
1039
|
-
tool_choice: isBuiltInToolChoice(options?.tool_choice)
|
|
1047
|
+
tool_choice: (0, tools_js_1.isBuiltInToolChoice)(options?.tool_choice)
|
|
1040
1048
|
? options?.tool_choice
|
|
1041
1049
|
: (() => {
|
|
1042
1050
|
const formatted = (0, openai_js_1.formatToOpenAIToolChoice)(options?.tool_choice);
|
|
1043
1051
|
if (typeof formatted === "object" && "type" in formatted) {
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1052
|
+
if (formatted.type === "function") {
|
|
1053
|
+
return { type: "function", name: formatted.function.name };
|
|
1054
|
+
}
|
|
1055
|
+
else if (formatted.type === "allowed_tools") {
|
|
1056
|
+
return {
|
|
1057
|
+
type: "allowed_tools",
|
|
1058
|
+
mode: formatted.allowed_tools.mode,
|
|
1059
|
+
tools: formatted.allowed_tools.tools,
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
else if (formatted.type === "custom") {
|
|
1063
|
+
return {
|
|
1064
|
+
type: "custom",
|
|
1065
|
+
name: formatted.custom.name,
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1048
1068
|
}
|
|
1069
|
+
return undefined;
|
|
1049
1070
|
})(),
|
|
1050
1071
|
text: (() => {
|
|
1051
1072
|
if (options?.text)
|
|
@@ -1069,6 +1090,7 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1069
1090
|
})(),
|
|
1070
1091
|
parallel_tool_calls: options?.parallel_tool_calls,
|
|
1071
1092
|
max_output_tokens: this.maxTokens === -1 ? undefined : this.maxTokens,
|
|
1093
|
+
prompt_cache_key: options?.promptCacheKey ?? this.promptCacheKey,
|
|
1072
1094
|
...(this.zdrEnabled ? { store: false } : {}),
|
|
1073
1095
|
...this.modelKwargs,
|
|
1074
1096
|
};
|
|
@@ -1231,6 +1253,15 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1231
1253
|
else if (item.type === "reasoning") {
|
|
1232
1254
|
additional_kwargs.reasoning = item;
|
|
1233
1255
|
}
|
|
1256
|
+
else if (item.type === "custom_tool_call") {
|
|
1257
|
+
const parsed = (0, tools_js_1.parseCustomToolCall)(item);
|
|
1258
|
+
if (parsed) {
|
|
1259
|
+
tool_calls.push(parsed);
|
|
1260
|
+
}
|
|
1261
|
+
else {
|
|
1262
|
+
invalid_tool_calls.push((0, openai_tools_1.makeInvalidToolCall)(item, "Malformed custom tool call"));
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1234
1265
|
else {
|
|
1235
1266
|
additional_kwargs.tool_outputs ??= [];
|
|
1236
1267
|
additional_kwargs.tool_outputs.push(item);
|
|
@@ -1262,7 +1293,7 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1262
1293
|
index: chunk.content_index,
|
|
1263
1294
|
});
|
|
1264
1295
|
}
|
|
1265
|
-
else if (chunk.type === "response.
|
|
1296
|
+
else if (chunk.type === "response.output_text.annotation.added") {
|
|
1266
1297
|
content.push({
|
|
1267
1298
|
type: "text",
|
|
1268
1299
|
text: "",
|
|
@@ -1297,6 +1328,7 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1297
1328
|
"mcp_list_tools",
|
|
1298
1329
|
"mcp_approval_request",
|
|
1299
1330
|
"image_generation_call",
|
|
1331
|
+
"custom_tool_call",
|
|
1300
1332
|
].includes(chunk.item.type)) {
|
|
1301
1333
|
additional_kwargs.tool_outputs = [chunk.item];
|
|
1302
1334
|
}
|
|
@@ -1438,6 +1470,14 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1438
1470
|
call_id: toolMessage.tool_call_id,
|
|
1439
1471
|
};
|
|
1440
1472
|
}
|
|
1473
|
+
// Handle custom tool output
|
|
1474
|
+
if (toolMessage.metadata?.customTool) {
|
|
1475
|
+
return {
|
|
1476
|
+
type: "custom_tool_call_output",
|
|
1477
|
+
call_id: toolMessage.tool_call_id,
|
|
1478
|
+
output: toolMessage.content,
|
|
1479
|
+
};
|
|
1480
|
+
}
|
|
1441
1481
|
return {
|
|
1442
1482
|
type: "function_call_output",
|
|
1443
1483
|
call_id: toolMessage.tool_call_id,
|
|
@@ -1476,41 +1516,54 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1476
1516
|
{ type: "refusal", refusal: additional_kwargs.refusal },
|
|
1477
1517
|
];
|
|
1478
1518
|
}
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
item.type === "
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1519
|
+
if (typeof content === "string" || content.length > 0) {
|
|
1520
|
+
input.push({
|
|
1521
|
+
type: "message",
|
|
1522
|
+
role: "assistant",
|
|
1523
|
+
...(lcMsg.id && !this.zdrEnabled && lcMsg.id.startsWith("msg_")
|
|
1524
|
+
? { id: lcMsg.id }
|
|
1525
|
+
: {}),
|
|
1526
|
+
content: typeof content === "string"
|
|
1527
|
+
? content
|
|
1528
|
+
: content.flatMap((item) => {
|
|
1529
|
+
if (item.type === "text") {
|
|
1530
|
+
return {
|
|
1531
|
+
type: "output_text",
|
|
1532
|
+
text: item.text,
|
|
1533
|
+
// @ts-expect-error TODO: add types for `annotations`
|
|
1534
|
+
annotations: item.annotations ?? [],
|
|
1535
|
+
};
|
|
1536
|
+
}
|
|
1537
|
+
if (item.type === "output_text" ||
|
|
1538
|
+
item.type === "refusal") {
|
|
1539
|
+
return item;
|
|
1540
|
+
}
|
|
1541
|
+
return [];
|
|
1542
|
+
}),
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1503
1545
|
const functionCallIds = additional_kwargs?.[_FUNCTION_CALL_IDS_MAP_KEY];
|
|
1504
1546
|
if ((0, messages_1.isAIMessage)(lcMsg) && !!lcMsg.tool_calls?.length) {
|
|
1505
|
-
input.push(...lcMsg.tool_calls.map((toolCall) =>
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1547
|
+
input.push(...lcMsg.tool_calls.map((toolCall) => {
|
|
1548
|
+
if ((0, tools_js_1.isCustomToolCall)(toolCall)) {
|
|
1549
|
+
return {
|
|
1550
|
+
type: "custom_tool_call",
|
|
1551
|
+
id: toolCall.call_id,
|
|
1552
|
+
call_id: toolCall.id ?? "",
|
|
1553
|
+
input: toolCall.args.input,
|
|
1554
|
+
name: toolCall.name,
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1557
|
+
return {
|
|
1558
|
+
type: "function_call",
|
|
1559
|
+
name: toolCall.name,
|
|
1560
|
+
arguments: JSON.stringify(toolCall.args),
|
|
1561
|
+
call_id: toolCall.id,
|
|
1562
|
+
...(this.zdrEnabled
|
|
1563
|
+
? { id: functionCallIds?.[toolCall.id] }
|
|
1564
|
+
: {}),
|
|
1565
|
+
};
|
|
1566
|
+
}));
|
|
1514
1567
|
}
|
|
1515
1568
|
else if (additional_kwargs?.tool_calls) {
|
|
1516
1569
|
input.push(...additional_kwargs.tool_calls.map((toolCall) => ({
|
|
@@ -1613,7 +1666,7 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1613
1666
|
_reduceChatOpenAITools(tools, fields) {
|
|
1614
1667
|
const reducedTools = [];
|
|
1615
1668
|
for (const tool of tools) {
|
|
1616
|
-
if (isBuiltInTool(tool)) {
|
|
1669
|
+
if ((0, tools_js_1.isBuiltInTool)(tool)) {
|
|
1617
1670
|
if (tool.type === "image_generation" && fields?.stream) {
|
|
1618
1671
|
// OpenAI sends a 400 error if partial_images is not set and we want to stream.
|
|
1619
1672
|
// We also set it to 1 since we don't support partial images yet.
|
|
@@ -1630,6 +1683,9 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1630
1683
|
strict: fields?.strict ?? null,
|
|
1631
1684
|
});
|
|
1632
1685
|
}
|
|
1686
|
+
else if ((0, tools_js_1.isOpenAICustomTool)(tool)) {
|
|
1687
|
+
reducedTools.push((0, tools_js_1.convertCompletionsCustomTool)(tool));
|
|
1688
|
+
}
|
|
1633
1689
|
}
|
|
1634
1690
|
return reducedTools;
|
|
1635
1691
|
}
|
|
@@ -1687,6 +1743,7 @@ class ChatOpenAICompletions extends BaseChatOpenAI {
|
|
|
1687
1743
|
? { modalities: this.modalities || options?.modalities }
|
|
1688
1744
|
: {}),
|
|
1689
1745
|
...this.modelKwargs,
|
|
1746
|
+
prompt_cache_key: options?.promptCacheKey ?? this.promptCacheKey,
|
|
1690
1747
|
};
|
|
1691
1748
|
if (options?.prediction !== undefined) {
|
|
1692
1749
|
params.prediction = options.prediction;
|
|
@@ -1934,6 +1991,7 @@ class ChatOpenAICompletions extends BaseChatOpenAI {
|
|
|
1934
1991
|
return await this.client.chat.completions.parse(request, clientOptions);
|
|
1935
1992
|
}
|
|
1936
1993
|
else {
|
|
1994
|
+
console.log("request", request);
|
|
1937
1995
|
return await this.client.chat.completions.create(request, clientOptions);
|
|
1938
1996
|
}
|
|
1939
1997
|
}
|
|
@@ -2656,14 +2714,18 @@ class ChatOpenAI extends BaseChatOpenAI {
|
|
|
2656
2714
|
this.completions = fields?.completions ?? new ChatOpenAICompletions(fields);
|
|
2657
2715
|
}
|
|
2658
2716
|
_useResponsesApi(options) {
|
|
2659
|
-
const usesBuiltInTools = options?.tools?.some(isBuiltInTool);
|
|
2717
|
+
const usesBuiltInTools = options?.tools?.some(tools_js_1.isBuiltInTool);
|
|
2660
2718
|
const hasResponsesOnlyKwargs = options?.previous_response_id != null ||
|
|
2661
2719
|
options?.text != null ||
|
|
2662
2720
|
options?.truncation != null ||
|
|
2663
2721
|
options?.include != null ||
|
|
2664
2722
|
options?.reasoning?.summary != null ||
|
|
2665
2723
|
this.reasoning?.summary != null;
|
|
2666
|
-
|
|
2724
|
+
const hasCustomTools = options?.tools?.some(tools_js_1.isOpenAICustomTool);
|
|
2725
|
+
return (this.useResponsesApi ||
|
|
2726
|
+
usesBuiltInTools ||
|
|
2727
|
+
hasResponsesOnlyKwargs ||
|
|
2728
|
+
hasCustomTools);
|
|
2667
2729
|
}
|
|
2668
2730
|
getLsParams(options) {
|
|
2669
2731
|
const optionsWithDefaults = this._combineCallOptions(options);
|
package/dist/chat_models.d.ts
CHANGED
|
@@ -2,16 +2,13 @@ import { type ClientOptions, OpenAI as OpenAIClient } from "openai";
|
|
|
2
2
|
import { CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager";
|
|
3
3
|
import { AIMessageChunk, type BaseMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, SystemMessageChunk, ToolMessageChunk } from "@langchain/core/messages";
|
|
4
4
|
import { ChatGenerationChunk, type ChatGeneration, type ChatResult } from "@langchain/core/outputs";
|
|
5
|
-
import { BaseChatModel, type
|
|
5
|
+
import { BaseChatModel, type LangSmithParams, type BaseChatModelParams } from "@langchain/core/language_models/chat_models";
|
|
6
6
|
import { type BaseFunctionCallOptions, type BaseLanguageModelInput, type StructuredOutputMethodOptions } from "@langchain/core/language_models/base";
|
|
7
7
|
import { Runnable } from "@langchain/core/runnables";
|
|
8
|
-
import type { ResponseFormatText, ResponseFormatJSONObject, ResponseFormatJSONSchema } from "openai/resources/shared";
|
|
9
8
|
import { InteropZodType } from "@langchain/core/utils/types";
|
|
10
|
-
import { type OpenAICallOptions, type OpenAIChatInput, type OpenAICoreRequestOptions, type ChatOpenAIResponseFormat, ChatOpenAIReasoningSummary } from "./types.js";
|
|
9
|
+
import { type OpenAICallOptions, type OpenAIChatInput, type OpenAICoreRequestOptions, type ChatOpenAIResponseFormat, ChatOpenAIReasoningSummary, ResponseFormatConfiguration } from "./types.js";
|
|
11
10
|
import { OpenAIToolChoice } from "./utils/openai.js";
|
|
12
|
-
|
|
13
|
-
type ResponsesToolChoice = NonNullable<OpenAIClient.Responses.ResponseCreateParams["tool_choice"]>;
|
|
14
|
-
type ChatOpenAIToolType = BindToolsInput | OpenAIClient.Chat.ChatCompletionTool | ResponsesTool;
|
|
11
|
+
import { ChatOpenAIToolType, ResponsesTool, ResponsesToolChoice } from "./utils/tools.js";
|
|
15
12
|
interface OpenAILLMOutput {
|
|
16
13
|
tokenUsage: {
|
|
17
14
|
completionTokens?: number;
|
|
@@ -112,6 +109,12 @@ export interface BaseChatOpenAICallOptions extends OpenAICallOptions, BaseFuncti
|
|
|
112
109
|
* Specifies the service tier for prioritization and latency optimization.
|
|
113
110
|
*/
|
|
114
111
|
service_tier?: OpenAIClient.Chat.ChatCompletionCreateParams["service_tier"];
|
|
112
|
+
/**
|
|
113
|
+
* Used by OpenAI to cache responses for similar requests to optimize your cache
|
|
114
|
+
* hit rates. Replaces the `user` field.
|
|
115
|
+
* [Learn more](https://platform.openai.com/docs/guides/prompt-caching).
|
|
116
|
+
*/
|
|
117
|
+
promptCacheKey?: string;
|
|
115
118
|
}
|
|
116
119
|
export interface BaseChatOpenAIFields extends Partial<OpenAIChatInput>, BaseChatModelParams {
|
|
117
120
|
/**
|
|
@@ -170,6 +173,12 @@ export declare abstract class BaseChatOpenAI<CallOptions extends BaseChatOpenAIC
|
|
|
170
173
|
* Specifies the service tier for prioritization and latency optimization.
|
|
171
174
|
*/
|
|
172
175
|
service_tier?: OpenAIClient.Chat.ChatCompletionCreateParams["service_tier"];
|
|
176
|
+
/**
|
|
177
|
+
* Used by OpenAI to cache responses for similar requests to optimize your cache
|
|
178
|
+
* hit rates.
|
|
179
|
+
* [Learn more](https://platform.openai.com/docs/guides/prompt-caching).
|
|
180
|
+
*/
|
|
181
|
+
promptCacheKey: string;
|
|
173
182
|
protected defaultOptions: CallOptions;
|
|
174
183
|
_llmType(): string;
|
|
175
184
|
static lc_name(): string;
|
|
@@ -201,7 +210,7 @@ export declare abstract class BaseChatOpenAI<CallOptions extends BaseChatOpenAIC
|
|
|
201
210
|
* Returns an openai compatible response format from a set of options
|
|
202
211
|
* @internal
|
|
203
212
|
*/
|
|
204
|
-
protected _getResponseFormat(resFormat?: CallOptions["response_format"]):
|
|
213
|
+
protected _getResponseFormat(resFormat?: CallOptions["response_format"]): ResponseFormatConfiguration | undefined;
|
|
205
214
|
protected _combineCallOptions(additionalOptions?: this["ParsedCallOptions"]): this["ParsedCallOptions"];
|
|
206
215
|
/** @internal */
|
|
207
216
|
_getClientOptions(options: OpenAICoreRequestOptions | undefined): OpenAICoreRequestOptions;
|
|
@@ -285,7 +294,7 @@ export declare class ChatOpenAIResponses<CallOptions extends ChatOpenAIResponses
|
|
|
285
294
|
/** @internal */
|
|
286
295
|
protected _convertResponsesDeltaToBaseMessageChunk(chunk: OpenAIClient.Responses.ResponseStreamEvent): ChatGenerationChunk | null;
|
|
287
296
|
/** @internal */
|
|
288
|
-
protected _convertMessagesToResponsesParams(messages: BaseMessage[]): (OpenAIClient.Responses.ResponseReasoningItem | OpenAIClient.Responses.EasyInputMessage | OpenAIClient.Responses.ResponseInputItem.Message | OpenAIClient.Responses.ResponseOutputMessage | OpenAIClient.Responses.ResponseFileSearchToolCall | OpenAIClient.Responses.ResponseComputerToolCall | OpenAIClient.Responses.ResponseInputItem.ComputerCallOutput | OpenAIClient.Responses.ResponseFunctionWebSearch | OpenAIClient.Responses.ResponseFunctionToolCall | OpenAIClient.Responses.ResponseInputItem.FunctionCallOutput | OpenAIClient.Responses.ResponseInputItem.ImageGenerationCall | OpenAIClient.Responses.ResponseCodeInterpreterToolCall | OpenAIClient.Responses.ResponseInputItem.LocalShellCall | OpenAIClient.Responses.ResponseInputItem.LocalShellCallOutput | OpenAIClient.Responses.ResponseInputItem.McpListTools | OpenAIClient.Responses.ResponseInputItem.McpApprovalRequest | OpenAIClient.Responses.ResponseInputItem.McpApprovalResponse | OpenAIClient.Responses.ResponseInputItem.McpCall | OpenAIClient.Responses.ResponseInputItem.ItemReference)[];
|
|
297
|
+
protected _convertMessagesToResponsesParams(messages: BaseMessage[]): (OpenAIClient.Responses.ResponseReasoningItem | OpenAIClient.Responses.EasyInputMessage | OpenAIClient.Responses.ResponseInputItem.Message | OpenAIClient.Responses.ResponseOutputMessage | OpenAIClient.Responses.ResponseFileSearchToolCall | OpenAIClient.Responses.ResponseComputerToolCall | OpenAIClient.Responses.ResponseInputItem.ComputerCallOutput | OpenAIClient.Responses.ResponseFunctionWebSearch | OpenAIClient.Responses.ResponseFunctionToolCall | OpenAIClient.Responses.ResponseInputItem.FunctionCallOutput | OpenAIClient.Responses.ResponseInputItem.ImageGenerationCall | OpenAIClient.Responses.ResponseCodeInterpreterToolCall | OpenAIClient.Responses.ResponseInputItem.LocalShellCall | OpenAIClient.Responses.ResponseInputItem.LocalShellCallOutput | OpenAIClient.Responses.ResponseInputItem.McpListTools | OpenAIClient.Responses.ResponseInputItem.McpApprovalRequest | OpenAIClient.Responses.ResponseInputItem.McpApprovalResponse | OpenAIClient.Responses.ResponseInputItem.McpCall | OpenAIClient.Responses.ResponseCustomToolCallOutput | OpenAIClient.Responses.ResponseCustomToolCall | OpenAIClient.Responses.ResponseInputItem.ItemReference)[];
|
|
289
298
|
/** @internal */
|
|
290
299
|
protected _convertReasoningSummary(reasoning: ChatOpenAIReasoningSummary): OpenAIClient.Responses.ResponseReasoningItem;
|
|
291
300
|
/** @internal */
|
|
@@ -882,7 +891,7 @@ export declare class ChatOpenAI<CallOptions extends ChatOpenAICallOptions = Chat
|
|
|
882
891
|
protected completions: ChatOpenAICompletions;
|
|
883
892
|
get lc_serializable_keys(): string[];
|
|
884
893
|
constructor(fields?: ChatOpenAIFields | undefined);
|
|
885
|
-
protected _useResponsesApi(options: this["ParsedCallOptions"] | undefined): boolean;
|
|
894
|
+
protected _useResponsesApi(options: this["ParsedCallOptions"] | undefined): boolean | undefined;
|
|
886
895
|
getLsParams(options: this["ParsedCallOptions"]): LangSmithParams;
|
|
887
896
|
invocationParams(options?: this["ParsedCallOptions"]): ChatResponsesInvocationParams | ChatCompletionsInvocationParams;
|
|
888
897
|
/** @ignore */
|
package/dist/chat_models.js
CHANGED
|
@@ -3,7 +3,7 @@ import { AIMessage, AIMessageChunk, ChatMessage, ChatMessageChunk, FunctionMessa
|
|
|
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";
|
|
6
|
-
import { isOpenAITool, } from "@langchain/core/language_models/base";
|
|
6
|
+
import { isOpenAITool as isOpenAIFunctionTool, } from "@langchain/core/language_models/base";
|
|
7
7
|
import { RunnableLambda, RunnablePassthrough, RunnableSequence, } from "@langchain/core/runnables";
|
|
8
8
|
import { JsonOutputParser, StructuredOutputParser, } from "@langchain/core/output_parsers";
|
|
9
9
|
import { JsonOutputKeyToolsParser, convertLangChainToolCallToOpenAI, makeInvalidToolCall, parseToolCall, } from "@langchain/core/output_parsers/openai_tools";
|
|
@@ -12,19 +12,10 @@ import { toJsonSchema } from "@langchain/core/utils/json_schema";
|
|
|
12
12
|
import { getEndpoint } from "./utils/azure.js";
|
|
13
13
|
import { formatToOpenAIToolChoice, interopZodResponseFormat, wrapOpenAIClientError, } from "./utils/openai.js";
|
|
14
14
|
import { formatFunctionDefinitions, } from "./utils/openai-format-fndef.js";
|
|
15
|
-
import { _convertToOpenAITool } from "./utils/tools.js";
|
|
15
|
+
import { _convertToOpenAITool, convertCompletionsCustomTool, convertResponsesCustomTool, isBuiltInTool, isBuiltInToolChoice, isCustomTool, isCustomToolCall, isOpenAICustomTool, parseCustomToolCall, } from "./utils/tools.js";
|
|
16
16
|
const _FUNCTION_CALL_IDS_MAP_KEY = "__openai_function_call_ids__";
|
|
17
|
-
function isBuiltInTool(tool) {
|
|
18
|
-
return "type" in tool && tool.type !== "function";
|
|
19
|
-
}
|
|
20
|
-
function isBuiltInToolChoice(tool_choice) {
|
|
21
|
-
return (tool_choice != null &&
|
|
22
|
-
typeof tool_choice === "object" &&
|
|
23
|
-
"type" in tool_choice &&
|
|
24
|
-
tool_choice.type !== "function");
|
|
25
|
-
}
|
|
26
17
|
function isReasoningModel(model) {
|
|
27
|
-
return model && /^o\d/.test(model);
|
|
18
|
+
return model && (/^o\d/.test(model) || model.startsWith("gpt-5"));
|
|
28
19
|
}
|
|
29
20
|
function isStructuredOutputMethodParams(x
|
|
30
21
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -322,6 +313,8 @@ export class BaseChatOpenAI extends BaseChatModel {
|
|
|
322
313
|
"disableStreaming",
|
|
323
314
|
"zdrEnabled",
|
|
324
315
|
"reasoning",
|
|
316
|
+
"verbosity",
|
|
317
|
+
"promptCacheKey",
|
|
325
318
|
];
|
|
326
319
|
}
|
|
327
320
|
getLsParams(options) {
|
|
@@ -540,6 +533,17 @@ export class BaseChatOpenAI extends BaseChatModel {
|
|
|
540
533
|
writable: true,
|
|
541
534
|
value: void 0
|
|
542
535
|
});
|
|
536
|
+
/**
|
|
537
|
+
* Used by OpenAI to cache responses for similar requests to optimize your cache
|
|
538
|
+
* hit rates.
|
|
539
|
+
* [Learn more](https://platform.openai.com/docs/guides/prompt-caching).
|
|
540
|
+
*/
|
|
541
|
+
Object.defineProperty(this, "promptCacheKey", {
|
|
542
|
+
enumerable: true,
|
|
543
|
+
configurable: true,
|
|
544
|
+
writable: true,
|
|
545
|
+
value: void 0
|
|
546
|
+
});
|
|
543
547
|
Object.defineProperty(this, "defaultOptions", {
|
|
544
548
|
enumerable: true,
|
|
545
549
|
configurable: true,
|
|
@@ -579,6 +583,7 @@ export class BaseChatOpenAI extends BaseChatModel {
|
|
|
579
583
|
this.reasoning = fields?.reasoning;
|
|
580
584
|
this.maxTokens = fields?.maxCompletionTokens ?? fields?.maxTokens;
|
|
581
585
|
this.disableStreaming = fields?.disableStreaming ?? this.disableStreaming;
|
|
586
|
+
this.promptCacheKey = fields?.promptCacheKey ?? this.promptCacheKey;
|
|
582
587
|
this.streaming = fields?.streaming ?? false;
|
|
583
588
|
if (this.disableStreaming)
|
|
584
589
|
this.streaming = false;
|
|
@@ -672,7 +677,10 @@ export class BaseChatOpenAI extends BaseChatModel {
|
|
|
672
677
|
}
|
|
673
678
|
// TODO: move to completions class
|
|
674
679
|
_convertChatOpenAIToolToCompletionsTool(tool, fields) {
|
|
675
|
-
if (
|
|
680
|
+
if (isCustomTool(tool)) {
|
|
681
|
+
return convertResponsesCustomTool(tool.metadata.customTool);
|
|
682
|
+
}
|
|
683
|
+
if (isOpenAIFunctionTool(tool)) {
|
|
676
684
|
if (fields?.strict !== undefined) {
|
|
677
685
|
return {
|
|
678
686
|
...tool,
|
|
@@ -1035,11 +1043,24 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1035
1043
|
: (() => {
|
|
1036
1044
|
const formatted = formatToOpenAIToolChoice(options?.tool_choice);
|
|
1037
1045
|
if (typeof formatted === "object" && "type" in formatted) {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1046
|
+
if (formatted.type === "function") {
|
|
1047
|
+
return { type: "function", name: formatted.function.name };
|
|
1048
|
+
}
|
|
1049
|
+
else if (formatted.type === "allowed_tools") {
|
|
1050
|
+
return {
|
|
1051
|
+
type: "allowed_tools",
|
|
1052
|
+
mode: formatted.allowed_tools.mode,
|
|
1053
|
+
tools: formatted.allowed_tools.tools,
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
else if (formatted.type === "custom") {
|
|
1057
|
+
return {
|
|
1058
|
+
type: "custom",
|
|
1059
|
+
name: formatted.custom.name,
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1042
1062
|
}
|
|
1063
|
+
return undefined;
|
|
1043
1064
|
})(),
|
|
1044
1065
|
text: (() => {
|
|
1045
1066
|
if (options?.text)
|
|
@@ -1063,6 +1084,7 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1063
1084
|
})(),
|
|
1064
1085
|
parallel_tool_calls: options?.parallel_tool_calls,
|
|
1065
1086
|
max_output_tokens: this.maxTokens === -1 ? undefined : this.maxTokens,
|
|
1087
|
+
prompt_cache_key: options?.promptCacheKey ?? this.promptCacheKey,
|
|
1066
1088
|
...(this.zdrEnabled ? { store: false } : {}),
|
|
1067
1089
|
...this.modelKwargs,
|
|
1068
1090
|
};
|
|
@@ -1225,6 +1247,15 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1225
1247
|
else if (item.type === "reasoning") {
|
|
1226
1248
|
additional_kwargs.reasoning = item;
|
|
1227
1249
|
}
|
|
1250
|
+
else if (item.type === "custom_tool_call") {
|
|
1251
|
+
const parsed = parseCustomToolCall(item);
|
|
1252
|
+
if (parsed) {
|
|
1253
|
+
tool_calls.push(parsed);
|
|
1254
|
+
}
|
|
1255
|
+
else {
|
|
1256
|
+
invalid_tool_calls.push(makeInvalidToolCall(item, "Malformed custom tool call"));
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1228
1259
|
else {
|
|
1229
1260
|
additional_kwargs.tool_outputs ??= [];
|
|
1230
1261
|
additional_kwargs.tool_outputs.push(item);
|
|
@@ -1256,7 +1287,7 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1256
1287
|
index: chunk.content_index,
|
|
1257
1288
|
});
|
|
1258
1289
|
}
|
|
1259
|
-
else if (chunk.type === "response.
|
|
1290
|
+
else if (chunk.type === "response.output_text.annotation.added") {
|
|
1260
1291
|
content.push({
|
|
1261
1292
|
type: "text",
|
|
1262
1293
|
text: "",
|
|
@@ -1291,6 +1322,7 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1291
1322
|
"mcp_list_tools",
|
|
1292
1323
|
"mcp_approval_request",
|
|
1293
1324
|
"image_generation_call",
|
|
1325
|
+
"custom_tool_call",
|
|
1294
1326
|
].includes(chunk.item.type)) {
|
|
1295
1327
|
additional_kwargs.tool_outputs = [chunk.item];
|
|
1296
1328
|
}
|
|
@@ -1432,6 +1464,14 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1432
1464
|
call_id: toolMessage.tool_call_id,
|
|
1433
1465
|
};
|
|
1434
1466
|
}
|
|
1467
|
+
// Handle custom tool output
|
|
1468
|
+
if (toolMessage.metadata?.customTool) {
|
|
1469
|
+
return {
|
|
1470
|
+
type: "custom_tool_call_output",
|
|
1471
|
+
call_id: toolMessage.tool_call_id,
|
|
1472
|
+
output: toolMessage.content,
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1435
1475
|
return {
|
|
1436
1476
|
type: "function_call_output",
|
|
1437
1477
|
call_id: toolMessage.tool_call_id,
|
|
@@ -1470,41 +1510,54 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1470
1510
|
{ type: "refusal", refusal: additional_kwargs.refusal },
|
|
1471
1511
|
];
|
|
1472
1512
|
}
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
item.type === "
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1513
|
+
if (typeof content === "string" || content.length > 0) {
|
|
1514
|
+
input.push({
|
|
1515
|
+
type: "message",
|
|
1516
|
+
role: "assistant",
|
|
1517
|
+
...(lcMsg.id && !this.zdrEnabled && lcMsg.id.startsWith("msg_")
|
|
1518
|
+
? { id: lcMsg.id }
|
|
1519
|
+
: {}),
|
|
1520
|
+
content: typeof content === "string"
|
|
1521
|
+
? content
|
|
1522
|
+
: content.flatMap((item) => {
|
|
1523
|
+
if (item.type === "text") {
|
|
1524
|
+
return {
|
|
1525
|
+
type: "output_text",
|
|
1526
|
+
text: item.text,
|
|
1527
|
+
// @ts-expect-error TODO: add types for `annotations`
|
|
1528
|
+
annotations: item.annotations ?? [],
|
|
1529
|
+
};
|
|
1530
|
+
}
|
|
1531
|
+
if (item.type === "output_text" ||
|
|
1532
|
+
item.type === "refusal") {
|
|
1533
|
+
return item;
|
|
1534
|
+
}
|
|
1535
|
+
return [];
|
|
1536
|
+
}),
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1497
1539
|
const functionCallIds = additional_kwargs?.[_FUNCTION_CALL_IDS_MAP_KEY];
|
|
1498
1540
|
if (isAIMessage(lcMsg) && !!lcMsg.tool_calls?.length) {
|
|
1499
|
-
input.push(...lcMsg.tool_calls.map((toolCall) =>
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1541
|
+
input.push(...lcMsg.tool_calls.map((toolCall) => {
|
|
1542
|
+
if (isCustomToolCall(toolCall)) {
|
|
1543
|
+
return {
|
|
1544
|
+
type: "custom_tool_call",
|
|
1545
|
+
id: toolCall.call_id,
|
|
1546
|
+
call_id: toolCall.id ?? "",
|
|
1547
|
+
input: toolCall.args.input,
|
|
1548
|
+
name: toolCall.name,
|
|
1549
|
+
};
|
|
1550
|
+
}
|
|
1551
|
+
return {
|
|
1552
|
+
type: "function_call",
|
|
1553
|
+
name: toolCall.name,
|
|
1554
|
+
arguments: JSON.stringify(toolCall.args),
|
|
1555
|
+
call_id: toolCall.id,
|
|
1556
|
+
...(this.zdrEnabled
|
|
1557
|
+
? { id: functionCallIds?.[toolCall.id] }
|
|
1558
|
+
: {}),
|
|
1559
|
+
};
|
|
1560
|
+
}));
|
|
1508
1561
|
}
|
|
1509
1562
|
else if (additional_kwargs?.tool_calls) {
|
|
1510
1563
|
input.push(...additional_kwargs.tool_calls.map((toolCall) => ({
|
|
@@ -1615,7 +1668,7 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1615
1668
|
}
|
|
1616
1669
|
reducedTools.push(tool);
|
|
1617
1670
|
}
|
|
1618
|
-
else if (
|
|
1671
|
+
else if (isOpenAIFunctionTool(tool)) {
|
|
1619
1672
|
reducedTools.push({
|
|
1620
1673
|
type: "function",
|
|
1621
1674
|
name: tool.function.name,
|
|
@@ -1624,6 +1677,9 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1624
1677
|
strict: fields?.strict ?? null,
|
|
1625
1678
|
});
|
|
1626
1679
|
}
|
|
1680
|
+
else if (isOpenAICustomTool(tool)) {
|
|
1681
|
+
reducedTools.push(convertCompletionsCustomTool(tool));
|
|
1682
|
+
}
|
|
1627
1683
|
}
|
|
1628
1684
|
return reducedTools;
|
|
1629
1685
|
}
|
|
@@ -1680,6 +1736,7 @@ export class ChatOpenAICompletions extends BaseChatOpenAI {
|
|
|
1680
1736
|
? { modalities: this.modalities || options?.modalities }
|
|
1681
1737
|
: {}),
|
|
1682
1738
|
...this.modelKwargs,
|
|
1739
|
+
prompt_cache_key: options?.promptCacheKey ?? this.promptCacheKey,
|
|
1683
1740
|
};
|
|
1684
1741
|
if (options?.prediction !== undefined) {
|
|
1685
1742
|
params.prediction = options.prediction;
|
|
@@ -1927,6 +1984,7 @@ export class ChatOpenAICompletions extends BaseChatOpenAI {
|
|
|
1927
1984
|
return await this.client.chat.completions.parse(request, clientOptions);
|
|
1928
1985
|
}
|
|
1929
1986
|
else {
|
|
1987
|
+
console.log("request", request);
|
|
1930
1988
|
return await this.client.chat.completions.create(request, clientOptions);
|
|
1931
1989
|
}
|
|
1932
1990
|
}
|
|
@@ -2655,7 +2713,11 @@ export class ChatOpenAI extends BaseChatOpenAI {
|
|
|
2655
2713
|
options?.include != null ||
|
|
2656
2714
|
options?.reasoning?.summary != null ||
|
|
2657
2715
|
this.reasoning?.summary != null;
|
|
2658
|
-
|
|
2716
|
+
const hasCustomTools = options?.tools?.some(isOpenAICustomTool);
|
|
2717
|
+
return (this.useResponsesApi ||
|
|
2718
|
+
usesBuiltInTools ||
|
|
2719
|
+
hasResponsesOnlyKwargs ||
|
|
2720
|
+
hasCustomTools);
|
|
2659
2721
|
}
|
|
2660
2722
|
getLsParams(options) {
|
|
2661
2723
|
const optionsWithDefaults = this._combineCallOptions(options);
|
package/dist/index.cjs
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.convertPromptToOpenAI = exports.toFile = exports.OpenAIClient = void 0;
|
|
17
|
+
exports.customTool = exports.convertPromptToOpenAI = exports.toFile = exports.OpenAIClient = void 0;
|
|
18
18
|
var openai_1 = require("openai");
|
|
19
19
|
Object.defineProperty(exports, "OpenAIClient", { enumerable: true, get: function () { return openai_1.OpenAI; } });
|
|
20
20
|
Object.defineProperty(exports, "toFile", { enumerable: true, get: function () { return openai_1.toFile; } });
|
|
@@ -30,3 +30,5 @@ __exportStar(require("./utils/azure.cjs"), exports);
|
|
|
30
30
|
__exportStar(require("./tools/index.cjs"), exports);
|
|
31
31
|
var prompts_js_1 = require("./utils/prompts.cjs");
|
|
32
32
|
Object.defineProperty(exports, "convertPromptToOpenAI", { enumerable: true, get: function () { return prompts_js_1.convertPromptToOpenAI; } });
|
|
33
|
+
var custom_js_1 = require("./tools/custom.cjs");
|
|
34
|
+
Object.defineProperty(exports, "customTool", { enumerable: true, get: function () { return custom_js_1.customTool; } });
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.customTool = customTool;
|
|
4
|
+
const runnables_1 = require("@langchain/core/runnables");
|
|
5
|
+
const singletons_1 = require("@langchain/core/singletons");
|
|
6
|
+
const tools_1 = require("@langchain/core/tools");
|
|
7
|
+
function customTool(func, fields) {
|
|
8
|
+
return new tools_1.DynamicTool({
|
|
9
|
+
...fields,
|
|
10
|
+
description: "",
|
|
11
|
+
metadata: {
|
|
12
|
+
customTool: fields,
|
|
13
|
+
},
|
|
14
|
+
func: async (input, runManager, config) => new Promise((resolve, reject) => {
|
|
15
|
+
const childConfig = (0, runnables_1.patchConfig)(config, {
|
|
16
|
+
callbacks: runManager?.getChild(),
|
|
17
|
+
});
|
|
18
|
+
void singletons_1.AsyncLocalStorageProviderSingleton.runWithConfig((0, runnables_1.pickRunnableConfigKeys)(childConfig), async () => {
|
|
19
|
+
try {
|
|
20
|
+
resolve(func(input, childConfig));
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
reject(e);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { RunnableFunc } from "@langchain/core/runnables";
|
|
2
|
+
import { DynamicTool, ToolRunnableConfig } from "@langchain/core/tools";
|
|
3
|
+
import OpenAI from "openai";
|
|
4
|
+
export type CustomToolFields = Omit<OpenAI.Responses.CustomTool, "type">;
|
|
5
|
+
export declare function customTool(func: RunnableFunc<string, string, ToolRunnableConfig>, fields: CustomToolFields): DynamicTool<string>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { patchConfig, pickRunnableConfigKeys, } from "@langchain/core/runnables";
|
|
2
|
+
import { AsyncLocalStorageProviderSingleton } from "@langchain/core/singletons";
|
|
3
|
+
import { DynamicTool } from "@langchain/core/tools";
|
|
4
|
+
export function customTool(func, fields) {
|
|
5
|
+
return new DynamicTool({
|
|
6
|
+
...fields,
|
|
7
|
+
description: "",
|
|
8
|
+
metadata: {
|
|
9
|
+
customTool: fields,
|
|
10
|
+
},
|
|
11
|
+
func: async (input, runManager, config) => new Promise((resolve, reject) => {
|
|
12
|
+
const childConfig = patchConfig(config, {
|
|
13
|
+
callbacks: runManager?.getChild(),
|
|
14
|
+
});
|
|
15
|
+
void AsyncLocalStorageProviderSingleton.runWithConfig(pickRunnableConfigKeys(childConfig), async () => {
|
|
16
|
+
try {
|
|
17
|
+
resolve(func(input, childConfig));
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
reject(e);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}),
|
|
24
|
+
});
|
|
25
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { OpenAI as OpenAIClient } from "openai";
|
|
2
|
-
import type { ResponseFormatText, ResponseFormatJSONObject, ResponseFormatJSONSchema } from "openai/resources/shared";
|
|
2
|
+
import type { ResponseFormatText, ResponseFormatJSONObject, ResponseFormatJSONSchema, ResponseFormatTextPython, ResponseFormatTextGrammar } from "openai/resources/shared";
|
|
3
3
|
import { TiktokenModel } from "js-tiktoken/lite";
|
|
4
4
|
import type { BaseLanguageModelCallOptions } from "@langchain/core/language_models/base";
|
|
5
5
|
import { InteropZodObject } from "@langchain/core/utils/types";
|
|
@@ -76,6 +76,8 @@ export declare interface OpenAIBaseInput {
|
|
|
76
76
|
* `OPENAI_API_KEY` environment variable.
|
|
77
77
|
*/
|
|
78
78
|
apiKey?: string;
|
|
79
|
+
/** The verbosity of the model's response. */
|
|
80
|
+
verbosity: "low" | "medium" | "high";
|
|
79
81
|
}
|
|
80
82
|
export type OpenAICoreRequestOptions = OpenAIClient.RequestOptions;
|
|
81
83
|
export interface OpenAICallOptions extends BaseLanguageModelCallOptions {
|
|
@@ -154,6 +156,12 @@ export interface OpenAIChatInput extends OpenAIBaseInput {
|
|
|
154
156
|
* Specifies the service tier for prioritization and latency optimization.
|
|
155
157
|
*/
|
|
156
158
|
service_tier?: OpenAIClient.Responses.ResponseCreateParams["service_tier"];
|
|
159
|
+
/**
|
|
160
|
+
* Used by OpenAI to cache responses for similar requests to optimize your cache
|
|
161
|
+
* hit rates. Replaces the `user` field.
|
|
162
|
+
* [Learn more](https://platform.openai.com/docs/guides/prompt-caching).
|
|
163
|
+
*/
|
|
164
|
+
promptCacheKey?: string;
|
|
157
165
|
}
|
|
158
166
|
export interface AzureOpenAIInput {
|
|
159
167
|
/**
|
|
@@ -241,4 +249,5 @@ export type ChatOpenAIReasoningSummary = Omit<OpenAIClient.Responses.ResponseRea
|
|
|
241
249
|
index?: number;
|
|
242
250
|
}>;
|
|
243
251
|
};
|
|
244
|
-
export type ChatOpenAIResponseFormat = ResponseFormatText | ResponseFormatJSONObject | ChatOpenAIResponseFormatJSONSchema;
|
|
252
|
+
export type ChatOpenAIResponseFormat = ResponseFormatText | ResponseFormatJSONObject | ResponseFormatTextGrammar | ResponseFormatTextPython | ChatOpenAIResponseFormatJSONSchema;
|
|
253
|
+
export type ResponseFormatConfiguration = ResponseFormatText | ResponseFormatJSONObject | ResponseFormatJSONSchema;
|
package/dist/utils/tools.cjs
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports._convertToOpenAITool = _convertToOpenAITool;
|
|
4
|
+
exports.isBuiltInTool = isBuiltInTool;
|
|
5
|
+
exports.isBuiltInToolChoice = isBuiltInToolChoice;
|
|
6
|
+
exports.isCustomTool = isCustomTool;
|
|
7
|
+
exports.isOpenAICustomTool = isOpenAICustomTool;
|
|
8
|
+
exports.parseCustomToolCall = parseCustomToolCall;
|
|
9
|
+
exports.isCustomToolCall = isCustomToolCall;
|
|
10
|
+
exports.convertCompletionsCustomTool = convertCompletionsCustomTool;
|
|
11
|
+
exports.convertResponsesCustomTool = convertResponsesCustomTool;
|
|
4
12
|
const function_calling_1 = require("@langchain/core/utils/function_calling");
|
|
5
13
|
const openai_js_1 = require("./openai.cjs");
|
|
6
14
|
/**
|
|
@@ -24,8 +32,113 @@ tool, fields) {
|
|
|
24
32
|
else {
|
|
25
33
|
toolDef = tool;
|
|
26
34
|
}
|
|
27
|
-
if (fields?.strict !== undefined) {
|
|
35
|
+
if (toolDef.type === "function" && fields?.strict !== undefined) {
|
|
28
36
|
toolDef.function.strict = fields.strict;
|
|
29
37
|
}
|
|
30
38
|
return toolDef;
|
|
31
39
|
}
|
|
40
|
+
function isBuiltInTool(tool) {
|
|
41
|
+
return "type" in tool && tool.type !== "function" && tool.type !== "custom";
|
|
42
|
+
}
|
|
43
|
+
function isBuiltInToolChoice(tool_choice) {
|
|
44
|
+
return (tool_choice != null &&
|
|
45
|
+
typeof tool_choice === "object" &&
|
|
46
|
+
"type" in tool_choice &&
|
|
47
|
+
tool_choice.type !== "function");
|
|
48
|
+
}
|
|
49
|
+
function isCustomTool(tool) {
|
|
50
|
+
return (typeof tool === "object" &&
|
|
51
|
+
tool !== null &&
|
|
52
|
+
"metadata" in tool &&
|
|
53
|
+
typeof tool.metadata === "object" &&
|
|
54
|
+
tool.metadata !== null &&
|
|
55
|
+
"customTool" in tool.metadata &&
|
|
56
|
+
typeof tool.metadata.customTool === "object" &&
|
|
57
|
+
tool.metadata.customTool !== null);
|
|
58
|
+
}
|
|
59
|
+
function isOpenAICustomTool(tool) {
|
|
60
|
+
return ("type" in tool &&
|
|
61
|
+
tool.type === "custom" &&
|
|
62
|
+
"custom" in tool &&
|
|
63
|
+
typeof tool.custom === "object" &&
|
|
64
|
+
tool.custom !== null);
|
|
65
|
+
}
|
|
66
|
+
function parseCustomToolCall(
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
68
|
+
rawToolCall) {
|
|
69
|
+
if (rawToolCall.type !== "custom_tool_call") {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
...rawToolCall,
|
|
74
|
+
type: "tool_call",
|
|
75
|
+
call_id: rawToolCall.id,
|
|
76
|
+
id: rawToolCall.call_id,
|
|
77
|
+
name: rawToolCall.name,
|
|
78
|
+
isCustomTool: true,
|
|
79
|
+
args: {
|
|
80
|
+
input: rawToolCall.input,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function isCustomToolCall(toolCall) {
|
|
85
|
+
return (toolCall.type === "tool_call" &&
|
|
86
|
+
"isCustomTool" in toolCall &&
|
|
87
|
+
toolCall.isCustomTool === true);
|
|
88
|
+
}
|
|
89
|
+
function convertCompletionsCustomTool(tool) {
|
|
90
|
+
const getFormat = () => {
|
|
91
|
+
if (!tool.custom.format) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
if (tool.custom.format.type === "grammar") {
|
|
95
|
+
return {
|
|
96
|
+
type: "grammar",
|
|
97
|
+
definition: tool.custom.format.grammar.definition,
|
|
98
|
+
syntax: tool.custom.format.grammar.syntax,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (tool.custom.format.type === "text") {
|
|
102
|
+
return {
|
|
103
|
+
type: "text",
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
};
|
|
108
|
+
return {
|
|
109
|
+
type: "custom",
|
|
110
|
+
name: tool.custom.name,
|
|
111
|
+
description: tool.custom.description,
|
|
112
|
+
format: getFormat(),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function convertResponsesCustomTool(tool) {
|
|
116
|
+
const getFormat = () => {
|
|
117
|
+
if (!tool.format) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
if (tool.format.type === "grammar") {
|
|
121
|
+
return {
|
|
122
|
+
type: "grammar",
|
|
123
|
+
grammar: {
|
|
124
|
+
definition: tool.format.definition,
|
|
125
|
+
syntax: tool.format.syntax,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
if (tool.format.type === "text") {
|
|
130
|
+
return {
|
|
131
|
+
type: "text",
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return undefined;
|
|
135
|
+
};
|
|
136
|
+
return {
|
|
137
|
+
type: "custom",
|
|
138
|
+
custom: {
|
|
139
|
+
name: tool.name,
|
|
140
|
+
description: tool.description,
|
|
141
|
+
format: getFormat(),
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
package/dist/utils/tools.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { OpenAI as OpenAIClient } from "openai";
|
|
2
|
+
import { ToolCall } from "@langchain/core/messages/tool";
|
|
2
3
|
import { BindToolsInput } from "@langchain/core/language_models/chat_models";
|
|
4
|
+
import { DynamicTool } from "@langchain/core/tools";
|
|
5
|
+
import { OpenAIToolChoice } from "./openai.js";
|
|
6
|
+
export type ResponsesTool = NonNullable<OpenAIClient.Responses.ResponseCreateParams["tools"]>[number];
|
|
7
|
+
export type ResponsesToolChoice = NonNullable<OpenAIClient.Responses.ResponseCreateParams["tool_choice"]>;
|
|
8
|
+
export type ChatOpenAIToolType = BindToolsInput | OpenAIClient.Chat.ChatCompletionTool | ResponsesTool;
|
|
3
9
|
/**
|
|
4
10
|
* Formats a tool in either OpenAI format, or LangChain structured tool format
|
|
5
11
|
* into an OpenAI tool format. If the tool is already in OpenAI format, return without
|
|
@@ -18,3 +24,21 @@ export declare function _convertToOpenAITool(tool: BindToolsInput, fields?: {
|
|
|
18
24
|
*/
|
|
19
25
|
strict?: boolean;
|
|
20
26
|
}): OpenAIClient.ChatCompletionTool;
|
|
27
|
+
export declare function isBuiltInTool(tool: ChatOpenAIToolType): tool is ResponsesTool;
|
|
28
|
+
export declare function isBuiltInToolChoice(tool_choice: OpenAIToolChoice | ResponsesToolChoice | undefined): tool_choice is ResponsesToolChoice;
|
|
29
|
+
export type CustomToolCall = ToolCall & {
|
|
30
|
+
call_id: string;
|
|
31
|
+
isCustomTool: true;
|
|
32
|
+
};
|
|
33
|
+
type LangchainCustomTool = DynamicTool<string> & {
|
|
34
|
+
metadata: {
|
|
35
|
+
customTool: OpenAIClient.Responses.CustomTool;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
export declare function isCustomTool(tool: unknown): tool is LangchainCustomTool;
|
|
39
|
+
export declare function isOpenAICustomTool(tool: ChatOpenAIToolType): tool is OpenAIClient.Chat.ChatCompletionCustomTool;
|
|
40
|
+
export declare function parseCustomToolCall(rawToolCall: Record<string, any>): CustomToolCall | undefined;
|
|
41
|
+
export declare function isCustomToolCall(toolCall: ToolCall): toolCall is CustomToolCall;
|
|
42
|
+
export declare function convertCompletionsCustomTool(tool: OpenAIClient.Chat.ChatCompletionCustomTool): OpenAIClient.Responses.CustomTool;
|
|
43
|
+
export declare function convertResponsesCustomTool(tool: OpenAIClient.Responses.CustomTool): OpenAIClient.Chat.ChatCompletionCustomTool;
|
|
44
|
+
export {};
|
package/dist/utils/tools.js
CHANGED
|
@@ -21,8 +21,113 @@ tool, fields) {
|
|
|
21
21
|
else {
|
|
22
22
|
toolDef = tool;
|
|
23
23
|
}
|
|
24
|
-
if (fields?.strict !== undefined) {
|
|
24
|
+
if (toolDef.type === "function" && fields?.strict !== undefined) {
|
|
25
25
|
toolDef.function.strict = fields.strict;
|
|
26
26
|
}
|
|
27
27
|
return toolDef;
|
|
28
28
|
}
|
|
29
|
+
export function isBuiltInTool(tool) {
|
|
30
|
+
return "type" in tool && tool.type !== "function" && tool.type !== "custom";
|
|
31
|
+
}
|
|
32
|
+
export function isBuiltInToolChoice(tool_choice) {
|
|
33
|
+
return (tool_choice != null &&
|
|
34
|
+
typeof tool_choice === "object" &&
|
|
35
|
+
"type" in tool_choice &&
|
|
36
|
+
tool_choice.type !== "function");
|
|
37
|
+
}
|
|
38
|
+
export function isCustomTool(tool) {
|
|
39
|
+
return (typeof tool === "object" &&
|
|
40
|
+
tool !== null &&
|
|
41
|
+
"metadata" in tool &&
|
|
42
|
+
typeof tool.metadata === "object" &&
|
|
43
|
+
tool.metadata !== null &&
|
|
44
|
+
"customTool" in tool.metadata &&
|
|
45
|
+
typeof tool.metadata.customTool === "object" &&
|
|
46
|
+
tool.metadata.customTool !== null);
|
|
47
|
+
}
|
|
48
|
+
export function isOpenAICustomTool(tool) {
|
|
49
|
+
return ("type" in tool &&
|
|
50
|
+
tool.type === "custom" &&
|
|
51
|
+
"custom" in tool &&
|
|
52
|
+
typeof tool.custom === "object" &&
|
|
53
|
+
tool.custom !== null);
|
|
54
|
+
}
|
|
55
|
+
export function parseCustomToolCall(
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
|
+
rawToolCall) {
|
|
58
|
+
if (rawToolCall.type !== "custom_tool_call") {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
...rawToolCall,
|
|
63
|
+
type: "tool_call",
|
|
64
|
+
call_id: rawToolCall.id,
|
|
65
|
+
id: rawToolCall.call_id,
|
|
66
|
+
name: rawToolCall.name,
|
|
67
|
+
isCustomTool: true,
|
|
68
|
+
args: {
|
|
69
|
+
input: rawToolCall.input,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export function isCustomToolCall(toolCall) {
|
|
74
|
+
return (toolCall.type === "tool_call" &&
|
|
75
|
+
"isCustomTool" in toolCall &&
|
|
76
|
+
toolCall.isCustomTool === true);
|
|
77
|
+
}
|
|
78
|
+
export function convertCompletionsCustomTool(tool) {
|
|
79
|
+
const getFormat = () => {
|
|
80
|
+
if (!tool.custom.format) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
if (tool.custom.format.type === "grammar") {
|
|
84
|
+
return {
|
|
85
|
+
type: "grammar",
|
|
86
|
+
definition: tool.custom.format.grammar.definition,
|
|
87
|
+
syntax: tool.custom.format.grammar.syntax,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (tool.custom.format.type === "text") {
|
|
91
|
+
return {
|
|
92
|
+
type: "text",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
};
|
|
97
|
+
return {
|
|
98
|
+
type: "custom",
|
|
99
|
+
name: tool.custom.name,
|
|
100
|
+
description: tool.custom.description,
|
|
101
|
+
format: getFormat(),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export function convertResponsesCustomTool(tool) {
|
|
105
|
+
const getFormat = () => {
|
|
106
|
+
if (!tool.format) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
if (tool.format.type === "grammar") {
|
|
110
|
+
return {
|
|
111
|
+
type: "grammar",
|
|
112
|
+
grammar: {
|
|
113
|
+
definition: tool.format.definition,
|
|
114
|
+
syntax: tool.format.syntax,
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (tool.format.type === "text") {
|
|
119
|
+
return {
|
|
120
|
+
type: "text",
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return undefined;
|
|
124
|
+
};
|
|
125
|
+
return {
|
|
126
|
+
type: "custom",
|
|
127
|
+
custom: {
|
|
128
|
+
name: tool.name,
|
|
129
|
+
description: tool.description,
|
|
130
|
+
format: getFormat(),
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/openai",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.6",
|
|
4
4
|
"description": "OpenAI integrations for LangChain.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"license": "MIT",
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"js-tiktoken": "^1.0.12",
|
|
39
|
-
"openai": "^5.
|
|
39
|
+
"openai": "^5.12.1",
|
|
40
40
|
"zod": "^3.25.32"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@langchain/core": ">=0.3.
|
|
43
|
+
"@langchain/core": ">=0.3.68 <0.4.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@azure/identity": "^4.2.1",
|