@orkestrel/toolbox 0.0.13 → 0.0.15

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.
@@ -591,7 +591,7 @@ var INFER_TOOL_DESCRIPTION = [
591
591
  * @remarks
592
592
  * Carries a machine-readable `code` (see {@link import('./types.js').ToolboxErrorCode}) and
593
593
  * an optional `context` bag for structured diagnostics. They are readable through an in-process
594
- * catch, including around a direct `tool.execute(args)` call. The `ToolManagerInterface`
594
+ * catch, including around a direct `tool.execute(args, context)` call. The `ToolManagerInterface`
595
595
  * (`@orkestrel/tool`) instead flattens every throw to the canonical tool result's top-level
596
596
  * `error` message string under AGENTS' “narrow untrusted input with guards” rule.
597
597
  *
@@ -633,7 +633,7 @@ var ToolboxError = class extends Error {
633
633
  * ```
634
634
  */
635
635
  function isToolboxError(value) {
636
- return value instanceof ToolboxError;
636
+ return (0, _orkestrel_contract.isInstance)(value, ToolboxError);
637
637
  }
638
638
  //#endregion
639
639
  //#region src/core/validators.ts
@@ -645,7 +645,7 @@ function isToolboxError(value) {
645
645
  */
646
646
  function isWorkflowLineage(value) {
647
647
  const inspected = (0, _orkestrel_contract.attempt)(() => {
648
- if (!Array.isArray(value)) return false;
648
+ if (!(0, _orkestrel_contract.isArray)(value)) return false;
649
649
  const seen = /* @__PURE__ */ new Set();
650
650
  for (const [index, tag] of value.entries()) {
651
651
  if (!(0, _orkestrel_contract.isString)(tag)) return false;
@@ -665,7 +665,7 @@ function isWorkflowLineage(value) {
665
665
  */
666
666
  function isAgentFunction(value) {
667
667
  const inspected = (0, _orkestrel_contract.attempt)(() => {
668
- if (typeof value !== "function" || !Object.isFrozen(value)) return false;
668
+ if (!(0, _orkestrel_contract.isFunction)(value) || !Object.isFrozen(value)) return false;
669
669
  const category = Reflect.getOwnPropertyDescriptor(value, "category");
670
670
  const lineage = Reflect.getOwnPropertyDescriptor(value, "lineage");
671
671
  return category?.value === "agent" && lineage !== void 0 && "value" in lineage && Object.isFrozen(lineage.value) && isWorkflowLineage(lineage.value);
@@ -681,7 +681,7 @@ function isAgentFunction(value) {
681
681
  function isColumnSpec(value) {
682
682
  if (isColumnPrimitive(value)) return true;
683
683
  if (!(0, _orkestrel_contract.isRecord)(value)) return false;
684
- return isColumnPrimitive(value.primitive) && (value.optional === void 0 || typeof value.optional === "boolean");
684
+ return isColumnPrimitive(value.primitive) && (value.optional === void 0 || (0, _orkestrel_contract.isBoolean)(value.optional));
685
685
  }
686
686
  /**
687
687
  * Narrows an unknown value to a {@link ColumnPrimitive}.
@@ -689,9 +689,7 @@ function isColumnSpec(value) {
689
689
  * @param value - The value to inspect
690
690
  * @returns True if `value` is `'string'`, `'integer'`, `'number'`, or `'boolean'`; false otherwise
691
691
  */
692
- function isColumnPrimitive(value) {
693
- return value === "string" || value === "integer" || value === "number" || value === "boolean";
694
- }
692
+ var isColumnPrimitive = (0, _orkestrel_contract.literalOf)("string", "integer", "number", "boolean");
695
693
  /**
696
694
  * Narrows an unknown value to a {@link DatabaseDefinition} — a non-empty `id` and `driver`, a
697
695
  * `tables` record whose every value is `{ columns: record of valid ColumnSpec }`, plus optional
@@ -718,9 +716,9 @@ function isDatabaseDefinition(value) {
718
716
  if (value.indexes !== void 0) {
719
717
  if (!(0, _orkestrel_contract.isRecord)(value.indexes)) return false;
720
718
  for (const groups of Object.values(value.indexes)) {
721
- if (!Array.isArray(groups)) return false;
719
+ if (!(0, _orkestrel_contract.isArray)(groups)) return false;
722
720
  for (const group of groups) {
723
- if (!Array.isArray(group) || group.length === 0) return false;
721
+ if (!(0, _orkestrel_contract.isArray)(group) || group.length === 0) return false;
724
722
  for (const column of group) if (!(0, _orkestrel_contract.isNonEmptyString)(column)) return false;
725
723
  }
726
724
  }
@@ -1576,7 +1574,7 @@ function expandInclude(paths, depth) {
1576
1574
  });
1577
1575
  ancestors.push(branch);
1578
1576
  const existing = branch[segment];
1579
- branch = typeof existing === "object" ? existing : {};
1577
+ branch = (0, _orkestrel_contract.isObject)(existing) ? existing : {};
1580
1578
  }
1581
1579
  const leaf = segments[last];
1582
1580
  if (leaf === void 0) throw new ToolboxError("TOOL", `malformed include path '${path}'`, {
@@ -2059,7 +2057,9 @@ var DatabaseResolver = class {
2059
2057
  * (`{ publish: createToolFunction(tools, 'publish') }`); the pure workflow runner has no
2060
2058
  * knowledge of tools itself. The returned function executes `name` against `tools` with the
2061
2059
  * task's `controller.input` as the call arguments. The adapter resolves the live tool, calls its
2062
- * `execute` method directly, and deep-gates the returned unknown through `parseJSONValue`.
2060
+ * `execute` method directly, and deep-gates the returned unknown through `parseJSONValue`. The
2061
+ * execution context it passes carries the task's own `controller.signal`, so a handler that
2062
+ * reads `context.signal` observes the caller's cancellation.
2063
2063
  * Genuine execution throws retain identity. An unregistered name or non-JSON return throws this
2064
2064
  * package's typed `TOOL` `ToolboxError`.
2065
2065
  *
@@ -2084,7 +2084,7 @@ function createToolFunction(tools, name) {
2084
2084
  return async (controller) => {
2085
2085
  const tool = tools.tool(name);
2086
2086
  if (tool === void 0) throw new ToolboxError("TOOL", `tool '${name}' is not registered`, { tool: name });
2087
- const result = (0, _orkestrel_contract.parseJSONValue)(await tool.execute(controller.input));
2087
+ const result = (0, _orkestrel_contract.parseJSONValue)(await tool.execute(controller.input, { signal: controller.signal }));
2088
2088
  if (result === void 0) throw new ToolboxError("TOOL", `tool '${name}' returned a non-JSON value`, { tool: name });
2089
2089
  return result;
2090
2090
  };
@@ -2209,7 +2209,7 @@ function createWorkflowFunctions(runner, options) {
2209
2209
  const composed = {};
2210
2210
  Object.setPrototypeOf(composed, null);
2211
2211
  for (const [name, fn] of Object.entries(functions)) {
2212
- if (typeof fn !== "function") throw new ToolboxError("TOOL", `workflow function '${name}' is not callable`, { function: name });
2212
+ if (!(0, _orkestrel_contract.isFunction)(fn)) throw new ToolboxError("TOOL", `workflow function '${name}' is not callable`, { function: name });
2213
2213
  if (isAgentFunction(fn)) throw new ToolboxError("TOOL", `agent function '${name}' must be supplied through agents`, { function: name });
2214
2214
  composed[name] = fn;
2215
2215
  }
@@ -2338,7 +2338,7 @@ function createWorkflowTool(definition, runner, options) {
2338
2338
  const owned = cloned.value;
2339
2339
  let target;
2340
2340
  if (Object.keys(owned).length === 0) target = definition;
2341
- else if (Array.isArray(owned.steps)) {
2341
+ else if ((0, _orkestrel_contract.isArray)(owned.steps)) {
2342
2342
  const flat = steps.parse(owned);
2343
2343
  target = flat === void 0 ? void 0 : expandSteps(flat);
2344
2344
  } else {
@@ -2886,15 +2886,18 @@ function createDatabaseDefinitionStore(driver = (0, _orkestrel_database.createMe
2886
2886
  * import { createDatabaseTool } from '@src/core'
2887
2887
  *
2888
2888
  * const tool = createDatabaseTool()
2889
- * await tool.execute({
2890
- * operation: 'create',
2891
- * id: 'shop',
2892
- * tables: { products: { columns: { name: 'string', price: 'number' } } },
2893
- * })
2889
+ * await tool.execute(
2890
+ * {
2891
+ * operation: 'create',
2892
+ * id: 'shop',
2893
+ * tables: { products: { columns: { name: 'string', price: 'number' } } },
2894
+ * },
2895
+ * { signal: new AbortController().signal },
2896
+ * )
2894
2897
  * ```
2895
2898
  */
2896
2899
  function createDatabaseTool(options = {}) {
2897
- if (options.timeout !== void 0 && (options.timeout < 0 || !Number.isSafeInteger(options.timeout))) throw new ToolboxError("TOOL", "database timeout must be a nonnegative safe integer", { timeout: options.timeout });
2900
+ if (options.timeout !== void 0 && (options.timeout < 0 || !(0, _orkestrel_contract.isNumber)(options.timeout) || !Number.isSafeInteger(options.timeout))) throw new ToolboxError("TOOL", "database timeout must be a nonnegative safe integer", { timeout: options.timeout });
2898
2901
  const contract = (0, _orkestrel_contract.createContract)(databaseToolShape);
2899
2902
  const parameters = (0, _orkestrel_contract.schemaToParameters)(contract.schema);
2900
2903
  const handles = new Map(Object.entries(options.databases ?? {}));
@@ -2964,8 +2967,8 @@ function createDatabaseTool(options = {}) {
2964
2967
  }
2965
2968
  case "get": {
2966
2969
  const table = (await resolver.resolve(call.id)).table(call.table);
2967
- const many = Array.isArray(call.key);
2968
- const keys = Array.isArray(call.key) ? call.key : [call.key];
2970
+ const many = (0, _orkestrel_contract.isArray)(call.key);
2971
+ const keys = (0, _orkestrel_contract.isArray)(call.key) ? call.key : [call.key];
2969
2972
  const rows = await table.get(keys);
2970
2973
  return many ? { rows } : { row: rows[0] };
2971
2974
  }
@@ -2986,30 +2989,30 @@ function createDatabaseTool(options = {}) {
2986
2989
  case "aggregate": return { value: await (await resolver.resolve(call.id)).table(call.table).aggregate(call.function, call.column, normalizeQuery(call.query), read) };
2987
2990
  case "add": {
2988
2991
  const table = (await resolver.resolve(call.id)).table(call.table);
2989
- const many = Array.isArray(call.row);
2990
- const rows = Array.isArray(call.row) ? call.row : [call.row];
2992
+ const many = (0, _orkestrel_contract.isArray)(call.row);
2993
+ const rows = (0, _orkestrel_contract.isArray)(call.row) ? call.row : [call.row];
2991
2994
  const keys = await table.add(rows, read);
2992
2995
  return many ? { keys } : { key: keys[0] };
2993
2996
  }
2994
2997
  case "set": {
2995
2998
  const table = (await resolver.resolve(call.id)).table(call.table);
2996
- const many = Array.isArray(call.row);
2997
- const rows = Array.isArray(call.row) ? call.row : [call.row];
2999
+ const many = (0, _orkestrel_contract.isArray)(call.row);
3000
+ const rows = (0, _orkestrel_contract.isArray)(call.row) ? call.row : [call.row];
2998
3001
  const keys = await table.set(rows, read);
2999
3002
  return many ? { keys } : { key: keys[0] };
3000
3003
  }
3001
3004
  case "update": {
3002
3005
  const table = (await resolver.resolve(call.id)).table(call.table);
3003
3006
  const changes = call.changes;
3004
- const many = Array.isArray(call.key);
3005
- const keys = Array.isArray(call.key) ? call.key : [call.key];
3007
+ const many = (0, _orkestrel_contract.isArray)(call.key);
3008
+ const keys = (0, _orkestrel_contract.isArray)(call.key) ? call.key : [call.key];
3006
3009
  const updated = await table.update(keys, changes, read);
3007
3010
  return many ? { updated } : { updated: updated[0] };
3008
3011
  }
3009
3012
  case "remove": {
3010
3013
  const table = (await resolver.resolve(call.id)).table(call.table);
3011
- const many = Array.isArray(call.key);
3012
- const keys = Array.isArray(call.key) ? call.key : [call.key];
3014
+ const many = (0, _orkestrel_contract.isArray)(call.key);
3015
+ const keys = (0, _orkestrel_contract.isArray)(call.key) ? call.key : [call.key];
3013
3016
  const removed = await table.remove(keys, read);
3014
3017
  return many ? { removed } : { removed: removed[0] };
3015
3018
  }
@@ -3031,7 +3034,7 @@ function createDatabaseTool(options = {}) {
3031
3034
  if (isToolboxError(error)) throw error;
3032
3035
  const code = inferDatabaseCode(error);
3033
3036
  if (code === void 0) throw error;
3034
- throw new ToolboxError("DATABASE", error instanceof Error ? error.message : String(error), {
3037
+ throw new ToolboxError("DATABASE", (0, _orkestrel_contract.isError)(error) ? error.message : String(error), {
3035
3038
  code,
3036
3039
  operation: call.operation,
3037
3040
  id: call.id,
@@ -3086,7 +3089,10 @@ function createDatabaseTool(options = {}) {
3086
3089
  * import { createRelationTool } from '@src/core'
3087
3090
  *
3088
3091
  * const tool = createRelationTool({ managers: { shop: manager } })
3089
- * await tool.execute({ operation: 'load', model: 'accounts', key: 'acc1', include: ['contacts'] })
3092
+ * await tool.execute(
3093
+ * { operation: 'load', model: 'accounts', key: 'acc1', include: ['contacts'] },
3094
+ * { signal: new AbortController().signal },
3095
+ * )
3090
3096
  * ```
3091
3097
  */
3092
3098
  function createRelationTool(options) {
@@ -3107,7 +3113,7 @@ function createRelationTool(options) {
3107
3113
  switch (call.operation) {
3108
3114
  case "load": {
3109
3115
  const include = expandInclude(call.include, depth);
3110
- if (typeof call.key === "string" || typeof call.key === "number") return { row: await model.load(call.key, include) };
3116
+ if ((0, _orkestrel_contract.isString)(call.key) || (0, _orkestrel_contract.isNumber)(call.key)) return { row: await model.load(call.key, include) };
3111
3117
  return { rows: await model.load(call.key, include) };
3112
3118
  }
3113
3119
  case "find": {
@@ -3150,7 +3156,7 @@ function createRelationTool(options) {
3150
3156
  } catch (error) {
3151
3157
  if (isToolboxError(error)) throw error;
3152
3158
  const relation = inferRelationCode(error);
3153
- if (relation !== void 0) throw new ToolboxError("RELATION", error instanceof Error ? error.message : String(error), {
3159
+ if (relation !== void 0) throw new ToolboxError("RELATION", (0, _orkestrel_contract.isError)(error) ? error.message : String(error), {
3154
3160
  code: relation,
3155
3161
  operation: call.operation,
3156
3162
  model: call.model,
@@ -3158,7 +3164,7 @@ function createRelationTool(options) {
3158
3164
  });
3159
3165
  const database = inferDatabaseCode(error);
3160
3166
  if (database === void 0) throw error;
3161
- throw new ToolboxError("DATABASE", error instanceof Error ? error.message : String(error), {
3167
+ throw new ToolboxError("DATABASE", (0, _orkestrel_contract.isError)(error) ? error.message : String(error), {
3162
3168
  code: database,
3163
3169
  operation: call.operation
3164
3170
  });
@@ -3305,8 +3311,10 @@ function createInferTool(options) {
3305
3311
  * never asserted, and a key outside the closed inferred schema is silently dropped rather than
3306
3312
  * rejected (see {@link import('./types.js').EndpointToolOptions.validate}). With
3307
3313
  * `validate: false`, the tool's `execute` passes through the model-supplied `args` to
3308
- * `definition.execute` without re-validation — the raw-passthrough opt-out. Either way, the
3309
- * definition's return flows back as the tool call's plain result; a throw propagates uncaught,
3314
+ * `definition.execute` without re-validation — the raw-passthrough opt-out. The execution context
3315
+ * the tool's `execute` receives reaches `definition.execute` unchanged whichever way `args` are
3316
+ * handled, so a handler that reads `context.signal` observes the caller's cancellation. Either way,
3317
+ * the definition's return flows back as the tool call's plain result; a throw propagates uncaught,
3310
3318
  * isolated by the `ToolManagerInterface` (`@orkestrel/tool`) into the canonical error envelope
3311
3319
  * — never caught or re-wrapped here.
3312
3320
  *
@@ -3359,8 +3367,8 @@ function createEndpointTool(definition, options) {
3359
3367
  name: definition.name,
3360
3368
  description: definition.description,
3361
3369
  ...parameters === void 0 ? {} : { parameters },
3362
- execute(args) {
3363
- return definition.execute(args);
3370
+ execute(args, context) {
3371
+ return definition.execute(args, context);
3364
3372
  }
3365
3373
  });
3366
3374
  const contract = (0, _orkestrel_contract.createContract)((0, _orkestrel_contract.schemaToShape)(objectSchema));
@@ -3368,13 +3376,13 @@ function createEndpointTool(definition, options) {
3368
3376
  name: definition.name,
3369
3377
  description: definition.description,
3370
3378
  ...parameters === void 0 ? {} : { parameters },
3371
- execute(args) {
3379
+ execute(args, context) {
3372
3380
  const parsed = contract.parse(args);
3373
3381
  if (parsed === void 0 || !(0, _orkestrel_contract.isRecord)(parsed)) throw new ToolboxError("TOOL", "malformed endpoint call arguments", {
3374
3382
  name: definition.name,
3375
3383
  faults: contract.explain(args)
3376
3384
  });
3377
- return definition.execute(parsed);
3385
+ return definition.execute(parsed, context);
3378
3386
  }
3379
3387
  });
3380
3388
  }