@toolforge-js/sdk 0.8.3 → 0.8.5

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,10 +1,10 @@
1
- import { C as __toESM, S as __require, _ as stopToolMessageSchema, a as AGENT_TAG_NAME, b as invariant, c as runWithRetries, d as heartbeatAckMessageSchema, f as initCommunicationMessageSchema, g as stopAgentMessageSchema, h as startToolMessageSchema, i as AGENT_STEP_TAG_NAME, l as ackMessageSchema, m as startAgentMessageSchema, n as TOOL_TAG_NAME, o as Agent, p as runnerId, r as Tool, s as exponentialBackoff, t as TOOL_HANDLER_TAG_NAME, u as baseMessageSchema, v as convertToWords, x as __commonJS, y as getErrorMessage } from "../tool-DDDEH8M3.js";
2
- import { n as toolForgeConfigSchema, t as TF_CONFIG_TAG_NAME } from "../config-schema-V_1JIDL9.js";
3
- import * as z$1 from "zod";
4
- import z from "zod";
1
+ import { C as __toESM, S as __require, _ as stopToolMessageSchema, a as AGENT_TAG_NAME, b as invariant, c as runWithRetries, d as heartbeatAckMessageSchema, f as initCommunicationMessageSchema, g as stopAgentMessageSchema, h as startToolMessageSchema, i as AGENT_STEP_TAG_NAME, l as ackMessageSchema, m as startAgentMessageSchema, n as TOOL_TAG_NAME, o as Agent, p as runnerId, r as Tool, s as exponentialBackoff, t as TOOL_HANDLER_TAG_NAME, u as baseMessageSchema, v as convertToWords, x as __commonJS, y as getErrorMessage } from "../tool-BHVNhWPh.js";
2
+ import { r as toolForgeConfigSchema } from "../config-schema-D6ZIesbW.js";
5
3
  import { createReadStream, readFileSync } from "node:fs";
6
4
  import * as path from "node:path";
7
5
  import { EventEmitter } from "node:events";
6
+ import * as z$1 from "zod";
7
+ import z from "zod";
8
8
  import ora from "ora";
9
9
  import { pino } from "pino";
10
10
  import * as crypto from "node:crypto";
@@ -3284,7 +3284,7 @@ async function getToolForgeConfig(configRelPath) {
3284
3284
  try {
3285
3285
  const configPath = path.resolve(process.cwd(), configRelPath);
3286
3286
  return {
3287
- config: toolForgeConfigSchema.extend({ __tf__tag__name__: z$1.symbol(TF_CONFIG_TAG_NAME.description) }).parse(await import(configPath).then((mod) => mod.default)),
3287
+ config: toolForgeConfigSchema.parse(await import(configPath).then((mod) => mod.default)),
3288
3288
  configPath
3289
3289
  };
3290
3290
  } catch (error) {
@@ -3692,7 +3692,6 @@ function getDeviceLabel() {
3692
3692
  //#endregion
3693
3693
  //#region ../core/dist/token/index.js
3694
3694
  const TOKEN_PREFIX = "tf_token--";
3695
- const TOOL_FORGE_TOKEN_FILE = "TOOL_FORGE_TOKEN_FILE";
3696
3695
 
3697
3696
  //#endregion
3698
3697
  //#region src/internal/websocket-client.ts
@@ -3990,13 +3989,22 @@ var WebSocketClient = class extends EventEmitter {
3990
3989
 
3991
3990
  //#endregion
3992
3991
  //#region src/internal/forge-runner.ts
3992
+ /**
3993
+ * ForgeRunner should start with apiKey
3994
+ */
3993
3995
  const toForgeRunnerMessages = z$1.discriminatedUnion("type", [
3994
3996
  startToolMessageSchema,
3995
3997
  stopToolMessageSchema,
3996
3998
  startAgentMessageSchema,
3997
3999
  stopAgentMessageSchema
3998
4000
  ]);
3999
- const optionsSchema = z$1.object({ mode: z$1.enum(["development", "production"]) });
4001
+ const optionsSchema = z$1.object({
4002
+ mode: z$1.enum(["development", "production"]),
4003
+ apiKey: z$1.string().refine((val) => val.startsWith("sk_live") || val.startsWith("pk_test") || val.startsWith(TOKEN_PREFIX)),
4004
+ tokenProviderEndpoint: z$1.url().optional(),
4005
+ sdkServerUrl: z$1.url(),
4006
+ toolsDir: z$1.string()
4007
+ });
4000
4008
  /**
4001
4009
  * ForgeRunner manages the lifecycle of tools or agents, including discovery, loading, and communication with the SDK server.
4002
4010
  *
@@ -4007,9 +4015,8 @@ var ForgeRunner = class extends EventEmitter {
4007
4015
  #id = `tf-runner:${nanoid(32)}`;
4008
4016
  #options;
4009
4017
  #logger;
4010
- #config;
4011
- #serverUrl;
4012
4018
  #apiKey;
4019
+ #sdkServerUrl;
4013
4020
  #refreshApiKeyInterval;
4014
4021
  #forgeItems = [];
4015
4022
  #tools = {};
@@ -4019,32 +4026,22 @@ var ForgeRunner = class extends EventEmitter {
4019
4026
  #fsWatcher;
4020
4027
  #sessionTools = /* @__PURE__ */ new Map();
4021
4028
  #sessionAgents = /* @__PURE__ */ new Map();
4022
- constructor(config, options, logger) {
4029
+ constructor(options, logger) {
4023
4030
  super({ captureRejections: true });
4024
- this.#config = config;
4025
- if (typeof config.apiKey === "string") this.#apiKey = config.apiKey;
4026
- else if (typeof process.env[TOOL_FORGE_TOKEN_FILE] === "string") {
4027
- const token = readFileSync(process.env[TOOL_FORGE_TOKEN_FILE], "utf-8").trim();
4028
- if (!token.startsWith(TOKEN_PREFIX)) throw new Error(`API key in ${process.env[TOOL_FORGE_TOKEN_FILE]} is invalid`);
4029
- this.#apiKey = token;
4030
- } else throw new Error("API key is required to initialize ForgeRunner");
4031
- const url = new URL(this.#config.sdkServer);
4031
+ this.#options = optionsSchema.parse(options);
4032
+ this.#logger = logger.child({ id: this.#id });
4033
+ this.#apiKey = this.#options.apiKey;
4034
+ if (this.#apiKey.startsWith(TOKEN_PREFIX)) this.#refreshApiKeyInterval = setInterval(this.#refreshApiKey.bind(this), 840 * 1e3);
4035
+ const url = new URL(this.#options.sdkServerUrl);
4032
4036
  url.searchParams.set("apiKey", this.#apiKey);
4033
4037
  url.searchParams.set("runnerId", this.#id);
4034
4038
  url.pathname = "/socket";
4035
- this.#serverUrl = url.toString();
4036
- this.#options = optionsSchema.parse(options);
4037
- this.#logger = logger.child({ id: this.#id });
4039
+ this.#sdkServerUrl = url.toString();
4038
4040
  this.#webSocketClient = new WebSocketClient({
4039
- serverUrl: this.#serverUrl,
4041
+ serverUrl: this.#sdkServerUrl,
4040
4042
  runnerId: this.#id
4041
4043
  }, this, this.#logger);
4042
4044
  this.#webSocketClient.on(WEB_SOCKET_CLIENT_EVENTS.COMMUNICATION_INITIALIZED, this.#handleWebSocketCommunicationInitialized.bind(this));
4043
- if (this.#apiKey.startsWith(TOKEN_PREFIX)) this.#refreshApiKeyInterval = setInterval(this.#refreshApiKey.bind(this), 840 * 1e3);
4044
- this.#logger.info({
4045
- mode: this.#options.mode,
4046
- id: this.#id
4047
- }, "created tool runner");
4048
4045
  this.#start();
4049
4046
  }
4050
4047
  get activeSessionsCount() {
@@ -4053,7 +4050,7 @@ var ForgeRunner = class extends EventEmitter {
4053
4050
  async #start() {
4054
4051
  try {
4055
4052
  this.#logger.debug("gathering tools...");
4056
- const { forgeItems, tools, agents } = await gatherForgeItems(path.resolve(process.cwd(), this.#config.toolsDir), this.#options.mode, this.#logger);
4053
+ const { forgeItems, tools, agents } = await gatherForgeItems(path.resolve(process.cwd(), this.#options.toolsDir), this.#options.mode, this.#logger);
4057
4054
  this.#forgeItems = forgeItems;
4058
4055
  this.#tools = tools;
4059
4056
  this.#agents = agents;
@@ -4089,7 +4086,6 @@ var ForgeRunner = class extends EventEmitter {
4089
4086
  */
4090
4087
  async #handleStartToolMessage(message) {
4091
4088
  this.#logger.debug({ message }, "received start tool message");
4092
- if (!this.#config) throw new Error("config should be initialized before starting tool");
4093
4089
  const { sessionId, itemId } = message.data;
4094
4090
  const toolDefinition = this.#tools[itemId];
4095
4091
  if (!toolDefinition) {
@@ -4146,7 +4142,7 @@ var ForgeRunner = class extends EventEmitter {
4146
4142
  this.#sessionTools.delete(sessionId);
4147
4143
  }
4148
4144
  #watchToolChanges() {
4149
- const resolvedToolsDir = path.resolve(process.cwd(), this.#config.toolsDir);
4145
+ const resolvedToolsDir = path.resolve(process.cwd(), this.#options.toolsDir);
4150
4146
  this.#fsWatcher = chokidar.watch(resolvedToolsDir, {
4151
4147
  ignored: /(^|[/\\])\../,
4152
4148
  persistent: true,
@@ -4162,7 +4158,7 @@ var ForgeRunner = class extends EventEmitter {
4162
4158
  }).otherwise(() => picocolors.blue("tools changed"));
4163
4159
  this.#logger.info(`${message}, reloading server...`);
4164
4160
  try {
4165
- const { forgeItems, tools, agents } = await gatherForgeItems(path.resolve(process.cwd(), this.#config.toolsDir), this.#options.mode, this.#logger);
4161
+ const { forgeItems, tools, agents } = await gatherForgeItems(path.resolve(process.cwd(), this.#options.toolsDir), this.#options.mode, this.#logger);
4166
4162
  this.#forgeItems = forgeItems;
4167
4163
  this.#tools = tools;
4168
4164
  this.#agents = agents;
@@ -4185,7 +4181,6 @@ var ForgeRunner = class extends EventEmitter {
4185
4181
  }
4186
4182
  #handleStartAgentMessage(message) {
4187
4183
  this.#logger.debug({ message }, "received start agent message");
4188
- if (!this.#config) throw new Error("config should be initialized before starting agent");
4189
4184
  const { sessionId, itemId } = message.data;
4190
4185
  const agentDefinition = this.#agents[itemId];
4191
4186
  if (!agentDefinition) {
@@ -4227,16 +4222,25 @@ var ForgeRunner = class extends EventEmitter {
4227
4222
  this.#sessionAgents.delete(sessionId);
4228
4223
  });
4229
4224
  }
4230
- #handleStopAgentMessage(message) {}
4225
+ #handleStopAgentMessage(message) {
4226
+ this.#logger.debug({ message }, "received stop agent message");
4227
+ const { sessionId } = message.data;
4228
+ const agent = this.#sessionAgents.get(sessionId);
4229
+ if (!agent) {
4230
+ this.#logger.warn("received stop agent message for unknown session id %s, ignoring", sessionId);
4231
+ return;
4232
+ }
4233
+ agent.stop();
4234
+ this.#sessionTools.delete(sessionId);
4235
+ }
4231
4236
  /**
4232
4237
  * Refreshes the API key by requesting a new token from the SDK server,
4233
4238
  * when the apiKey is a (short lived) token used when runner is deployed
4234
4239
  * using Tool Forge Cloud.
4235
4240
  */
4236
4241
  async #refreshApiKey() {
4237
- const url = new URL(this.#serverUrl);
4238
- url.pathname = "/token/refresh";
4239
- const res = await fetch(url.toString(), {
4242
+ if (!this.#options.tokenProviderEndpoint) return;
4243
+ const res = await fetch(new URL("/token/refresh", this.#options.tokenProviderEndpoint), {
4240
4244
  method: "POST",
4241
4245
  headers: { "Content-Type": "application/json" },
4242
4246
  body: JSON.stringify({ token: this.#apiKey })
@@ -4274,16 +4278,36 @@ var ForgeRunner = class extends EventEmitter {
4274
4278
  //#endregion
4275
4279
  //#region src/cli/actions/start-tool-forge.ts
4276
4280
  async function startToolForge({ configRelPath, debug, mode }) {
4277
- const logger = pino({
4278
- level: debug ? "debug" : "info",
4279
- transport: { target: "pino-pretty" }
4280
- });
4281
+ const logger = pino({ level: debug ? "debug" : "info" });
4281
4282
  try {
4282
4283
  const spinner = ora("loading configuration...").start();
4283
4284
  const { config, configPath } = await getToolForgeConfig(configRelPath);
4284
4285
  spinner.stop();
4285
4286
  logger.debug({ config }, "loaded config from %s", configPath);
4286
- const runner = new ForgeRunner(config, { mode }, logger);
4287
+ const sdkServerUrl = z$1.url().parse(process.env.SDK_SERVER_URL);
4288
+ let apiKey;
4289
+ if (config.apiKey) apiKey = config.apiKey;
4290
+ else {
4291
+ const parsed = z$1.url().safeParse(process.env.TOKEN_PROVIDER_ENDPOINT);
4292
+ if (!parsed.success) throw new Error("either provide apiKey in config, or set the TOKEN_PROVIDER_ENDPOINT");
4293
+ logger.debug("generating token");
4294
+ apiKey = await fetch(new URL("/token/generate", parsed.data), { method: "POST" }).then((res) => res.json()).then((data) => {
4295
+ const parsed$1 = z$1.object({ token: z$1.string() }).safeParse(data);
4296
+ if (!parsed$1.success) throw new Error("invalid token");
4297
+ return parsed$1.data.token;
4298
+ }).catch((error) => {
4299
+ logger.error(error, "error fetching token from TOKEN_PROVIDER_ENDPOINT");
4300
+ throw error;
4301
+ });
4302
+ logger.debug("token generated");
4303
+ }
4304
+ invariant(!!apiKey, "apiKey should be present");
4305
+ const runner = new ForgeRunner({
4306
+ mode,
4307
+ apiKey,
4308
+ sdkServerUrl,
4309
+ toolsDir: config.toolsDir
4310
+ }, logger);
4287
4311
  runner.on("error", async (error) => {
4288
4312
  logger.error(error, "tool runner error - shutting down");
4289
4313
  await runner.stop();
@@ -1,5 +1,5 @@
1
- import * as z$1 from "zod";
2
1
  import { EventEmitter } from "node:events";
2
+ import * as z$1 from "zod";
3
3
  import { Logger } from "pino";
4
4
  import * as better_auth0 from "better-auth";
5
5
 
@@ -6083,21 +6083,18 @@ declare class Block {
6083
6083
  };
6084
6084
  }
6085
6085
  //#endregion
6086
- //#region src/config/config-schema.d.ts
6087
- declare const toolForgeConfigSchema: z$1.ZodObject<{
6088
- toolsDir: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodString>>;
6089
- apiKey: z$1.ZodOptional<z$1.ZodString>;
6090
- sdkServer: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodURL>>;
6091
- appServerUrl: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodURL>>;
6092
- appUrl: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodURL>>;
6093
- maxRetries: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodNumber>>;
6094
- }, z$1.core.$strip>;
6095
- type ToolForgeConfig = z$1.infer<typeof toolForgeConfigSchema>;
6096
- //#endregion
6097
6086
  //#region src/internal/forge-runner.d.ts
6098
6087
  type ForgeRunnerOptions = {
6099
6088
  /** Runtime mode for the tool runner. In the development mode, more verbose logging is enabled and tools are automatically reloaded on changes. */
6100
6089
  mode: 'development' | 'production';
6090
+ /** API key */
6091
+ apiKey: string;
6092
+ /** Endpoint to refresh the short term token. If the apiKey is the format of tf_token--****, then ForgeRunner needs to refresh the token before expiration. */
6093
+ tokenProviderEndpoint?: string;
6094
+ /** SDK Server endpoint */
6095
+ sdkServerUrl: string;
6096
+ /** Path to the directory containing tools */
6097
+ toolsDir: string;
6101
6098
  };
6102
6099
  /**
6103
6100
  * ForgeRunner manages the lifecycle of tools or agents, including discovery, loading, and communication with the SDK server.
@@ -6107,7 +6104,7 @@ type ForgeRunnerOptions = {
6107
6104
  */
6108
6105
  declare class ForgeRunner extends EventEmitter {
6109
6106
  #private;
6110
- constructor(config: ToolForgeConfig, options: ForgeRunnerOptions, logger: Logger);
6107
+ constructor(options: ForgeRunnerOptions, logger: Logger);
6111
6108
  get activeSessionsCount(): number;
6112
6109
  stop(): void;
6113
6110
  }
@@ -1,4 +1,4 @@
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-DDDEH8M3.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-BHVNhWPh.js";
2
2
 
3
3
  //#region src/components/tool.ts
4
4
  /**
@@ -8,12 +8,6 @@ type ToolForgeConfig = {
8
8
  * Get your API key from the Tool Forge environment dashboard.
9
9
  */
10
10
  apiKey?: string;
11
- /** Optional URL for the SDK server (overrides default). */
12
- sdkServer?: string;
13
- /** Optional URL for the Tool Forge app server (overrides default). */
14
- appServerUrl?: string;
15
- /** Optional URL for the Tool Forge app (overrides default). */
16
- appUrl?: string;
17
11
  };
18
12
  /**
19
13
  * Define and validate Tool Forge SDK configuration.
@@ -21,10 +15,10 @@ type ToolForgeConfig = {
21
15
  * @param config - The configuration object for Tool Forge SDK.
22
16
  */
23
17
  declare function defineConfig(input: ToolForgeConfig): {
24
- toolsDir: string;
25
- sdkServer: string;
18
+ sdkServerUrl: string;
26
19
  appServerUrl: string;
27
20
  appUrl: string;
21
+ toolsDir: string;
28
22
  maxRetries: number;
29
23
  apiKey?: string | undefined;
30
24
  __tf__tag__name__: symbol;
@@ -1,4 +1,5 @@
1
- import { n as toolForgeConfigSchema, t as TF_CONFIG_TAG_NAME } from "../config-schema-V_1JIDL9.js";
1
+ import { i as urlConfigSchema, n as baseConfigSchema, t as TF_CONFIG_TAG_NAME } from "../config-schema-D6ZIesbW.js";
2
+ import * as z$1 from "zod";
2
3
 
3
4
  //#region src/config/index.ts
4
5
  /**
@@ -7,9 +8,24 @@ import { n as toolForgeConfigSchema, t as TF_CONFIG_TAG_NAME } from "../config-s
7
8
  * @param config - The configuration object for Tool Forge SDK.
8
9
  */
9
10
  function defineConfig(input) {
11
+ const parsedInput = baseConfigSchema.safeParse(input);
12
+ if (!parsedInput.success) {
13
+ const { errors } = z$1.treeifyError(parsedInput.error);
14
+ throw new Error(`invalid input. ${errors.join(", ")}`);
15
+ }
16
+ const parsedUrls = urlConfigSchema.safeParse({
17
+ sdkServerUrl: process.env.SDK_SERVER_URL,
18
+ appServerUrl: process.env.APP_SERVER_URL,
19
+ appUrl: process.env.APP_URL
20
+ });
21
+ if (!parsedUrls.success) {
22
+ const { errors } = z$1.treeifyError(parsedUrls.error);
23
+ throw new Error(`invalid urls. ${errors.join(", ")}`);
24
+ }
10
25
  return {
11
26
  __tf__tag__name__: TF_CONFIG_TAG_NAME,
12
- ...toolForgeConfigSchema.parse(input)
27
+ ...parsedInput.data,
28
+ ...parsedUrls.data
13
29
  };
14
30
  }
15
31
 
@@ -1,15 +1,18 @@
1
1
  import * as z$1 from "zod";
2
2
 
3
3
  //#region src/config/config-schema.ts
4
- const toolForgeConfigSchema = z$1.object({
4
+ const urlConfigSchema = z$1.object({
5
+ sdkServerUrl: z$1.url().describe("URL of the Tool Forge SDK server").optional().default("https://sdk.tool-forge.ai"),
6
+ appServerUrl: z$1.url().optional().describe("URL of the Tool Forge application server").default("https://api.tool-forge.ai"),
7
+ appUrl: z$1.url().optional().describe("URL of the Tool Forge application").default("https://app.tool-forge.ai")
8
+ });
9
+ const baseConfigSchema = z$1.object({
5
10
  toolsDir: z$1.string().describe("Directory where the tools are located").optional().default("tools"),
6
11
  apiKey: z$1.string().describe("API key for authenticating with the Tool Forge platform").refine((val) => val.startsWith("sk_live") || val.startsWith("pk_test"), { message: "API key must start with sk_live, pk_test" }).describe("API key for authenticating with the Tool Forge platform.").optional(),
7
- sdkServer: z$1.url().describe("URL of the Tool Forge SDK server").optional().default("https://sdk.tool-forge.ai"),
8
- appServerUrl: z$1.url().optional().describe("URL of the Tool Forge application server").default("https://api.tool-forge.ai"),
9
- appUrl: z$1.url().optional().describe("URL of the Tool Forge application").default("https://app.tool-forge.ai"),
10
12
  maxRetries: z$1.number().optional().default(100)
11
13
  });
12
14
  const TF_CONFIG_TAG_NAME = Symbol("TOOL_FORGE_CONFIG");
15
+ const toolForgeConfigSchema = baseConfigSchema.and(urlConfigSchema).and(z$1.object({ __tf__tag__name__: z$1.symbol(TF_CONFIG_TAG_NAME.description) }));
13
16
 
14
17
  //#endregion
15
- export { toolForgeConfigSchema as n, TF_CONFIG_TAG_NAME as t };
18
+ export { urlConfigSchema as i, baseConfigSchema as n, toolForgeConfigSchema as r, TF_CONFIG_TAG_NAME as t };
@@ -2915,6 +2915,11 @@ var Agent = class {
2915
2915
  }
2916
2916
  return this.#context;
2917
2917
  }
2918
+ stop() {
2919
+ this.#logger.info("stopping agent...");
2920
+ this.#abortController.abort();
2921
+ this.#logger.info("Agent stopped");
2922
+ }
2918
2923
  async #executeSteps(stepsToExecute) {
2919
2924
  const stepDefinitions = stepsToExecute.filter((stepName) => stepName !== "START" && stepName !== "END").map((stepName) => {
2920
2925
  const stepDef = this.#stepDefinitions[stepName];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolforge-js/sdk",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",