Open radiantone opened 2 weeks ago
To resolve the TypeScript error indicating that DynamicStructuredTool
is not assignable to type Record<string, unknown>
, you need to ensure that the DynamicStructuredTool
class implements the Record<string, unknown>
type correctly.
Here is an example of how you can modify the DynamicStructuredTool
class to ensure it is assignable to Record<string, unknown>
:
import { z } from "zod";
import {
CallbackManagerForToolRun,
Callbacks,
parseCallbackConfigArg,
} from "./callbacks/manager.js";
import { ensureConfig, RunnableConfig } from "./runnables/config.js";
import { StructuredTool, ToolParams, ToolInputParsingException } from "./tools.js";
export interface DynamicStructuredToolInput<
T extends z.ZodObject<any, any, any, any> = z.ZodObject<any, any, any, any>
> extends ToolParams {
name: string;
description: string;
func: (
input: z.infer<T>,
runManager?: CallbackManagerForToolRun,
config?: RunnableConfig
) => Promise<string>;
schema: T;
}
export class DynamicStructuredTool<
T extends z.ZodObject<any, any, any, any> = z.ZodObject<any, any, any, any>
> extends StructuredTool<T> implements Record<string, unknown> {
name: string;
description: string;
func: DynamicStructuredToolInput<T>["func"];
schema: T;
constructor(fields: DynamicStructuredToolInput<T>) {
super(fields);
this.name = fields.name;
this.description = fields.description;
this.func = fields.func;
this.returnDirect = fields.returnDirect ?? this.returnDirect;
this.schema = fields.schema;
}
async call(
arg: z.output<T>,
configArg?: RunnableConfig | Callbacks,
tags?: string[]
): Promise<string> {
const config = parseCallbackConfigArg(configArg);
if (config.runName === undefined) {
config.runName = this.name;
}
return super.call(arg, config, tags);
}
protected _call(
arg: z.output<T>,
runManager?: CallbackManagerForToolRun,
config?: RunnableConfig
): Promise<string> {
return this.func(arg, runManager, config);
}
}
Additionally, ensure you are importing the necessary types and classes from the correct module as shown in the LangChain.js library:
export {
type BaseDynamicToolInput,
type DynamicToolInput,
type DynamicStructuredToolInput,
DynamicTool,
DynamicStructuredTool,
} from "@langchain/core/tools";
In this example, the DynamicStructuredTool
class implements the Record<string, unknown>
interface, which should resolve the TypeScript error.
Here is an example usage of DynamicStructuredTool
from the LangChain.js library:
import { z } from "zod";
import { DynamicStructuredTool } from "@langchain/core/tools";
const addTool = new DynamicStructuredTool({
name: "add",
description: "Add two integers together.",
schema: z.object({
firstInt: z.number(),
secondInt: z.number(),
}),
func: async ({ firstInt, secondInt }) => {
return (firstInt + secondInt).toString();
},
});
const multiplyTool = new DynamicStructuredTool({
name: "multiply",
description: "Multiply two integers together.",
schema: z.object({
firstInt: z.number(),
secondInt: z.number(),
}),
func: async ({ firstInt, secondInt }) => {
return (firstInt * secondInt).toString();
},
});
const exponentiateTool = new DynamicStructuredTool({
name: "exponentiate",
description: "Exponentiate the base to the exponent power.",
schema: z.object({
base: z.number(),
exponent: z.number(),
}),
func: async ({ base, exponent }) => {
return (base ** exponent).toString();
},
});
import { ChatOpenAI } from "@langchain/openai";
import { convertToOpenAITool } from "@langchain/core/utils/function_calling";
import {
RunnableLambda,
RunnablePassthrough,
RunnableSequence,
} from "@langchain/core/runnables";
import { JsonOutputToolsParser } from "@langchain/core/output_parsers/openai_tools";
const model = new ChatOpenAI({
model: "gpt-3.5-turbo-1106",
});
const tools = [multiplyTool, exponentiateTool, addTool];
const toolMap: Record<string, any> = {
multiply: multiplyTool,
exponentiate: exponentiateTool,
add: addTool,
};
const modelWithTools = model.bind({
tools: tools.map(convertToOpenAITool),
});
const callSelectedTool = RunnableLambda.from(
(toolInvocation: Record<string, any>) => {
const selectedTool = toolMap[toolInvocation.type];
if (!selectedTool) {
throw new Error(
`No matching tool available for requested type "${toolInvocation.type}".`
);
}
const toolCallChain = RunnableSequence.from([
(toolInvocation) => toolInvocation.args,
selectedTool,
]);
return RunnablePassthrough.assign({
output: toolCallChain,
});
}
);
const chain = RunnableSequence.from([
modelWithTools,
new JsonOutputToolsParser(),
callSelectedTool.map(),
]);
console.log(await chain.invoke("What's 23 times 7"));
console.log(await chain.invoke("add a million plus a billion"));
console.log(await chain.invoke("cube thirty-seven"));
This example demonstrates how to create and use DynamicStructuredTool
instances in a LangChain.js application [1][2][3].
To continue talking to Dosu, mention @dosu.
Thanks for reporting!
This seemed ok to me when I checked - sometimes errors like this can manifest as a result of package managers resolving multiple versions of @langchain/core
.
Can you try the instructions here to ensure this isn't the case?
https://js.langchain.com/v0.2/docs/how_to/installation/#installing-integration-packages
should be
type ZodAny = z.ZodObject<any, any, any, any, any>;
or
type ZodAny = z.ZodObject;
Checked other resources
Example Code
/**
const calculatorTool = new DynamicStructuredTool({ name: "calculator", description: "Can perform mathematical operations.", schema: calculatorSchema, func: async ({ operation, number1, number2 }) => { // Functions must return strings if (operation === "add") { return
${number1 + number2}
; } else if (operation === "subtract") { return${number1 - number2}
; } else if (operation === "multiply") { return${number1 * number2}
; } else if (operation === "divide") { return${number1 / number2}
; } else { throw new Error("Invalid operation."); } }, });const llmWithTools = llm.bindTools([calculatorTool]);
const res = await llmWithTools.invoke("What is 3 * 12");
console.log(res.tool_calls);
Error Message and Stack Trace (if applicable)
tools.ts:43:37 - error TS2322: Type 'DynamicStructuredTool<ZodObject<{ operation: ZodEnum<["add", "subtract", "multiply", "divide"]>; number1: ZodNumber; number2: ZodNumber; }, "strip", ZodTypeAny, { ...; }, { ...; }>>' is not assignable to type 'Record<string, unknown> | StructuredToolInterface<ZodObject<any, any, any, any, { [x: string]: any; }>>'. Type 'DynamicStructuredTool<ZodObject<{ operation: ZodEnum<["add", "subtract", "multiply", "divide"]>; number1: ZodNumber; number2: ZodNumber; }, "strip", ZodTypeAny, { ...; }, { ...; }>>' is not assignable to type 'Record<string, unknown>'. Index signature for type 'string' is missing in type 'DynamicStructuredTool<ZodObject<{ operation: ZodEnum<["add", "subtract", "multiply", "divide"]>; number1: ZodNumber; number2: ZodNumber; }, "strip", ZodTypeAny, { ...; }, { ...; }>>'.
43 const llmWithTools = llm.bindTools([calculatorTool]);