index.cjs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.tool = exports.BaseToolkit = exports.DynamicStructuredTool = exports.DynamicTool = exports.Tool = exports.StructuredTool = exports.ToolInputParsingException = exports.isStructuredToolParams = exports.isStructuredTool = exports.isRunnableToolLike = exports.isLangChainTool = void 0;
  4. const zod_1 = require("zod");
  5. const json_schema_1 = require("@cfworker/json-schema");
  6. const manager_js_1 = require("../callbacks/manager.cjs");
  7. const base_js_1 = require("../language_models/base.cjs");
  8. const config_js_1 = require("../runnables/config.cjs");
  9. const tool_js_1 = require("../messages/tool.cjs");
  10. const index_js_1 = require("../singletons/index.cjs");
  11. const utils_js_1 = require("./utils.cjs");
  12. Object.defineProperty(exports, "ToolInputParsingException", { enumerable: true, get: function () { return utils_js_1.ToolInputParsingException; } });
  13. const is_zod_schema_js_1 = require("../utils/types/is_zod_schema.cjs");
  14. const json_schema_js_1 = require("../utils/json_schema.cjs");
  15. var types_js_1 = require("./types.cjs");
  16. Object.defineProperty(exports, "isLangChainTool", { enumerable: true, get: function () { return types_js_1.isLangChainTool; } });
  17. Object.defineProperty(exports, "isRunnableToolLike", { enumerable: true, get: function () { return types_js_1.isRunnableToolLike; } });
  18. Object.defineProperty(exports, "isStructuredTool", { enumerable: true, get: function () { return types_js_1.isStructuredTool; } });
  19. Object.defineProperty(exports, "isStructuredToolParams", { enumerable: true, get: function () { return types_js_1.isStructuredToolParams; } });
  20. /**
  21. * Base class for Tools that accept input of any shape defined by a Zod schema.
  22. */
  23. class StructuredTool extends base_js_1.BaseLangChain {
  24. get lc_namespace() {
  25. return ["langchain", "tools"];
  26. }
  27. constructor(fields) {
  28. super(fields ?? {});
  29. /**
  30. * Whether to return the tool's output directly.
  31. *
  32. * Setting this to true means that after the tool is called,
  33. * an agent should stop looping.
  34. */
  35. Object.defineProperty(this, "returnDirect", {
  36. enumerable: true,
  37. configurable: true,
  38. writable: true,
  39. value: false
  40. });
  41. Object.defineProperty(this, "verboseParsingErrors", {
  42. enumerable: true,
  43. configurable: true,
  44. writable: true,
  45. value: false
  46. });
  47. /**
  48. * The tool response format.
  49. *
  50. * If "content" then the output of the tool is interpreted as the contents of a
  51. * ToolMessage. If "content_and_artifact" then the output is expected to be a
  52. * two-tuple corresponding to the (content, artifact) of a ToolMessage.
  53. *
  54. * @default "content"
  55. */
  56. Object.defineProperty(this, "responseFormat", {
  57. enumerable: true,
  58. configurable: true,
  59. writable: true,
  60. value: "content"
  61. });
  62. this.verboseParsingErrors =
  63. fields?.verboseParsingErrors ?? this.verboseParsingErrors;
  64. this.responseFormat = fields?.responseFormat ?? this.responseFormat;
  65. }
  66. /**
  67. * Invokes the tool with the provided input and configuration.
  68. * @param input The input for the tool.
  69. * @param config Optional configuration for the tool.
  70. * @returns A Promise that resolves with the tool's output.
  71. */
  72. async invoke(input, config) {
  73. let toolInput;
  74. let enrichedConfig = (0, config_js_1.ensureConfig)(config);
  75. if ((0, utils_js_1._isToolCall)(input)) {
  76. toolInput = input.args;
  77. enrichedConfig = {
  78. ...enrichedConfig,
  79. toolCall: input,
  80. };
  81. }
  82. else {
  83. toolInput = input;
  84. }
  85. return this.call(toolInput, enrichedConfig);
  86. }
  87. /**
  88. * @deprecated Use .invoke() instead. Will be removed in 0.3.0.
  89. *
  90. * Calls the tool with the provided argument, configuration, and tags. It
  91. * parses the input according to the schema, handles any errors, and
  92. * manages callbacks.
  93. * @param arg The input argument for the tool.
  94. * @param configArg Optional configuration or callbacks for the tool.
  95. * @param tags Optional tags for the tool.
  96. * @returns A Promise that resolves with a string.
  97. */
  98. async call(arg, configArg,
  99. /** @deprecated */
  100. tags) {
  101. // Determine the actual input that needs parsing/validation.
  102. // If arg is a ToolCall, use its args; otherwise, use arg directly.
  103. const inputForValidation = (0, utils_js_1._isToolCall)(arg) ? arg.args : arg;
  104. let parsed; // This will hold the successfully parsed input of the expected output type.
  105. if ((0, is_zod_schema_js_1.isZodSchema)(this.schema)) {
  106. try {
  107. // Validate the inputForValidation - TS needs help here as it can't exclude ToolCall based on the check
  108. parsed = await this.schema.parseAsync(inputForValidation);
  109. }
  110. catch (e) {
  111. let message = `Received tool input did not match expected schema`;
  112. if (this.verboseParsingErrors) {
  113. message = `${message}\nDetails: ${e.message}`;
  114. }
  115. // Pass the original raw input arg to the exception
  116. throw new utils_js_1.ToolInputParsingException(message, JSON.stringify(arg));
  117. }
  118. }
  119. else {
  120. const result = (0, json_schema_1.validate)(inputForValidation, this.schema);
  121. if (!result.valid) {
  122. let message = `Received tool input did not match expected schema`;
  123. if (this.verboseParsingErrors) {
  124. message = `${message}\nDetails: ${result.errors
  125. .map((e) => `${e.keywordLocation}: ${e.error}`)
  126. .join("\n")}`;
  127. }
  128. // Pass the original raw input arg to the exception
  129. throw new utils_js_1.ToolInputParsingException(message, JSON.stringify(arg));
  130. }
  131. // Assign the validated input to parsed
  132. // We cast here because validate() doesn't narrow the type sufficiently for TS, but we know it's valid.
  133. parsed = inputForValidation;
  134. }
  135. const config = (0, manager_js_1.parseCallbackConfigArg)(configArg);
  136. const callbackManager_ = manager_js_1.CallbackManager.configure(config.callbacks, this.callbacks, config.tags || tags, this.tags, config.metadata, this.metadata, { verbose: this.verbose });
  137. const runManager = await callbackManager_?.handleToolStart(this.toJSON(),
  138. // Log the original raw input arg
  139. typeof arg === "string" ? arg : JSON.stringify(arg), config.runId, undefined, undefined, undefined, config.runName);
  140. delete config.runId;
  141. let result;
  142. try {
  143. // Pass the correctly typed parsed input to _call
  144. result = await this._call(parsed, runManager, config);
  145. }
  146. catch (e) {
  147. await runManager?.handleToolError(e);
  148. throw e;
  149. }
  150. let content;
  151. let artifact;
  152. if (this.responseFormat === "content_and_artifact") {
  153. if (Array.isArray(result) && result.length === 2) {
  154. [content, artifact] = result;
  155. }
  156. else {
  157. throw new Error(`Tool response format is "content_and_artifact" but the output was not a two-tuple.\nResult: ${JSON.stringify(result)}`);
  158. }
  159. }
  160. else {
  161. content = result;
  162. }
  163. let toolCallId;
  164. // Extract toolCallId ONLY if the original arg was a ToolCall
  165. if ((0, utils_js_1._isToolCall)(arg)) {
  166. toolCallId = arg.id;
  167. }
  168. // Or if it was provided in the config's toolCall property
  169. if (!toolCallId && (0, utils_js_1._configHasToolCallId)(config)) {
  170. toolCallId = config.toolCall.id;
  171. }
  172. const formattedOutput = _formatToolOutput({
  173. content,
  174. artifact,
  175. toolCallId,
  176. name: this.name,
  177. });
  178. await runManager?.handleToolEnd(formattedOutput);
  179. return formattedOutput;
  180. }
  181. }
  182. exports.StructuredTool = StructuredTool;
  183. /**
  184. * Base class for Tools that accept input as a string.
  185. */
  186. class Tool extends StructuredTool {
  187. constructor(fields) {
  188. super(fields);
  189. Object.defineProperty(this, "schema", {
  190. enumerable: true,
  191. configurable: true,
  192. writable: true,
  193. value: zod_1.z
  194. .object({ input: zod_1.z.string().optional() })
  195. .transform((obj) => obj.input)
  196. });
  197. }
  198. /**
  199. * @deprecated Use .invoke() instead. Will be removed in 0.3.0.
  200. *
  201. * Calls the tool with the provided argument and callbacks. It handles
  202. * string inputs specifically.
  203. * @param arg The input argument for the tool, which can be a string, undefined, or an input of the tool's schema.
  204. * @param callbacks Optional callbacks for the tool.
  205. * @returns A Promise that resolves with a string.
  206. */
  207. // Match the base class signature including the generics and conditional return type
  208. call(arg, callbacks) {
  209. // Prepare the input for the base class call method.
  210. // If arg is string or undefined, wrap it; otherwise, pass ToolCall or { input: ... } directly.
  211. const structuredArg = typeof arg === "string" || arg == null ? { input: arg } : arg;
  212. // Ensure TConfig is passed to super.call
  213. return super.call(structuredArg, callbacks);
  214. }
  215. }
  216. exports.Tool = Tool;
  217. /**
  218. * A tool that can be created dynamically from a function, name, and description.
  219. */
  220. class DynamicTool extends Tool {
  221. static lc_name() {
  222. return "DynamicTool";
  223. }
  224. constructor(fields) {
  225. super(fields);
  226. Object.defineProperty(this, "name", {
  227. enumerable: true,
  228. configurable: true,
  229. writable: true,
  230. value: void 0
  231. });
  232. Object.defineProperty(this, "description", {
  233. enumerable: true,
  234. configurable: true,
  235. writable: true,
  236. value: void 0
  237. });
  238. Object.defineProperty(this, "func", {
  239. enumerable: true,
  240. configurable: true,
  241. writable: true,
  242. value: void 0
  243. });
  244. this.name = fields.name;
  245. this.description = fields.description;
  246. this.func = fields.func;
  247. this.returnDirect = fields.returnDirect ?? this.returnDirect;
  248. }
  249. /**
  250. * @deprecated Use .invoke() instead. Will be removed in 0.3.0.
  251. */
  252. async call(arg, configArg) {
  253. const config = (0, manager_js_1.parseCallbackConfigArg)(configArg);
  254. if (config.runName === undefined) {
  255. config.runName = this.name;
  256. }
  257. // Call the Tool class's call method, passing generics through
  258. // Cast config to TConfig to satisfy the super.call signature
  259. return super.call(arg, config);
  260. }
  261. /** @ignore */
  262. async _call(input, // DynamicTool's _call specifically expects a string after schema transformation
  263. runManager, parentConfig) {
  264. return this.func(input, runManager, parentConfig);
  265. }
  266. }
  267. exports.DynamicTool = DynamicTool;
  268. /**
  269. * A tool that can be created dynamically from a function, name, and
  270. * description, designed to work with structured data. It extends the
  271. * StructuredTool class and overrides the _call method to execute the
  272. * provided function when the tool is called.
  273. *
  274. * Schema can be passed as Zod or JSON schema. The tool will not validate
  275. * input if JSON schema is passed.
  276. */
  277. class DynamicStructuredTool extends StructuredTool {
  278. static lc_name() {
  279. return "DynamicStructuredTool";
  280. }
  281. constructor(fields) {
  282. super(fields);
  283. Object.defineProperty(this, "name", {
  284. enumerable: true,
  285. configurable: true,
  286. writable: true,
  287. value: void 0
  288. });
  289. Object.defineProperty(this, "description", {
  290. enumerable: true,
  291. configurable: true,
  292. writable: true,
  293. value: void 0
  294. });
  295. Object.defineProperty(this, "func", {
  296. enumerable: true,
  297. configurable: true,
  298. writable: true,
  299. value: void 0
  300. });
  301. Object.defineProperty(this, "schema", {
  302. enumerable: true,
  303. configurable: true,
  304. writable: true,
  305. value: void 0
  306. });
  307. this.name = fields.name;
  308. this.description = fields.description;
  309. this.func = fields.func;
  310. this.returnDirect = fields.returnDirect ?? this.returnDirect;
  311. this.schema = fields.schema;
  312. }
  313. /**
  314. * @deprecated Use .invoke() instead. Will be removed in 0.3.0.
  315. */
  316. // Match the base class signature
  317. async call(arg, configArg,
  318. /** @deprecated */
  319. tags) {
  320. const config = (0, manager_js_1.parseCallbackConfigArg)(configArg);
  321. if (config.runName === undefined) {
  322. config.runName = this.name;
  323. }
  324. // Call the base class method, passing generics through
  325. // Cast config to TConfig to satisfy the super.call signature
  326. return super.call(arg, config, tags);
  327. }
  328. _call(arg, runManager, parentConfig) {
  329. return this.func(arg, runManager, parentConfig);
  330. }
  331. }
  332. exports.DynamicStructuredTool = DynamicStructuredTool;
  333. /**
  334. * Abstract base class for toolkits in LangChain. Toolkits are collections
  335. * of tools that agents can use. Subclasses must implement the `tools`
  336. * property to provide the specific tools for the toolkit.
  337. */
  338. class BaseToolkit {
  339. getTools() {
  340. return this.tools;
  341. }
  342. }
  343. exports.BaseToolkit = BaseToolkit;
  344. function tool(func, fields) {
  345. const isShapelessZodSchema = fields.schema &&
  346. (0, is_zod_schema_js_1.isZodSchema)(fields.schema) &&
  347. (!("shape" in fields.schema) || !fields.schema.shape);
  348. const isStringJSONSchema = (0, json_schema_js_1.validatesOnlyStrings)(fields.schema);
  349. // If the schema is not provided, or it's a shapeless schema (e.g. a ZodString), create a DynamicTool
  350. if (!fields.schema || isShapelessZodSchema || isStringJSONSchema) {
  351. return new DynamicTool({
  352. ...fields,
  353. description: fields.description ??
  354. fields.schema?.description ??
  355. `${fields.name} tool`,
  356. func: async (input, runManager, config) => {
  357. return new Promise((resolve, reject) => {
  358. const childConfig = (0, config_js_1.patchConfig)(config, {
  359. callbacks: runManager?.getChild(),
  360. });
  361. void index_js_1.AsyncLocalStorageProviderSingleton.runWithConfig((0, config_js_1.pickRunnableConfigKeys)(childConfig), async () => {
  362. try {
  363. // TS doesn't restrict the type here based on the guard above
  364. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  365. resolve(func(input, childConfig));
  366. }
  367. catch (e) {
  368. reject(e);
  369. }
  370. });
  371. });
  372. },
  373. });
  374. }
  375. const schema = fields.schema;
  376. const description = fields.description ??
  377. fields.schema.description ??
  378. `${fields.name} tool`;
  379. return new DynamicStructuredTool({
  380. ...fields,
  381. description,
  382. schema,
  383. func: async (input, runManager, config) => {
  384. return new Promise((resolve, reject) => {
  385. const childConfig = (0, config_js_1.patchConfig)(config, {
  386. callbacks: runManager?.getChild(),
  387. });
  388. void index_js_1.AsyncLocalStorageProviderSingleton.runWithConfig((0, config_js_1.pickRunnableConfigKeys)(childConfig), async () => {
  389. try {
  390. resolve(func(input, childConfig));
  391. }
  392. catch (e) {
  393. reject(e);
  394. }
  395. });
  396. });
  397. },
  398. });
  399. }
  400. exports.tool = tool;
  401. function _formatToolOutput(params) {
  402. const { content, artifact, toolCallId } = params;
  403. if (toolCallId && !(0, tool_js_1.isDirectToolOutput)(content)) {
  404. if (typeof content === "string" ||
  405. (Array.isArray(content) &&
  406. content.every((item) => typeof item === "object"))) {
  407. return new tool_js_1.ToolMessage({
  408. content,
  409. artifact,
  410. tool_call_id: toolCallId,
  411. name: params.name,
  412. });
  413. }
  414. else {
  415. return new tool_js_1.ToolMessage({
  416. content: _stringify(content),
  417. artifact,
  418. tool_call_id: toolCallId,
  419. name: params.name,
  420. });
  421. }
  422. }
  423. else {
  424. return content;
  425. }
  426. }
  427. function _stringify(content) {
  428. try {
  429. return JSON.stringify(content, null, 2) ?? "";
  430. }
  431. catch (_noOp) {
  432. return `${content}`;
  433. }
  434. }