@langchain/openai 0.6.5 → 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 +97 -48
- package/dist/chat_models.d.ts +17 -8
- package/dist/chat_models.js +97 -48
- 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 +2 -2
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,7 +1044,7 @@ 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);
|
|
@@ -1082,6 +1090,7 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1082
1090
|
})(),
|
|
1083
1091
|
parallel_tool_calls: options?.parallel_tool_calls,
|
|
1084
1092
|
max_output_tokens: this.maxTokens === -1 ? undefined : this.maxTokens,
|
|
1093
|
+
prompt_cache_key: options?.promptCacheKey ?? this.promptCacheKey,
|
|
1085
1094
|
...(this.zdrEnabled ? { store: false } : {}),
|
|
1086
1095
|
...this.modelKwargs,
|
|
1087
1096
|
};
|
|
@@ -1244,6 +1253,15 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1244
1253
|
else if (item.type === "reasoning") {
|
|
1245
1254
|
additional_kwargs.reasoning = item;
|
|
1246
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
|
+
}
|
|
1247
1265
|
else {
|
|
1248
1266
|
additional_kwargs.tool_outputs ??= [];
|
|
1249
1267
|
additional_kwargs.tool_outputs.push(item);
|
|
@@ -1310,6 +1328,7 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1310
1328
|
"mcp_list_tools",
|
|
1311
1329
|
"mcp_approval_request",
|
|
1312
1330
|
"image_generation_call",
|
|
1331
|
+
"custom_tool_call",
|
|
1313
1332
|
].includes(chunk.item.type)) {
|
|
1314
1333
|
additional_kwargs.tool_outputs = [chunk.item];
|
|
1315
1334
|
}
|
|
@@ -1451,6 +1470,14 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1451
1470
|
call_id: toolMessage.tool_call_id,
|
|
1452
1471
|
};
|
|
1453
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
|
+
}
|
|
1454
1481
|
return {
|
|
1455
1482
|
type: "function_call_output",
|
|
1456
1483
|
call_id: toolMessage.tool_call_id,
|
|
@@ -1489,41 +1516,54 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1489
1516
|
{ type: "refusal", refusal: additional_kwargs.refusal },
|
|
1490
1517
|
];
|
|
1491
1518
|
}
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
item.type === "
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
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
|
+
}
|
|
1516
1545
|
const functionCallIds = additional_kwargs?.[_FUNCTION_CALL_IDS_MAP_KEY];
|
|
1517
1546
|
if ((0, messages_1.isAIMessage)(lcMsg) && !!lcMsg.tool_calls?.length) {
|
|
1518
|
-
input.push(...lcMsg.tool_calls.map((toolCall) =>
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
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
|
+
}));
|
|
1527
1567
|
}
|
|
1528
1568
|
else if (additional_kwargs?.tool_calls) {
|
|
1529
1569
|
input.push(...additional_kwargs.tool_calls.map((toolCall) => ({
|
|
@@ -1626,7 +1666,7 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1626
1666
|
_reduceChatOpenAITools(tools, fields) {
|
|
1627
1667
|
const reducedTools = [];
|
|
1628
1668
|
for (const tool of tools) {
|
|
1629
|
-
if (isBuiltInTool(tool)) {
|
|
1669
|
+
if ((0, tools_js_1.isBuiltInTool)(tool)) {
|
|
1630
1670
|
if (tool.type === "image_generation" && fields?.stream) {
|
|
1631
1671
|
// OpenAI sends a 400 error if partial_images is not set and we want to stream.
|
|
1632
1672
|
// We also set it to 1 since we don't support partial images yet.
|
|
@@ -1643,6 +1683,9 @@ class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1643
1683
|
strict: fields?.strict ?? null,
|
|
1644
1684
|
});
|
|
1645
1685
|
}
|
|
1686
|
+
else if ((0, tools_js_1.isOpenAICustomTool)(tool)) {
|
|
1687
|
+
reducedTools.push((0, tools_js_1.convertCompletionsCustomTool)(tool));
|
|
1688
|
+
}
|
|
1646
1689
|
}
|
|
1647
1690
|
return reducedTools;
|
|
1648
1691
|
}
|
|
@@ -1700,6 +1743,7 @@ class ChatOpenAICompletions extends BaseChatOpenAI {
|
|
|
1700
1743
|
? { modalities: this.modalities || options?.modalities }
|
|
1701
1744
|
: {}),
|
|
1702
1745
|
...this.modelKwargs,
|
|
1746
|
+
prompt_cache_key: options?.promptCacheKey ?? this.promptCacheKey,
|
|
1703
1747
|
};
|
|
1704
1748
|
if (options?.prediction !== undefined) {
|
|
1705
1749
|
params.prediction = options.prediction;
|
|
@@ -1947,6 +1991,7 @@ class ChatOpenAICompletions extends BaseChatOpenAI {
|
|
|
1947
1991
|
return await this.client.chat.completions.parse(request, clientOptions);
|
|
1948
1992
|
}
|
|
1949
1993
|
else {
|
|
1994
|
+
console.log("request", request);
|
|
1950
1995
|
return await this.client.chat.completions.create(request, clientOptions);
|
|
1951
1996
|
}
|
|
1952
1997
|
}
|
|
@@ -2669,14 +2714,18 @@ class ChatOpenAI extends BaseChatOpenAI {
|
|
|
2669
2714
|
this.completions = fields?.completions ?? new ChatOpenAICompletions(fields);
|
|
2670
2715
|
}
|
|
2671
2716
|
_useResponsesApi(options) {
|
|
2672
|
-
const usesBuiltInTools = options?.tools?.some(isBuiltInTool);
|
|
2717
|
+
const usesBuiltInTools = options?.tools?.some(tools_js_1.isBuiltInTool);
|
|
2673
2718
|
const hasResponsesOnlyKwargs = options?.previous_response_id != null ||
|
|
2674
2719
|
options?.text != null ||
|
|
2675
2720
|
options?.truncation != null ||
|
|
2676
2721
|
options?.include != null ||
|
|
2677
2722
|
options?.reasoning?.summary != null ||
|
|
2678
2723
|
this.reasoning?.summary != null;
|
|
2679
|
-
|
|
2724
|
+
const hasCustomTools = options?.tools?.some(tools_js_1.isOpenAICustomTool);
|
|
2725
|
+
return (this.useResponsesApi ||
|
|
2726
|
+
usesBuiltInTools ||
|
|
2727
|
+
hasResponsesOnlyKwargs ||
|
|
2728
|
+
hasCustomTools);
|
|
2680
2729
|
}
|
|
2681
2730
|
getLsParams(options) {
|
|
2682
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;
|
|
@@ -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,
|
|
@@ -1076,6 +1084,7 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1076
1084
|
})(),
|
|
1077
1085
|
parallel_tool_calls: options?.parallel_tool_calls,
|
|
1078
1086
|
max_output_tokens: this.maxTokens === -1 ? undefined : this.maxTokens,
|
|
1087
|
+
prompt_cache_key: options?.promptCacheKey ?? this.promptCacheKey,
|
|
1079
1088
|
...(this.zdrEnabled ? { store: false } : {}),
|
|
1080
1089
|
...this.modelKwargs,
|
|
1081
1090
|
};
|
|
@@ -1238,6 +1247,15 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1238
1247
|
else if (item.type === "reasoning") {
|
|
1239
1248
|
additional_kwargs.reasoning = item;
|
|
1240
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
|
+
}
|
|
1241
1259
|
else {
|
|
1242
1260
|
additional_kwargs.tool_outputs ??= [];
|
|
1243
1261
|
additional_kwargs.tool_outputs.push(item);
|
|
@@ -1304,6 +1322,7 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1304
1322
|
"mcp_list_tools",
|
|
1305
1323
|
"mcp_approval_request",
|
|
1306
1324
|
"image_generation_call",
|
|
1325
|
+
"custom_tool_call",
|
|
1307
1326
|
].includes(chunk.item.type)) {
|
|
1308
1327
|
additional_kwargs.tool_outputs = [chunk.item];
|
|
1309
1328
|
}
|
|
@@ -1445,6 +1464,14 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1445
1464
|
call_id: toolMessage.tool_call_id,
|
|
1446
1465
|
};
|
|
1447
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
|
+
}
|
|
1448
1475
|
return {
|
|
1449
1476
|
type: "function_call_output",
|
|
1450
1477
|
call_id: toolMessage.tool_call_id,
|
|
@@ -1483,41 +1510,54 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1483
1510
|
{ type: "refusal", refusal: additional_kwargs.refusal },
|
|
1484
1511
|
];
|
|
1485
1512
|
}
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
item.type === "
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
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
|
+
}
|
|
1510
1539
|
const functionCallIds = additional_kwargs?.[_FUNCTION_CALL_IDS_MAP_KEY];
|
|
1511
1540
|
if (isAIMessage(lcMsg) && !!lcMsg.tool_calls?.length) {
|
|
1512
|
-
input.push(...lcMsg.tool_calls.map((toolCall) =>
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
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
|
+
}));
|
|
1521
1561
|
}
|
|
1522
1562
|
else if (additional_kwargs?.tool_calls) {
|
|
1523
1563
|
input.push(...additional_kwargs.tool_calls.map((toolCall) => ({
|
|
@@ -1628,7 +1668,7 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1628
1668
|
}
|
|
1629
1669
|
reducedTools.push(tool);
|
|
1630
1670
|
}
|
|
1631
|
-
else if (
|
|
1671
|
+
else if (isOpenAIFunctionTool(tool)) {
|
|
1632
1672
|
reducedTools.push({
|
|
1633
1673
|
type: "function",
|
|
1634
1674
|
name: tool.function.name,
|
|
@@ -1637,6 +1677,9 @@ export class ChatOpenAIResponses extends BaseChatOpenAI {
|
|
|
1637
1677
|
strict: fields?.strict ?? null,
|
|
1638
1678
|
});
|
|
1639
1679
|
}
|
|
1680
|
+
else if (isOpenAICustomTool(tool)) {
|
|
1681
|
+
reducedTools.push(convertCompletionsCustomTool(tool));
|
|
1682
|
+
}
|
|
1640
1683
|
}
|
|
1641
1684
|
return reducedTools;
|
|
1642
1685
|
}
|
|
@@ -1693,6 +1736,7 @@ export class ChatOpenAICompletions extends BaseChatOpenAI {
|
|
|
1693
1736
|
? { modalities: this.modalities || options?.modalities }
|
|
1694
1737
|
: {}),
|
|
1695
1738
|
...this.modelKwargs,
|
|
1739
|
+
prompt_cache_key: options?.promptCacheKey ?? this.promptCacheKey,
|
|
1696
1740
|
};
|
|
1697
1741
|
if (options?.prediction !== undefined) {
|
|
1698
1742
|
params.prediction = options.prediction;
|
|
@@ -1940,6 +1984,7 @@ export class ChatOpenAICompletions extends BaseChatOpenAI {
|
|
|
1940
1984
|
return await this.client.chat.completions.parse(request, clientOptions);
|
|
1941
1985
|
}
|
|
1942
1986
|
else {
|
|
1987
|
+
console.log("request", request);
|
|
1943
1988
|
return await this.client.chat.completions.create(request, clientOptions);
|
|
1944
1989
|
}
|
|
1945
1990
|
}
|
|
@@ -2668,7 +2713,11 @@ export class ChatOpenAI extends BaseChatOpenAI {
|
|
|
2668
2713
|
options?.include != null ||
|
|
2669
2714
|
options?.reasoning?.summary != null ||
|
|
2670
2715
|
this.reasoning?.summary != null;
|
|
2671
|
-
|
|
2716
|
+
const hasCustomTools = options?.tools?.some(isOpenAICustomTool);
|
|
2717
|
+
return (this.useResponsesApi ||
|
|
2718
|
+
usesBuiltInTools ||
|
|
2719
|
+
hasResponsesOnlyKwargs ||
|
|
2720
|
+
hasCustomTools);
|
|
2672
2721
|
}
|
|
2673
2722
|
getLsParams(options) {
|
|
2674
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": {
|
|
@@ -40,7 +40,7 @@
|
|
|
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",
|