langchain-ai / langchainjs

🦜🔗 Build context-aware reasoning applications 🦜🔗
https://js.langchain.com/docs/
MIT License
11.76k stars 1.97k forks source link

Example Code No Longer Works: ZodTypeAny, { ...; }, { ...; }>>' is not assignable to type 'Record<string, unknown>' #5772

Open radiantone opened 2 weeks ago

radiantone commented 2 weeks ago

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]);



    at createTSError (/home/darren/git/visualagents-ai/visualagents/node_modules/ts-node/src/index.ts:859:12)
    at reportTSError (/home/darren/git/visualagents-ai/visualagents/node_modules/ts-node/src/index.ts:863:19)
    at getOutput (/home/darren/git/visualagents-ai/visualagents/node_modules/ts-node/src/index.ts:1077:36)
    at Object.compile (/home/darren/git/visualagents-ai/visualagents/node_modules/ts-node/src/index.ts:1433:41)
    at Module.m._compile (/home/darren/git/visualagents-ai/visualagents/node_modules/ts-node/src/index.ts:1617:30)
    at Module._extensions..js (node:internal/modules/cjs/loader:1416:10)
    at Object.require.extensions.<computed> [as .ts] (/home/darren/git/visualagents-ai/visualagents/node_modules/ts-node/src/index.ts:1621:12)
    at Module.load (node:internal/modules/cjs/loader:1208:32)
    at Function.Module._load (node:internal/modules/cjs/loader:1024:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12) {
  diagnosticCodes: [ 2322 ]
}

### Description

Tried running the example code found here: https://js.langchain.com/v0.2/docs/how_to/tool_calling/#passing-tools-to-llms

This worked before latest updates

### System Info

langchain@0.2.5 | MIT | deps: 16 | versions: 277
Typescript bindings for langchain
https://github.com/langchain-ai/langchainjs/tree/main/langchain/

keywords: llm, ai, gpt3, chain, prompt, prompt engineering, chatgpt, machine learning, ml, openai, embeddings, vectorstores

dist
.tarball: https://registry.npmjs.org/langchain/-/langchain-0.2.5.tgz
.shasum: fc23848c20244a1d0a3dd5dd4663af9a41017ccb
.integrity: sha512-H5WL0NanCdQ+tzoeEt7Fyz9YGdR3wbfDvfQrJvxAO95istKo5JraRh24dzyvqxM9439xwRMNaMIpMwsyqtWDtQ==
.unpackedSize: 4.0 MB

dependencies:
@langchain/core: ~0.2.0
@langchain/openai: ~0.1.0
@langchain/textsplitters: ~0.0.0
binary-extensions: ^2.2.0
js-tiktoken: ^1.0.12
js-yaml: ^4.1.0
jsonpointer: ^5.0.1
langchainhub: ~0.0.8
langsmith: ~0.1.30
ml-distance: ^4.0.0
openapi-types: ^12.1.3
p-retry: 4
uuid: ^9.0.0
yaml: ^2.2.1
zod-to-json-schema: ^3.22.3
zod: ^3.22.4

maintainers:
- nfcampos <nuno@boringbits.io>
- jacoblee93 <jacoblee93@gmail.com>
- andrewnguonly <andrewnguonly@gmail.com>
- davidduong <david@duong.cz>
- hwchase17 <hw.chase.17@gmail.com>
- basproul <braceasproul@gmail.com>

dist-tags:
latest: 0.2.5
next: 0.2.3-rc.0

published a week ago by jacoblee93 <jacoblee93@gmail.com>
dosubot[bot] commented 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.

jacoblee93 commented 2 weeks ago

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

matzkoh commented 2 weeks ago

https://github.com/langchain-ai/langchainjs/blob/b76ead9e0539752501b5fc023fb177f52e7c7d69/langchain-core/src/tools.ts#L16

should be

type ZodAny = z.ZodObject<any, any, any, any, any>;

or

type ZodAny = z.ZodObject;