@langchain/anthropic 0.1.2 → 0.1.4
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/experimental/tests/tool_calling.int.test.js +66 -6
- package/dist/experimental/tool_calling.cjs +55 -17
- package/dist/experimental/tool_calling.d.ts +4 -3
- package/dist/experimental/tool_calling.js +56 -18
- package/dist/experimental/utils/tool_calling.cjs +36 -1
- package/dist/experimental/utils/tool_calling.d.ts +2 -0
- package/dist/experimental/utils/tool_calling.js +34 -0
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ import { test } from "@jest/globals";
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
6
6
|
import { HumanMessage } from "@langchain/core/messages";
|
|
7
|
+
import { ChatPromptTemplate } from "@langchain/core/prompts";
|
|
7
8
|
import { ChatAnthropicTools } from "../tool_calling.js";
|
|
8
9
|
test("Test ChatAnthropicTools", async () => {
|
|
9
10
|
const chat = new ChatAnthropicTools({
|
|
@@ -189,12 +190,11 @@ test("Test ChatAnthropic withStructuredOutput", async () => {
|
|
|
189
190
|
const runnable = new ChatAnthropicTools({
|
|
190
191
|
modelName: "claude-3-sonnet-20240229",
|
|
191
192
|
maxRetries: 0,
|
|
192
|
-
}).withStructuredOutput({
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}),
|
|
193
|
+
}).withStructuredOutput(z.object({
|
|
194
|
+
name: z.string().describe("The name of a person"),
|
|
195
|
+
height: z.number().describe("The person's height"),
|
|
196
|
+
hairColor: z.optional(z.string()).describe("The person's hair color"),
|
|
197
|
+
}), {
|
|
198
198
|
name: "person",
|
|
199
199
|
});
|
|
200
200
|
const message = new HumanMessage("Alex is 5 feet tall. Alex is blonde.");
|
|
@@ -202,3 +202,63 @@ test("Test ChatAnthropic withStructuredOutput", async () => {
|
|
|
202
202
|
console.log(JSON.stringify(res, null, 2));
|
|
203
203
|
expect(res).toEqual({ name: "Alex", height: 5, hairColor: "blonde" });
|
|
204
204
|
});
|
|
205
|
+
test("Test ChatAnthropic withStructuredOutput on a single array item", async () => {
|
|
206
|
+
const runnable = new ChatAnthropicTools({
|
|
207
|
+
modelName: "claude-3-sonnet-20240229",
|
|
208
|
+
maxRetries: 0,
|
|
209
|
+
}).withStructuredOutput(z.object({
|
|
210
|
+
people: z.array(z.object({
|
|
211
|
+
name: z.string().describe("The name of a person"),
|
|
212
|
+
height: z.number().describe("The person's height"),
|
|
213
|
+
hairColor: z.optional(z.string()).describe("The person's hair color"),
|
|
214
|
+
})),
|
|
215
|
+
}));
|
|
216
|
+
const message = new HumanMessage("Alex is 5 feet tall. Alex is blonde.");
|
|
217
|
+
const res = await runnable.invoke([message]);
|
|
218
|
+
console.log(JSON.stringify(res, null, 2));
|
|
219
|
+
expect(res).toEqual({
|
|
220
|
+
people: [{ hairColor: "blonde", height: 5, name: "Alex" }],
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
test("Test ChatAnthropic withStructuredOutput on a single array item", async () => {
|
|
224
|
+
const runnable = new ChatAnthropicTools({
|
|
225
|
+
modelName: "claude-3-sonnet-20240229",
|
|
226
|
+
maxRetries: 0,
|
|
227
|
+
}).withStructuredOutput(z.object({
|
|
228
|
+
sender: z
|
|
229
|
+
.optional(z.string())
|
|
230
|
+
.describe("The sender's name, if available"),
|
|
231
|
+
sender_phone_number: z
|
|
232
|
+
.optional(z.string())
|
|
233
|
+
.describe("The sender's phone number, if available"),
|
|
234
|
+
sender_address: z
|
|
235
|
+
.optional(z.string())
|
|
236
|
+
.describe("The sender's address, if available"),
|
|
237
|
+
action_items: z
|
|
238
|
+
.array(z.string())
|
|
239
|
+
.describe("A list of action items requested by the email"),
|
|
240
|
+
topic: z
|
|
241
|
+
.string()
|
|
242
|
+
.describe("High level description of what the email is about"),
|
|
243
|
+
tone: z.enum(["positive", "negative"]).describe("The tone of the email."),
|
|
244
|
+
}), {
|
|
245
|
+
name: "Email",
|
|
246
|
+
});
|
|
247
|
+
const prompt = ChatPromptTemplate.fromMessages([
|
|
248
|
+
[
|
|
249
|
+
"human",
|
|
250
|
+
"What can you tell me about the following email? Make sure to answer in the correct format: {email}",
|
|
251
|
+
],
|
|
252
|
+
]);
|
|
253
|
+
const extractionChain = prompt.pipe(runnable);
|
|
254
|
+
const response = await extractionChain.invoke({
|
|
255
|
+
email: "From: Erick. The email is about the new project. The tone is positive. The action items are to send the report and to schedule a meeting.",
|
|
256
|
+
});
|
|
257
|
+
console.log(JSON.stringify(response, null, 2));
|
|
258
|
+
expect(response).toEqual({
|
|
259
|
+
sender: "Erick",
|
|
260
|
+
action_items: [expect.any(String), expect.any(String)],
|
|
261
|
+
topic: expect.any(String),
|
|
262
|
+
tone: "positive",
|
|
263
|
+
});
|
|
264
|
+
});
|
|
@@ -63,6 +63,7 @@ class ChatAnthropicTools extends chat_models_1.BaseChatModel {
|
|
|
63
63
|
let promptMessages = messages;
|
|
64
64
|
let forced = false;
|
|
65
65
|
let toolCall;
|
|
66
|
+
const tools = options.tools === undefined ? [] : [...options.tools];
|
|
66
67
|
if (options.tools !== undefined && options.tools.length > 0) {
|
|
67
68
|
const content = await systemPromptTemplate.format({
|
|
68
69
|
tools: `<tools>\n${options.tools
|
|
@@ -121,14 +122,20 @@ class ChatAnthropicTools extends chat_models_1.BaseChatModel {
|
|
|
121
122
|
const responseMessageWithFunctions = new messages_1.AIMessage({
|
|
122
123
|
content: "",
|
|
123
124
|
additional_kwargs: {
|
|
124
|
-
tool_calls: invocations.map((toolInvocation, i) =>
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
125
|
+
tool_calls: invocations.map((toolInvocation, i) => {
|
|
126
|
+
const calledTool = tools.find((tool) => tool.function.name === toolCall);
|
|
127
|
+
if (calledTool === undefined) {
|
|
128
|
+
throw new Error(`Called tool "${toolCall}" did not match an existing tool.`);
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
id: i.toString(),
|
|
132
|
+
type: "function",
|
|
133
|
+
function: {
|
|
134
|
+
name: toolInvocation.tool_name,
|
|
135
|
+
arguments: JSON.stringify((0, tool_calling_js_1.fixArrayXMLParameters)(calledTool.function.parameters, toolInvocation.parameters)),
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}),
|
|
132
139
|
},
|
|
133
140
|
});
|
|
134
141
|
return {
|
|
@@ -144,14 +151,20 @@ class ChatAnthropicTools extends chat_models_1.BaseChatModel {
|
|
|
144
151
|
const responseMessageWithFunctions = new messages_1.AIMessage({
|
|
145
152
|
content: chatGenerationContent.split("<function_calls>")[0],
|
|
146
153
|
additional_kwargs: {
|
|
147
|
-
tool_calls: invocations.map((toolInvocation, i) =>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
tool_calls: invocations.map((toolInvocation, i) => {
|
|
155
|
+
const calledTool = tools.find((tool) => tool.function.name === toolInvocation.tool_name);
|
|
156
|
+
if (calledTool === undefined) {
|
|
157
|
+
throw new Error(`Called tool "${toolCall}" did not match an existing tool.`);
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
id: i.toString(),
|
|
161
|
+
type: "function",
|
|
162
|
+
function: {
|
|
163
|
+
name: toolInvocation.tool_name,
|
|
164
|
+
arguments: JSON.stringify((0, tool_calling_js_1.fixArrayXMLParameters)(calledTool.function.parameters, toolInvocation.parameters)),
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}),
|
|
155
168
|
},
|
|
156
169
|
});
|
|
157
170
|
return {
|
|
@@ -171,7 +184,24 @@ class ChatAnthropicTools extends chat_models_1.BaseChatModel {
|
|
|
171
184
|
_llmType() {
|
|
172
185
|
return "anthropic_tool_calling";
|
|
173
186
|
}
|
|
174
|
-
withStructuredOutput(
|
|
187
|
+
withStructuredOutput(outputSchema, config) {
|
|
188
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
189
|
+
let schema;
|
|
190
|
+
let name;
|
|
191
|
+
let method;
|
|
192
|
+
let includeRaw;
|
|
193
|
+
if (isStructuredOutputMethodParams(outputSchema)) {
|
|
194
|
+
schema = outputSchema.schema;
|
|
195
|
+
name = outputSchema.name;
|
|
196
|
+
method = outputSchema.method;
|
|
197
|
+
includeRaw = outputSchema.includeRaw;
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
schema = outputSchema;
|
|
201
|
+
name = config?.name;
|
|
202
|
+
method = config?.method;
|
|
203
|
+
includeRaw = config?.includeRaw;
|
|
204
|
+
}
|
|
175
205
|
if (method === "jsonMode") {
|
|
176
206
|
throw new Error(`Anthropic only supports "functionCalling" as a method.`);
|
|
177
207
|
}
|
|
@@ -245,3 +275,11 @@ function isZodSchema(input) {
|
|
|
245
275
|
// Check for a characteristic method of Zod schemas
|
|
246
276
|
return typeof input?.parse === "function";
|
|
247
277
|
}
|
|
278
|
+
function isStructuredOutputMethodParams(x
|
|
279
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
280
|
+
) {
|
|
281
|
+
return (x !== undefined &&
|
|
282
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
283
|
+
typeof x.schema ===
|
|
284
|
+
"object");
|
|
285
|
+
}
|
|
@@ -3,8 +3,9 @@ import { ChatGenerationChunk, ChatResult } from "@langchain/core/outputs";
|
|
|
3
3
|
import { BaseChatModel, BaseChatModelParams } from "@langchain/core/language_models/chat_models";
|
|
4
4
|
import { CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager";
|
|
5
5
|
import { BasePromptTemplate } from "@langchain/core/prompts";
|
|
6
|
-
import { BaseLanguageModelCallOptions, BaseLanguageModelInput, StructuredOutputMethodParams, ToolDefinition } from "@langchain/core/language_models/base";
|
|
6
|
+
import { BaseLanguageModelCallOptions, BaseLanguageModelInput, StructuredOutputMethodParams, StructuredOutputMethodOptions, ToolDefinition } from "@langchain/core/language_models/base";
|
|
7
7
|
import { Runnable } from "@langchain/core/runnables";
|
|
8
|
+
import { z } from "zod";
|
|
8
9
|
import { type AnthropicInput } from "../chat_models.js";
|
|
9
10
|
export interface ChatAnthropicToolsCallOptions extends BaseLanguageModelCallOptions {
|
|
10
11
|
tools?: ToolDefinition[];
|
|
@@ -43,8 +44,8 @@ export declare class ChatAnthropicTools extends BaseChatModel<ChatAnthropicTools
|
|
|
43
44
|
}): Promise<ChatResult>;
|
|
44
45
|
_generate(messages: BaseMessage[], options: this["ParsedCallOptions"], _runManager?: CallbackManagerForLLMRun | undefined): Promise<ChatResult>;
|
|
45
46
|
_llmType(): string;
|
|
46
|
-
withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(
|
|
47
|
-
withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(
|
|
47
|
+
withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(outputSchema: StructuredOutputMethodParams<RunOutput, false> | z.ZodType<RunOutput> | Record<string, any>, config?: StructuredOutputMethodOptions<false>): Runnable<BaseLanguageModelInput, RunOutput>;
|
|
48
|
+
withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(outputSchema: StructuredOutputMethodParams<RunOutput, true> | z.ZodType<RunOutput> | Record<string, any>, config?: StructuredOutputMethodOptions<true>): Runnable<BaseLanguageModelInput, {
|
|
48
49
|
raw: BaseMessage;
|
|
49
50
|
parsed: RunOutput;
|
|
50
51
|
}>;
|
|
@@ -5,7 +5,7 @@ import { RunnablePassthrough, RunnableSequence, } from "@langchain/core/runnable
|
|
|
5
5
|
import { JsonOutputKeyToolsParser } from "@langchain/core/output_parsers/openai_tools";
|
|
6
6
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
7
7
|
import { ChatAnthropic } from "../chat_models.js";
|
|
8
|
-
import { DEFAULT_TOOL_SYSTEM_PROMPT, formatAsXMLRepresentation, } from "./utils/tool_calling.js";
|
|
8
|
+
import { DEFAULT_TOOL_SYSTEM_PROMPT, formatAsXMLRepresentation, fixArrayXMLParameters, } from "./utils/tool_calling.js";
|
|
9
9
|
/**
|
|
10
10
|
* Experimental wrapper over Anthropic chat models that adds support for
|
|
11
11
|
* a function calling interface.
|
|
@@ -60,6 +60,7 @@ export class ChatAnthropicTools extends BaseChatModel {
|
|
|
60
60
|
let promptMessages = messages;
|
|
61
61
|
let forced = false;
|
|
62
62
|
let toolCall;
|
|
63
|
+
const tools = options.tools === undefined ? [] : [...options.tools];
|
|
63
64
|
if (options.tools !== undefined && options.tools.length > 0) {
|
|
64
65
|
const content = await systemPromptTemplate.format({
|
|
65
66
|
tools: `<tools>\n${options.tools
|
|
@@ -118,14 +119,20 @@ export class ChatAnthropicTools extends BaseChatModel {
|
|
|
118
119
|
const responseMessageWithFunctions = new AIMessage({
|
|
119
120
|
content: "",
|
|
120
121
|
additional_kwargs: {
|
|
121
|
-
tool_calls: invocations.map((toolInvocation, i) =>
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
122
|
+
tool_calls: invocations.map((toolInvocation, i) => {
|
|
123
|
+
const calledTool = tools.find((tool) => tool.function.name === toolCall);
|
|
124
|
+
if (calledTool === undefined) {
|
|
125
|
+
throw new Error(`Called tool "${toolCall}" did not match an existing tool.`);
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
id: i.toString(),
|
|
129
|
+
type: "function",
|
|
130
|
+
function: {
|
|
131
|
+
name: toolInvocation.tool_name,
|
|
132
|
+
arguments: JSON.stringify(fixArrayXMLParameters(calledTool.function.parameters, toolInvocation.parameters)),
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}),
|
|
129
136
|
},
|
|
130
137
|
});
|
|
131
138
|
return {
|
|
@@ -141,14 +148,20 @@ export class ChatAnthropicTools extends BaseChatModel {
|
|
|
141
148
|
const responseMessageWithFunctions = new AIMessage({
|
|
142
149
|
content: chatGenerationContent.split("<function_calls>")[0],
|
|
143
150
|
additional_kwargs: {
|
|
144
|
-
tool_calls: invocations.map((toolInvocation, i) =>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
151
|
+
tool_calls: invocations.map((toolInvocation, i) => {
|
|
152
|
+
const calledTool = tools.find((tool) => tool.function.name === toolInvocation.tool_name);
|
|
153
|
+
if (calledTool === undefined) {
|
|
154
|
+
throw new Error(`Called tool "${toolCall}" did not match an existing tool.`);
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
id: i.toString(),
|
|
158
|
+
type: "function",
|
|
159
|
+
function: {
|
|
160
|
+
name: toolInvocation.tool_name,
|
|
161
|
+
arguments: JSON.stringify(fixArrayXMLParameters(calledTool.function.parameters, toolInvocation.parameters)),
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}),
|
|
152
165
|
},
|
|
153
166
|
});
|
|
154
167
|
return {
|
|
@@ -168,7 +181,24 @@ export class ChatAnthropicTools extends BaseChatModel {
|
|
|
168
181
|
_llmType() {
|
|
169
182
|
return "anthropic_tool_calling";
|
|
170
183
|
}
|
|
171
|
-
withStructuredOutput(
|
|
184
|
+
withStructuredOutput(outputSchema, config) {
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
186
|
+
let schema;
|
|
187
|
+
let name;
|
|
188
|
+
let method;
|
|
189
|
+
let includeRaw;
|
|
190
|
+
if (isStructuredOutputMethodParams(outputSchema)) {
|
|
191
|
+
schema = outputSchema.schema;
|
|
192
|
+
name = outputSchema.name;
|
|
193
|
+
method = outputSchema.method;
|
|
194
|
+
includeRaw = outputSchema.includeRaw;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
schema = outputSchema;
|
|
198
|
+
name = config?.name;
|
|
199
|
+
method = config?.method;
|
|
200
|
+
includeRaw = config?.includeRaw;
|
|
201
|
+
}
|
|
172
202
|
if (method === "jsonMode") {
|
|
173
203
|
throw new Error(`Anthropic only supports "functionCalling" as a method.`);
|
|
174
204
|
}
|
|
@@ -241,3 +271,11 @@ function isZodSchema(input) {
|
|
|
241
271
|
// Check for a characteristic method of Zod schemas
|
|
242
272
|
return typeof input?.parse === "function";
|
|
243
273
|
}
|
|
274
|
+
function isStructuredOutputMethodParams(x
|
|
275
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
276
|
+
) {
|
|
277
|
+
return (x !== undefined &&
|
|
278
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
279
|
+
typeof x.schema ===
|
|
280
|
+
"object");
|
|
281
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatAsXMLRepresentation = exports.DEFAULT_TOOL_SYSTEM_PROMPT = void 0;
|
|
3
|
+
exports.fixArrayXMLParameters = exports.formatAsXMLRepresentation = exports.DEFAULT_TOOL_SYSTEM_PROMPT = void 0;
|
|
4
4
|
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
5
5
|
const prompts_1 = require("@langchain/core/prompts");
|
|
6
6
|
exports.DEFAULT_TOOL_SYSTEM_PROMPT =
|
|
@@ -50,3 +50,38 @@ ${parameterXml}
|
|
|
50
50
|
</tool_description>`;
|
|
51
51
|
}
|
|
52
52
|
exports.formatAsXMLRepresentation = formatAsXMLRepresentation;
|
|
53
|
+
function fixArrayXMLParameters(schema,
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
+
xmlParameters
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
|
+
) {
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
|
+
const fixedParameters = {};
|
|
60
|
+
for (const key of Object.keys(xmlParameters)) {
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
62
|
+
const schemaType = schema.properties[key].type;
|
|
63
|
+
// Crawl for lists indistinguishable from single items
|
|
64
|
+
if (schema.properties && schema.properties[key] && schemaType === "array") {
|
|
65
|
+
fixedParameters[key] = Array.isArray(xmlParameters[key])
|
|
66
|
+
? xmlParameters[key]
|
|
67
|
+
: [xmlParameters[key]];
|
|
68
|
+
// Crawl for objects like {"item": "my string"} that should really just be "my string"
|
|
69
|
+
if (schemaType !== "object" &&
|
|
70
|
+
typeof xmlParameters[key] === "object" &&
|
|
71
|
+
!Array.isArray(xmlParameters[key]) &&
|
|
72
|
+
Object.keys(xmlParameters[key]).length === 1) {
|
|
73
|
+
// eslint-disable-next-line prefer-destructuring
|
|
74
|
+
fixedParameters[key] = Object.values(xmlParameters[key])[0];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (typeof xmlParameters[key] === "object" &&
|
|
78
|
+
xmlParameters[key] !== null) {
|
|
79
|
+
fixedParameters[key] = fixArrayXMLParameters(schema, xmlParameters[key]);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
fixedParameters[key] = xmlParameters[key];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return fixedParameters;
|
|
86
|
+
}
|
|
87
|
+
exports.fixArrayXMLParameters = fixArrayXMLParameters;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { JsonSchema7ObjectType } from "zod-to-json-schema";
|
|
1
2
|
import { PromptTemplate } from "@langchain/core/prompts";
|
|
2
3
|
import { ToolDefinition } from "@langchain/core/language_models/base";
|
|
3
4
|
export declare const DEFAULT_TOOL_SYSTEM_PROMPT: PromptTemplate<import("@langchain/core/prompts").ParamsFromFString<"In this environment you have access to a set of tools you can use to answer the user's question.\n\nYou may call them like this:\n<function_calls>\n<invoke>\n<tool_name>$TOOL_NAME</tool_name>\n<parameters>\n<$PARAMETER_NAME>$PARAMETER_VALUE</$PARAMETER_NAME>\n...\n</parameters>\n</invoke>\n</function_calls>\n\nHere are the tools available:\n{tools}">, any>;
|
|
@@ -6,3 +7,4 @@ export type ToolInvocation = {
|
|
|
6
7
|
parameters: Record<string, unknown>;
|
|
7
8
|
};
|
|
8
9
|
export declare function formatAsXMLRepresentation(tool: ToolDefinition): string;
|
|
10
|
+
export declare function fixArrayXMLParameters(schema: JsonSchema7ObjectType, xmlParameters: Record<string, any>): Record<string, any>;
|
|
@@ -46,3 +46,37 @@ ${parameterXml}
|
|
|
46
46
|
</parameters>
|
|
47
47
|
</tool_description>`;
|
|
48
48
|
}
|
|
49
|
+
export function fixArrayXMLParameters(schema,
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
|
+
xmlParameters
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
+
) {
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
+
const fixedParameters = {};
|
|
56
|
+
for (const key of Object.keys(xmlParameters)) {
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
58
|
+
const schemaType = schema.properties[key].type;
|
|
59
|
+
// Crawl for lists indistinguishable from single items
|
|
60
|
+
if (schema.properties && schema.properties[key] && schemaType === "array") {
|
|
61
|
+
fixedParameters[key] = Array.isArray(xmlParameters[key])
|
|
62
|
+
? xmlParameters[key]
|
|
63
|
+
: [xmlParameters[key]];
|
|
64
|
+
// Crawl for objects like {"item": "my string"} that should really just be "my string"
|
|
65
|
+
if (schemaType !== "object" &&
|
|
66
|
+
typeof xmlParameters[key] === "object" &&
|
|
67
|
+
!Array.isArray(xmlParameters[key]) &&
|
|
68
|
+
Object.keys(xmlParameters[key]).length === 1) {
|
|
69
|
+
// eslint-disable-next-line prefer-destructuring
|
|
70
|
+
fixedParameters[key] = Object.values(xmlParameters[key])[0];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else if (typeof xmlParameters[key] === "object" &&
|
|
74
|
+
xmlParameters[key] !== null) {
|
|
75
|
+
fixedParameters[key] = fixArrayXMLParameters(schema, xmlParameters[key]);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
fixedParameters[key] = xmlParameters[key];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return fixedParameters;
|
|
82
|
+
}
|