@orkestrel/tool 0.0.19 → 0.0.20

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.
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _orkestrel_contract = require("@orkestrel/contract");
3
3
  let _orkestrel_emitter = require("@orkestrel/emitter");
4
- //#region src/core/errors.ts
4
+ // src/core/errors.ts
5
5
  /**
6
6
  * Reports a schema conflict or argument validation failure with a machine-readable code.
7
7
  *
@@ -19,6 +19,7 @@ var ToolError = class extends Error {
19
19
  context;
20
20
  constructor(code, message, context) {
21
21
  super(message);
22
+ _orkestrel_contract.INTRINSICS.define(this, Symbol.for("@orkestrel/tool.ToolError"), { value: this });
22
23
  this.code = code;
23
24
  if (context !== void 0) this.context = context;
24
25
  }
@@ -26,6 +27,10 @@ var ToolError = class extends Error {
26
27
  /**
27
28
  * Checks whether a value is a tool error, containing hostile prototype access.
28
29
  *
30
+ * @remarks
31
+ * Recognizes self-branded errors across package copies and subclasses and refuses
32
+ * transparent proxies. Validates the declared code and optional fault report.
33
+ *
29
34
  * @param value - The value to test
30
35
  * @returns True if the value is an instance of the tool error class; false otherwise
31
36
  *
@@ -38,10 +43,47 @@ var ToolError = class extends Error {
38
43
  * ```
39
44
  */
40
45
  function isToolError(value) {
41
- return (0, _orkestrel_contract.isInstance)(value, ToolError);
46
+ return (0, _orkestrel_contract.holds)(() => {
47
+ if (!(value instanceof Error) || _orkestrel_contract.INTRINSICS.prototype(value) === Error.prototype) return false;
48
+ if (_orkestrel_contract.INTRINSICS.describe(value, Symbol.for("@orkestrel/tool.ToolError"))?.value !== value) return false;
49
+ const code = _orkestrel_contract.INTRINSICS.reflect.read(value, "code");
50
+ if (code !== "SCHEMA" && code !== "ARGUMENTS") return false;
51
+ const context = _orkestrel_contract.INTRINSICS.reflect.read(value, "context");
52
+ if (context === void 0) return true;
53
+ if (!(0, _orkestrel_contract.isObject)(context) && !(0, _orkestrel_contract.isFunction)(context)) return false;
54
+ const faults = _orkestrel_contract.INTRINSICS.reflect.read(context, "faults");
55
+ if (faults === void 0) return true;
56
+ return (0, _orkestrel_contract.arrayOf)((fault) => {
57
+ if (!(0, _orkestrel_contract.isObject)(fault)) return false;
58
+ const path = _orkestrel_contract.INTRINSICS.reflect.read(fault, "path");
59
+ if (!(0, _orkestrel_contract.isString)(path) && !(0, _orkestrel_contract.arrayOf)(_orkestrel_contract.isString)(path)) return false;
60
+ const reason = _orkestrel_contract.INTRINSICS.reflect.read(fault, "reason");
61
+ if (reason === "variant") return typeof _orkestrel_contract.INTRINSICS.reflect.read(fault, "variants") === "number";
62
+ if (reason === "oneOf") return typeof _orkestrel_contract.INTRINSICS.reflect.read(fault, "matched") === "number";
63
+ const expected = _orkestrel_contract.INTRINSICS.reflect.read(fault, "expected");
64
+ if (![
65
+ "string",
66
+ "number",
67
+ "integer",
68
+ "boolean",
69
+ "null",
70
+ "literal",
71
+ "array",
72
+ "object",
73
+ "union",
74
+ "json"
75
+ ].some((candidate) => candidate === expected)) return false;
76
+ if (reason === "missing") return true;
77
+ if (!(0, _orkestrel_contract.isString)(_orkestrel_contract.INTRINSICS.reflect.read(fault, "received"))) return false;
78
+ if (reason === "type") return true;
79
+ if (reason !== "constraint") return false;
80
+ const constraint = _orkestrel_contract.INTRINSICS.reflect.read(fault, "constraint");
81
+ const limit = _orkestrel_contract.INTRINSICS.reflect.read(fault, "limit");
82
+ return (constraint === "min" || constraint === "max" || constraint === "pattern" || constraint === "integer") && (limit === void 0 || typeof limit === "number" || typeof limit === "string");
83
+ })(faults);
84
+ });
42
85
  }
43
- //#endregion
44
- //#region src/core/validators.ts
86
+ // src/core/validators.ts
45
87
  /**
46
88
  * Determines whether an unknown value is structurally a {@link ToolCall}, staying total
47
89
  * for malformed and adversarial input.
@@ -64,8 +106,7 @@ function isToolError(value) {
64
106
  function isToolCall(value) {
65
107
  return (0, _orkestrel_contract.holds)(() => (0, _orkestrel_contract.isRecord)(value) && (0, _orkestrel_contract.isString)(value.id) && (0, _orkestrel_contract.isString)(value.name) && (0, _orkestrel_contract.isRecord)(value.arguments));
66
108
  }
67
- //#endregion
68
- //#region src/core/helpers.ts
109
+ // src/core/helpers.ts
69
110
  /**
70
111
  * Projects a tool onto the plain definition advertised to a caller, advertising an
71
112
  * authored `summary` in place of the full description and carrying `parameters` and
@@ -97,8 +138,7 @@ function toolToDefinition(tool) {
97
138
  ...tool.annotations === void 0 ? {} : { annotations: tool.annotations }
98
139
  };
99
140
  }
100
- //#endregion
101
- //#region src/core/tools/Tool.ts
141
+ // src/core/tools/Tool.ts
102
142
  /**
103
143
  * Binds an executable tool definition to a handler.
104
144
  *
@@ -151,16 +191,15 @@ var Tool = class {
151
191
  execute(args, context) {
152
192
  const faults = this.#contract?.explain(args) ?? [];
153
193
  const fault = faults[0];
154
- if (fault !== void 0) {
155
- let message = `${(0, _orkestrel_contract.isString)(fault.path) ? fault.path : fault.path.join(".")}: ${fault.reason}`;
156
- if ("expected" in fault) message += `; expected ${fault.expected}`;
157
- if ("received" in fault) message += `; received ${fault.received}`;
158
- if ("constraint" in fault) message += `; constraint ${fault.constraint}`;
159
- if ("limit" in fault && fault.limit !== void 0) message += `; limit ${fault.limit}`;
160
- if ("variants" in fault) message += `; variants ${fault.variants}`;
161
- if ("matched" in fault) message += `; matched ${fault.matched}`;
162
- throw new ToolError("ARGUMENTS", message, { faults });
163
- }
194
+ if (fault !== void 0) throw new ToolError("ARGUMENTS", [
195
+ `${(0, _orkestrel_contract.isString)(fault.path) ? fault.path : fault.path.join(".")}: ${fault.reason}`,
196
+ ..."expected" in fault ? [`expected ${fault.expected}`] : [],
197
+ ..."received" in fault ? [`received ${fault.received}`] : [],
198
+ ..."constraint" in fault ? [`constraint ${fault.constraint}`] : [],
199
+ ..."limit" in fault && fault.limit !== void 0 ? [`limit ${fault.limit}`] : [],
200
+ ..."variants" in fault ? [`variants ${fault.variants}`] : [],
201
+ ..."matched" in fault ? [`matched ${fault.matched}`] : []
202
+ ].join("; "), { faults });
164
203
  if (this.#contract !== void 0) {
165
204
  const parsed = this.#contract.parse(args);
166
205
  if (!(0, _orkestrel_contract.isRecord)(parsed)) throw new ToolError("ARGUMENTS", "Arguments did not parse");
@@ -169,8 +208,7 @@ var Tool = class {
169
208
  return this.#execute(args, context);
170
209
  }
171
210
  };
172
- //#endregion
173
- //#region src/core/tools/ToolManager.ts
211
+ // src/core/tools/ToolManager.ts
174
212
  /**
175
213
  * Represents an insertion-ordered tool registry with per-call error isolation.
176
214
  *
@@ -237,11 +275,7 @@ var ToolManager = class {
237
275
  return this.#run(call, context);
238
276
  }
239
277
  remove(names) {
240
- if ((0, _orkestrel_contract.isArray)(names)) {
241
- let removed = true;
242
- for (const name of names) if (!this.remove(name)) removed = false;
243
- return removed;
244
- }
278
+ if ((0, _orkestrel_contract.isArray)(names)) return this.#remove(names).reduce((all, removed) => removed && all, true);
245
279
  const tool = this.#tools.get(names);
246
280
  if (tool === void 0) return false;
247
281
  this.#tools.delete(names);
@@ -258,6 +292,9 @@ var ToolManager = class {
258
292
  this.#emitter.destroy();
259
293
  this.#tools.clear();
260
294
  }
295
+ *#remove(names) {
296
+ for (const name of names) yield this.remove(name);
297
+ }
261
298
  async #run(call, context) {
262
299
  const tool = this.#tools.get(call.name);
263
300
  if (tool === void 0) return {
@@ -294,8 +331,7 @@ var ToolManager = class {
294
331
  }
295
332
  }
296
333
  };
297
- //#endregion
298
- //#region src/core/factories.ts
334
+ // src/core/factories.ts
299
335
  /**
300
336
  * Creates an executable tool bound to the supplied handler, returned as a
301
337
  * `ToolInterface` so a call site holds the published contract rather than the `Tool`
@@ -351,7 +387,6 @@ function createTool(options) {
351
387
  function createToolManager(options) {
352
388
  return new ToolManager(options);
353
389
  }
354
- //#endregion
355
390
  exports.Tool = Tool;
356
391
  exports.ToolError = ToolError;
357
392
  exports.ToolManager = ToolManager;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["isInstance","holds","isRecord","isString","createContract","schemaToParameters","isString","isRecord","Emitter","isArray","attempt","isError"],"sources":["../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/tools/Tool.ts","../../../src/core/tools/ToolManager.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { ToolErrorCode, ToolErrorContext } from './types.js'\nimport { isInstance } from '@orkestrel/contract'\n\n/**\n * Reports a schema conflict or argument validation failure with a machine-readable code.\n *\n * @example\n * ```ts\n * import { ToolError } from '@orkestrel/tool'\n *\n * const error = new ToolError('SCHEMA', 'Choose contract or parameters')\n * error.code // 'SCHEMA'\n * ```\n */\nexport class ToolError extends Error {\n\toverride readonly name = 'ToolError' as const\n\treadonly code: ToolErrorCode\n\treadonly context?: ToolErrorContext\n\n\tconstructor(code: ToolErrorCode, message: string, context?: ToolErrorContext) {\n\t\tsuper(message)\n\t\tthis.code = code\n\t\tif (context !== undefined) this.context = context\n\t}\n}\n\n/**\n * Checks whether a value is a tool error, containing hostile prototype access.\n *\n * @param value - The value to test\n * @returns True if the value is an instance of the tool error class; false otherwise\n *\n * @example\n * ```ts\n * import { ToolError, isToolError } from '@orkestrel/tool'\n *\n * isToolError(new ToolError('ARGUMENTS', 'Invalid amount')) // true\n * isToolError(new Error('Unrelated')) // false\n * ```\n */\nexport function isToolError(value: unknown): value is ToolError {\n\treturn isInstance(value, ToolError)\n}\n","import type { ToolCall } from './types.js'\nimport { holds, isRecord, isString } from '@orkestrel/contract'\n\n/**\n * Determines whether an unknown value is structurally a {@link ToolCall}, staying total\n * for malformed and adversarial input.\n *\n * @remarks\n * The accepted shape is a plain record with string `id` and `name` fields and a\n * plain-record `arguments` field. Extra fields are not read or verified.\n *\n * @param value - The value to test\n * @returns True if the value has the complete tool-call shape; false otherwise\n *\n * @example\n * ```ts\n * import { isToolCall } from '@orkestrel/tool'\n *\n * isToolCall({ id: '1', name: 'search', arguments: { query: 'birds' } }) // true\n * isToolCall({ id: '1', name: 'search', arguments: [] }) // false\n * ```\n */\nexport function isToolCall(value: unknown): value is ToolCall {\n\treturn holds(\n\t\t() =>\n\t\t\tisRecord(value) && isString(value.id) && isString(value.name) && isRecord(value.arguments),\n\t)\n}\n","import type { ToolDefinition, ToolInterface } from './types.js'\n\n/**\n * Projects a tool onto the plain definition advertised to a caller, advertising an\n * authored `summary` in place of the full description and carrying `parameters` and\n * `annotations` by reference.\n *\n * @remarks\n * The projection carries `name` and present `title`, `description`, `parameters`, and\n * `annotations` fields in that order. The full `description` stays on the tool for\n * direct lookup, and the definition is never a live handle on the tool's handler.\n *\n * @param tool - The tool to project\n * @returns A fresh definition carrying only the fields the tool authored\n *\n * @example\n * ```ts\n * import { Tool, toolToDefinition } from '@orkestrel/tool'\n *\n * const echo = new Tool({ name: 'echo', summary: 'Echo a value.', execute: (args) => args.value })\n * toolToDefinition(echo) // { name: 'echo', description: 'Echo a value.' }\n * ```\n */\nexport function toolToDefinition(tool: ToolInterface): ToolDefinition {\n\tconst description = tool.summary ?? tool.description\n\treturn {\n\t\tname: tool.name,\n\t\t...(tool.title === undefined ? {} : { title: tool.title }),\n\t\t...(description === undefined ? {} : { description }),\n\t\t...(tool.parameters === undefined ? {} : { parameters: tool.parameters }),\n\t\t...(tool.annotations === undefined ? {} : { annotations: tool.annotations }),\n\t}\n}\n","import type { ContractInterface } from '@orkestrel/contract'\nimport type { ToolAnnotations, ToolContext, ToolInterface, ToolOptions } from '../types.js'\nimport { createContract, isRecord, isString, schemaToParameters } from '@orkestrel/contract'\nimport { ToolError } from '../errors.js'\n\n/**\n * Binds an executable tool definition to a handler.\n *\n * @remarks\n * Advertised fields and execution context are forwarded by reference.\n * A contract derives parameters at construction and refuses parse faults before the\n * handler runs, then forwards the parsed arguments; without a contract, arguments\n * retain their identity. Supplying a contract and parameters throws a schema conflict.\n * Caller context is consumer-asserted and is not verified. Handler failures are not\n * caught here; {@link ToolManager} owns per-call error isolation.\n *\n * @example\n * ```ts\n * import { Tool } from '@orkestrel/tool'\n *\n * const tool = new Tool({\n * \tname: 'add',\n * \tdescription: 'Add two numbers',\n * \tparameters: {\n * \t\ttype: 'object',\n * \t\tproperties: { a: { type: 'number' }, b: { type: 'number' } },\n * \t},\n * \texecute: (args) => Number(args.a) + Number(args.b),\n * })\n * ```\n */\nexport class Tool implements ToolInterface {\n\treadonly #contract?: ContractInterface<unknown>\n\treadonly #execute: ToolOptions['execute']\n\n\treadonly name: string\n\treadonly title?: string\n\treadonly description?: string\n\treadonly summary?: string\n\treadonly parameters?: Readonly<Record<string, unknown>>\n\treadonly annotations?: ToolAnnotations\n\n\tconstructor(options: ToolOptions) {\n\t\tif (options.contract !== undefined && options.parameters !== undefined) {\n\t\t\tthrow new ToolError('SCHEMA', 'Choose contract or parameters, not both')\n\t\t}\n\t\tthis.name = options.name\n\t\tif (options.title !== undefined) this.title = options.title\n\t\tif (options.description !== undefined) this.description = options.description\n\t\tif (options.summary !== undefined) this.summary = options.summary\n\t\tif (options.annotations !== undefined) this.annotations = options.annotations\n\t\tif (options.contract !== undefined) {\n\t\t\tthis.#contract = createContract(options.contract)\n\t\t\tconst parameters = schemaToParameters(this.#contract.schema)\n\t\t\tif (parameters !== undefined) this.parameters = parameters\n\t\t} else if (options.parameters !== undefined) this.parameters = options.parameters\n\t\tthis.#execute = options.execute\n\t}\n\n\texecute(\n\t\targs: Readonly<Record<string, unknown>>,\n\t\tcontext: ToolContext,\n\t): Promise<unknown> | unknown {\n\t\tconst faults = this.#contract?.explain(args) ?? []\n\t\tconst fault = faults[0]\n\t\tif (fault !== undefined) {\n\t\t\tconst path = isString(fault.path) ? fault.path : fault.path.join('.')\n\t\t\tlet message = `${path}: ${fault.reason}`\n\t\t\tif ('expected' in fault) message += `; expected ${fault.expected}`\n\t\t\tif ('received' in fault) message += `; received ${fault.received}`\n\t\t\tif ('constraint' in fault) message += `; constraint ${fault.constraint}`\n\t\t\tif ('limit' in fault && fault.limit !== undefined) message += `; limit ${fault.limit}`\n\t\t\tif ('variants' in fault) message += `; variants ${fault.variants}`\n\t\t\tif ('matched' in fault) message += `; matched ${fault.matched}`\n\t\t\tthrow new ToolError('ARGUMENTS', message, { faults })\n\t\t}\n\t\tif (this.#contract !== undefined) {\n\t\t\tconst parsed = this.#contract.parse(args)\n\t\t\tif (!isRecord(parsed)) throw new ToolError('ARGUMENTS', 'Arguments did not parse')\n\t\t\treturn this.#execute(parsed, context)\n\t\t}\n\t\treturn this.#execute(args, context)\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tToolCall,\n\tToolContext,\n\tToolDefinition,\n\tToolInterface,\n\tToolManagerEventMap,\n\tToolManagerInterface,\n\tToolManagerOptions,\n\tToolResult,\n} from '../types.js'\nimport { attempt, isArray, isError } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { toolToDefinition } from '../helpers.js'\n\n/**\n * Represents an insertion-ordered tool registry with per-call error isolation.\n *\n * @remarks\n * A repeated name overwrites the registered tool without changing its insertion\n * position. Definitions advertise `summary` in place of `description` when present.\n * Unknown names and handler throws resolve to error results; a call whose `id` or `name`\n * accessor throws when read makes its call, and the batch holding it, reject. Batch\n * execution preserves input order and isolates each call whose members are plain\n * values. Execution context is shared across a batch and forwarded unchanged. An\n * omitted context receives a non-aborted signal. A signal aborted before handler\n * entry produces an error result; later cancellation is the handler's responsibility.\n * Registry changes publish synchronously. Replacements publish `remove`, then `add`\n * if the map still holds that exact replacement after the removal listeners return.\n * Destruction clears the tools before releasing listeners. A destroyed registry\n * publishes nothing, even when later additions update its tool map.\n *\n * @example\n * ```ts\n * import { Tool, ToolManager } from '@orkestrel/tool'\n *\n * const tools = new ToolManager()\n * tools.add(new Tool({ name: 'add', execute: (args) => Number(args.x) + Number(args.y) }))\n * const result = await tools.execute({\n * \tid: '1',\n * \tname: 'add',\n * \targuments: { x: 1, y: 2 },\n * })\n * ```\n */\nexport class ToolManager implements ToolManagerInterface {\n\treadonly #tools = new Map<string, ToolInterface>()\n\treadonly #emitter: Emitter<ToolManagerEventMap>\n\n\tconstructor(options?: ToolManagerOptions) {\n\t\tthis.#emitter = new Emitter<ToolManagerEventMap>(options)\n\t}\n\n\tget count(): number {\n\t\treturn this.#tools.size\n\t}\n\n\tget emitter(): EmitterInterface<ToolManagerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tadd(tool: ToolInterface): void\n\tadd(tools: readonly ToolInterface[]): void\n\tadd(tools: ToolInterface | readonly ToolInterface[]): void {\n\t\tif (isArray(tools)) {\n\t\t\tfor (const tool of tools) this.add(tool)\n\t\t\treturn\n\t\t}\n\t\tconst previous = this.#tools.get(tools.name)\n\t\tthis.#tools.set(tools.name, tools)\n\t\tif (previous !== undefined) this.#emitter.emit('remove', previous)\n\t\tif (this.#tools.get(tools.name) === tools) this.#emitter.emit('add', tools)\n\t}\n\n\ttool(name: string): ToolInterface | undefined {\n\t\treturn this.#tools.get(name)\n\t}\n\n\ttools(): readonly ToolInterface[] {\n\t\treturn [...this.#tools.values()]\n\t}\n\n\tdefinitions(): readonly ToolDefinition[] {\n\t\treturn [...this.#tools.values()].map((tool) => toolToDefinition(tool))\n\t}\n\n\texecute(call: ToolCall, context?: ToolContext): Promise<ToolResult>\n\texecute(calls: readonly ToolCall[], context?: ToolContext): Promise<readonly ToolResult[]>\n\texecute(\n\t\tcall: ToolCall | readonly ToolCall[],\n\t\tcontext: ToolContext = { signal: new AbortController().signal },\n\t): Promise<ToolResult | readonly ToolResult[]> {\n\t\tif (isArray(call)) return Promise.all(call.map((one) => this.#run(one, context)))\n\t\treturn this.#run(call, context)\n\t}\n\n\tremove(name: string): boolean\n\tremove(names: readonly string[]): boolean\n\tremove(names: string | readonly string[]): boolean {\n\t\tif (isArray(names)) {\n\t\t\tlet removed = true\n\t\t\tfor (const name of names) {\n\t\t\t\tif (!this.remove(name)) removed = false\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\tconst tool = this.#tools.get(names)\n\t\tif (tool === undefined) return false\n\t\tthis.#tools.delete(names)\n\t\tthis.#emitter.emit('remove', tool)\n\t\treturn true\n\t}\n\n\tclear(): void {\n\t\tconst tools = this.tools()\n\t\tthis.#tools.clear()\n\t\tthis.#emitter.emit('clear', tools)\n\t}\n\n\tdestroy(): void {\n\t\tthis.clear()\n\t\tthis.#emitter.destroy()\n\t\tthis.#tools.clear()\n\t}\n\n\tasync #run(call: ToolCall, context: ToolContext): Promise<ToolResult> {\n\t\tconst tool = this.#tools.get(call.name)\n\t\tif (tool === undefined) {\n\t\t\treturn {\n\t\t\t\tid: call.id,\n\t\t\t\tname: call.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: `tool not found: ${call.name}`,\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tif (context.signal.aborted) {\n\t\t\t\tconst reason: unknown = context.signal.reason\n\t\t\t\treturn {\n\t\t\t\t\tid: call.id,\n\t\t\t\t\tname: call.name,\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: reason === undefined ? 'aborted' : String(reason),\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst value = await tool.execute(call.arguments, context)\n\t\t\treturn { id: call.id, name: call.name, success: true, value }\n\t\t} catch (error) {\n\t\t\tconst message = attempt(() => (isError(error) ? error.message : String(error)))\n\t\t\treturn {\n\t\t\t\tid: call.id,\n\t\t\t\tname: call.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: message.success ? message.value : 'Unknown thrown value',\n\t\t\t}\n\t\t}\n\t}\n}\n","import type {\n\tToolInterface,\n\tToolManagerInterface,\n\tToolManagerOptions,\n\tToolOptions,\n} from './types.js'\nimport { Tool } from './tools/Tool.js'\nimport { ToolManager } from './tools/ToolManager.js'\n\n/**\n * Creates an executable tool bound to the supplied handler, returned as a\n * `ToolInterface` so a call site holds the published contract rather than the `Tool`\n * class.\n *\n * @param options - The advertised definition and execution handler\n * @returns A tool bound to the supplied handler\n *\n * @example Anatomy of a tool\n * ```ts\n * import { createTool } from '@orkestrel/tool'\n *\n * const add = createTool({\n * \tname: 'add',\n * \tdescription: 'Add two numeric values and return their sum. Both operands are required.',\n * \tsummary: 'Add two numbers.',\n * \tparameters: {\n * \t\ttype: 'object',\n * \t\tproperties: {\n * \t\t\tleft: { type: 'number' },\n * \t\t\tright: { type: 'number' },\n * \t\t},\n * \t\trequired: ['left', 'right'],\n * \t},\n * \texecute: (args) => Number(args.left) + Number(args.right),\n * })\n * ```\n */\nexport function createTool(options: ToolOptions): ToolInterface {\n\treturn new Tool(options)\n}\n\n/**\n * Creates an empty registry that advertises definitions and executes calls with\n * per-call error isolation, returned as a `ToolManagerInterface` so a caller holds the\n * published contract rather than the `ToolManager` class.\n *\n * @param options - The initial registry listeners and listener-error handler\n * @returns A registry bound to no tools\n *\n * @example\n * ```ts\n * import { createTool, createToolManager } from '@orkestrel/tool'\n *\n * const tools = createToolManager()\n * tools.add(createTool({ name: 'echo', execute: (args) => args.value }))\n * const result = await tools.execute({\n * \tid: '1',\n * \tname: 'echo',\n * \targuments: { value: 'hello' },\n * })\n * ```\n */\nexport function createToolManager(options?: ToolManagerOptions): ToolManagerInterface {\n\treturn new ToolManager(options)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["holds","INTRINSICS","isObject","isFunction","arrayOf","isString","holds","isRecord","isString","createContract","schemaToParameters","isString","isRecord","Emitter","isArray","attempt","isError"],"sources":["../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/tools/Tool.ts","../../../src/core/tools/ToolManager.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { ToolErrorCode, ToolErrorContext } from './types.js'\nimport { arrayOf, holds, INTRINSICS, isFunction, isObject, isString } from '@orkestrel/contract'\n\n/**\n * Reports a schema conflict or argument validation failure with a machine-readable code.\n *\n * @example\n * ```ts\n * import { ToolError } from '@orkestrel/tool'\n *\n * const error = new ToolError('SCHEMA', 'Choose contract or parameters')\n * error.code // 'SCHEMA'\n * ```\n */\nexport class ToolError extends Error {\n\toverride readonly name = 'ToolError' as const\n\treadonly code: ToolErrorCode\n\treadonly context?: ToolErrorContext\n\n\tconstructor(code: ToolErrorCode, message: string, context?: ToolErrorContext) {\n\t\tsuper(message)\n\t\tINTRINSICS.define(this, Symbol.for('@orkestrel/tool.ToolError'), { value: this })\n\t\tthis.code = code\n\t\tif (context !== undefined) this.context = context\n\t}\n}\n\n/**\n * Checks whether a value is a tool error, containing hostile prototype access.\n *\n * @remarks\n * Recognizes self-branded errors across package copies and subclasses and refuses\n * transparent proxies. Validates the declared code and optional fault report.\n *\n * @param value - The value to test\n * @returns True if the value is an instance of the tool error class; false otherwise\n *\n * @example\n * ```ts\n * import { ToolError, isToolError } from '@orkestrel/tool'\n *\n * isToolError(new ToolError('ARGUMENTS', 'Invalid amount')) // true\n * isToolError(new Error('Unrelated')) // false\n * ```\n */\nexport function isToolError(value: unknown): value is ToolError {\n\treturn holds(() => {\n\t\tif (!(value instanceof Error) || INTRINSICS.prototype(value) === Error.prototype) return false\n\t\tconst brand = INTRINSICS.describe(value, Symbol.for('@orkestrel/tool.ToolError'))\n\t\tif (brand?.value !== value) return false\n\t\tconst code: unknown = INTRINSICS.reflect.read(value, 'code')\n\t\tif (code !== 'SCHEMA' && code !== 'ARGUMENTS') return false\n\t\tconst context: unknown = INTRINSICS.reflect.read(value, 'context')\n\t\tif (context === undefined) return true\n\t\tif (!isObject(context) && !isFunction(context)) return false\n\t\tconst faults: unknown = INTRINSICS.reflect.read(context, 'faults')\n\t\tif (faults === undefined) return true\n\t\treturn arrayOf((fault: unknown) => {\n\t\t\tif (!isObject(fault)) return false\n\t\t\tconst path: unknown = INTRINSICS.reflect.read(fault, 'path')\n\t\t\tif (!isString(path) && !arrayOf(isString)(path)) return false\n\t\t\tconst reason: unknown = INTRINSICS.reflect.read(fault, 'reason')\n\t\t\tif (reason === 'variant') {\n\t\t\t\treturn typeof INTRINSICS.reflect.read(fault, 'variants') === 'number'\n\t\t\t}\n\t\t\tif (reason === 'oneOf') {\n\t\t\t\treturn typeof INTRINSICS.reflect.read(fault, 'matched') === 'number'\n\t\t\t}\n\t\t\tconst expected: unknown = INTRINSICS.reflect.read(fault, 'expected')\n\t\t\tif (\n\t\t\t\t![\n\t\t\t\t\t'string',\n\t\t\t\t\t'number',\n\t\t\t\t\t'integer',\n\t\t\t\t\t'boolean',\n\t\t\t\t\t'null',\n\t\t\t\t\t'literal',\n\t\t\t\t\t'array',\n\t\t\t\t\t'object',\n\t\t\t\t\t'union',\n\t\t\t\t\t'json',\n\t\t\t\t].some((candidate) => candidate === expected)\n\t\t\t)\n\t\t\t\treturn false\n\t\t\tif (reason === 'missing') return true\n\t\t\tif (!isString(INTRINSICS.reflect.read(fault, 'received'))) return false\n\t\t\tif (reason === 'type') return true\n\t\t\tif (reason !== 'constraint') return false\n\t\t\tconst constraint: unknown = INTRINSICS.reflect.read(fault, 'constraint')\n\t\t\tconst limit: unknown = INTRINSICS.reflect.read(fault, 'limit')\n\t\t\treturn (\n\t\t\t\t(constraint === 'min' ||\n\t\t\t\t\tconstraint === 'max' ||\n\t\t\t\t\tconstraint === 'pattern' ||\n\t\t\t\t\tconstraint === 'integer') &&\n\t\t\t\t(limit === undefined || typeof limit === 'number' || typeof limit === 'string')\n\t\t\t)\n\t\t})(faults)\n\t})\n}\n","import type { ToolCall } from './types.js'\nimport { holds, isRecord, isString } from '@orkestrel/contract'\n\n/**\n * Determines whether an unknown value is structurally a {@link ToolCall}, staying total\n * for malformed and adversarial input.\n *\n * @remarks\n * The accepted shape is a plain record with string `id` and `name` fields and a\n * plain-record `arguments` field. Extra fields are not read or verified.\n *\n * @param value - The value to test\n * @returns True if the value has the complete tool-call shape; false otherwise\n *\n * @example\n * ```ts\n * import { isToolCall } from '@orkestrel/tool'\n *\n * isToolCall({ id: '1', name: 'search', arguments: { query: 'birds' } }) // true\n * isToolCall({ id: '1', name: 'search', arguments: [] }) // false\n * ```\n */\nexport function isToolCall(value: unknown): value is ToolCall {\n\treturn holds(\n\t\t() =>\n\t\t\tisRecord(value) && isString(value.id) && isString(value.name) && isRecord(value.arguments),\n\t)\n}\n","import type { ToolDefinition, ToolInterface } from './types.js'\n\n/**\n * Projects a tool onto the plain definition advertised to a caller, advertising an\n * authored `summary` in place of the full description and carrying `parameters` and\n * `annotations` by reference.\n *\n * @remarks\n * The projection carries `name` and present `title`, `description`, `parameters`, and\n * `annotations` fields in that order. The full `description` stays on the tool for\n * direct lookup, and the definition is never a live handle on the tool's handler.\n *\n * @param tool - The tool to project\n * @returns A fresh definition carrying only the fields the tool authored\n *\n * @example\n * ```ts\n * import { Tool, toolToDefinition } from '@orkestrel/tool'\n *\n * const echo = new Tool({ name: 'echo', summary: 'Echo a value.', execute: (args) => args.value })\n * toolToDefinition(echo) // { name: 'echo', description: 'Echo a value.' }\n * ```\n */\nexport function toolToDefinition(tool: ToolInterface): ToolDefinition {\n\tconst description = tool.summary ?? tool.description\n\treturn {\n\t\tname: tool.name,\n\t\t...(tool.title === undefined ? {} : { title: tool.title }),\n\t\t...(description === undefined ? {} : { description }),\n\t\t...(tool.parameters === undefined ? {} : { parameters: tool.parameters }),\n\t\t...(tool.annotations === undefined ? {} : { annotations: tool.annotations }),\n\t}\n}\n","import type { ContractInterface } from '@orkestrel/contract'\nimport type { ToolAnnotations, ToolContext, ToolInterface, ToolOptions } from '../types.js'\nimport { createContract, isRecord, isString, schemaToParameters } from '@orkestrel/contract'\nimport { ToolError } from '../errors.js'\n\n/**\n * Binds an executable tool definition to a handler.\n *\n * @remarks\n * Advertised fields and execution context are forwarded by reference.\n * A contract derives parameters at construction and refuses parse faults before the\n * handler runs, then forwards the parsed arguments; without a contract, arguments\n * retain their identity. Supplying a contract and parameters throws a schema conflict.\n * Caller context is consumer-asserted and is not verified. Handler failures are not\n * caught here; {@link ToolManager} owns per-call error isolation.\n *\n * @example\n * ```ts\n * import { Tool } from '@orkestrel/tool'\n *\n * const tool = new Tool({\n * \tname: 'add',\n * \tdescription: 'Add two numbers',\n * \tparameters: {\n * \t\ttype: 'object',\n * \t\tproperties: { a: { type: 'number' }, b: { type: 'number' } },\n * \t},\n * \texecute: (args) => Number(args.a) + Number(args.b),\n * })\n * ```\n */\nexport class Tool implements ToolInterface {\n\treadonly #contract?: ContractInterface<unknown>\n\treadonly #execute: ToolOptions['execute']\n\n\treadonly name: string\n\treadonly title?: string\n\treadonly description?: string\n\treadonly summary?: string\n\treadonly parameters?: Readonly<Record<string, unknown>>\n\treadonly annotations?: ToolAnnotations\n\n\tconstructor(options: ToolOptions) {\n\t\tif (options.contract !== undefined && options.parameters !== undefined) {\n\t\t\tthrow new ToolError('SCHEMA', 'Choose contract or parameters, not both')\n\t\t}\n\t\tthis.name = options.name\n\t\tif (options.title !== undefined) this.title = options.title\n\t\tif (options.description !== undefined) this.description = options.description\n\t\tif (options.summary !== undefined) this.summary = options.summary\n\t\tif (options.annotations !== undefined) this.annotations = options.annotations\n\t\tif (options.contract !== undefined) {\n\t\t\tthis.#contract = createContract(options.contract)\n\t\t\tconst parameters = schemaToParameters(this.#contract.schema)\n\t\t\tif (parameters !== undefined) this.parameters = parameters\n\t\t} else if (options.parameters !== undefined) this.parameters = options.parameters\n\t\tthis.#execute = options.execute\n\t}\n\n\texecute(\n\t\targs: Readonly<Record<string, unknown>>,\n\t\tcontext: ToolContext,\n\t): Promise<unknown> | unknown {\n\t\tconst faults = this.#contract?.explain(args) ?? []\n\t\tconst fault = faults[0]\n\t\tif (fault !== undefined) {\n\t\t\tconst path = isString(fault.path) ? fault.path : fault.path.join('.')\n\t\t\tconst message = [\n\t\t\t\t`${path}: ${fault.reason}`,\n\t\t\t\t...('expected' in fault ? [`expected ${fault.expected}`] : []),\n\t\t\t\t...('received' in fault ? [`received ${fault.received}`] : []),\n\t\t\t\t...('constraint' in fault ? [`constraint ${fault.constraint}`] : []),\n\t\t\t\t...('limit' in fault && fault.limit !== undefined ? [`limit ${fault.limit}`] : []),\n\t\t\t\t...('variants' in fault ? [`variants ${fault.variants}`] : []),\n\t\t\t\t...('matched' in fault ? [`matched ${fault.matched}`] : []),\n\t\t\t].join('; ')\n\t\t\tthrow new ToolError('ARGUMENTS', message, { faults })\n\t\t}\n\t\tif (this.#contract !== undefined) {\n\t\t\tconst parsed = this.#contract.parse(args)\n\t\t\tif (!isRecord(parsed)) throw new ToolError('ARGUMENTS', 'Arguments did not parse')\n\t\t\treturn this.#execute(parsed, context)\n\t\t}\n\t\treturn this.#execute(args, context)\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tToolCall,\n\tToolContext,\n\tToolDefinition,\n\tToolInterface,\n\tToolManagerEventMap,\n\tToolManagerInterface,\n\tToolManagerOptions,\n\tToolResult,\n} from '../types.js'\nimport { attempt, isArray, isError } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { toolToDefinition } from '../helpers.js'\n\n/**\n * Represents an insertion-ordered tool registry with per-call error isolation.\n *\n * @remarks\n * A repeated name overwrites the registered tool without changing its insertion\n * position. Definitions advertise `summary` in place of `description` when present.\n * Unknown names and handler throws resolve to error results; a call whose `id` or `name`\n * accessor throws when read makes its call, and the batch holding it, reject. Batch\n * execution preserves input order and isolates each call whose members are plain\n * values. Execution context is shared across a batch and forwarded unchanged. An\n * omitted context receives a non-aborted signal. A signal aborted before handler\n * entry produces an error result; later cancellation is the handler's responsibility.\n * Registry changes publish synchronously. Replacements publish `remove`, then `add`\n * if the map still holds that exact replacement after the removal listeners return.\n * Destruction clears the tools before releasing listeners. A destroyed registry\n * publishes nothing, even when later additions update its tool map.\n *\n * @example\n * ```ts\n * import { Tool, ToolManager } from '@orkestrel/tool'\n *\n * const tools = new ToolManager()\n * tools.add(new Tool({ name: 'add', execute: (args) => Number(args.x) + Number(args.y) }))\n * const result = await tools.execute({\n * \tid: '1',\n * \tname: 'add',\n * \targuments: { x: 1, y: 2 },\n * })\n * ```\n */\nexport class ToolManager implements ToolManagerInterface {\n\treadonly #tools = new Map<string, ToolInterface>()\n\treadonly #emitter: Emitter<ToolManagerEventMap>\n\n\tconstructor(options?: ToolManagerOptions) {\n\t\tthis.#emitter = new Emitter<ToolManagerEventMap>(options)\n\t}\n\n\tget count(): number {\n\t\treturn this.#tools.size\n\t}\n\n\tget emitter(): EmitterInterface<ToolManagerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tadd(tool: ToolInterface): void\n\tadd(tools: readonly ToolInterface[]): void\n\tadd(tools: ToolInterface | readonly ToolInterface[]): void {\n\t\tif (isArray(tools)) {\n\t\t\tfor (const tool of tools) this.add(tool)\n\t\t\treturn\n\t\t}\n\t\tconst previous = this.#tools.get(tools.name)\n\t\tthis.#tools.set(tools.name, tools)\n\t\tif (previous !== undefined) this.#emitter.emit('remove', previous)\n\t\tif (this.#tools.get(tools.name) === tools) this.#emitter.emit('add', tools)\n\t}\n\n\ttool(name: string): ToolInterface | undefined {\n\t\treturn this.#tools.get(name)\n\t}\n\n\ttools(): readonly ToolInterface[] {\n\t\treturn [...this.#tools.values()]\n\t}\n\n\tdefinitions(): readonly ToolDefinition[] {\n\t\treturn [...this.#tools.values()].map((tool) => toolToDefinition(tool))\n\t}\n\n\texecute(call: ToolCall, context?: ToolContext): Promise<ToolResult>\n\texecute(calls: readonly ToolCall[], context?: ToolContext): Promise<readonly ToolResult[]>\n\texecute(\n\t\tcall: ToolCall | readonly ToolCall[],\n\t\tcontext: ToolContext = { signal: new AbortController().signal },\n\t): Promise<ToolResult | readonly ToolResult[]> {\n\t\tif (isArray(call)) return Promise.all(call.map((one) => this.#run(one, context)))\n\t\treturn this.#run(call, context)\n\t}\n\n\tremove(name: string): boolean\n\tremove(names: readonly string[]): boolean\n\tremove(names: string | readonly string[]): boolean {\n\t\tif (isArray(names)) {\n\t\t\treturn this.#remove(names).reduce((all, removed) => removed && all, true)\n\t\t}\n\t\tconst tool = this.#tools.get(names)\n\t\tif (tool === undefined) return false\n\t\tthis.#tools.delete(names)\n\t\tthis.#emitter.emit('remove', tool)\n\t\treturn true\n\t}\n\n\tclear(): void {\n\t\tconst tools = this.tools()\n\t\tthis.#tools.clear()\n\t\tthis.#emitter.emit('clear', tools)\n\t}\n\n\tdestroy(): void {\n\t\tthis.clear()\n\t\tthis.#emitter.destroy()\n\t\tthis.#tools.clear()\n\t}\n\n\t*#remove(names: readonly string[]): Generator<boolean> {\n\t\tfor (const name of names) yield this.remove(name)\n\t}\n\n\tasync #run(call: ToolCall, context: ToolContext): Promise<ToolResult> {\n\t\tconst tool = this.#tools.get(call.name)\n\t\tif (tool === undefined) {\n\t\t\treturn {\n\t\t\t\tid: call.id,\n\t\t\t\tname: call.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: `tool not found: ${call.name}`,\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tif (context.signal.aborted) {\n\t\t\t\tconst reason: unknown = context.signal.reason\n\t\t\t\treturn {\n\t\t\t\t\tid: call.id,\n\t\t\t\t\tname: call.name,\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: reason === undefined ? 'aborted' : String(reason),\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst value = await tool.execute(call.arguments, context)\n\t\t\treturn { id: call.id, name: call.name, success: true, value }\n\t\t} catch (error) {\n\t\t\tconst message = attempt(() => (isError(error) ? error.message : String(error)))\n\t\t\treturn {\n\t\t\t\tid: call.id,\n\t\t\t\tname: call.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: message.success ? message.value : 'Unknown thrown value',\n\t\t\t}\n\t\t}\n\t}\n}\n","import type {\n\tToolInterface,\n\tToolManagerInterface,\n\tToolManagerOptions,\n\tToolOptions,\n} from './types.js'\nimport { Tool } from './tools/Tool.js'\nimport { ToolManager } from './tools/ToolManager.js'\n\n/**\n * Creates an executable tool bound to the supplied handler, returned as a\n * `ToolInterface` so a call site holds the published contract rather than the `Tool`\n * class.\n *\n * @param options - The advertised definition and execution handler\n * @returns A tool bound to the supplied handler\n *\n * @example Anatomy of a tool\n * ```ts\n * import { createTool } from '@orkestrel/tool'\n *\n * const add = createTool({\n * \tname: 'add',\n * \tdescription: 'Add two numeric values and return their sum. Both operands are required.',\n * \tsummary: 'Add two numbers.',\n * \tparameters: {\n * \t\ttype: 'object',\n * \t\tproperties: {\n * \t\t\tleft: { type: 'number' },\n * \t\t\tright: { type: 'number' },\n * \t\t},\n * \t\trequired: ['left', 'right'],\n * \t},\n * \texecute: (args) => Number(args.left) + Number(args.right),\n * })\n * ```\n */\nexport function createTool(options: ToolOptions): ToolInterface {\n\treturn new Tool(options)\n}\n\n/**\n * Creates an empty registry that advertises definitions and executes calls with\n * per-call error isolation, returned as a `ToolManagerInterface` so a caller holds the\n * published contract rather than the `ToolManager` class.\n *\n * @param options - The initial registry listeners and listener-error handler\n * @returns A registry bound to no tools\n *\n * @example\n * ```ts\n * import { createTool, createToolManager } from '@orkestrel/tool'\n *\n * const tools = createToolManager()\n * tools.add(createTool({ name: 'echo', execute: (args) => args.value }))\n * const result = await tools.execute({\n * \tid: '1',\n * \tname: 'echo',\n * \targuments: { value: 'hello' },\n * })\n * ```\n */\nexport function createToolManager(options?: ToolManagerOptions): ToolManagerInterface {\n\treturn new ToolManager(options)\n}\n"],"mappings":"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"}
@@ -83,6 +83,10 @@ export declare function isToolCall(value: unknown): value is ToolCall;
83
83
  /**
84
84
  * Checks whether a value is a tool error, containing hostile prototype access.
85
85
  *
86
+ * @remarks
87
+ * Recognizes self-branded errors across package copies and subclasses and refuses
88
+ * transparent proxies. Validates the declared code and optional fault report.
89
+ *
86
90
  * @param value - The value to test
87
91
  * @returns True if the value is an instance of the tool error class; false otherwise
88
92
  *
@@ -200,7 +204,7 @@ export declare interface ToolDefinition {
200
204
  * ```
201
205
  */
202
206
  export declare class ToolError extends Error {
203
- readonly name: "ToolError";
207
+ readonly name: 'ToolError';
204
208
  readonly code: ToolErrorCode;
205
209
  readonly context?: ToolErrorContext;
206
210
  constructor(code: ToolErrorCode, message: string, context?: ToolErrorContext);
@@ -83,6 +83,10 @@ export declare function isToolCall(value: unknown): value is ToolCall;
83
83
  /**
84
84
  * Checks whether a value is a tool error, containing hostile prototype access.
85
85
  *
86
+ * @remarks
87
+ * Recognizes self-branded errors across package copies and subclasses and refuses
88
+ * transparent proxies. Validates the declared code and optional fault report.
89
+ *
86
90
  * @param value - The value to test
87
91
  * @returns True if the value is an instance of the tool error class; false otherwise
88
92
  *
@@ -200,7 +204,7 @@ export declare interface ToolDefinition {
200
204
  * ```
201
205
  */
202
206
  export declare class ToolError extends Error {
203
- readonly name: "ToolError";
207
+ readonly name: 'ToolError';
204
208
  readonly code: ToolErrorCode;
205
209
  readonly context?: ToolErrorContext;
206
210
  constructor(code: ToolErrorCode, message: string, context?: ToolErrorContext);
@@ -1,6 +1,6 @@
1
- import { attempt, createContract, holds, isArray, isError, isInstance, isRecord, isString, schemaToParameters } from "@orkestrel/contract";
1
+ import { INTRINSICS, arrayOf, attempt, createContract, holds, isArray, isError, isFunction, isObject, isRecord, isString, schemaToParameters } from "@orkestrel/contract";
2
2
  import { Emitter } from "@orkestrel/emitter";
3
- //#region src/core/errors.ts
3
+ // src/core/errors.ts
4
4
  /**
5
5
  * Reports a schema conflict or argument validation failure with a machine-readable code.
6
6
  *
@@ -18,6 +18,7 @@ var ToolError = class extends Error {
18
18
  context;
19
19
  constructor(code, message, context) {
20
20
  super(message);
21
+ INTRINSICS.define(this, Symbol.for("@orkestrel/tool.ToolError"), { value: this });
21
22
  this.code = code;
22
23
  if (context !== void 0) this.context = context;
23
24
  }
@@ -25,6 +26,10 @@ var ToolError = class extends Error {
25
26
  /**
26
27
  * Checks whether a value is a tool error, containing hostile prototype access.
27
28
  *
29
+ * @remarks
30
+ * Recognizes self-branded errors across package copies and subclasses and refuses
31
+ * transparent proxies. Validates the declared code and optional fault report.
32
+ *
28
33
  * @param value - The value to test
29
34
  * @returns True if the value is an instance of the tool error class; false otherwise
30
35
  *
@@ -37,10 +42,47 @@ var ToolError = class extends Error {
37
42
  * ```
38
43
  */
39
44
  function isToolError(value) {
40
- return isInstance(value, ToolError);
45
+ return holds(() => {
46
+ if (!(value instanceof Error) || INTRINSICS.prototype(value) === Error.prototype) return false;
47
+ if (INTRINSICS.describe(value, Symbol.for("@orkestrel/tool.ToolError"))?.value !== value) return false;
48
+ const code = INTRINSICS.reflect.read(value, "code");
49
+ if (code !== "SCHEMA" && code !== "ARGUMENTS") return false;
50
+ const context = INTRINSICS.reflect.read(value, "context");
51
+ if (context === void 0) return true;
52
+ if (!isObject(context) && !isFunction(context)) return false;
53
+ const faults = INTRINSICS.reflect.read(context, "faults");
54
+ if (faults === void 0) return true;
55
+ return arrayOf((fault) => {
56
+ if (!isObject(fault)) return false;
57
+ const path = INTRINSICS.reflect.read(fault, "path");
58
+ if (!isString(path) && !arrayOf(isString)(path)) return false;
59
+ const reason = INTRINSICS.reflect.read(fault, "reason");
60
+ if (reason === "variant") return typeof INTRINSICS.reflect.read(fault, "variants") === "number";
61
+ if (reason === "oneOf") return typeof INTRINSICS.reflect.read(fault, "matched") === "number";
62
+ const expected = INTRINSICS.reflect.read(fault, "expected");
63
+ if (![
64
+ "string",
65
+ "number",
66
+ "integer",
67
+ "boolean",
68
+ "null",
69
+ "literal",
70
+ "array",
71
+ "object",
72
+ "union",
73
+ "json"
74
+ ].some((candidate) => candidate === expected)) return false;
75
+ if (reason === "missing") return true;
76
+ if (!isString(INTRINSICS.reflect.read(fault, "received"))) return false;
77
+ if (reason === "type") return true;
78
+ if (reason !== "constraint") return false;
79
+ const constraint = INTRINSICS.reflect.read(fault, "constraint");
80
+ const limit = INTRINSICS.reflect.read(fault, "limit");
81
+ return (constraint === "min" || constraint === "max" || constraint === "pattern" || constraint === "integer") && (limit === void 0 || typeof limit === "number" || typeof limit === "string");
82
+ })(faults);
83
+ });
41
84
  }
42
- //#endregion
43
- //#region src/core/validators.ts
85
+ // src/core/validators.ts
44
86
  /**
45
87
  * Determines whether an unknown value is structurally a {@link ToolCall}, staying total
46
88
  * for malformed and adversarial input.
@@ -63,8 +105,7 @@ function isToolError(value) {
63
105
  function isToolCall(value) {
64
106
  return holds(() => isRecord(value) && isString(value.id) && isString(value.name) && isRecord(value.arguments));
65
107
  }
66
- //#endregion
67
- //#region src/core/helpers.ts
108
+ // src/core/helpers.ts
68
109
  /**
69
110
  * Projects a tool onto the plain definition advertised to a caller, advertising an
70
111
  * authored `summary` in place of the full description and carrying `parameters` and
@@ -96,8 +137,7 @@ function toolToDefinition(tool) {
96
137
  ...tool.annotations === void 0 ? {} : { annotations: tool.annotations }
97
138
  };
98
139
  }
99
- //#endregion
100
- //#region src/core/tools/Tool.ts
140
+ // src/core/tools/Tool.ts
101
141
  /**
102
142
  * Binds an executable tool definition to a handler.
103
143
  *
@@ -150,16 +190,15 @@ var Tool = class {
150
190
  execute(args, context) {
151
191
  const faults = this.#contract?.explain(args) ?? [];
152
192
  const fault = faults[0];
153
- if (fault !== void 0) {
154
- let message = `${isString(fault.path) ? fault.path : fault.path.join(".")}: ${fault.reason}`;
155
- if ("expected" in fault) message += `; expected ${fault.expected}`;
156
- if ("received" in fault) message += `; received ${fault.received}`;
157
- if ("constraint" in fault) message += `; constraint ${fault.constraint}`;
158
- if ("limit" in fault && fault.limit !== void 0) message += `; limit ${fault.limit}`;
159
- if ("variants" in fault) message += `; variants ${fault.variants}`;
160
- if ("matched" in fault) message += `; matched ${fault.matched}`;
161
- throw new ToolError("ARGUMENTS", message, { faults });
162
- }
193
+ if (fault !== void 0) throw new ToolError("ARGUMENTS", [
194
+ `${isString(fault.path) ? fault.path : fault.path.join(".")}: ${fault.reason}`,
195
+ ..."expected" in fault ? [`expected ${fault.expected}`] : [],
196
+ ..."received" in fault ? [`received ${fault.received}`] : [],
197
+ ..."constraint" in fault ? [`constraint ${fault.constraint}`] : [],
198
+ ..."limit" in fault && fault.limit !== void 0 ? [`limit ${fault.limit}`] : [],
199
+ ..."variants" in fault ? [`variants ${fault.variants}`] : [],
200
+ ..."matched" in fault ? [`matched ${fault.matched}`] : []
201
+ ].join("; "), { faults });
163
202
  if (this.#contract !== void 0) {
164
203
  const parsed = this.#contract.parse(args);
165
204
  if (!isRecord(parsed)) throw new ToolError("ARGUMENTS", "Arguments did not parse");
@@ -168,8 +207,7 @@ var Tool = class {
168
207
  return this.#execute(args, context);
169
208
  }
170
209
  };
171
- //#endregion
172
- //#region src/core/tools/ToolManager.ts
210
+ // src/core/tools/ToolManager.ts
173
211
  /**
174
212
  * Represents an insertion-ordered tool registry with per-call error isolation.
175
213
  *
@@ -236,11 +274,7 @@ var ToolManager = class {
236
274
  return this.#run(call, context);
237
275
  }
238
276
  remove(names) {
239
- if (isArray(names)) {
240
- let removed = true;
241
- for (const name of names) if (!this.remove(name)) removed = false;
242
- return removed;
243
- }
277
+ if (isArray(names)) return this.#remove(names).reduce((all, removed) => removed && all, true);
244
278
  const tool = this.#tools.get(names);
245
279
  if (tool === void 0) return false;
246
280
  this.#tools.delete(names);
@@ -257,6 +291,9 @@ var ToolManager = class {
257
291
  this.#emitter.destroy();
258
292
  this.#tools.clear();
259
293
  }
294
+ *#remove(names) {
295
+ for (const name of names) yield this.remove(name);
296
+ }
260
297
  async #run(call, context) {
261
298
  const tool = this.#tools.get(call.name);
262
299
  if (tool === void 0) return {
@@ -293,8 +330,7 @@ var ToolManager = class {
293
330
  }
294
331
  }
295
332
  };
296
- //#endregion
297
- //#region src/core/factories.ts
333
+ // src/core/factories.ts
298
334
  /**
299
335
  * Creates an executable tool bound to the supplied handler, returned as a
300
336
  * `ToolInterface` so a call site holds the published contract rather than the `Tool`
@@ -350,7 +386,6 @@ function createTool(options) {
350
386
  function createToolManager(options) {
351
387
  return new ToolManager(options);
352
388
  }
353
- //#endregion
354
389
  export { Tool, ToolError, ToolManager, createTool, createToolManager, isToolCall, isToolError, toolToDefinition };
355
390
 
356
391
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/tools/Tool.ts","../../../src/core/tools/ToolManager.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { ToolErrorCode, ToolErrorContext } from './types.js'\nimport { isInstance } from '@orkestrel/contract'\n\n/**\n * Reports a schema conflict or argument validation failure with a machine-readable code.\n *\n * @example\n * ```ts\n * import { ToolError } from '@orkestrel/tool'\n *\n * const error = new ToolError('SCHEMA', 'Choose contract or parameters')\n * error.code // 'SCHEMA'\n * ```\n */\nexport class ToolError extends Error {\n\toverride readonly name = 'ToolError' as const\n\treadonly code: ToolErrorCode\n\treadonly context?: ToolErrorContext\n\n\tconstructor(code: ToolErrorCode, message: string, context?: ToolErrorContext) {\n\t\tsuper(message)\n\t\tthis.code = code\n\t\tif (context !== undefined) this.context = context\n\t}\n}\n\n/**\n * Checks whether a value is a tool error, containing hostile prototype access.\n *\n * @param value - The value to test\n * @returns True if the value is an instance of the tool error class; false otherwise\n *\n * @example\n * ```ts\n * import { ToolError, isToolError } from '@orkestrel/tool'\n *\n * isToolError(new ToolError('ARGUMENTS', 'Invalid amount')) // true\n * isToolError(new Error('Unrelated')) // false\n * ```\n */\nexport function isToolError(value: unknown): value is ToolError {\n\treturn isInstance(value, ToolError)\n}\n","import type { ToolCall } from './types.js'\nimport { holds, isRecord, isString } from '@orkestrel/contract'\n\n/**\n * Determines whether an unknown value is structurally a {@link ToolCall}, staying total\n * for malformed and adversarial input.\n *\n * @remarks\n * The accepted shape is a plain record with string `id` and `name` fields and a\n * plain-record `arguments` field. Extra fields are not read or verified.\n *\n * @param value - The value to test\n * @returns True if the value has the complete tool-call shape; false otherwise\n *\n * @example\n * ```ts\n * import { isToolCall } from '@orkestrel/tool'\n *\n * isToolCall({ id: '1', name: 'search', arguments: { query: 'birds' } }) // true\n * isToolCall({ id: '1', name: 'search', arguments: [] }) // false\n * ```\n */\nexport function isToolCall(value: unknown): value is ToolCall {\n\treturn holds(\n\t\t() =>\n\t\t\tisRecord(value) && isString(value.id) && isString(value.name) && isRecord(value.arguments),\n\t)\n}\n","import type { ToolDefinition, ToolInterface } from './types.js'\n\n/**\n * Projects a tool onto the plain definition advertised to a caller, advertising an\n * authored `summary` in place of the full description and carrying `parameters` and\n * `annotations` by reference.\n *\n * @remarks\n * The projection carries `name` and present `title`, `description`, `parameters`, and\n * `annotations` fields in that order. The full `description` stays on the tool for\n * direct lookup, and the definition is never a live handle on the tool's handler.\n *\n * @param tool - The tool to project\n * @returns A fresh definition carrying only the fields the tool authored\n *\n * @example\n * ```ts\n * import { Tool, toolToDefinition } from '@orkestrel/tool'\n *\n * const echo = new Tool({ name: 'echo', summary: 'Echo a value.', execute: (args) => args.value })\n * toolToDefinition(echo) // { name: 'echo', description: 'Echo a value.' }\n * ```\n */\nexport function toolToDefinition(tool: ToolInterface): ToolDefinition {\n\tconst description = tool.summary ?? tool.description\n\treturn {\n\t\tname: tool.name,\n\t\t...(tool.title === undefined ? {} : { title: tool.title }),\n\t\t...(description === undefined ? {} : { description }),\n\t\t...(tool.parameters === undefined ? {} : { parameters: tool.parameters }),\n\t\t...(tool.annotations === undefined ? {} : { annotations: tool.annotations }),\n\t}\n}\n","import type { ContractInterface } from '@orkestrel/contract'\nimport type { ToolAnnotations, ToolContext, ToolInterface, ToolOptions } from '../types.js'\nimport { createContract, isRecord, isString, schemaToParameters } from '@orkestrel/contract'\nimport { ToolError } from '../errors.js'\n\n/**\n * Binds an executable tool definition to a handler.\n *\n * @remarks\n * Advertised fields and execution context are forwarded by reference.\n * A contract derives parameters at construction and refuses parse faults before the\n * handler runs, then forwards the parsed arguments; without a contract, arguments\n * retain their identity. Supplying a contract and parameters throws a schema conflict.\n * Caller context is consumer-asserted and is not verified. Handler failures are not\n * caught here; {@link ToolManager} owns per-call error isolation.\n *\n * @example\n * ```ts\n * import { Tool } from '@orkestrel/tool'\n *\n * const tool = new Tool({\n * \tname: 'add',\n * \tdescription: 'Add two numbers',\n * \tparameters: {\n * \t\ttype: 'object',\n * \t\tproperties: { a: { type: 'number' }, b: { type: 'number' } },\n * \t},\n * \texecute: (args) => Number(args.a) + Number(args.b),\n * })\n * ```\n */\nexport class Tool implements ToolInterface {\n\treadonly #contract?: ContractInterface<unknown>\n\treadonly #execute: ToolOptions['execute']\n\n\treadonly name: string\n\treadonly title?: string\n\treadonly description?: string\n\treadonly summary?: string\n\treadonly parameters?: Readonly<Record<string, unknown>>\n\treadonly annotations?: ToolAnnotations\n\n\tconstructor(options: ToolOptions) {\n\t\tif (options.contract !== undefined && options.parameters !== undefined) {\n\t\t\tthrow new ToolError('SCHEMA', 'Choose contract or parameters, not both')\n\t\t}\n\t\tthis.name = options.name\n\t\tif (options.title !== undefined) this.title = options.title\n\t\tif (options.description !== undefined) this.description = options.description\n\t\tif (options.summary !== undefined) this.summary = options.summary\n\t\tif (options.annotations !== undefined) this.annotations = options.annotations\n\t\tif (options.contract !== undefined) {\n\t\t\tthis.#contract = createContract(options.contract)\n\t\t\tconst parameters = schemaToParameters(this.#contract.schema)\n\t\t\tif (parameters !== undefined) this.parameters = parameters\n\t\t} else if (options.parameters !== undefined) this.parameters = options.parameters\n\t\tthis.#execute = options.execute\n\t}\n\n\texecute(\n\t\targs: Readonly<Record<string, unknown>>,\n\t\tcontext: ToolContext,\n\t): Promise<unknown> | unknown {\n\t\tconst faults = this.#contract?.explain(args) ?? []\n\t\tconst fault = faults[0]\n\t\tif (fault !== undefined) {\n\t\t\tconst path = isString(fault.path) ? fault.path : fault.path.join('.')\n\t\t\tlet message = `${path}: ${fault.reason}`\n\t\t\tif ('expected' in fault) message += `; expected ${fault.expected}`\n\t\t\tif ('received' in fault) message += `; received ${fault.received}`\n\t\t\tif ('constraint' in fault) message += `; constraint ${fault.constraint}`\n\t\t\tif ('limit' in fault && fault.limit !== undefined) message += `; limit ${fault.limit}`\n\t\t\tif ('variants' in fault) message += `; variants ${fault.variants}`\n\t\t\tif ('matched' in fault) message += `; matched ${fault.matched}`\n\t\t\tthrow new ToolError('ARGUMENTS', message, { faults })\n\t\t}\n\t\tif (this.#contract !== undefined) {\n\t\t\tconst parsed = this.#contract.parse(args)\n\t\t\tif (!isRecord(parsed)) throw new ToolError('ARGUMENTS', 'Arguments did not parse')\n\t\t\treturn this.#execute(parsed, context)\n\t\t}\n\t\treturn this.#execute(args, context)\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tToolCall,\n\tToolContext,\n\tToolDefinition,\n\tToolInterface,\n\tToolManagerEventMap,\n\tToolManagerInterface,\n\tToolManagerOptions,\n\tToolResult,\n} from '../types.js'\nimport { attempt, isArray, isError } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { toolToDefinition } from '../helpers.js'\n\n/**\n * Represents an insertion-ordered tool registry with per-call error isolation.\n *\n * @remarks\n * A repeated name overwrites the registered tool without changing its insertion\n * position. Definitions advertise `summary` in place of `description` when present.\n * Unknown names and handler throws resolve to error results; a call whose `id` or `name`\n * accessor throws when read makes its call, and the batch holding it, reject. Batch\n * execution preserves input order and isolates each call whose members are plain\n * values. Execution context is shared across a batch and forwarded unchanged. An\n * omitted context receives a non-aborted signal. A signal aborted before handler\n * entry produces an error result; later cancellation is the handler's responsibility.\n * Registry changes publish synchronously. Replacements publish `remove`, then `add`\n * if the map still holds that exact replacement after the removal listeners return.\n * Destruction clears the tools before releasing listeners. A destroyed registry\n * publishes nothing, even when later additions update its tool map.\n *\n * @example\n * ```ts\n * import { Tool, ToolManager } from '@orkestrel/tool'\n *\n * const tools = new ToolManager()\n * tools.add(new Tool({ name: 'add', execute: (args) => Number(args.x) + Number(args.y) }))\n * const result = await tools.execute({\n * \tid: '1',\n * \tname: 'add',\n * \targuments: { x: 1, y: 2 },\n * })\n * ```\n */\nexport class ToolManager implements ToolManagerInterface {\n\treadonly #tools = new Map<string, ToolInterface>()\n\treadonly #emitter: Emitter<ToolManagerEventMap>\n\n\tconstructor(options?: ToolManagerOptions) {\n\t\tthis.#emitter = new Emitter<ToolManagerEventMap>(options)\n\t}\n\n\tget count(): number {\n\t\treturn this.#tools.size\n\t}\n\n\tget emitter(): EmitterInterface<ToolManagerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tadd(tool: ToolInterface): void\n\tadd(tools: readonly ToolInterface[]): void\n\tadd(tools: ToolInterface | readonly ToolInterface[]): void {\n\t\tif (isArray(tools)) {\n\t\t\tfor (const tool of tools) this.add(tool)\n\t\t\treturn\n\t\t}\n\t\tconst previous = this.#tools.get(tools.name)\n\t\tthis.#tools.set(tools.name, tools)\n\t\tif (previous !== undefined) this.#emitter.emit('remove', previous)\n\t\tif (this.#tools.get(tools.name) === tools) this.#emitter.emit('add', tools)\n\t}\n\n\ttool(name: string): ToolInterface | undefined {\n\t\treturn this.#tools.get(name)\n\t}\n\n\ttools(): readonly ToolInterface[] {\n\t\treturn [...this.#tools.values()]\n\t}\n\n\tdefinitions(): readonly ToolDefinition[] {\n\t\treturn [...this.#tools.values()].map((tool) => toolToDefinition(tool))\n\t}\n\n\texecute(call: ToolCall, context?: ToolContext): Promise<ToolResult>\n\texecute(calls: readonly ToolCall[], context?: ToolContext): Promise<readonly ToolResult[]>\n\texecute(\n\t\tcall: ToolCall | readonly ToolCall[],\n\t\tcontext: ToolContext = { signal: new AbortController().signal },\n\t): Promise<ToolResult | readonly ToolResult[]> {\n\t\tif (isArray(call)) return Promise.all(call.map((one) => this.#run(one, context)))\n\t\treturn this.#run(call, context)\n\t}\n\n\tremove(name: string): boolean\n\tremove(names: readonly string[]): boolean\n\tremove(names: string | readonly string[]): boolean {\n\t\tif (isArray(names)) {\n\t\t\tlet removed = true\n\t\t\tfor (const name of names) {\n\t\t\t\tif (!this.remove(name)) removed = false\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\tconst tool = this.#tools.get(names)\n\t\tif (tool === undefined) return false\n\t\tthis.#tools.delete(names)\n\t\tthis.#emitter.emit('remove', tool)\n\t\treturn true\n\t}\n\n\tclear(): void {\n\t\tconst tools = this.tools()\n\t\tthis.#tools.clear()\n\t\tthis.#emitter.emit('clear', tools)\n\t}\n\n\tdestroy(): void {\n\t\tthis.clear()\n\t\tthis.#emitter.destroy()\n\t\tthis.#tools.clear()\n\t}\n\n\tasync #run(call: ToolCall, context: ToolContext): Promise<ToolResult> {\n\t\tconst tool = this.#tools.get(call.name)\n\t\tif (tool === undefined) {\n\t\t\treturn {\n\t\t\t\tid: call.id,\n\t\t\t\tname: call.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: `tool not found: ${call.name}`,\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tif (context.signal.aborted) {\n\t\t\t\tconst reason: unknown = context.signal.reason\n\t\t\t\treturn {\n\t\t\t\t\tid: call.id,\n\t\t\t\t\tname: call.name,\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: reason === undefined ? 'aborted' : String(reason),\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst value = await tool.execute(call.arguments, context)\n\t\t\treturn { id: call.id, name: call.name, success: true, value }\n\t\t} catch (error) {\n\t\t\tconst message = attempt(() => (isError(error) ? error.message : String(error)))\n\t\t\treturn {\n\t\t\t\tid: call.id,\n\t\t\t\tname: call.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: message.success ? message.value : 'Unknown thrown value',\n\t\t\t}\n\t\t}\n\t}\n}\n","import type {\n\tToolInterface,\n\tToolManagerInterface,\n\tToolManagerOptions,\n\tToolOptions,\n} from './types.js'\nimport { Tool } from './tools/Tool.js'\nimport { ToolManager } from './tools/ToolManager.js'\n\n/**\n * Creates an executable tool bound to the supplied handler, returned as a\n * `ToolInterface` so a call site holds the published contract rather than the `Tool`\n * class.\n *\n * @param options - The advertised definition and execution handler\n * @returns A tool bound to the supplied handler\n *\n * @example Anatomy of a tool\n * ```ts\n * import { createTool } from '@orkestrel/tool'\n *\n * const add = createTool({\n * \tname: 'add',\n * \tdescription: 'Add two numeric values and return their sum. Both operands are required.',\n * \tsummary: 'Add two numbers.',\n * \tparameters: {\n * \t\ttype: 'object',\n * \t\tproperties: {\n * \t\t\tleft: { type: 'number' },\n * \t\t\tright: { type: 'number' },\n * \t\t},\n * \t\trequired: ['left', 'right'],\n * \t},\n * \texecute: (args) => Number(args.left) + Number(args.right),\n * })\n * ```\n */\nexport function createTool(options: ToolOptions): ToolInterface {\n\treturn new Tool(options)\n}\n\n/**\n * Creates an empty registry that advertises definitions and executes calls with\n * per-call error isolation, returned as a `ToolManagerInterface` so a caller holds the\n * published contract rather than the `ToolManager` class.\n *\n * @param options - The initial registry listeners and listener-error handler\n * @returns A registry bound to no tools\n *\n * @example\n * ```ts\n * import { createTool, createToolManager } from '@orkestrel/tool'\n *\n * const tools = createToolManager()\n * tools.add(createTool({ name: 'echo', execute: (args) => args.value }))\n * const result = await tools.execute({\n * \tid: '1',\n * \tname: 'echo',\n * \targuments: { value: 'hello' },\n * })\n * ```\n */\nexport function createToolManager(options?: ToolManagerOptions): ToolManagerInterface {\n\treturn new ToolManager(options)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/tools/Tool.ts","../../../src/core/tools/ToolManager.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { ToolErrorCode, ToolErrorContext } from './types.js'\nimport { arrayOf, holds, INTRINSICS, isFunction, isObject, isString } from '@orkestrel/contract'\n\n/**\n * Reports a schema conflict or argument validation failure with a machine-readable code.\n *\n * @example\n * ```ts\n * import { ToolError } from '@orkestrel/tool'\n *\n * const error = new ToolError('SCHEMA', 'Choose contract or parameters')\n * error.code // 'SCHEMA'\n * ```\n */\nexport class ToolError extends Error {\n\toverride readonly name = 'ToolError' as const\n\treadonly code: ToolErrorCode\n\treadonly context?: ToolErrorContext\n\n\tconstructor(code: ToolErrorCode, message: string, context?: ToolErrorContext) {\n\t\tsuper(message)\n\t\tINTRINSICS.define(this, Symbol.for('@orkestrel/tool.ToolError'), { value: this })\n\t\tthis.code = code\n\t\tif (context !== undefined) this.context = context\n\t}\n}\n\n/**\n * Checks whether a value is a tool error, containing hostile prototype access.\n *\n * @remarks\n * Recognizes self-branded errors across package copies and subclasses and refuses\n * transparent proxies. Validates the declared code and optional fault report.\n *\n * @param value - The value to test\n * @returns True if the value is an instance of the tool error class; false otherwise\n *\n * @example\n * ```ts\n * import { ToolError, isToolError } from '@orkestrel/tool'\n *\n * isToolError(new ToolError('ARGUMENTS', 'Invalid amount')) // true\n * isToolError(new Error('Unrelated')) // false\n * ```\n */\nexport function isToolError(value: unknown): value is ToolError {\n\treturn holds(() => {\n\t\tif (!(value instanceof Error) || INTRINSICS.prototype(value) === Error.prototype) return false\n\t\tconst brand = INTRINSICS.describe(value, Symbol.for('@orkestrel/tool.ToolError'))\n\t\tif (brand?.value !== value) return false\n\t\tconst code: unknown = INTRINSICS.reflect.read(value, 'code')\n\t\tif (code !== 'SCHEMA' && code !== 'ARGUMENTS') return false\n\t\tconst context: unknown = INTRINSICS.reflect.read(value, 'context')\n\t\tif (context === undefined) return true\n\t\tif (!isObject(context) && !isFunction(context)) return false\n\t\tconst faults: unknown = INTRINSICS.reflect.read(context, 'faults')\n\t\tif (faults === undefined) return true\n\t\treturn arrayOf((fault: unknown) => {\n\t\t\tif (!isObject(fault)) return false\n\t\t\tconst path: unknown = INTRINSICS.reflect.read(fault, 'path')\n\t\t\tif (!isString(path) && !arrayOf(isString)(path)) return false\n\t\t\tconst reason: unknown = INTRINSICS.reflect.read(fault, 'reason')\n\t\t\tif (reason === 'variant') {\n\t\t\t\treturn typeof INTRINSICS.reflect.read(fault, 'variants') === 'number'\n\t\t\t}\n\t\t\tif (reason === 'oneOf') {\n\t\t\t\treturn typeof INTRINSICS.reflect.read(fault, 'matched') === 'number'\n\t\t\t}\n\t\t\tconst expected: unknown = INTRINSICS.reflect.read(fault, 'expected')\n\t\t\tif (\n\t\t\t\t![\n\t\t\t\t\t'string',\n\t\t\t\t\t'number',\n\t\t\t\t\t'integer',\n\t\t\t\t\t'boolean',\n\t\t\t\t\t'null',\n\t\t\t\t\t'literal',\n\t\t\t\t\t'array',\n\t\t\t\t\t'object',\n\t\t\t\t\t'union',\n\t\t\t\t\t'json',\n\t\t\t\t].some((candidate) => candidate === expected)\n\t\t\t)\n\t\t\t\treturn false\n\t\t\tif (reason === 'missing') return true\n\t\t\tif (!isString(INTRINSICS.reflect.read(fault, 'received'))) return false\n\t\t\tif (reason === 'type') return true\n\t\t\tif (reason !== 'constraint') return false\n\t\t\tconst constraint: unknown = INTRINSICS.reflect.read(fault, 'constraint')\n\t\t\tconst limit: unknown = INTRINSICS.reflect.read(fault, 'limit')\n\t\t\treturn (\n\t\t\t\t(constraint === 'min' ||\n\t\t\t\t\tconstraint === 'max' ||\n\t\t\t\t\tconstraint === 'pattern' ||\n\t\t\t\t\tconstraint === 'integer') &&\n\t\t\t\t(limit === undefined || typeof limit === 'number' || typeof limit === 'string')\n\t\t\t)\n\t\t})(faults)\n\t})\n}\n","import type { ToolCall } from './types.js'\nimport { holds, isRecord, isString } from '@orkestrel/contract'\n\n/**\n * Determines whether an unknown value is structurally a {@link ToolCall}, staying total\n * for malformed and adversarial input.\n *\n * @remarks\n * The accepted shape is a plain record with string `id` and `name` fields and a\n * plain-record `arguments` field. Extra fields are not read or verified.\n *\n * @param value - The value to test\n * @returns True if the value has the complete tool-call shape; false otherwise\n *\n * @example\n * ```ts\n * import { isToolCall } from '@orkestrel/tool'\n *\n * isToolCall({ id: '1', name: 'search', arguments: { query: 'birds' } }) // true\n * isToolCall({ id: '1', name: 'search', arguments: [] }) // false\n * ```\n */\nexport function isToolCall(value: unknown): value is ToolCall {\n\treturn holds(\n\t\t() =>\n\t\t\tisRecord(value) && isString(value.id) && isString(value.name) && isRecord(value.arguments),\n\t)\n}\n","import type { ToolDefinition, ToolInterface } from './types.js'\n\n/**\n * Projects a tool onto the plain definition advertised to a caller, advertising an\n * authored `summary` in place of the full description and carrying `parameters` and\n * `annotations` by reference.\n *\n * @remarks\n * The projection carries `name` and present `title`, `description`, `parameters`, and\n * `annotations` fields in that order. The full `description` stays on the tool for\n * direct lookup, and the definition is never a live handle on the tool's handler.\n *\n * @param tool - The tool to project\n * @returns A fresh definition carrying only the fields the tool authored\n *\n * @example\n * ```ts\n * import { Tool, toolToDefinition } from '@orkestrel/tool'\n *\n * const echo = new Tool({ name: 'echo', summary: 'Echo a value.', execute: (args) => args.value })\n * toolToDefinition(echo) // { name: 'echo', description: 'Echo a value.' }\n * ```\n */\nexport function toolToDefinition(tool: ToolInterface): ToolDefinition {\n\tconst description = tool.summary ?? tool.description\n\treturn {\n\t\tname: tool.name,\n\t\t...(tool.title === undefined ? {} : { title: tool.title }),\n\t\t...(description === undefined ? {} : { description }),\n\t\t...(tool.parameters === undefined ? {} : { parameters: tool.parameters }),\n\t\t...(tool.annotations === undefined ? {} : { annotations: tool.annotations }),\n\t}\n}\n","import type { ContractInterface } from '@orkestrel/contract'\nimport type { ToolAnnotations, ToolContext, ToolInterface, ToolOptions } from '../types.js'\nimport { createContract, isRecord, isString, schemaToParameters } from '@orkestrel/contract'\nimport { ToolError } from '../errors.js'\n\n/**\n * Binds an executable tool definition to a handler.\n *\n * @remarks\n * Advertised fields and execution context are forwarded by reference.\n * A contract derives parameters at construction and refuses parse faults before the\n * handler runs, then forwards the parsed arguments; without a contract, arguments\n * retain their identity. Supplying a contract and parameters throws a schema conflict.\n * Caller context is consumer-asserted and is not verified. Handler failures are not\n * caught here; {@link ToolManager} owns per-call error isolation.\n *\n * @example\n * ```ts\n * import { Tool } from '@orkestrel/tool'\n *\n * const tool = new Tool({\n * \tname: 'add',\n * \tdescription: 'Add two numbers',\n * \tparameters: {\n * \t\ttype: 'object',\n * \t\tproperties: { a: { type: 'number' }, b: { type: 'number' } },\n * \t},\n * \texecute: (args) => Number(args.a) + Number(args.b),\n * })\n * ```\n */\nexport class Tool implements ToolInterface {\n\treadonly #contract?: ContractInterface<unknown>\n\treadonly #execute: ToolOptions['execute']\n\n\treadonly name: string\n\treadonly title?: string\n\treadonly description?: string\n\treadonly summary?: string\n\treadonly parameters?: Readonly<Record<string, unknown>>\n\treadonly annotations?: ToolAnnotations\n\n\tconstructor(options: ToolOptions) {\n\t\tif (options.contract !== undefined && options.parameters !== undefined) {\n\t\t\tthrow new ToolError('SCHEMA', 'Choose contract or parameters, not both')\n\t\t}\n\t\tthis.name = options.name\n\t\tif (options.title !== undefined) this.title = options.title\n\t\tif (options.description !== undefined) this.description = options.description\n\t\tif (options.summary !== undefined) this.summary = options.summary\n\t\tif (options.annotations !== undefined) this.annotations = options.annotations\n\t\tif (options.contract !== undefined) {\n\t\t\tthis.#contract = createContract(options.contract)\n\t\t\tconst parameters = schemaToParameters(this.#contract.schema)\n\t\t\tif (parameters !== undefined) this.parameters = parameters\n\t\t} else if (options.parameters !== undefined) this.parameters = options.parameters\n\t\tthis.#execute = options.execute\n\t}\n\n\texecute(\n\t\targs: Readonly<Record<string, unknown>>,\n\t\tcontext: ToolContext,\n\t): Promise<unknown> | unknown {\n\t\tconst faults = this.#contract?.explain(args) ?? []\n\t\tconst fault = faults[0]\n\t\tif (fault !== undefined) {\n\t\t\tconst path = isString(fault.path) ? fault.path : fault.path.join('.')\n\t\t\tconst message = [\n\t\t\t\t`${path}: ${fault.reason}`,\n\t\t\t\t...('expected' in fault ? [`expected ${fault.expected}`] : []),\n\t\t\t\t...('received' in fault ? [`received ${fault.received}`] : []),\n\t\t\t\t...('constraint' in fault ? [`constraint ${fault.constraint}`] : []),\n\t\t\t\t...('limit' in fault && fault.limit !== undefined ? [`limit ${fault.limit}`] : []),\n\t\t\t\t...('variants' in fault ? [`variants ${fault.variants}`] : []),\n\t\t\t\t...('matched' in fault ? [`matched ${fault.matched}`] : []),\n\t\t\t].join('; ')\n\t\t\tthrow new ToolError('ARGUMENTS', message, { faults })\n\t\t}\n\t\tif (this.#contract !== undefined) {\n\t\t\tconst parsed = this.#contract.parse(args)\n\t\t\tif (!isRecord(parsed)) throw new ToolError('ARGUMENTS', 'Arguments did not parse')\n\t\t\treturn this.#execute(parsed, context)\n\t\t}\n\t\treturn this.#execute(args, context)\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tToolCall,\n\tToolContext,\n\tToolDefinition,\n\tToolInterface,\n\tToolManagerEventMap,\n\tToolManagerInterface,\n\tToolManagerOptions,\n\tToolResult,\n} from '../types.js'\nimport { attempt, isArray, isError } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { toolToDefinition } from '../helpers.js'\n\n/**\n * Represents an insertion-ordered tool registry with per-call error isolation.\n *\n * @remarks\n * A repeated name overwrites the registered tool without changing its insertion\n * position. Definitions advertise `summary` in place of `description` when present.\n * Unknown names and handler throws resolve to error results; a call whose `id` or `name`\n * accessor throws when read makes its call, and the batch holding it, reject. Batch\n * execution preserves input order and isolates each call whose members are plain\n * values. Execution context is shared across a batch and forwarded unchanged. An\n * omitted context receives a non-aborted signal. A signal aborted before handler\n * entry produces an error result; later cancellation is the handler's responsibility.\n * Registry changes publish synchronously. Replacements publish `remove`, then `add`\n * if the map still holds that exact replacement after the removal listeners return.\n * Destruction clears the tools before releasing listeners. A destroyed registry\n * publishes nothing, even when later additions update its tool map.\n *\n * @example\n * ```ts\n * import { Tool, ToolManager } from '@orkestrel/tool'\n *\n * const tools = new ToolManager()\n * tools.add(new Tool({ name: 'add', execute: (args) => Number(args.x) + Number(args.y) }))\n * const result = await tools.execute({\n * \tid: '1',\n * \tname: 'add',\n * \targuments: { x: 1, y: 2 },\n * })\n * ```\n */\nexport class ToolManager implements ToolManagerInterface {\n\treadonly #tools = new Map<string, ToolInterface>()\n\treadonly #emitter: Emitter<ToolManagerEventMap>\n\n\tconstructor(options?: ToolManagerOptions) {\n\t\tthis.#emitter = new Emitter<ToolManagerEventMap>(options)\n\t}\n\n\tget count(): number {\n\t\treturn this.#tools.size\n\t}\n\n\tget emitter(): EmitterInterface<ToolManagerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tadd(tool: ToolInterface): void\n\tadd(tools: readonly ToolInterface[]): void\n\tadd(tools: ToolInterface | readonly ToolInterface[]): void {\n\t\tif (isArray(tools)) {\n\t\t\tfor (const tool of tools) this.add(tool)\n\t\t\treturn\n\t\t}\n\t\tconst previous = this.#tools.get(tools.name)\n\t\tthis.#tools.set(tools.name, tools)\n\t\tif (previous !== undefined) this.#emitter.emit('remove', previous)\n\t\tif (this.#tools.get(tools.name) === tools) this.#emitter.emit('add', tools)\n\t}\n\n\ttool(name: string): ToolInterface | undefined {\n\t\treturn this.#tools.get(name)\n\t}\n\n\ttools(): readonly ToolInterface[] {\n\t\treturn [...this.#tools.values()]\n\t}\n\n\tdefinitions(): readonly ToolDefinition[] {\n\t\treturn [...this.#tools.values()].map((tool) => toolToDefinition(tool))\n\t}\n\n\texecute(call: ToolCall, context?: ToolContext): Promise<ToolResult>\n\texecute(calls: readonly ToolCall[], context?: ToolContext): Promise<readonly ToolResult[]>\n\texecute(\n\t\tcall: ToolCall | readonly ToolCall[],\n\t\tcontext: ToolContext = { signal: new AbortController().signal },\n\t): Promise<ToolResult | readonly ToolResult[]> {\n\t\tif (isArray(call)) return Promise.all(call.map((one) => this.#run(one, context)))\n\t\treturn this.#run(call, context)\n\t}\n\n\tremove(name: string): boolean\n\tremove(names: readonly string[]): boolean\n\tremove(names: string | readonly string[]): boolean {\n\t\tif (isArray(names)) {\n\t\t\treturn this.#remove(names).reduce((all, removed) => removed && all, true)\n\t\t}\n\t\tconst tool = this.#tools.get(names)\n\t\tif (tool === undefined) return false\n\t\tthis.#tools.delete(names)\n\t\tthis.#emitter.emit('remove', tool)\n\t\treturn true\n\t}\n\n\tclear(): void {\n\t\tconst tools = this.tools()\n\t\tthis.#tools.clear()\n\t\tthis.#emitter.emit('clear', tools)\n\t}\n\n\tdestroy(): void {\n\t\tthis.clear()\n\t\tthis.#emitter.destroy()\n\t\tthis.#tools.clear()\n\t}\n\n\t*#remove(names: readonly string[]): Generator<boolean> {\n\t\tfor (const name of names) yield this.remove(name)\n\t}\n\n\tasync #run(call: ToolCall, context: ToolContext): Promise<ToolResult> {\n\t\tconst tool = this.#tools.get(call.name)\n\t\tif (tool === undefined) {\n\t\t\treturn {\n\t\t\t\tid: call.id,\n\t\t\t\tname: call.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: `tool not found: ${call.name}`,\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tif (context.signal.aborted) {\n\t\t\t\tconst reason: unknown = context.signal.reason\n\t\t\t\treturn {\n\t\t\t\t\tid: call.id,\n\t\t\t\t\tname: call.name,\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: reason === undefined ? 'aborted' : String(reason),\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst value = await tool.execute(call.arguments, context)\n\t\t\treturn { id: call.id, name: call.name, success: true, value }\n\t\t} catch (error) {\n\t\t\tconst message = attempt(() => (isError(error) ? error.message : String(error)))\n\t\t\treturn {\n\t\t\t\tid: call.id,\n\t\t\t\tname: call.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: message.success ? message.value : 'Unknown thrown value',\n\t\t\t}\n\t\t}\n\t}\n}\n","import type {\n\tToolInterface,\n\tToolManagerInterface,\n\tToolManagerOptions,\n\tToolOptions,\n} from './types.js'\nimport { Tool } from './tools/Tool.js'\nimport { ToolManager } from './tools/ToolManager.js'\n\n/**\n * Creates an executable tool bound to the supplied handler, returned as a\n * `ToolInterface` so a call site holds the published contract rather than the `Tool`\n * class.\n *\n * @param options - The advertised definition and execution handler\n * @returns A tool bound to the supplied handler\n *\n * @example Anatomy of a tool\n * ```ts\n * import { createTool } from '@orkestrel/tool'\n *\n * const add = createTool({\n * \tname: 'add',\n * \tdescription: 'Add two numeric values and return their sum. Both operands are required.',\n * \tsummary: 'Add two numbers.',\n * \tparameters: {\n * \t\ttype: 'object',\n * \t\tproperties: {\n * \t\t\tleft: { type: 'number' },\n * \t\t\tright: { type: 'number' },\n * \t\t},\n * \t\trequired: ['left', 'right'],\n * \t},\n * \texecute: (args) => Number(args.left) + Number(args.right),\n * })\n * ```\n */\nexport function createTool(options: ToolOptions): ToolInterface {\n\treturn new Tool(options)\n}\n\n/**\n * Creates an empty registry that advertises definitions and executes calls with\n * per-call error isolation, returned as a `ToolManagerInterface` so a caller holds the\n * published contract rather than the `ToolManager` class.\n *\n * @param options - The initial registry listeners and listener-error handler\n * @returns A registry bound to no tools\n *\n * @example\n * ```ts\n * import { createTool, createToolManager } from '@orkestrel/tool'\n *\n * const tools = createToolManager()\n * tools.add(createTool({ name: 'echo', execute: (args) => args.value }))\n * const result = await tools.execute({\n * \tid: '1',\n * \tname: 'echo',\n * \targuments: { value: 'hello' },\n * })\n * ```\n */\nexport function createToolManager(options?: ToolManagerOptions): ToolManagerInterface {\n\treturn new ToolManager(options)\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orkestrel/tool",
3
- "version": "0.0.19",
3
+ "version": "0.0.20",
4
4
  "description": "The tool runtime for the @orkestrel line — JSON-Schema tool definitions, calls, results, executable tools, and a registry with per-call error isolation. Part of the @orkestrel line.",
5
5
  "keywords": [
6
6
  "agent",
@@ -64,28 +64,28 @@
64
64
  "prepublishOnly": "npm run format:check && npm run lint:check && npm run check && npm run build && npm test && npm run test:distribution -- --mode release",
65
65
  "test:distribution": "vitest run --config vite.config.ts --no-cache --reporter=dot --project distribution",
66
66
  "test:probe": "vitest run --config vite.config.ts --no-cache --reporter=verbose --project probe",
67
- "test:bench": "vitest bench --config vite.config.ts --no-cache --project probe",
67
+ "test:bench": "vitest bench --config vite.config.ts --no-cache --project \"probe (bench)\" --mode benchmark",
68
68
  "prepack": "npm run build",
69
69
  "test:setup": "vitest run --config vite.config.ts --no-cache --reporter=dot --project setup"
70
70
  },
71
71
  "dependencies": {
72
- "@orkestrel/contract": "^0.0.19",
73
- "@orkestrel/emitter": "^0.0.12"
72
+ "@orkestrel/contract": "^0.0.20",
73
+ "@orkestrel/emitter": "^0.0.13"
74
74
  },
75
75
  "devDependencies": {
76
- "@microsoft/api-extractor": "^7.59.4",
77
- "@orkestrel/guide": "^0.0.24",
78
- "@orkestrel/probe": "^0.0.22",
79
- "@orkestrel/scaffold": "^0.0.95",
80
- "@orkestrel/test": "^0.0.24",
81
- "@types/node": "^26.6.4",
82
- "oxfmt": "^0.72.0",
83
- "oxlint": "^1.87.0",
84
- "typescript": "^6.0.3",
85
- "vite": "^8.3.3",
86
- "vitest": "^4.1.11"
76
+ "@microsoft/api-extractor": "^7.60.0",
77
+ "@orkestrel/guide": "^0.0.25",
78
+ "@orkestrel/probe": "^0.0.25",
79
+ "@orkestrel/scaffold": "^0.0.113",
80
+ "@orkestrel/test": "^0.0.31",
81
+ "@types/node": "^24.19.2",
82
+ "oxfmt": "^0.75.0",
83
+ "oxlint": "^1.90.0",
84
+ "typescript": "^7.0.2",
85
+ "vite": "^8.3.5",
86
+ "vitest": "^5.0.5"
87
87
  },
88
88
  "engines": {
89
- "node": ">=22.12.0"
89
+ "node": ">=22.18.0"
90
90
  }
91
91
  }