123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.tool = exports.BaseToolkit = exports.DynamicStructuredTool = exports.DynamicTool = exports.Tool = exports.StructuredTool = exports.ToolInputParsingException = exports.isStructuredToolParams = exports.isStructuredTool = exports.isRunnableToolLike = exports.isLangChainTool = void 0;
- const zod_1 = require("zod");
- const json_schema_1 = require("@cfworker/json-schema");
- const manager_js_1 = require("../callbacks/manager.cjs");
- const base_js_1 = require("../language_models/base.cjs");
- const config_js_1 = require("../runnables/config.cjs");
- const tool_js_1 = require("../messages/tool.cjs");
- const index_js_1 = require("../singletons/index.cjs");
- const utils_js_1 = require("./utils.cjs");
- Object.defineProperty(exports, "ToolInputParsingException", { enumerable: true, get: function () { return utils_js_1.ToolInputParsingException; } });
- const is_zod_schema_js_1 = require("../utils/types/is_zod_schema.cjs");
- const json_schema_js_1 = require("../utils/json_schema.cjs");
- var types_js_1 = require("./types.cjs");
- Object.defineProperty(exports, "isLangChainTool", { enumerable: true, get: function () { return types_js_1.isLangChainTool; } });
- Object.defineProperty(exports, "isRunnableToolLike", { enumerable: true, get: function () { return types_js_1.isRunnableToolLike; } });
- Object.defineProperty(exports, "isStructuredTool", { enumerable: true, get: function () { return types_js_1.isStructuredTool; } });
- Object.defineProperty(exports, "isStructuredToolParams", { enumerable: true, get: function () { return types_js_1.isStructuredToolParams; } });
- /**
- * Base class for Tools that accept input of any shape defined by a Zod schema.
- */
- class StructuredTool extends base_js_1.BaseLangChain {
- get lc_namespace() {
- return ["langchain", "tools"];
- }
- constructor(fields) {
- super(fields ?? {});
- /**
- * Whether to return the tool's output directly.
- *
- * Setting this to true means that after the tool is called,
- * an agent should stop looping.
- */
- Object.defineProperty(this, "returnDirect", {
- enumerable: true,
- configurable: true,
- writable: true,
- value: false
- });
- Object.defineProperty(this, "verboseParsingErrors", {
- enumerable: true,
- configurable: true,
- writable: true,
- value: false
- });
- /**
- * The tool response format.
- *
- * If "content" then the output of the tool is interpreted as the contents of a
- * ToolMessage. If "content_and_artifact" then the output is expected to be a
- * two-tuple corresponding to the (content, artifact) of a ToolMessage.
- *
- * @default "content"
- */
- Object.defineProperty(this, "responseFormat", {
- enumerable: true,
- configurable: true,
- writable: true,
- value: "content"
- });
- this.verboseParsingErrors =
- fields?.verboseParsingErrors ?? this.verboseParsingErrors;
- this.responseFormat = fields?.responseFormat ?? this.responseFormat;
- }
- /**
- * Invokes the tool with the provided input and configuration.
- * @param input The input for the tool.
- * @param config Optional configuration for the tool.
- * @returns A Promise that resolves with the tool's output.
- */
- async invoke(input, config) {
- let toolInput;
- let enrichedConfig = (0, config_js_1.ensureConfig)(config);
- if ((0, utils_js_1._isToolCall)(input)) {
- toolInput = input.args;
- enrichedConfig = {
- ...enrichedConfig,
- toolCall: input,
- };
- }
- else {
- toolInput = input;
- }
- return this.call(toolInput, enrichedConfig);
- }
- /**
- * @deprecated Use .invoke() instead. Will be removed in 0.3.0.
- *
- * Calls the tool with the provided argument, configuration, and tags. It
- * parses the input according to the schema, handles any errors, and
- * manages callbacks.
- * @param arg The input argument for the tool.
- * @param configArg Optional configuration or callbacks for the tool.
- * @param tags Optional tags for the tool.
- * @returns A Promise that resolves with a string.
- */
- async call(arg, configArg,
- /** @deprecated */
- tags) {
- // Determine the actual input that needs parsing/validation.
- // If arg is a ToolCall, use its args; otherwise, use arg directly.
- const inputForValidation = (0, utils_js_1._isToolCall)(arg) ? arg.args : arg;
- let parsed; // This will hold the successfully parsed input of the expected output type.
- if ((0, is_zod_schema_js_1.isZodSchema)(this.schema)) {
- try {
- // Validate the inputForValidation - TS needs help here as it can't exclude ToolCall based on the check
- parsed = await this.schema.parseAsync(inputForValidation);
- }
- catch (e) {
- let message = `Received tool input did not match expected schema`;
- if (this.verboseParsingErrors) {
- message = `${message}\nDetails: ${e.message}`;
- }
- // Pass the original raw input arg to the exception
- throw new utils_js_1.ToolInputParsingException(message, JSON.stringify(arg));
- }
- }
- else {
- const result = (0, json_schema_1.validate)(inputForValidation, this.schema);
- if (!result.valid) {
- let message = `Received tool input did not match expected schema`;
- if (this.verboseParsingErrors) {
- message = `${message}\nDetails: ${result.errors
- .map((e) => `${e.keywordLocation}: ${e.error}`)
- .join("\n")}`;
- }
- // Pass the original raw input arg to the exception
- throw new utils_js_1.ToolInputParsingException(message, JSON.stringify(arg));
- }
- // Assign the validated input to parsed
- // We cast here because validate() doesn't narrow the type sufficiently for TS, but we know it's valid.
- parsed = inputForValidation;
- }
- const config = (0, manager_js_1.parseCallbackConfigArg)(configArg);
- const callbackManager_ = manager_js_1.CallbackManager.configure(config.callbacks, this.callbacks, config.tags || tags, this.tags, config.metadata, this.metadata, { verbose: this.verbose });
- const runManager = await callbackManager_?.handleToolStart(this.toJSON(),
- // Log the original raw input arg
- typeof arg === "string" ? arg : JSON.stringify(arg), config.runId, undefined, undefined, undefined, config.runName);
- delete config.runId;
- let result;
- try {
- // Pass the correctly typed parsed input to _call
- result = await this._call(parsed, runManager, config);
- }
- catch (e) {
- await runManager?.handleToolError(e);
- throw e;
- }
- let content;
- let artifact;
- if (this.responseFormat === "content_and_artifact") {
- if (Array.isArray(result) && result.length === 2) {
- [content, artifact] = result;
- }
- else {
- throw new Error(`Tool response format is "content_and_artifact" but the output was not a two-tuple.\nResult: ${JSON.stringify(result)}`);
- }
- }
- else {
- content = result;
- }
- let toolCallId;
- // Extract toolCallId ONLY if the original arg was a ToolCall
- if ((0, utils_js_1._isToolCall)(arg)) {
- toolCallId = arg.id;
- }
- // Or if it was provided in the config's toolCall property
- if (!toolCallId && (0, utils_js_1._configHasToolCallId)(config)) {
- toolCallId = config.toolCall.id;
- }
- const formattedOutput = _formatToolOutput({
- content,
- artifact,
- toolCallId,
- name: this.name,
- });
- await runManager?.handleToolEnd(formattedOutput);
- return formattedOutput;
- }
- }
- exports.StructuredTool = StructuredTool;
- /**
- * Base class for Tools that accept input as a string.
- */
- class Tool extends StructuredTool {
- constructor(fields) {
- super(fields);
- Object.defineProperty(this, "schema", {
- enumerable: true,
- configurable: true,
- writable: true,
- value: zod_1.z
- .object({ input: zod_1.z.string().optional() })
- .transform((obj) => obj.input)
- });
- }
- /**
- * @deprecated Use .invoke() instead. Will be removed in 0.3.0.
- *
- * Calls the tool with the provided argument and callbacks. It handles
- * string inputs specifically.
- * @param arg The input argument for the tool, which can be a string, undefined, or an input of the tool's schema.
- * @param callbacks Optional callbacks for the tool.
- * @returns A Promise that resolves with a string.
- */
- // Match the base class signature including the generics and conditional return type
- call(arg, callbacks) {
- // Prepare the input for the base class call method.
- // If arg is string or undefined, wrap it; otherwise, pass ToolCall or { input: ... } directly.
- const structuredArg = typeof arg === "string" || arg == null ? { input: arg } : arg;
- // Ensure TConfig is passed to super.call
- return super.call(structuredArg, callbacks);
- }
- }
- exports.Tool = Tool;
- /**
- * A tool that can be created dynamically from a function, name, and description.
- */
- class DynamicTool extends Tool {
- static lc_name() {
- return "DynamicTool";
- }
- constructor(fields) {
- super(fields);
- Object.defineProperty(this, "name", {
- enumerable: true,
- configurable: true,
- writable: true,
- value: void 0
- });
- Object.defineProperty(this, "description", {
- enumerable: true,
- configurable: true,
- writable: true,
- value: void 0
- });
- Object.defineProperty(this, "func", {
- enumerable: true,
- configurable: true,
- writable: true,
- value: void 0
- });
- this.name = fields.name;
- this.description = fields.description;
- this.func = fields.func;
- this.returnDirect = fields.returnDirect ?? this.returnDirect;
- }
- /**
- * @deprecated Use .invoke() instead. Will be removed in 0.3.0.
- */
- async call(arg, configArg) {
- const config = (0, manager_js_1.parseCallbackConfigArg)(configArg);
- if (config.runName === undefined) {
- config.runName = this.name;
- }
- // Call the Tool class's call method, passing generics through
- // Cast config to TConfig to satisfy the super.call signature
- return super.call(arg, config);
- }
- /** @ignore */
- async _call(input, // DynamicTool's _call specifically expects a string after schema transformation
- runManager, parentConfig) {
- return this.func(input, runManager, parentConfig);
- }
- }
- exports.DynamicTool = DynamicTool;
- /**
- * A tool that can be created dynamically from a function, name, and
- * description, designed to work with structured data. It extends the
- * StructuredTool class and overrides the _call method to execute the
- * provided function when the tool is called.
- *
- * Schema can be passed as Zod or JSON schema. The tool will not validate
- * input if JSON schema is passed.
- */
- class DynamicStructuredTool extends StructuredTool {
- static lc_name() {
- return "DynamicStructuredTool";
- }
- constructor(fields) {
- super(fields);
- Object.defineProperty(this, "name", {
- enumerable: true,
- configurable: true,
- writable: true,
- value: void 0
- });
- Object.defineProperty(this, "description", {
- enumerable: true,
- configurable: true,
- writable: true,
- value: void 0
- });
- Object.defineProperty(this, "func", {
- enumerable: true,
- configurable: true,
- writable: true,
- value: void 0
- });
- Object.defineProperty(this, "schema", {
- enumerable: true,
- configurable: true,
- writable: true,
- value: void 0
- });
- this.name = fields.name;
- this.description = fields.description;
- this.func = fields.func;
- this.returnDirect = fields.returnDirect ?? this.returnDirect;
- this.schema = fields.schema;
- }
- /**
- * @deprecated Use .invoke() instead. Will be removed in 0.3.0.
- */
- // Match the base class signature
- async call(arg, configArg,
- /** @deprecated */
- tags) {
- const config = (0, manager_js_1.parseCallbackConfigArg)(configArg);
- if (config.runName === undefined) {
- config.runName = this.name;
- }
- // Call the base class method, passing generics through
- // Cast config to TConfig to satisfy the super.call signature
- return super.call(arg, config, tags);
- }
- _call(arg, runManager, parentConfig) {
- return this.func(arg, runManager, parentConfig);
- }
- }
- exports.DynamicStructuredTool = DynamicStructuredTool;
- /**
- * Abstract base class for toolkits in LangChain. Toolkits are collections
- * of tools that agents can use. Subclasses must implement the `tools`
- * property to provide the specific tools for the toolkit.
- */
- class BaseToolkit {
- getTools() {
- return this.tools;
- }
- }
- exports.BaseToolkit = BaseToolkit;
- function tool(func, fields) {
- const isShapelessZodSchema = fields.schema &&
- (0, is_zod_schema_js_1.isZodSchema)(fields.schema) &&
- (!("shape" in fields.schema) || !fields.schema.shape);
- const isStringJSONSchema = (0, json_schema_js_1.validatesOnlyStrings)(fields.schema);
- // If the schema is not provided, or it's a shapeless schema (e.g. a ZodString), create a DynamicTool
- if (!fields.schema || isShapelessZodSchema || isStringJSONSchema) {
- return new DynamicTool({
- ...fields,
- description: fields.description ??
- fields.schema?.description ??
- `${fields.name} tool`,
- func: async (input, runManager, config) => {
- return new Promise((resolve, reject) => {
- const childConfig = (0, config_js_1.patchConfig)(config, {
- callbacks: runManager?.getChild(),
- });
- void index_js_1.AsyncLocalStorageProviderSingleton.runWithConfig((0, config_js_1.pickRunnableConfigKeys)(childConfig), async () => {
- try {
- // TS doesn't restrict the type here based on the guard above
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- resolve(func(input, childConfig));
- }
- catch (e) {
- reject(e);
- }
- });
- });
- },
- });
- }
- const schema = fields.schema;
- const description = fields.description ??
- fields.schema.description ??
- `${fields.name} tool`;
- return new DynamicStructuredTool({
- ...fields,
- description,
- schema,
- func: async (input, runManager, config) => {
- return new Promise((resolve, reject) => {
- const childConfig = (0, config_js_1.patchConfig)(config, {
- callbacks: runManager?.getChild(),
- });
- void index_js_1.AsyncLocalStorageProviderSingleton.runWithConfig((0, config_js_1.pickRunnableConfigKeys)(childConfig), async () => {
- try {
- resolve(func(input, childConfig));
- }
- catch (e) {
- reject(e);
- }
- });
- });
- },
- });
- }
- exports.tool = tool;
- function _formatToolOutput(params) {
- const { content, artifact, toolCallId } = params;
- if (toolCallId && !(0, tool_js_1.isDirectToolOutput)(content)) {
- if (typeof content === "string" ||
- (Array.isArray(content) &&
- content.every((item) => typeof item === "object"))) {
- return new tool_js_1.ToolMessage({
- content,
- artifact,
- tool_call_id: toolCallId,
- name: params.name,
- });
- }
- else {
- return new tool_js_1.ToolMessage({
- content: _stringify(content),
- artifact,
- tool_call_id: toolCallId,
- name: params.name,
- });
- }
- }
- else {
- return content;
- }
- }
- function _stringify(content) {
- try {
- return JSON.stringify(content, null, 2) ?? "";
- }
- catch (_noOp) {
- return `${content}`;
- }
- }
|