@toolforge-js/sdk 0.4.0 → 0.6.0

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/cli/index.js CHANGED
@@ -1,19 +1,20 @@
1
- import { C as __toESM, S as __require, _ as startAgentMessageSchema, a as TOOL_TAG_NAME, b as stopToolMessageSchema, c as getErrorMessage, d as runWithRetries, f as ackMessageSchema, g as runnerId, h as initCommunicationMessageSchema, i as TOOL_HANDLER_TAG_NAME, l as invariant, m as heartbeatAckMessageSchema, n as AGENT_TAG_NAME, o as Tool, p as baseMessageSchema, r as Agent, s as convertToWords, t as AGENT_STEP_TAG_NAME, u as exponentialBackoff, v as startToolMessageSchema, x as __commonJS, y as stopAgentMessageSchema } from "../agent-DBDnKm26.js";
1
+ import { C as __toESM, S as __require, _ as startAgentMessageSchema, a as AGENT_TAG_NAME, b as stopToolMessageSchema, c as getErrorMessage, d as runWithRetries, f as ackMessageSchema, g as runnerId, h as initCommunicationMessageSchema, i as AGENT_STEP_TAG_NAME, l as invariant, m as heartbeatAckMessageSchema, n as TOOL_TAG_NAME, o as Agent, p as baseMessageSchema, r as Tool, s as convertToWords, t as TOOL_HANDLER_TAG_NAME, u as exponentialBackoff, v as startToolMessageSchema, x as __commonJS, y as stopAgentMessageSchema } from "../tool-UVAGtnlr.js";
2
2
  import { t as toolForgeConfigSchema } from "../config-schema-CcWOtgOv.js";
3
3
  import * as z$1 from "zod";
4
4
  import z from "zod";
5
- import { P, match } from "ts-pattern";
6
- import { setTimeout as setTimeout$1 } from "node:timers/promises";
7
- import { nanoid } from "nanoid";
8
5
  import { readFileSync } from "node:fs";
9
6
  import * as path from "node:path";
10
7
  import { EventEmitter } from "node:events";
11
8
  import { pino } from "pino";
9
+ import { P, match } from "ts-pattern";
10
+ import { setTimeout as setTimeout$1 } from "node:timers/promises";
12
11
  import chokidar from "chokidar";
12
+ import { nanoid } from "nanoid";
13
13
  import picocolors from "picocolors";
14
14
  import * as fs from "node:fs/promises";
15
15
  import * as os from "node:os";
16
- import { capitalize, kebabCase } from "es-toolkit/string";
16
+ import { camelCase, capitalize, kebabCase } from "es-toolkit/string";
17
+ import esbuild from "esbuild";
17
18
 
18
19
  //#region ../../node_modules/.bun/commander@14.0.2/node_modules/commander/lib/error.js
19
20
  var require_error = /* @__PURE__ */ __commonJS({ "../../node_modules/.bun/commander@14.0.2/node_modules/commander/lib/error.js": ((exports) => {
@@ -3041,87 +3042,181 @@ const { program, createCommand, createArgument, createOption, CommanderError, In
3041
3042
 
3042
3043
  //#endregion
3043
3044
  //#region src/internal/utils.ts
3045
+ const TOOL_FORGE_BUILD_DIR = ".toolforge";
3046
+ const TOOL_FORGE_BUILD_BUNDLE_FILE = "tools-bundle.js";
3047
+ async function setupOutputDir(outDir, shouldClean = true) {
3048
+ if (shouldClean) await fs.rm(outDir, {
3049
+ recursive: true,
3050
+ force: true
3051
+ });
3052
+ if (!await fs.exists(outDir)) await fs.mkdir(outDir, { recursive: true });
3053
+ return outDir;
3054
+ }
3055
+ /**
3056
+ * Gather forge items from the specified directory.
3057
+ * In production mode, loads the bundled tools from the build directory.
3058
+ * In development mode, gathers tool and agent entries and bundles them using esbuild.
3059
+ */
3060
+ async function gatherForgeItems(toolsDir, mode, logger) {
3061
+ if (mode === "production") {
3062
+ const bundleFilePath = path.resolve(process.cwd(), TOOL_FORGE_BUILD_DIR, TOOL_FORGE_BUILD_BUNDLE_FILE);
3063
+ logger.debug("loading bundled tools from %s", bundleFilePath);
3064
+ if (!await fs.exists(bundleFilePath)) throw new Error(`tools bundle not found at ${bundleFilePath}, please build the tools before loading in production mode`);
3065
+ return await import(bundleFilePath);
3066
+ }
3067
+ const { forgeItems, toolEntries, agentEntries } = await gatherToolAndAgentEntries(toolsDir, mode, logger);
3068
+ if (forgeItems.length || toolEntries.length || agentEntries.length) return await import(`${await bundleForge({
3069
+ toolEntries,
3070
+ agentEntries,
3071
+ forgeItems,
3072
+ toolsDir,
3073
+ logger
3074
+ })}?t=${Date.now()}`);
3075
+ return {
3076
+ forgeItems: [],
3077
+ tools: {},
3078
+ agents: {}
3079
+ };
3080
+ }
3044
3081
  /**
3045
- * Recursively gather forge items from the specified directory.
3082
+ * Gather tool and agent entries from the specified directory.
3046
3083
  * Ignores files and directories starting with '-'.
3047
3084
  * Uses cache busting in development mode to ensure the latest version of tools are loaded.
3085
+ * Returns the gathered forge items along with tool and agent entries.
3086
+ *
3087
+ * A tool entry contains the variable name (camelCase of the tool ID), ID, and relative path to the tool file.
3088
+ * An agent entry contains the variable name (camelCase of the agent ID), ID, and relative path to the agent file.
3089
+ * forgeItems is an array of ForgeItem objects representing the tools, agents, and directories.
3048
3090
  */
3049
- async function gatherForgeItems(toolsDir, mode, logger) {
3091
+ async function gatherToolAndAgentEntries(toolsDir, mode, logger) {
3050
3092
  const forgeItems = [];
3051
- const tools = {};
3052
- const agents = {};
3093
+ const toolEntries = [];
3094
+ const agentEntries = [];
3053
3095
  const nodes = [{
3054
3096
  dir: toolsDir,
3055
3097
  depth: -1
3056
3098
  }];
3057
3099
  while (nodes.length) {
3058
3100
  const node = nodes.pop();
3059
- if (node.dir.startsWith("-")) {
3060
- logger.warn(`skipping ${node} as it starts with -`);
3061
- continue;
3062
- }
3063
- const content = await fs.readdir(node.dir);
3064
- for (const item of content) {
3065
- if (item.startsWith("-")) continue;
3066
- const itemPath = path.join(node.dir, item);
3067
- const stat = await fs.stat(itemPath);
3101
+ const children = await fs.readdir(node.dir, { withFileTypes: true });
3102
+ for (const child of children) {
3103
+ if (child.name.startsWith("-")) {
3104
+ logger.debug(`skipping ${child.name} as it starts with -`);
3105
+ continue;
3106
+ }
3107
+ const itemPath = path.join(node.dir, child.name);
3068
3108
  const parent = toolsDir === node.dir ? void 0 : kebabCase(path.relative(toolsDir, node.dir));
3069
- const id = kebabCase(path.relative(toolsDir, itemPath));
3070
- if (stat.isDirectory()) {
3109
+ const itemId = kebabCase(path.relative(toolsDir, itemPath));
3110
+ if (child.isDirectory()) {
3071
3111
  nodes.push({
3072
3112
  dir: itemPath,
3073
3113
  depth: node.depth + 1
3074
3114
  });
3075
3115
  forgeItems.push({
3076
- id,
3116
+ id: itemId,
3077
3117
  type: "DIRECTORY",
3078
- name: convertToWords(item).map(capitalize).join(" "),
3118
+ name: convertToWords(child.name).map(capitalize).join(" "),
3079
3119
  parent,
3080
3120
  depth: node.depth + 1
3081
3121
  });
3082
- } else if (stat.isFile() && itemPath.endsWith(".ts")) try {
3083
- const fileExports = await (mode === "development" ? import(`${itemPath}?t=${Date.now()}`) : import(itemPath));
3084
- if ("default" in fileExports) {
3122
+ } else if (child.isFile() && (child.name.endsWith(".ts") || child.name.endsWith(".js"))) {
3123
+ const importPath = mode === "development" ? `${itemPath}?t=${Date.now()}` : itemPath;
3124
+ const id = itemId.replace(/(-ts|-js)$/, "");
3125
+ const fileExports = await import(importPath);
3126
+ if ("default" in fileExports && typeof fileExports.default === "object") {
3085
3127
  const defaultExport = fileExports.default;
3086
- if (typeof defaultExport !== "object") {
3087
- logger.warn(`default export in ${itemPath} is not an object, skipping`);
3088
- continue;
3089
- }
3090
3128
  if (isToolDefinition(defaultExport)) {
3091
- const toolId = id.replace(/-ts$/, "");
3092
3129
  forgeItems.push({
3093
3130
  type: "TOOL",
3094
- id: toolId,
3131
+ id,
3095
3132
  name: defaultExport.name,
3096
3133
  description: defaultExport.description,
3097
3134
  parent,
3098
3135
  depth: node.depth + 1
3099
3136
  });
3100
- tools[toolId] = defaultExport;
3137
+ toolEntries.push({
3138
+ variableName: camelCase(id),
3139
+ id,
3140
+ relPath: path.relative(toolsDir, itemPath)
3141
+ });
3101
3142
  } else if (isAgentDefinition(defaultExport)) {
3102
- const agentId = id.replace(/-ts$/, "");
3103
3143
  forgeItems.push({
3104
3144
  type: "AGENT",
3105
- id: agentId,
3145
+ id,
3106
3146
  name: defaultExport.name,
3107
3147
  description: defaultExport.description,
3108
3148
  parent,
3109
3149
  depth: node.depth + 1
3110
3150
  });
3111
- agents[agentId] = defaultExport;
3151
+ agentEntries.push({
3152
+ variableName: camelCase(id),
3153
+ id,
3154
+ relPath: path.relative(toolsDir, itemPath)
3155
+ });
3112
3156
  } else logger.warn(`default export in ${itemPath} is not a valid Tool or Agent definition, skipping`);
3113
3157
  }
3114
- } catch (error) {
3115
- logger.warn({ error }, "failed to load tool from %s", itemPath);
3116
3158
  }
3117
3159
  }
3118
3160
  }
3119
3161
  return {
3120
3162
  forgeItems,
3121
- tools,
3122
- agents
3163
+ toolEntries,
3164
+ agentEntries
3123
3165
  };
3124
3166
  }
3167
+ /**
3168
+ * Bundle the provided tool and agent entries using esbuild.
3169
+ * Generates an entry file that imports all tools and agents and exports them as records.
3170
+ * Outputs the bundled file to the build directory.
3171
+ * Returns the imported bundle module.
3172
+ */
3173
+ async function bundleForge({ toolEntries, agentEntries, forgeItems, toolsDir, logger }) {
3174
+ if (toolEntries.length || agentEntries.length || forgeItems.length) {
3175
+ const entryFileContentGroups = [];
3176
+ if (toolEntries.length) {
3177
+ const toolImports = toolEntries.map(({ variableName, relPath }) => `import tool_${variableName} from './${relPath.replace(/(.ts|.js)$/, "")}'`).join("\n");
3178
+ entryFileContentGroups.push(toolImports);
3179
+ const toolsRecord = `export const tools: Record<string, ToolDefinition> = {
3180
+ ${toolEntries.map(({ variableName, id }) => ` '${id}': tool_${variableName},`).join("\n")}
3181
+ }`;
3182
+ entryFileContentGroups.push(toolsRecord);
3183
+ }
3184
+ if (agentEntries.length) {
3185
+ const agentImports = agentEntries.map(({ variableName, relPath }) => `import agent_${variableName} from './${relPath.replace(/(.ts|.js)$/, "")}'`).join("\n");
3186
+ entryFileContentGroups.push(agentImports);
3187
+ const agentsRecord = `export const agents: Record<string, AgentDefinition> = {
3188
+ ${agentEntries.map(({ variableName, id }) => ` '${id}': agent_${variableName},`).join("\n")}
3189
+ }`;
3190
+ entryFileContentGroups.push(agentsRecord);
3191
+ }
3192
+ if (forgeItems.length) {
3193
+ const forgeItemsRecord = `export const forgeItems: ForgeItem[] = ${JSON.stringify(forgeItems, null, 2)}`;
3194
+ entryFileContentGroups.push(forgeItemsRecord);
3195
+ }
3196
+ const entryFileContent = entryFileContentGroups.join("\n\n");
3197
+ logger.debug(`generate file content\n${"-".repeat(70)}\n%s\n${"-".repeat(70)}`, entryFileContent);
3198
+ const outDir = path.resolve(process.cwd(), TOOL_FORGE_BUILD_DIR);
3199
+ const bundleFilePath = path.resolve(outDir, TOOL_FORGE_BUILD_BUNDLE_FILE);
3200
+ logger.debug("bundling tools to %s", bundleFilePath);
3201
+ await setupOutputDir(outDir);
3202
+ logger.debug("ensured output directory exists at %s", outDir);
3203
+ logger.debug("starting esbuild bundling...");
3204
+ await esbuild.build({
3205
+ stdin: {
3206
+ contents: entryFileContent,
3207
+ resolveDir: toolsDir,
3208
+ loader: "ts"
3209
+ },
3210
+ bundle: true,
3211
+ platform: "node",
3212
+ outfile: bundleFilePath,
3213
+ logLevel: "error",
3214
+ format: "esm"
3215
+ });
3216
+ logger.debug("esbuild bundling completed");
3217
+ return bundleFilePath;
3218
+ }
3219
+ }
3125
3220
  function isToolDefinition(obj) {
3126
3221
  return "__tf__tag__name__" in obj && obj.__tf__tag__name__ === TOOL_TAG_NAME && "handler" in obj && typeof obj.handler === "function" && "__tf__tag__name__" in obj.handler && obj.handler.__tf__tag__name__ === TOOL_HANDLER_TAG_NAME;
3127
3222
  }
@@ -3737,6 +3832,35 @@ program.command("dev").option("-c, --config <path>", "path to the tool-forge con
3737
3832
  process.exit(1);
3738
3833
  }
3739
3834
  });
3835
+ program.command("build").description("build the tools for production").option("-c, --config <path>", "path to the tool-forge config file", "toolforge.config.ts").option("-d, --debug", "enable debug logging", false).action(async function() {
3836
+ const logger = pino({
3837
+ level: z$1.boolean().optional().default(false).parse(this.opts().debug) ? "debug" : "info",
3838
+ transport: { target: "pino-pretty" }
3839
+ });
3840
+ try {
3841
+ const configRelPath = z$1.string().parse(this.opts().config);
3842
+ const configPath = path.resolve(process.cwd(), configRelPath);
3843
+ const config = toolForgeConfigSchema.parse(await import(configPath).then((mod) => mod.default));
3844
+ logger.debug({ config }, "loaded config from %s", configPath);
3845
+ const toolsDir = path.resolve(process.cwd(), config.toolsDir);
3846
+ const { toolEntries, agentEntries, forgeItems } = await gatherToolAndAgentEntries(toolsDir, "production", logger);
3847
+ if (forgeItems.length === 0) {
3848
+ logger.warn("no tools or agents found to build");
3849
+ process.exit(0);
3850
+ }
3851
+ await bundleForge({
3852
+ toolEntries,
3853
+ agentEntries,
3854
+ forgeItems,
3855
+ toolsDir,
3856
+ logger
3857
+ });
3858
+ logger.info("tools built successfully");
3859
+ } catch (error) {
3860
+ logger.error(error, "failed to build tools");
3861
+ process.exit(1);
3862
+ }
3863
+ });
3740
3864
  program.parse(Bun.argv);
3741
3865
 
3742
3866
  //#endregion
@@ -1,4 +1,4 @@
1
- import { a as TOOL_TAG_NAME, i as TOOL_HANDLER_TAG_NAME, n as AGENT_TAG_NAME, t as AGENT_STEP_TAG_NAME } from "../agent-DBDnKm26.js";
1
+ import { a as AGENT_TAG_NAME, i as AGENT_STEP_TAG_NAME, n as TOOL_TAG_NAME, t as TOOL_HANDLER_TAG_NAME } from "../tool-UVAGtnlr.js";
2
2
 
3
3
  //#region src/components/tool.ts
4
4
  /**
@@ -1771,6 +1771,47 @@ const agentErrorMessageSchema = baseMessageSchema.extend({
1771
1771
  })
1772
1772
  });
1773
1773
 
1774
+ //#endregion
1775
+ //#region ../core/dist/utils.js
1776
+ function exponentialBackoff(attempt, initialDelay = 1e3, maxRetryDelay = 3e4, jitterFactor = .5, backoffMultiplier = 2) {
1777
+ let delay = initialDelay * Math.pow(backoffMultiplier, attempt - 1);
1778
+ const jitter = delay * jitterFactor * Math.random();
1779
+ delay += jitter;
1780
+ return Math.min(delay, maxRetryDelay);
1781
+ }
1782
+ function runWithRetries(fn, retries = 3, config = {}) {
1783
+ let attempt = 0;
1784
+ const execute = async () => {
1785
+ try {
1786
+ return await fn();
1787
+ } catch (error) {
1788
+ if (attempt < retries) {
1789
+ attempt++;
1790
+ await setTimeout(exponentialBackoff(attempt, config.initialDelayMs, config.maxDelayMs, config.backoffMultiplier));
1791
+ return execute();
1792
+ }
1793
+ throw error;
1794
+ }
1795
+ };
1796
+ return execute();
1797
+ }
1798
+
1799
+ //#endregion
1800
+ //#region src/lib/utils.ts
1801
+ function convertToWords(input) {
1802
+ if (input.includes("-") || input.includes("_")) return input.split(/[-_]+/).filter((word) => word.length > 0).map((word) => word.toLowerCase());
1803
+ return input.split(/(?=[A-Z])/).filter((word) => word.length > 0).map((word) => word.toLowerCase());
1804
+ }
1805
+ function invariant(cond, message) {
1806
+ if (!cond) throw new Error(message);
1807
+ }
1808
+ function getErrorMessage(error, defaultMessage = "Something went wrong. Please try again") {
1809
+ let errorMessage = defaultMessage;
1810
+ if (error instanceof z$1.ZodError) errorMessage = error.issues.length ? error.issues.map((e) => e.message).join(", ") : error.message;
1811
+ else if (error instanceof Error) errorMessage = error.message;
1812
+ return errorMessage;
1813
+ }
1814
+
1774
1815
  //#endregion
1775
1816
  //#region src/internal/block.ts
1776
1817
  var Block = class {
@@ -2002,47 +2043,6 @@ var Block = class {
2002
2043
  }
2003
2044
  };
2004
2045
 
2005
- //#endregion
2006
- //#region ../core/dist/utils.js
2007
- function exponentialBackoff(attempt, initialDelay = 1e3, maxRetryDelay = 3e4, jitterFactor = .5, backoffMultiplier = 2) {
2008
- let delay = initialDelay * Math.pow(backoffMultiplier, attempt - 1);
2009
- const jitter = delay * jitterFactor * Math.random();
2010
- delay += jitter;
2011
- return Math.min(delay, maxRetryDelay);
2012
- }
2013
- function runWithRetries(fn, retries = 3, config = {}) {
2014
- let attempt = 0;
2015
- const execute = async () => {
2016
- try {
2017
- return await fn();
2018
- } catch (error) {
2019
- if (attempt < retries) {
2020
- attempt++;
2021
- await setTimeout(exponentialBackoff(attempt, config.initialDelayMs, config.maxDelayMs, config.backoffMultiplier));
2022
- return execute();
2023
- }
2024
- throw error;
2025
- }
2026
- };
2027
- return execute();
2028
- }
2029
-
2030
- //#endregion
2031
- //#region src/lib/utils.ts
2032
- function convertToWords(input) {
2033
- if (input.includes("-") || input.includes("_")) return input.split(/[-_]+/).filter((word) => word.length > 0).map((word) => word.toLowerCase());
2034
- return input.split(/(?=[A-Z])/).filter((word) => word.length > 0).map((word) => word.toLowerCase());
2035
- }
2036
- function invariant(cond, message) {
2037
- if (!cond) throw new Error(message);
2038
- }
2039
- function getErrorMessage(error, defaultMessage = "Something went wrong. Please try again") {
2040
- let errorMessage = defaultMessage;
2041
- if (error instanceof z$1.ZodError) errorMessage = error.issues.length ? error.issues.map((e) => e.message).join(", ") : error.message;
2042
- else if (error instanceof Error) errorMessage = error.message;
2043
- return errorMessage;
2044
- }
2045
-
2046
2046
  //#endregion
2047
2047
  //#region src/internal/loader.ts
2048
2048
  var Loader = class {
@@ -2624,73 +2624,6 @@ var IO = class {
2624
2624
  }
2625
2625
  };
2626
2626
 
2627
- //#endregion
2628
- //#region src/internal/tool.ts
2629
- const TOOL_HANDLER_TAG_NAME = Symbol("TOOL_HANDLER");
2630
- const TOOL_TAG_NAME = Symbol("TOOL");
2631
- /**
2632
- * Tool class is responsible for running the tool's logic.
2633
- * It manages the tool lifecycle, communication with the worker, and handles sending messages back to the ForgeRunner.
2634
- * It uses the IO component to facilitate input/output operations for the tool.
2635
- */
2636
- var Tool = class {
2637
- #metadata;
2638
- #abortController = new AbortController();
2639
- #handler;
2640
- #io;
2641
- #block;
2642
- #logger;
2643
- constructor(options, logger) {
2644
- this.#metadata = options.metadata;
2645
- this.#handler = options.handler;
2646
- this.#logger = logger.child({
2647
- sessionId: this.#metadata.sessionId,
2648
- component: "TOOL"
2649
- });
2650
- this.#io = new IO({
2651
- sessionId: this.#metadata.sessionId,
2652
- runnerId: this.#metadata.runnerId,
2653
- webSocketClient: options.webSocketClient,
2654
- signal: this.#abortController.signal,
2655
- executionContext: { type: "TOOL" }
2656
- }, this.#logger);
2657
- this.#block = new Block({ signal: this.#abortController.signal });
2658
- this.#logger.debug("initialized Tool instance");
2659
- }
2660
- async run() {
2661
- return new Promise(async (resolve, reject) => {
2662
- if (this.#abortController.signal.aborted) {
2663
- this.#logger.info("tool execution aborted before start");
2664
- return Promise.reject(/* @__PURE__ */ new Error("tool execution aborted"));
2665
- }
2666
- this.#abortController.signal.addEventListener("abort", () => {
2667
- this.#logger.info("tool execution aborted");
2668
- reject(/* @__PURE__ */ new Error("Tool execution aborted"));
2669
- });
2670
- try {
2671
- this.#logger.info("running tool handler...");
2672
- const output = await this.#handler({
2673
- io: this.#io,
2674
- signal: this.#abortController.signal,
2675
- block: this.#block,
2676
- metadata: this.#metadata
2677
- });
2678
- this.#logger.info("tool handler completed successfully");
2679
- this.#io[STOP_SYMBOL]();
2680
- resolve(output);
2681
- } catch (error) {
2682
- this.#logger.error(error, "error running tool handler");
2683
- return reject(error);
2684
- }
2685
- });
2686
- }
2687
- stop() {
2688
- this.#logger.info("stopping Tool...");
2689
- this.#abortController.abort();
2690
- this.#logger.info("Tool stopped");
2691
- }
2692
- };
2693
-
2694
2627
  //#endregion
2695
2628
  //#region src/internal/workflow-builder.ts
2696
2629
  var WorkflowBuilder = class {
@@ -3090,4 +3023,71 @@ var Agent = class {
3090
3023
  };
3091
3024
 
3092
3025
  //#endregion
3093
- export { __toESM as C, __require as S, startAgentMessageSchema as _, TOOL_TAG_NAME as a, stopToolMessageSchema as b, getErrorMessage as c, runWithRetries as d, ackMessageSchema as f, runnerId as g, initCommunicationMessageSchema as h, TOOL_HANDLER_TAG_NAME as i, invariant as l, heartbeatAckMessageSchema as m, AGENT_TAG_NAME as n, Tool as o, baseMessageSchema as p, Agent as r, convertToWords as s, AGENT_STEP_TAG_NAME as t, exponentialBackoff as u, startToolMessageSchema as v, __commonJS as x, stopAgentMessageSchema as y };
3026
+ //#region src/internal/tool.ts
3027
+ const TOOL_HANDLER_TAG_NAME = Symbol("TOOL_HANDLER");
3028
+ const TOOL_TAG_NAME = Symbol("TOOL");
3029
+ /**
3030
+ * Tool class is responsible for running the tool's logic.
3031
+ * It manages the tool lifecycle, communication with the worker, and handles sending messages back to the ForgeRunner.
3032
+ * It uses the IO component to facilitate input/output operations for the tool.
3033
+ */
3034
+ var Tool = class {
3035
+ #metadata;
3036
+ #abortController = new AbortController();
3037
+ #handler;
3038
+ #io;
3039
+ #block;
3040
+ #logger;
3041
+ constructor(options, logger) {
3042
+ this.#metadata = options.metadata;
3043
+ this.#handler = options.handler;
3044
+ this.#logger = logger.child({
3045
+ sessionId: this.#metadata.sessionId,
3046
+ component: "TOOL"
3047
+ });
3048
+ this.#io = new IO({
3049
+ sessionId: this.#metadata.sessionId,
3050
+ runnerId: this.#metadata.runnerId,
3051
+ webSocketClient: options.webSocketClient,
3052
+ signal: this.#abortController.signal,
3053
+ executionContext: { type: "TOOL" }
3054
+ }, this.#logger);
3055
+ this.#block = new Block({ signal: this.#abortController.signal });
3056
+ this.#logger.debug("initialized Tool instance");
3057
+ }
3058
+ async run() {
3059
+ return new Promise(async (resolve, reject) => {
3060
+ if (this.#abortController.signal.aborted) {
3061
+ this.#logger.info("tool execution aborted before start");
3062
+ return Promise.reject(/* @__PURE__ */ new Error("tool execution aborted"));
3063
+ }
3064
+ this.#abortController.signal.addEventListener("abort", () => {
3065
+ this.#logger.info("tool execution aborted");
3066
+ reject(/* @__PURE__ */ new Error("Tool execution aborted"));
3067
+ });
3068
+ try {
3069
+ this.#logger.info("running tool handler...");
3070
+ const output = await this.#handler({
3071
+ io: this.#io,
3072
+ signal: this.#abortController.signal,
3073
+ block: this.#block,
3074
+ metadata: this.#metadata
3075
+ });
3076
+ this.#logger.info("tool handler completed successfully");
3077
+ this.#io[STOP_SYMBOL]();
3078
+ resolve(output);
3079
+ } catch (error) {
3080
+ this.#logger.error(error, "error running tool handler");
3081
+ return reject(error);
3082
+ }
3083
+ });
3084
+ }
3085
+ stop() {
3086
+ this.#logger.info("stopping Tool...");
3087
+ this.#abortController.abort();
3088
+ this.#logger.info("Tool stopped");
3089
+ }
3090
+ };
3091
+
3092
+ //#endregion
3093
+ export { __toESM as C, __require as S, startAgentMessageSchema as _, AGENT_TAG_NAME as a, stopToolMessageSchema as b, getErrorMessage as c, runWithRetries as d, ackMessageSchema as f, runnerId as g, initCommunicationMessageSchema as h, AGENT_STEP_TAG_NAME as i, invariant as l, heartbeatAckMessageSchema as m, TOOL_TAG_NAME as n, Agent as o, baseMessageSchema as p, Tool as r, convertToWords as s, TOOL_HANDLER_TAG_NAME as t, exponentialBackoff as u, startToolMessageSchema as v, __commonJS as x, stopAgentMessageSchema as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolforge-js/sdk",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -19,6 +19,7 @@
19
19
  "dependencies": {
20
20
  "chokidar": "4.0.3",
21
21
  "es-toolkit": "1.39.10",
22
+ "esbuild": "0.27.0",
22
23
  "nanoid": "5.1.5",
23
24
  "picocolors": "1.1.1",
24
25
  "pino": "9.11.0",