@orkestrel/toolbox 0.0.12 → 0.0.14

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.
@@ -9,29 +9,33 @@ import { createTool } from "@orkestrel/tool";
9
9
  import { createForm, isFormError, isFormValues, parseForm } from "@orkestrel/form";
10
10
  //#region src/core/constants.ts
11
11
  /**
12
- * Holds the name {@link import('./factories.js').createAgentTool} advertises by default — the key a
13
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
12
+ * Holds the name {@link import('./factories.js').createAgentTool} advertises by default, `'agent'`
13
+ * — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
14
14
  */
15
15
  var AGENT_TOOL_NAME = "agent";
16
16
  /**
17
17
  * Holds the maximum nesting depth a delegation chain (agent tool → sub-agent → agent tool → …) may
18
- * reach — the bound {@link import('./factories.js').createAgentTool}'s depth/cycle guard
18
+ * reach, `8` — the bound {@link import('./factories.js').createAgentTool}'s depth/cycle guard
19
19
  * enforces.
20
20
  *
21
21
  * @remarks
22
- * Deliberately a SEPARATE constant from {@link MAX_WORKFLOW_CHAIN} (rather than the two guards
23
- * sharing one reference): the two guards bound DIFFERENT chains (workflow nesting vs. agent
22
+ * Deliberately a separate constant from {@link MAX_WORKFLOW_CHAIN} (rather than the guards
23
+ * sharing one reference): they bound different chains (workflow nesting against agent
24
24
  * delegation) that happen to share a value today, and keeping this bound decoupled means a
25
25
  * future change to one never silently shifts the other. Same numeric value by convention, not
26
26
  * by shared reference.
27
27
  */
28
28
  var AGENT_TOOL_DEPTH = 8;
29
29
  /**
30
- * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createAgentTool}
31
- * advertises in place of {@link AGENT_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
32
- * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
33
- * for the full teaching description; the full text stays retrievable through
34
- * {@link import('./factories.js').createDescribeTool}.
30
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
31
+ * {@link import('./factories.js').createAgentTool} advertises in place of
32
+ * {@link AGENT_TOOL_DESCRIPTION} — one sentence offering sub-agent delegation and pointing at
33
+ * `describe` for the optional overrides.
34
+ *
35
+ * @remarks
36
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
37
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
38
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
35
39
  */
36
40
  var AGENT_TOOL_SUMMARY = "Delegate a task to a sub-agent and return its result; each call runs one sub-agent turn to completion. Call describe('agent') for the optional provider/tools/system overrides.";
37
41
  /**
@@ -51,7 +55,7 @@ var AGENT_TOOL_DESCRIPTION = [
51
55
  JSON.stringify({ task: "Summarize the attached notes in three bullet points." })
52
56
  ].join("\n");
53
57
  /**
54
- * Holds the maximum nesting depth a workflow → agent → workflow chain may reach — the bound
58
+ * Holds the maximum nesting depth a workflow → agent → workflow chain may reach, `8` — the bound
55
59
  * {@link import('./factories.js').createAgentFunction} and
56
60
  * {@link import('./factories.js').createWorkflowTool}'s depth/cycle guards enforce.
57
61
  *
@@ -62,40 +66,40 @@ var AGENT_TOOL_DESCRIPTION = [
62
66
  */
63
67
  var MAX_WORKFLOW_CHAIN = 8;
64
68
  /**
65
- * Holds the name {@link import('./factories.js').createWorkflowTool} advertises by default — the key a
66
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under, and the name
67
- * {@link import('./factories.js').createAgentFunction} binds the depth/cycle-aware workflow tool
68
- * under onto a wrapped agent's `context.tools`.
69
+ * Holds the name {@link import('./factories.js').createWorkflowTool} advertises by default,
70
+ * `'workflow'` — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers
71
+ * under, and the name {@link import('./factories.js').createAgentFunction} binds the
72
+ * depth/cycle-aware workflow tool under onto a wrapped agent's `context.tools`.
69
73
  *
70
74
  * @remarks
71
75
  * The propagation seam's well-known key: when
72
76
  * `createAgentFunction`'s `runner` option is supplied, it adds a `createWorkflowTool`-built tool
73
- * under this name to the agent's `context.tools`, so it can author + run a NESTED workflow
77
+ * under this name to the agent's `context.tools`, so it can author and run a nested workflow
74
78
  * (bounded by {@link MAX_WORKFLOW_CHAIN}).
75
79
  */
76
80
  var WORKFLOW_TOOL_NAME = "workflow";
77
81
  /**
78
- * Holds a complete FLAT authoring example — the PRIMARY way a small model authors a workflow through
79
- * {@link import('./factories.js').createWorkflowTool}: `{ name, steps: [{ name }] }`.
82
+ * Holds a complete flat authoring example — the primary way a small model authors a workflow
83
+ * through {@link import('./factories.js').createWorkflowTool}: `{ name, steps: [{ name }] }`.
80
84
  *
81
85
  * @remarks
82
86
  * Each step becomes a one-task phase, in
83
- * order; a step's `name` is a REGISTERED behavior name (not a label) — the registry key its
87
+ * order; a step's `name` is a registered behavior name (not a label) — the registry key its
84
88
  * task's `behavior` resolves against. The tool expands this
85
89
  * ({@link import('./helpers.js').expandSteps}) into a valid `WorkflowDefinition`
86
- * (`@orkestrel/workflow`). It is embedded VERBATIM in {@link WORKFLOW_TOOL_DESCRIPTION}.
90
+ * (`@orkestrel/workflow`). It is embedded verbatim in {@link WORKFLOW_TOOL_DESCRIPTION}.
87
91
  */
88
92
  var WORKFLOW_TOOL_FLAT_EXAMPLE = Object.freeze({
89
93
  name: "release",
90
94
  steps: Object.freeze([Object.freeze({ name: "compile" }), Object.freeze({ name: "publish" })])
91
95
  });
92
96
  /**
93
- * Holds a minimal NESTED authoring example — the ADVANCED escape-hatch form a model may use instead of
94
- * the flat shape: a full `WorkflowDefinition` (`@orkestrel/workflow`).
97
+ * Holds a minimal nested authoring example — the advanced escape-hatch form a model can use instead
98
+ * of the flat shape: a full `WorkflowDefinition` (`@orkestrel/workflow`).
95
99
  *
96
100
  * @remarks
97
- * The full four-level form, documented in
98
- * {@link WORKFLOW_TOOL_DESCRIPTION} as the advanced alternative. It is embedded VERBATIM.
101
+ * The full nested form, documented in
102
+ * {@link WORKFLOW_TOOL_DESCRIPTION} as the advanced alternative. It is embedded verbatim.
99
103
  */
100
104
  var WORKFLOW_TOOL_NESTED_EXAMPLE = Object.freeze({
101
105
  id: "release",
@@ -111,11 +115,15 @@ var WORKFLOW_TOOL_NESTED_EXAMPLE = Object.freeze({
111
115
  })])
112
116
  });
113
117
  /**
114
- * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createWorkflowTool}
115
- * advertises in place of {@link WORKFLOW_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
116
- * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
117
- * for the full teaching description; the full text stays retrievable through
118
- * {@link import('./factories.js').createDescribeTool}.
118
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
119
+ * {@link import('./factories.js').createWorkflowTool} advertises in place of
120
+ * {@link WORKFLOW_TOOL_DESCRIPTION} — one sentence offering multi-phase authoring and pointing at
121
+ * `describe` for the authoring schema and its examples.
122
+ *
123
+ * @remarks
124
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
125
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
126
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
119
127
  */
120
128
  var WORKFLOW_TOOL_SUMMARY = "Author and run a multi-phase workflow in one call — phases run in sequence, tasks within a phase run concurrently. Call describe('workflow') for the full authoring schema and examples.";
121
129
  /**
@@ -138,13 +146,14 @@ var WORKFLOW_TOOL_DESCRIPTION = [
138
146
  "In the nested form you may omit any \"id\"/\"name\" and they are filled in positionally; a provided one is kept."
139
147
  ].join("\n");
140
148
  /**
141
- * Holds the name {@link import('./factories.js').createWorkspaceTool} advertises by default — the key a
142
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
149
+ * Holds the name {@link import('./factories.js').createWorkspaceTool} advertises by default,
150
+ * `'workspace'` — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`)
151
+ * registers under.
143
152
  */
144
153
  var WORKSPACE_TOOL_NAME = "workspace";
145
154
  /**
146
- * Holds a valid {@link import('./types.js').WorkspaceOperation} object — the canonical example embedded
147
- * VERBATIM in {@link WORKSPACE_TOOL_DESCRIPTION}.
155
+ * Holds a valid {@link import('./types.js').WorkspaceOperation} object — the canonical example
156
+ * embedded verbatim in {@link WORKSPACE_TOOL_DESCRIPTION}.
148
157
  *
149
158
  * @remarks
150
159
  * A `'write'` op (the most common authoring
@@ -157,11 +166,15 @@ var WORKSPACE_TOOL_EXAMPLE = Object.freeze({
157
166
  content: "hello"
158
167
  });
159
168
  /**
160
- * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createWorkspaceTool}
161
- * advertises in place of {@link WORKSPACE_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
162
- * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
163
- * for the full teaching description; the full text stays retrievable through
164
- * {@link import('./factories.js').createDescribeTool}.
169
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
170
+ * {@link import('./factories.js').createWorkspaceTool} advertises in place of
171
+ * {@link WORKSPACE_TOOL_DESCRIPTION} — one sentence offering the `operation`-keyed file editing and
172
+ * pointing at `describe` for the operation list and its fields.
173
+ *
174
+ * @remarks
175
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
176
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
177
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
165
178
  */
166
179
  var WORKSPACE_TOOL_SUMMARY = "Read and edit files in a workspace — one operation per call (read, write, list, search, replace, splice, move, remove, plus workspace switching), chosen by the 'operation' field. Call describe('workspace') for the full operation list and fields.";
167
180
  /**
@@ -197,8 +210,9 @@ var WORKSPACE_TOOL_DESCRIPTION = [
197
210
  JSON.stringify(WORKSPACE_TOOL_EXAMPLE)
198
211
  ].join("\n");
199
212
  /**
200
- * Holds the name {@link import('./factories.js').createDescribeTool} advertises by default — the key a
201
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
213
+ * Holds the name {@link import('./factories.js').createDescribeTool} advertises by default,
214
+ * `'describe'` — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers
215
+ * under.
202
216
  *
203
217
  * @remarks
204
218
  * Pairs with the lean {@link AGENT_TOOL_SUMMARY} / {@link WORKFLOW_TOOL_SUMMARY} /
@@ -214,7 +228,8 @@ var DESCRIBE_TOOL_NAME = "describe";
214
228
  */
215
229
  var DESCRIBE_TOOL_SUMMARY = "Return the full description of a named registered tool.";
216
230
  /**
217
- * Holds the DESCRIPTION {@link import('./factories.js').createDescribeTool} advertises.
231
+ * Holds the description {@link import('./factories.js').createDescribeTool} advertises — the
232
+ * registered tool `name` it requires, and the full description of that tool it returns.
218
233
  *
219
234
  * @remarks
220
235
  * Deliberately short — unlike the workflow / workspace / agent tools, this one has no authoring
@@ -222,19 +237,27 @@ var DESCRIBE_TOOL_SUMMARY = "Return the full description of a named registered t
222
237
  */
223
238
  var DESCRIBE_TOOL_DESCRIPTION = "Return the full description of a registered tool by its name. Required: name - the registered tool name (see another tool listing for available names).";
224
239
  /**
225
- * Holds the name {@link import('./factories.js').createPromptTool} advertises by default — the key a
226
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
240
+ * Holds the name {@link import('./factories.js').createPromptTool} advertises by default, `'ask'` —
241
+ * the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
227
242
  */
228
243
  var PROMPT_TOOL_NAME = "ask";
229
244
  /**
230
- * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createPromptTool}
231
- * advertises in place of {@link PROMPT_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
232
- * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
233
- * for the full teaching description; the full text stays retrievable through
234
- * {@link import('./factories.js').createDescribeTool}.
245
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
246
+ * {@link import('./factories.js').createPromptTool} advertises in place of
247
+ * {@link PROMPT_TOOL_DESCRIPTION} — one sentence offering the blocking multi-field ask and pointing
248
+ * at `describe` for the schema.
249
+ *
250
+ * @remarks
251
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
252
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
253
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
235
254
  */
236
255
  var PROMPT_TOOL_SUMMARY = "Ask another terminal a multi-field form and BLOCK until it answers; the call resolves with the values record. Call describe('ask') for the schema.";
237
- /** Holds the full form protocol {@link import('./factories.js').createPromptTool} advertises. */
256
+ /**
257
+ * Holds the form protocol {@link import('./factories.js').createPromptTool} advertises — the
258
+ * required `to` and `schema`, how a field declares its control and its rules, and a worked
259
+ * example.
260
+ */
238
261
  var PROMPT_TOOL_DESCRIPTION = [
239
262
  "Ask another terminal a multi-field form and block until it answers. This call does not return until the addressed terminal answers, or the form expires.",
240
263
  "",
@@ -260,19 +283,27 @@ var PROMPT_TOOL_DESCRIPTION = [
260
283
  })
261
284
  ].join("\n");
262
285
  /**
263
- * Holds the name {@link import('./factories.js').createAnswerTool} advertises by default — the key a
264
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
286
+ * Holds the name {@link import('./factories.js').createAnswerTool} advertises by default,
287
+ * `'answer'` — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers
288
+ * under.
265
289
  */
266
290
  var ANSWER_TOOL_NAME = "answer";
267
291
  /**
268
- * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createAnswerTool}
269
- * advertises in place of {@link ANSWER_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
270
- * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
271
- * for the full teaching description; the full text stays retrievable through
272
- * {@link import('./factories.js').createDescribeTool}.
292
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
293
+ * {@link import('./factories.js').createAnswerTool} advertises in place of
294
+ * {@link ANSWER_TOOL_DESCRIPTION} — one sentence offering the pending listing and the answer call,
295
+ * and pointing at `describe` for the fields each takes.
296
+ *
297
+ * @remarks
298
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
299
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
300
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
273
301
  */
274
302
  var ANSWER_TOOL_SUMMARY = "List forms addressed to this terminal, or answer one by id with a values record. Call describe('answer') for the required fields.";
275
- /** Holds the pending/answer protocol {@link import('./factories.js').createAnswerTool} advertises. */
303
+ /**
304
+ * Holds the protocol {@link import('./factories.js').createAnswerTool} advertises — the `pending`
305
+ * and `answer` operations and the `values` record an answer supplies, each with a worked example.
306
+ */
276
307
  var ANSWER_TOOL_DESCRIPTION = [
277
308
  "List the forms addressed to this terminal, or answer one of them by id. Every call is ONE operation, chosen by the \"operation\" field.",
278
309
  "",
@@ -292,24 +323,31 @@ var ANSWER_TOOL_DESCRIPTION = [
292
323
  })
293
324
  ].join("\n");
294
325
  /**
295
- * Holds the name {@link import('./factories.js').createDatabaseTool} advertises by default — the key
296
- * a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
326
+ * Holds the name {@link import('./factories.js').createDatabaseTool} advertises by default,
327
+ * `'database'` — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers
328
+ * under.
297
329
  */
298
330
  var DATABASE_TOOL_NAME = "database";
299
331
  /**
300
332
  * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
301
333
  * {@link import('./factories.js').createDatabaseTool} advertises in place of
302
- * {@link DATABASE_TOOL_DESCRIPTION}.
334
+ * {@link DATABASE_TOOL_DESCRIPTION} — one sentence offering the `operation`-keyed database call and
335
+ * pointing at `describe` for the operation list, the query form, and the column DSL.
336
+ *
337
+ * @remarks
338
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
339
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
340
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
303
341
  */
304
342
  var DATABASE_TOOL_SUMMARY = "Create and query a database — one operation per call (create, tables, get, records, count, aggregate, add, set, update, remove, destroy), chosen by the 'operation' field. Call describe('database') for the full operation list, the query form, and the column DSL.";
305
343
  /**
306
344
  * Holds the description {@link import('./factories.js').createDatabaseTool} advertises — a
307
- * multi-line guide that teaches a small model the operation list, the SERIALIZED query form, and
345
+ * multi-line guide that teaches a small model the operation list, the serialized query form, and
308
346
  * the {@link import('./types.js').TableSpec} column DSL.
309
347
  *
310
348
  * @remarks
311
- * The query form is deliberately SERIALIZED (never fluent) — every condition is a flat object
312
- * `{ column, operator, values, connector? }` where `values` is ALWAYS an array, even for a
349
+ * The query form is deliberately serialized (never fluent) — every condition is a flat object
350
+ * `{ column, operator, values, connector? }` where `values` is always an array, even for a
313
351
  * single-value operator (`{ column: 'age', operator: 'from', values: [18] }`), so a small model
314
352
  * never has to chain method calls or guess whether a value is scalar or a list.
315
353
  */
@@ -361,7 +399,10 @@ var DATABASE_TOOL_DESCRIPTION = [
361
399
  }] }
362
400
  })
363
401
  ].join("\n");
364
- /** Holds the default cap on rows a `records` call returns when the caller omits `query.limit` — the database tool's default row ceiling. */
402
+ /**
403
+ * Holds the default cap on rows a `records` call returns when the caller omits `query.limit`,
404
+ * `1000` — the database tool's default row ceiling.
405
+ */
365
406
  var DATABASE_TOOL_LIMIT = 1e3;
366
407
  /** Lists the runtime-frozen database-tool mutation names disabled by `DatabaseToolOptions.readonly`. */
367
408
  var DATABASE_TOOL_MUTATIONS = Object.freeze([
@@ -373,21 +414,30 @@ var DATABASE_TOOL_MUTATIONS = Object.freeze([
373
414
  "destroy"
374
415
  ]);
375
416
  /**
376
- * Holds the name `createRelationTool` advertises by default — the key a model calls and the
377
- * `ToolManagerInterface` (`@orkestrel/tool`) registers under.
417
+ * Holds the name {@link import('./factories.js').createRelationTool} advertises by default,
418
+ * `'relation'` — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers
419
+ * under.
378
420
  */
379
421
  var RELATION_TOOL_NAME = "relation";
380
422
  /**
381
- * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} the relation tool advertises
382
- * in place of {@link RELATION_TOOL_DESCRIPTION}.
423
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
424
+ * {@link import('./factories.js').createRelationTool} advertises in place of
425
+ * {@link RELATION_TOOL_DESCRIPTION} — one sentence offering the `operation`-keyed relationship
426
+ * traversal and pointing at `describe` for the include-path syntax.
427
+ *
428
+ * @remarks
429
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
430
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
431
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
383
432
  */
384
433
  var RELATION_TOOL_SUMMARY = "Traverse and edit relationships between database rows — one operation per call (load, find, link, unlink, links), chosen by the 'operation' field. Call describe('relation') for the include-path syntax.";
385
434
  /**
386
- * Holds the DESCRIPTION the relation tool advertises — a multi-line guide that teaches a small model
387
- * the operation list and the flat dot-path `include` syntax.
435
+ * Holds the description {@link import('./factories.js').createRelationTool} advertises — a
436
+ * multi-line guide that teaches a small model the operation list and the flat dot-path `include`
437
+ * syntax.
388
438
  *
389
439
  * @remarks
390
- * An include path is a FLAT dot-separated string (`'contacts.account'`), never a nested object —
440
+ * An include path is a flat dot-separated string (`'contacts.account'`), never a nested object —
391
441
  * the same small-model ergonomic lever the other tools in this package use for flat args.
392
442
  */
393
443
  var RELATION_TOOL_DESCRIPTION = [
@@ -409,24 +459,38 @@ var RELATION_TOOL_DESCRIPTION = [
409
459
  include: ["contacts.account"]
410
460
  })
411
461
  ].join("\n");
412
- /** Holds the default cap on rows a `find` / `links` call returns when the caller omits `limit` — the relation tool's default row ceiling. */
462
+ /**
463
+ * Holds the default cap on rows a `find` or `links` call returns when the caller omits `limit`,
464
+ * `1000` — the relation tool's default row ceiling.
465
+ */
413
466
  var RELATION_TOOL_LIMIT = 1e3;
414
- /** Holds the default cap on how many `include` path segments deep a `load` / `find` call may traverse — the relation tool's default include-depth ceiling. */
467
+ /**
468
+ * Holds the default cap on how many `include` path segments deep a `load` or `find` call may
469
+ * traverse, `3` — the relation tool's default include-depth ceiling.
470
+ */
415
471
  var RELATION_TOOL_DEPTH = 3;
416
472
  /**
417
- * Holds the name {@link import('./factories.js').createInferTool} advertises by default — the key a
418
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
473
+ * Holds the name {@link import('./factories.js').createInferTool} advertises by default, `'infer'`
474
+ * — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
419
475
  */
420
476
  var INFER_TOOL_NAME = "infer";
421
477
  /**
422
- * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createInferTool}
423
- * advertises in place of {@link INFER_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
424
- * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
425
- * for the full teaching description; the full text stays retrievable through
426
- * {@link import('./factories.js').createDescribeTool}.
478
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
479
+ * {@link import('./factories.js').createInferTool} advertises in place of
480
+ * {@link INFER_TOOL_DESCRIPTION} — one sentence offering schema inference from example values and
481
+ * pointing at `describe` for the fields it takes.
482
+ *
483
+ * @remarks
484
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
485
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
486
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
427
487
  */
428
488
  var INFER_TOOL_SUMMARY = "Infer a JSON Schema (as advertised tool parameters) from one or more example values. Call describe('infer') for the required fields.";
429
- /** Holds the schema-inference protocol {@link import('./factories.js').createInferTool} advertises. */
489
+ /**
490
+ * Holds the schema-inference protocol {@link import('./factories.js').createInferTool} advertises —
491
+ * the required `samples`, the optional `format`, `enum`, and `candidates` arguments, and a worked
492
+ * example of the bare return and of the `candidates`-wrapped return.
493
+ */
430
494
  var INFER_TOOL_DESCRIPTION = [
431
495
  "Infer a JSON Schema from example values, returned in the same shape a tool advertises its parameters.",
432
496
  "",
@@ -526,7 +590,7 @@ var INFER_TOOL_DESCRIPTION = [
526
590
  * @remarks
527
591
  * Carries a machine-readable `code` (see {@link import('./types.js').ToolboxErrorCode}) and
528
592
  * an optional `context` bag for structured diagnostics. They are readable through an in-process
529
- * catch, including around a direct `tool.execute(args)` call. The `ToolManagerInterface`
593
+ * catch, including around a direct `tool.execute(args, context)` call. The `ToolManagerInterface`
530
594
  * (`@orkestrel/tool`) instead flattens every throw to the canonical tool result's top-level
531
595
  * `error` message string under AGENTS' “narrow untrusted input with guards” rule.
532
596
  *
@@ -551,7 +615,7 @@ var ToolboxError = class extends Error {
551
615
  }
552
616
  };
553
617
  /**
554
- * Narrows an unknown caught value to an {@link ToolboxError}.
618
+ * Narrows an unknown caught value to a {@link ToolboxError}.
555
619
  *
556
620
  * @param value - The value to test (typically a `catch` binding)
557
621
  * @returns True if `value` is an {@link ToolboxError}; false otherwise
@@ -628,7 +692,7 @@ function isColumnPrimitive(value) {
628
692
  return value === "string" || value === "integer" || value === "number" || value === "boolean";
629
693
  }
630
694
  /**
631
- * Narrows an unknown value to a {@link DatabaseDefinition} — a non-empty `id` + `driver`, a
695
+ * Narrows an unknown value to a {@link DatabaseDefinition} — a non-empty `id` and `driver`, a
632
696
  * `tables` record whose every value is `{ columns: record of valid ColumnSpec }`, plus optional
633
697
  * `primary`, `indexes`, and finite `version` schema configuration. The boundary guard a
634
698
  * {@link import('./types.js').DefinitionStoreInterface} applies to an untrusted persisted blob
@@ -729,8 +793,8 @@ var describeToolShape = objectShape({ name: stringShape({
729
793
  description: "The registered name of the tool whose full description to return."
730
794
  }) });
731
795
  /**
732
- * Describes the shape of a {@link import('./types.js').TaskDraft} — identical to a strict task shape
733
- * EXCEPT `id` and `name` are OPTIONAL.
796
+ * Describes the shape of a {@link import('./types.js').TaskDraft} — identical to a strict task
797
+ * shape except that `id` and `name` are optional.
734
798
  */
735
799
  var taskDraftShape = objectShape({
736
800
  id: optionalShape(stringShape({
@@ -757,8 +821,8 @@ var taskDraftShape = objectShape({
757
821
  }))
758
822
  });
759
823
  /**
760
- * Describes the shape of a PHASE in a draft workflow — identical to a strict phase shape EXCEPT `id` and
761
- * `name` are OPTIONAL, and its tasks are {@link taskDraftShape}s.
824
+ * Describes the shape of a phase in a draft workflow — identical to a strict phase shape except
825
+ * that `id` and `name` are optional and each task takes {@link taskDraftShape}.
762
826
  */
763
827
  var phaseDraftShape = objectShape({
764
828
  id: optionalShape(stringShape({
@@ -778,17 +842,17 @@ var phaseDraftShape = objectShape({
778
842
  bail: optionalShape(literalShape([true, false], { description: "Per-phase failure-policy override; omitted inherits the workflow bail." }))
779
843
  });
780
844
  /**
781
- * Describes the shape of a DRAFT workflow — identical to a strict workflow shape EXCEPT `id` and `name`
782
- * are OPTIONAL at all three levels (workflow / phase / task), so a small model can omit the six
783
- * identity strings and let the tool synthesize them positionally.
845
+ * Describes the shape of a draft workflow — identical to a strict workflow shape except that `id`
846
+ * and `name` are optional at the workflow, phase, and task levels, so a small model can omit every
847
+ * identity string and let the tool synthesize them positionally.
784
848
  *
785
849
  * @remarks
786
850
  * The lenient counterpart {@link import('./factories.js').createWorkflowDraftContract} compiles.
787
851
  * `behavior` stays optional like the strict form; omission is the deliberate JSON `null` no-op. A
788
852
  * provided `id` / `name` still has `minLength: 1` (so
789
- * an explicitly-empty `id: ''` is REJECTED, not auto-filled). After
853
+ * an explicitly-empty `id: ''` is rejected, not auto-filled). After
790
854
  * {@link import('./helpers.js').completeDraft} fills the missing ids/names, the result is
791
- * validated against the STRICT `createWorkflowContract` (`@orkestrel/workflow`) gate before
855
+ * validated against the strict `createWorkflowContract` (`@orkestrel/workflow`) gate before
792
856
  * running.
793
857
  */
794
858
  var workflowDraftShape = objectShape({
@@ -805,10 +869,11 @@ var workflowDraftShape = objectShape({
805
869
  bail: optionalShape(literalShape([true, false], { description: "Failure policy: false (default) continues gracefully, true halts on the first failure." }))
806
870
  });
807
871
  /**
808
- * Describes the shape of ONE flat step — `{ name }` — the building block of {@link workflowStepsShape}.
872
+ * Describes the shape of one flat step — `{ name }` — the building block of
873
+ * {@link workflowStepsShape}.
809
874
  *
810
875
  * @remarks
811
- * `name` is the REGISTERED behavior name the step runs (it becomes the task's `behavior`). The tool
876
+ * `name` is the registered behavior name the step runs (it becomes the task's `behavior`). The tool
812
877
  * expands each step into a one-task phase, in order ({@link import('./helpers.js').expandSteps}).
813
878
  */
814
879
  var stepShape = objectShape({ name: stringShape({
@@ -816,16 +881,17 @@ var stepShape = objectShape({ name: stringShape({
816
881
  description: "The registered behavior name this step runs (becomes the task behavior)."
817
882
  }) });
818
883
  /**
819
- * Describes the FLAT authoring shape {@link import('./factories.js').createWorkflowTool} advertises as its
820
- * `parameters` — the simplest surface a small model can fill: `{ name?, steps: [{ name }] }`.
884
+ * Describes the flat authoring shape {@link import('./factories.js').createWorkflowTool} advertises
885
+ * as its `parameters` — the simplest surface a small model can fill:
886
+ * `{ name?, steps: [{ name }] }`.
821
887
  *
822
888
  * @remarks
823
889
  * A deliberately-reduced surface: a flat ordered list of steps, each a `{ name }`. The tool
824
- * EXPANDS it ({@link import('./helpers.js').expandSteps}) into a full
890
+ * expands it ({@link import('./helpers.js').expandSteps}) into a full
825
891
  * {@link import('./types.js').WorkflowDefinition} — one one-task phase per step, in order —
826
- * then validates against the STRICT `createWorkflowContract` (`@orkestrel/workflow`) gate. The
827
- * full nested form is STILL accepted by the tool (it branches on the args' shape) and is
828
- * documented as the advanced escape-hatch in the tool's description — but THIS is what
892
+ * then validates against the strict `createWorkflowContract` (`@orkestrel/workflow`) gate. The
893
+ * full nested form is still accepted by the tool (it branches on the args' shape) and is
894
+ * documented as the advanced escape-hatch in the tool's description — but this is what
829
895
  * `parameters` advertises.
830
896
  */
831
897
  var workflowStepsShape = objectShape({
@@ -839,17 +905,17 @@ var workflowStepsShape = objectShape({
839
905
  * Describes the shape of a {@link import('./types.js').WorkspaceOperation} — a descriptive tagged union
840
906
  * over the workspace edit, read, and navigation operations, discriminated by the `operation`
841
907
  * literal (never a bare `kind`). Each variant leads with its `operation`
842
- * discriminant then its FLAT fields, every field through `stringShape` / `optionalShape` /
908
+ * discriminant then its flat fields, every field through `stringShape` / `optionalShape` /
843
909
  * `integerShape({ min: 1 })` / `booleanShape`, each carrying a strong field-level `description`.
844
910
  *
845
911
  * @remarks
846
- * The union compiles to an `anyOf` JSON Schema + a `unionOf` guard + a first-match parser
912
+ * The union compiles to an `anyOf` JSON Schema, a `unionOf` guard, and a first-match parser
847
913
  * automatically ({@link import('./factories.js').createWorkspaceTool} types the result to the
848
- * hand-written {@link import('./types.js').WorkspaceOperation}). `limit` and the four `'splice'`
849
- * caret components are POSITIVE integers (`integerShape({ min: 1 })`); `regex` / `sensitive`
850
- * are `optionalShape(booleanShape(...))`. The two REGISTRY arms — `workspaces` (list the
914
+ * hand-written {@link import('./types.js').WorkspaceOperation}). `limit` and the `'splice'`
915
+ * caret components are positive integers (`integerShape({ min: 1 })`); `regex` / `sensitive`
916
+ * are `optionalShape(booleanShape(...))`. The registry arms — `workspaces` (list the
851
917
  * workspaces the model can move between) and `switch` (re-point the active one by `id`) — let a
852
- * model DISCOVER then CHOOSE which workspace the edit / read arms target.
918
+ * model discover then choose which workspace the edit / read arms target.
853
919
  */
854
920
  var workspaceToolShape = unionShape(objectShape({
855
921
  operation: literalShape(["read"], { description: "Read a whole text file's text by path." }),
@@ -933,13 +999,23 @@ var columnSpecShape = unionShape(columnPrimitiveShape, objectShape({
933
999
  }));
934
1000
  /** Describes a {@link import('./types.js').TableSpec} — table name to `{ columns }`, each column a {@link columnSpecShape}. */
935
1001
  var tableSpecShape = recordShape(objectShape({ columns: recordShape(columnSpecShape, { description: "Column name to its primitive or its { primitive, optional } spec." }) }), { description: "Table name to its column layout." });
936
- /** Describes one key value for the database tool and the relation tool — a string or number; the array form (multiple keys, positional) resolves FIRST, so an array argument is read as many keys rather than one. */
1002
+ /**
1003
+ * Describes one key value for the database tool and the relation tool — a string or number; the
1004
+ * array form (multiple keys, positional) resolves first, so an array argument is read as many keys
1005
+ * rather than one.
1006
+ */
937
1007
  var keyShape = unionShape(arrayShape(unionShape(stringShape(), numberShape()), { description: "Multiple row keys, positional — a miss at an index is undefined there." }), stringShape({ description: "One row key." }), numberShape({ description: "One row key." }));
938
- /** Describes a loose row — a flat object of column name to JSON value; the array form (multiple rows) resolves FIRST, so an array argument is read as many rows rather than one. */
1008
+ /** Describes a loose row — a flat object of column name to JSON value. */
939
1009
  var rowShape = recordShape(jsonShape(), { description: "A row as a flat object of column name to value." });
940
- /** Describes one or many loose rows — the array form resolves FIRST, so an array argument is read as many rows rather than one. */
1010
+ /**
1011
+ * Describes one or many loose rows — the array form resolves first, so an array argument is read as
1012
+ * many rows rather than one.
1013
+ */
941
1014
  var rowsShape = unionShape(arrayShape(rowShape, { description: "Multiple rows." }), rowShape);
942
- /** Describes one SERIALIZED WHERE condition — `values` is ALWAYS an array, even for a single-value operator. */
1015
+ /**
1016
+ * Describes one serialized where condition — `values` is always an array, even for a single-value
1017
+ * operator.
1018
+ */
943
1019
  var conditionShape = objectShape({
944
1020
  column: stringShape({ description: "The column this condition applies to." }),
945
1021
  operator: literalShape([
@@ -962,12 +1038,12 @@ var conditionShape = objectShape({
962
1038
  values: arrayShape(jsonShape(), { description: "The operand values the operator needs (always an array, even for one value)." }),
963
1039
  connector: optionalShape(literalShape(["and", "or"], { description: "Joins this condition to the next; omit on the last condition." }))
964
1040
  });
965
- /** Describes one sort term. */
1041
+ /** Describes one sort term — a `column` to sort by and the `direction` to sort it in. */
966
1042
  var orderShape = objectShape({
967
1043
  column: stringShape({ description: "The column to sort by." }),
968
1044
  direction: literalShape(["ascending", "descending"], { description: "The sort direction." })
969
1045
  });
970
- /** Describes the SERIALIZED query form — conditions, order, and pagination. */
1046
+ /** Describes the serialized query form — conditions, order, and pagination. */
971
1047
  var queryShape = objectShape({
972
1048
  conditions: optionalShape(arrayShape(conditionShape, { description: "The WHERE conditions, folded left to right." })),
973
1049
  order: optionalShape(arrayShape(orderShape, { description: "The sort terms, applied in order." })),
@@ -982,9 +1058,8 @@ var queryShape = objectShape({
982
1058
  });
983
1059
  /**
984
1060
  * Describes the shape of {@link import('./factories.js').createDatabaseTool}'s call arguments —
985
- * discriminated by `operation` into the 11 database operations (`'create'` / `'tables'` /
986
- * `'get'` / `'records'` / `'count'` / `'aggregate'` / `'add'` / `'set'` / `'update'` /
987
- * `'remove'` / `'destroy'`).
1061
+ * discriminated by `operation` into the database operations `'create'`, `'tables'`, `'get'`,
1062
+ * `'records'`, `'count'`, `'aggregate'`, `'add'`, `'set'`, `'update'`, `'remove'`, and `'destroy'`.
988
1063
  *
989
1064
  * @remarks
990
1065
  * Every arm carries `id` (the database id). `'create'` carries `tables` (the
@@ -992,7 +1067,7 @@ var queryShape = objectShape({
992
1067
  * {@link import('./compilers.js').expandTables}); `'get'` / `'update'` / `'remove'` carry `key`
993
1068
  * (one key or an array of keys, positional); `'add'` / `'set'` carry `row` (one row or an array of
994
1069
  * rows); `'update'` also carries `changes` (a loose partial row); `'records'` / `'count'` /
995
- * `'aggregate'` carry an optional `query` (the SERIALIZED form — `values` is ALWAYS an array,
1070
+ * `'aggregate'` carry an optional `query` (the serialized form — `values` is always an array,
996
1071
  * even for a single-value operator, so a caller never chains method calls or guesses arity).
997
1072
  */
998
1073
  var databaseToolShape = unionShape(objectShape({
@@ -1136,8 +1211,8 @@ var managerShape = optionalShape(stringShape({
1136
1211
  }));
1137
1212
  /**
1138
1213
  * Describes the shape of {@link import('./factories.js').createRelationTool}'s call arguments —
1139
- * discriminated by `operation` into the 5 relation operations (`'load'` / `'find'` / `'link'` /
1140
- * `'unlink'` / `'links'`).
1214
+ * discriminated by `operation` into the relation operations `'load'`, `'find'`, `'link'`,
1215
+ * `'unlink'`, and `'links'`.
1141
1216
  *
1142
1217
  * @remarks
1143
1218
  * `'load'` fetches one or more rows (positional key/array) with `include` attached. `'find'`
@@ -1222,8 +1297,8 @@ var relationToolShape = unionShape(objectShape({
1222
1297
  * `samples` requires at least one element (`min: 1`) — an empty array parses to `undefined`,
1223
1298
  * surfaced by the handler as a typed `TOOL` {@link import('./errors.js').ToolboxError}. When
1224
1299
  * `candidates` is present (any array, including empty), the handler compiles a contract from the
1225
- * freshly inferred schema and checks each candidate against it with a STRICT guard (`.is`, no
1226
- * coercion) — the opposite of {@link import('./factories.js').createEndpointTool}'s NORMALIZING
1300
+ * freshly inferred schema and checks each candidate against it with a strict guard (`.is`, no
1301
+ * coercion) — the opposite of {@link import('./factories.js').createEndpointTool}'s normalizing
1227
1302
  * `.parse` enforcement.
1228
1303
  */
1229
1304
  var inferToolShape = objectShape({
@@ -1241,8 +1316,8 @@ var inferToolShape = objectShape({
1241
1316
  * Returns the ancestry identifier of a workflow in a run chain — `workflow:<id>`.
1242
1317
  *
1243
1318
  * @remarks
1244
- * Namespacing keeps a workflow id and a {@link tagAgent} agent name in ONE set without
1245
- * collision, so re-entering a workflow OR an agent already in the chain is a single `includes`
1319
+ * Namespacing keeps a workflow id and a {@link tagAgent} agent name in one set without
1320
+ * collision, so re-entering a workflow or an agent already in the chain is a single `includes`
1246
1321
  * check.
1247
1322
  *
1248
1323
  * @param id - The workflow definition's `id`
@@ -1297,12 +1372,12 @@ function deriveWorkflowDepth(lineage) {
1297
1372
  return Math.max(0, workflows - 1);
1298
1373
  }
1299
1374
  /**
1300
- * Builds the plain success summary {@link import('./factories.js').createWorkflowTool} returns on
1301
- * a completed run — the universal tool-handler contract: return a plain value on success,
1302
- * appearing identically over BOTH the agent loop and MCP.
1375
+ * Builds the plain success summary {@link import('./factories.js').createWorkflowTool} returns on a
1376
+ * completed run — the universal tool-handler contract: return a plain value on success, appearing
1377
+ * identically over both the agent loop and MCP.
1303
1378
  *
1304
1379
  * @remarks
1305
- * The summary is LEAN: the workflow's terminal `status`, settled-task count, and exact optional
1380
+ * The summary is lean: the workflow's terminal `status`, settled-task count, and exact optional
1306
1381
  * native persistence outcome. It carries no synthetic `id` / `name`: a tool handler has no call
1307
1382
  * id; the `ToolManagerInterface` (`@orkestrel/tool`) supplies the canonical envelope's identity.
1308
1383
  *
@@ -1318,21 +1393,21 @@ function summarizeWorkflow(result) {
1318
1393
  };
1319
1394
  }
1320
1395
  /**
1321
- * Completes a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesizes any
1322
- * MISSING `id` deterministically + positionally, and defaults any MISSING `name` to its
1323
- * (now-resolved) `id`.
1396
+ * Completes a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesizes a
1397
+ * missing `id` deterministically and positionally, and defaults a missing `name` to its resolved
1398
+ * `id`.
1324
1399
  *
1325
1400
  * @remarks
1326
1401
  * The positional id scheme is stable and human-legible: the workflow is `wf`, phase `i` is
1327
1402
  * `phase-<i>`, and task `j` of that phase is `<phaseId>-task-<j>` (so a provided phase id flows
1328
- * into its tasks' synthesized ids). A PROVIDED `id` / `name` at any level is kept VERBATIM —
1403
+ * into its tasks' synthesized ids). A provided `id` / `name` at any level is kept verbatim —
1329
1404
  * synthesis touches only the omitted ones. A missing `name` defaults to the resolved `id` (never
1330
- * the other way round), so the result always has both. `behavior`, `description`, the per-phase
1405
+ * the other way round), so the result always carries an `id` and a `name`. `behavior`, `description`, the per-phase
1331
1406
  * `concurrency` / `bail`, the per-task `retries` / `timeout`, and the workflow `bail` carry over
1332
1407
  * unchanged. The result is a complete {@link WorkflowDefinition}; the caller still validates it
1333
- * against the STRICT contract.
1408
+ * against the strict contract.
1334
1409
  *
1335
- * @param draft - The draft workflow (id/name optional at all three levels)
1410
+ * @param draft - The draft workflow (`id` and `name` optional at the workflow, phase, and task levels)
1336
1411
  * @returns A complete {@link WorkflowDefinition} with every id/name filled
1337
1412
  */
1338
1413
  function completeDraft(draft) {
@@ -1387,18 +1462,18 @@ function completeTaskDraft(task, phaseId, index) {
1387
1462
  }
1388
1463
  /**
1389
1464
  * Expands a flat {@link WorkflowSteps} blob into a strict {@link WorkflowDefinition} — each step
1390
- * becomes a one-task phase, IN ORDER.
1465
+ * becomes a one-task phase, in order.
1391
1466
  *
1392
1467
  * @remarks
1393
- * The expansion of the tool's ADVERTISED surface: the deliberately-reduced flat form. Each
1468
+ * The expansion of the tool's advertised surface: the deliberately-reduced flat form. Each
1394
1469
  * {@link import('./types.js').WorkflowStep} maps to a phase holding exactly one task: the step's
1395
1470
  * `name` becomes the task's `behavior` (the behavior-registry key). Ids/names are auto-filled
1396
1471
  * positionally — it builds an ids-omitted {@link WorkflowDraft} and delegates to
1397
- * {@link completeDraft}, so the two lenient surfaces share ONE synthesis path (step `i` → phase
1472
+ * {@link completeDraft}, so the lenient surfaces share one synthesis path (step `i` → phase
1398
1473
  * `phase-<i>`, its task `phase-<i>-task-0`). The optional `name` becomes both the workflow's
1399
1474
  * deterministic id and its name, so named flat workflows retain distinct persistence keys;
1400
1475
  * omission keeps the shared draft fallback `wf`. The result is a complete definition the caller
1401
- * validates against the STRICT contract before running.
1476
+ * validates against the strict contract before running.
1402
1477
  *
1403
1478
  * @param flat - The flat steps blob (`{ name?, steps: [{ name }] }`)
1404
1479
  * @returns A complete {@link WorkflowDefinition} (one one-task phase per step)
@@ -1458,15 +1533,15 @@ function inferRelationCode(error) {
1458
1533
  return isRelationError(error) ? error.code : void 0;
1459
1534
  }
1460
1535
  /**
1461
- * Expands the relation tool's FLAT dot-path `include` list into a live `@orkestrel/relation`
1536
+ * Expands the relation tool's flat dot-path `include` list into a live `@orkestrel/relation`
1462
1537
  * {@link Include} tree — the pure leaf {@link import('./factories.js').createRelationTool} calls
1463
1538
  * before a `'load'` / `'find'` call.
1464
1539
  *
1465
1540
  * @remarks
1466
1541
  * Each path splits on `'.'` into a chain of relation names, deep-merged into one nested
1467
- * `Include` object with a leaf `true`. A longer path SUBSUMES a shorter sibling's bare `true` —
1542
+ * `Include` object with a leaf `true`. A longer path subsumes a shorter sibling's bare `true` —
1468
1543
  * `'contacts'` followed by `'contacts.account'` yields `{ contacts: { account: true } }`, never
1469
- * overwriting the deeper chain. An EMPTY segment (`''`, from a leading/trailing/doubled `.`) or a
1544
+ * overwriting the deeper chain. An empty segment (`''`, from a leading/trailing/doubled `.`) or a
1470
1545
  * path whose segment count exceeds `depth` throws a typed `TOOL` {@link ToolboxError}.
1471
1546
  *
1472
1547
  * @param paths - The flat dot-path `include` list (or `undefined` — yields `{}`)
@@ -1535,7 +1610,7 @@ function expandInclude(paths, depth) {
1535
1610
  *
1536
1611
  * @remarks
1537
1612
  * An explicit `name` must match a key of `managers` (a miss throws a typed `TOOL`
1538
- * {@link ToolboxError} naming the registered managers). An OMITTED `name` resolves to the sole
1613
+ * {@link ToolboxError} naming the registered managers). An omitted `name` resolves to the sole
1539
1614
  * registered manager when exactly one is registered, else throws the same typed error.
1540
1615
  *
1541
1616
  * @param managers - The tool's registered `RelationManagerInterface` map
@@ -1577,11 +1652,11 @@ function resolveRelationModel(manager, name) {
1577
1652
  }
1578
1653
  /**
1579
1654
  * Returns the canonical live `@orkestrel/database` {@link QueryInput} for the database tool's
1580
- * parsed SERIALIZED query — each condition's OMITTED `connector` defaults to `'and'`.
1655
+ * parsed serialized query — each condition's omitted `connector` defaults to `'and'`.
1581
1656
  *
1582
1657
  * @remarks
1583
1658
  * The wire form ({@link import('./shapers.js').databaseToolShape}) lets a caller drop `connector`
1584
- * on the last condition (it has nothing to join FORWARD to); the compiled `Condition` a live
1659
+ * on the last condition (it has nothing to join forward to); the compiled `Condition` a live
1585
1660
  * `@orkestrel/database` table call accepts always carries one, so this fills the gap. `order` /
1586
1661
  * `limit` / `offset` pass through unchanged. Pure and total.
1587
1662
  *
@@ -1627,14 +1702,14 @@ function resolveLimit(requested, cap) {
1627
1702
  return Math.max(0, Math.min(requested ?? cap, cap));
1628
1703
  }
1629
1704
  /**
1630
- * Clamps a `'records'` call's query to a row cap, and builds the PROBE query the caller reads
1631
- * with — the pure leaf {@link import('./factories.js').createDatabaseTool}'s `'records'` operation
1632
- * uses to detect truncation without a separate `count` round trip.
1705
+ * Clamps a `'records'` call's query to a row cap, and builds the probe query the caller reads with
1706
+ * — the pure leaf {@link import('./factories.js').createDatabaseTool}'s `'records'` operation uses
1707
+ * to detect truncation without a separate `count` round trip.
1633
1708
  *
1634
1709
  * @remarks
1635
1710
  * {@link resolveLimit} picks the effective limit, so a caller can never exceed the configured cap
1636
1711
  * by supplying a larger `query.limit`, and can never drive it below `0`. The returned probe query
1637
- * requests ONE MORE row than the effective limit (`limit: effective + 1`) — if storage returns
1712
+ * requests one more row than the effective limit (`limit: effective + 1`) — if storage returns
1638
1713
  * that many, the caller knows the true result was truncated (`rows.length > effective`) and slices
1639
1714
  * back down to `effective` before returning.
1640
1715
  *
@@ -1650,7 +1725,7 @@ function resolveLimit(requested, cap) {
1650
1725
  *
1651
1726
  * @param query - The live query to clamp (or `undefined`)
1652
1727
  * @param cap - The row-count ceiling
1653
- * @returns The PROBE query (`limit` bumped by one) and the effective `limit`
1728
+ * @returns The probe query (`limit` bumped by one) and the effective `limit`
1654
1729
  */
1655
1730
  function clampQuery(query, cap) {
1656
1731
  const limit = resolveLimit(query?.limit, cap);
@@ -1712,7 +1787,7 @@ function compileColumnPrimitive(primitive) {
1712
1787
  //#region src/core/stores/MemoryDefinitionStore.ts
1713
1788
  /**
1714
1789
  * Represents the in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of
1715
- * {@link DatabaseDefinition}s keyed by database id, the DEFAULT store
1790
+ * {@link DatabaseDefinition}s keyed by database id, the default store
1716
1791
  * {@link import('../factories.js').createMemoryDefinitionStore} builds. It implements the same
1717
1792
  * {@link DefinitionStoreInterface} contract as
1718
1793
  * {@link import('./DatabaseDefinitionStore.js').DatabaseDefinitionStore}: this store copies on
@@ -1721,19 +1796,19 @@ function compileColumnPrimitive(primitive) {
1721
1796
  *
1722
1797
  * @remarks
1723
1798
  * A plain `Map<string, DatabaseDefinition>` (the definition is already pure,
1724
- * self-contained CONFIG-only JSON, so no encoding is needed for the memory tier). Values are
1725
- * structured-cloned on both write and read, keeping caller mutation outside the store. There is NO
1726
- * idle-TTL and NO eviction: a persisted definition lives until an explicit `delete`. A durable
1727
- * backend (JSON / SQLite / IndexedDB) swaps in through the SAME interface without touching a
1799
+ * self-contained config-only JSON, so no encoding is needed for the memory tier). Values are
1800
+ * structured-cloned on both write and read, keeping caller mutation outside the store. There is no
1801
+ * idle-TTL and no eviction: a persisted definition lives until an explicit `delete`. A durable
1802
+ * backend (JSON / SQLite / IndexedDB) swaps in through the same interface without touching a
1728
1803
  * consumer — its driver-pluggable twin is
1729
1804
  * {@link import('./DatabaseDefinitionStore.js').DatabaseDefinitionStore} (the definition as one
1730
1805
  * opaque JSON column).
1731
1806
  *
1732
1807
  * - **`get` resolves the persisted definition for an id**, or `undefined` if none is stored.
1733
- * - **`set` inserts / replaces under the definition's OWN `id`** (no separate id param).
1808
+ * - **`set` inserts / replaces under the definition's own `id`** (no separate id param).
1734
1809
  * - **`delete` drops a definition by id**; an absent id is a no-op (no throw).
1735
1810
  *
1736
- * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the method
1811
+ * The public surface is exactly `get` / `set` / `delete` — no extra members (the method
1737
1812
  * bijection with {@link DefinitionStoreInterface}).
1738
1813
  *
1739
1814
  * @example
@@ -1759,10 +1834,10 @@ var MemoryDefinitionStore = class {
1759
1834
  return Promise.resolve(definition === void 0 ? void 0 : structuredClone(definition));
1760
1835
  }
1761
1836
  /**
1762
- * Inserts or replaces a definition under its OWN `id`, copied into the backing `Map`.
1837
+ * Inserts or replaces a definition under its own `id`, copied into the backing `Map`.
1763
1838
  *
1764
1839
  * @param definition - The config to persist; its own `id` is the key (no separate id param)
1765
- * @returns A promise settling once the definition is stored
1840
+ * @returns A promise settling after the definition is stored
1766
1841
  */
1767
1842
  set(definition) {
1768
1843
  this.#definitions.set(definition.id, structuredClone(definition));
@@ -1772,7 +1847,7 @@ var MemoryDefinitionStore = class {
1772
1847
  * Drops the definition stored under `id`.
1773
1848
  *
1774
1849
  * @param id - The database id to drop; an absent id is a no-op, never a throw
1775
- * @returns A promise settling once no definition is stored under `id`
1850
+ * @returns A promise settling after no definition is stored under `id`
1776
1851
  */
1777
1852
  delete(id) {
1778
1853
  this.#definitions.delete(id);
@@ -1783,25 +1858,25 @@ var MemoryDefinitionStore = class {
1783
1858
  //#region src/core/stores/DatabaseDefinitionStore.ts
1784
1859
  /**
1785
1860
  * Represents a {@link DefinitionStoreInterface} backed by one table of the `@orkestrel/database` layer — a
1786
- * database's durable CONFIG state IS a row, so persistence reduces to keyed point-access
1861
+ * database's durable config state is a row, so persistence reduces to keyed point-access
1787
1862
  * (`get` / `set` / `delete`) over a {@link TableInterface}, the driver-pluggable twin of the
1788
1863
  * plain-`Map` {@link import('./MemoryDefinitionStore.js').MemoryDefinitionStore}.
1789
1864
  *
1790
1865
  * @remarks
1791
1866
  * The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,
1792
1867
  * JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a JSON / SQLite /
1793
- * IndexedDB backend swaps in WITHOUT touching a consumer — the same seam as
1868
+ * IndexedDB backend swaps in without touching a consumer — the same seam as
1794
1869
  * {@link import('./MemoryDefinitionStore.js').MemoryDefinitionStore}. The driver defaults to
1795
1870
  * memory ({@link import('../factories.js').createDatabaseDefinitionStore} passes
1796
- * `createMemoryDriver()`), so it ALSO works in memory out of the box; you opt into the durable
1871
+ * `createMemoryDriver()`), so it also works in memory out of the box; you opt into the durable
1797
1872
  * plumbing by passing a JSON / SQLite / IndexedDB driver.
1798
1873
  *
1799
- * The {@link DatabaseDefinition} is stored as ONE OPAQUE JSON COLUMN — the table is a row of
1800
- * `{ id; definition }` ({@link DatabaseDefinitionRow}). The definition is already a COMPLETE,
1801
- * self-contained, pure-JSON CONFIG payload (never a live handle), so storing it whole is lossless
1802
- * AND keeps the row type flat (`definition` reads back as `unknown`).
1874
+ * The {@link DatabaseDefinition} is stored as one opaque JSON column — the table is a row of
1875
+ * `{ id; definition }` ({@link DatabaseDefinitionRow}). The definition is already a complete,
1876
+ * self-contained, pure-JSON config payload (never a live handle), so storing it whole is lossless
1877
+ * and keeps the row type flat (`definition` reads back as `unknown`).
1803
1878
  *
1804
- * - **`set(definition)` upserts under the definition's OWN `id`** (no separate id param) — it
1879
+ * - **`set(definition)` upserts under the definition's own `id`** (no separate id param) — it
1805
1880
  * writes the row `{ id: definition.id, definition }`.
1806
1881
  * - **`get(id)` resolves the stored definition for an id**, narrowing the opaque JSON column back
1807
1882
  * to a {@link DatabaseDefinition} ({@link import('../validators.js').isDatabaseDefinition} — the
@@ -1809,7 +1884,7 @@ var MemoryDefinitionStore = class {
1809
1884
  * or the stored blob is malformed.
1810
1885
  * - **`delete(id)` drops a definition by id**; an absent id is a no-op (no throw).
1811
1886
  *
1812
- * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the method
1887
+ * The public surface is exactly `get` / `set` / `delete` — no extra members (the method
1813
1888
  * bijection with {@link DefinitionStoreInterface}).
1814
1889
  *
1815
1890
  * @example
@@ -1847,10 +1922,10 @@ var DatabaseDefinitionStore = class {
1847
1922
  return isDatabaseDefinition(row.definition) ? row.definition : void 0;
1848
1923
  }
1849
1924
  /**
1850
- * Inserts or replaces a definition under its OWN `id` — the written row is `{ id, definition }`.
1925
+ * Inserts or replaces a definition under its own `id` — the written row is `{ id, definition }`.
1851
1926
  *
1852
1927
  * @param definition - The config to persist; its own `id` is the row key (no separate id param)
1853
- * @returns A promise settling once the row is written
1928
+ * @returns A promise settling after the row is written
1854
1929
  */
1855
1930
  async set(definition) {
1856
1931
  await this.#table.set({
@@ -1862,7 +1937,7 @@ var DatabaseDefinitionStore = class {
1862
1937
  * Drops the definition stored under `id`.
1863
1938
  *
1864
1939
  * @param id - The database id to drop; an absent id is a no-op, never a throw
1865
- * @returns A promise settling once no row is stored under `id`
1940
+ * @returns A promise settling after no row is stored under `id`
1866
1941
  */
1867
1942
  async delete(id) {
1868
1943
  await this.#table.remove(id);
@@ -1871,7 +1946,8 @@ var DatabaseDefinitionStore = class {
1871
1946
  //#endregion
1872
1947
  //#region src/core/databases/DatabaseResolver.ts
1873
1948
  /**
1874
- * Resolves database definitions into cached live handles for database tools.
1949
+ * Resolves a database definition into a cached live handle for a database tool, over the tool's
1950
+ * live handles, its stored definitions, its driver registry, and an optional key generator.
1875
1951
  *
1876
1952
  * @example
1877
1953
  * ```ts
@@ -1938,7 +2014,8 @@ var DatabaseResolver = class {
1938
2014
  this.#handles.delete(id);
1939
2015
  }
1940
2016
  /**
1941
- * Resolves a cached or stored database by id.
2017
+ * Resolves a live database by id — the cached handle when one exists, otherwise a database
2018
+ * constructed from its stored definition.
1942
2019
  *
1943
2020
  * @param id - Database definition id
1944
2021
  * @returns The cached or newly constructed live database
@@ -1973,15 +2050,17 @@ var DatabaseResolver = class {
1973
2050
  //#endregion
1974
2051
  //#region src/core/factories.ts
1975
2052
  /**
1976
- * Wraps a registered tool as a {@link WorkflowFunction} (`@orkestrel/workflow`) — the OPT-IN
1977
- * adapter that lets a `function`-form task run a `@orkestrel/tool` tool BY NAME.
2053
+ * Wraps a registered tool as a {@link WorkflowFunction} (`@orkestrel/workflow`) — the opt-in
2054
+ * adapter that lets a `function`-form task run a `@orkestrel/tool` tool by name.
1978
2055
  *
1979
2056
  * @remarks
1980
2057
  * Composes into a caller's `WorkflowOptions.functions` registry like any other behavior
1981
2058
  * (`{ publish: createToolFunction(tools, 'publish') }`); the pure workflow runner has no
1982
2059
  * knowledge of tools itself. The returned function executes `name` against `tools` with the
1983
2060
  * task's `controller.input` as the call arguments. The adapter resolves the live tool, calls its
1984
- * `execute` method directly, and deep-gates the returned unknown through `parseJSONValue`.
2061
+ * `execute` method directly, and deep-gates the returned unknown through `parseJSONValue`. The
2062
+ * execution context it passes carries the task's own `controller.signal`, so a handler that
2063
+ * reads `context.signal` observes the caller's cancellation.
1985
2064
  * Genuine execution throws retain identity. An unregistered name or non-JSON return throws this
1986
2065
  * package's typed `TOOL` `ToolboxError`.
1987
2066
  *
@@ -2006,7 +2085,7 @@ function createToolFunction(tools, name) {
2006
2085
  return async (controller) => {
2007
2086
  const tool = tools.tool(name);
2008
2087
  if (tool === void 0) throw new ToolboxError("TOOL", `tool '${name}' is not registered`, { tool: name });
2009
- const result = parseJSONValue(await tool.execute(controller.input));
2088
+ const result = parseJSONValue(await tool.execute(controller.input, { signal: controller.signal }));
2010
2089
  if (result === void 0) throw new ToolboxError("TOOL", `tool '${name}' returned a non-JSON value`, { tool: name });
2011
2090
  return result;
2012
2091
  };
@@ -2148,7 +2227,9 @@ function createWorkflowFunctions(runner, options) {
2148
2227
  return Object.freeze(composed);
2149
2228
  }
2150
2229
  /**
2151
- * Compiles the lenient workflow draft contract used by {@link createWorkflowTool}.
2230
+ * Compiles the lenient workflow draft contract {@link createWorkflowTool} parses an authored tree
2231
+ * with — a `ContractInterface` over a {@link WorkflowDraft}, whose `id` and `name` are optional at
2232
+ * the workflow, phase, and task levels.
2152
2233
  *
2153
2234
  * @returns The compiled {@link import('./types.js').WorkflowDraft} contract
2154
2235
  */
@@ -2156,34 +2237,33 @@ function createWorkflowDraftContract() {
2156
2237
  return createContract(workflowDraftShape);
2157
2238
  }
2158
2239
  /**
2159
- * Wraps a {@link WorkflowDefinition} as an LLM-callable tool — it ADVERTISES the SIMPLE flat
2160
- * authoring shape (`{ name?, steps: [{ name }] }`) as its `parameters` so even a small model can
2161
- * author a complete tree, and its handler EXPANDS / COMPLETES the authored blob, validates it
2162
- * against the STRICT contract, and runs it through `runner`, forwarding the caller's optional
2163
- * named functions and native checkpoint store.
2240
+ * Wraps a {@link WorkflowDefinition} as an LLM-callable tool — it advertises the flat authoring
2241
+ * shape (`{ name?, steps: [{ name }] }`) as its `parameters`, and its handler completes the
2242
+ * authored blob, validates it against the strict contract, and runs it through `runner`, forwarding
2243
+ * the caller's optional named functions and native checkpoint store.
2164
2244
  *
2165
2245
  * @remarks
2166
2246
  * A plain `ToolManagerInterface`-compatible tool (`@orkestrel/tool`), reproducing
2167
2247
  * Toolbox's flat / draft / full authoring contract, strict soundness gate, and lineage guard.
2168
- * It is ALSO the propagation carrier
2248
+ * It is also the propagation carrier
2169
2249
  * {@link createAgentFunction} binds onto a wrapped agent's `context.tools`: because a tool
2170
2250
  * handler receives only the model-supplied `args`, the immutable lineage is closed over at bind
2171
2251
  * time. The authored target is appended and its zero-based depth derived from workflow tags.
2172
2252
  *
2173
- * **Widened authoring surface (additive — the canonical contract + runner stay STRICT and
2174
- * unchanged).** A 2B model reliably CALLS the tool but cannot reliably emit the full four-level
2175
- * nested {@link WorkflowDefinition} (six required `id`/`name` strings, an all-or-nothing tree).
2176
- * So the tool ACCEPTS three authoring forms and converges them on the SAME strict
2253
+ * **Widened authoring surface (additive — the canonical contract and runner stay strict and
2254
+ * unchanged).** A 2B model reliably calls the tool but cannot reliably emit the full nested
2255
+ * {@link WorkflowDefinition}, whose every `id` and `name` is required across an all-or-nothing
2256
+ * tree. So the tool accepts the authoring forms that follow and converges them on the same strict
2177
2257
  * `createWorkflowContract` gate before running (soundness preserved):
2178
- * - the FLAT shape `{ name?, steps: [{ name }] }` — the ADVERTISED `parameters` (the simplest
2258
+ * - the flat shape `{ name?, steps: [{ name }] }` — the advertised `parameters` (the simplest
2179
2259
  * form, {@link import('./helpers.js').expandSteps}'d into one one-task phase per step);
2180
- * - a nested DRAFT with any `id`/`name` OMITTED — {@link createWorkflowDraftContract}-parsed then
2260
+ * - a nested draft with any `id`/`name` omitted — {@link createWorkflowDraftContract}-parsed then
2181
2261
  * {@link import('./helpers.js').completeDraft}'d (missing ids synthesized positionally);
2182
2262
  * - the full nested {@link WorkflowDefinition} — the advanced escape-hatch, accepted as the draft
2183
2263
  * super-set.
2184
2264
  *
2185
2265
  * The universal tool-handler contract: returns the plain run summary
2186
- * (`{ status, count, durable?, fault? }`) on success, THROWS a typed `ToolboxError` on Toolbox
2266
+ * (`{ status, count, durable?, fault? }`) on success, throws a typed `ToolboxError` on Toolbox
2187
2267
  * boundary failures — malformed authored args (`TOOL`), or an over-deep / cyclic nested run
2188
2268
  * (`DEPTH`) — and preserves genuine runner `WorkflowError`s. The `ToolManagerInterface` isolates every throw into the canonical tool result's
2189
2269
  * top-level `error`, so nothing escapes the run. `options.lineage` is the propagation carrier
@@ -2197,6 +2277,34 @@ function createWorkflowDraftContract() {
2197
2277
  * @returns A `ToolInterface` (named {@link import('./constants.js').WORKFLOW_TOOL_NAME}) whose
2198
2278
  * `parameters` advertise the flat authoring schema
2199
2279
  *
2280
+ * @example Authoring and running a workflow through the tool with a real ToolManager
2281
+ * ```ts
2282
+ * import { createWorkflowTool } from '@orkestrel/toolbox'
2283
+ * import { createToolManager } from '@orkestrel/tool'
2284
+ * import { createWorkflowRunner } from '@orkestrel/workflow'
2285
+ * import type { WorkflowDefinition } from '@orkestrel/workflow'
2286
+ *
2287
+ * const definition: WorkflowDefinition = { id: 'release', name: 'Release', phases: [] }
2288
+ * const runner = createWorkflowRunner()
2289
+ * const functions = {
2290
+ * compile: () => 'compiled',
2291
+ * publish: () => 'published',
2292
+ * }
2293
+ * const tool = createWorkflowTool(definition, runner, { functions })
2294
+ *
2295
+ * const tools = createToolManager()
2296
+ * tools.add(tool)
2297
+ *
2298
+ * // A small model authors the simple flat shape — no ids/names required.
2299
+ * const result = await tools.execute({
2300
+ * id: 'call-1',
2301
+ * name: 'workflow',
2302
+ * arguments: { name: 'release', steps: [{ name: 'compile' }, { name: 'publish' }] },
2303
+ * })
2304
+ * if (!result.success) throw new Error(result.error)
2305
+ * result.value // { status: 'completed', count: 2 } — the single-level envelope; no nested { id, name, value }
2306
+ * ```
2307
+ *
2200
2308
  * @example
2201
2309
  * ```ts
2202
2310
  * import { createWorkflowTool } from '@src/core'
@@ -2265,42 +2373,35 @@ function createWorkflowTool(definition, runner, options) {
2265
2373
  });
2266
2374
  }
2267
2375
  /**
2268
- * Builds an LLM-callable workspace-editing tool — it ADVERTISES the `operation`-discriminated
2269
- * union ({@link import('./shapers.js').workspaceToolShape}) as its `parameters`, and its
2270
- * handler PARSES the model-supplied args against that contract and DISPATCHES the matched
2271
- * operation against the manager's ACTIVE workspace (the registry ops drive the manager itself),
2272
- * returning the plain result. A malformed operation throws this package's `ToolboxError`; a
2273
- * genuine workspace-domain failure propagates `@orkestrel/workspace`'s typed `WorkspaceError`.
2274
- * EITHER drives a caller-supplied {@link WorkspaceToolOptions.manager} directly, OR
2275
- * constructs a fresh `WorkspaceManagerInterface` (`@orkestrel/workspace`) over
2276
- * {@link import('./types.js').WorkspaceToolOptions.store} (through `@orkestrel/workspace`'s
2277
- * `createWorkspaceManager`); neither given constructs a manager backed by
2278
- * `@orkestrel/workspace`'s in-memory store default.
2376
+ * Builds an LLM-callable workspace-editing tool — it advertises the `operation`-discriminated union
2377
+ * ({@link import('./shapers.js').workspaceToolShape}) as its `parameters`, and its handler parses
2378
+ * the model-supplied args against that contract and dispatches the matched operation against the
2379
+ * manager's active workspace, returning the plain result.
2279
2380
  *
2280
2381
  * @remarks
2281
- * MANAGER-DRIVEN: every edit / read op (read / list / has / search / replace / write / splice /
2382
+ * Manager-driven: every edit / read op (read / list / has / search / replace / write / splice /
2282
2383
  * prepend / append / move / remove) targets `manager.active`, so the model edits whichever
2283
2384
  * workspace is active and a host can re-point it (`WorkspaceManagerInterface.switch`) between
2284
- * turns. Two REGISTRY ops make the model self-sufficient: `workspaces` LISTS the registered
2385
+ * turns. The registry ops make the model self-sufficient: `workspaces` lists the registered
2285
2386
  * workspaces (each `{ id, files, active }`) so it can discover an id, and `switch` re-points the
2286
2387
  * active workspace by id (lenient — an unknown id is a no-op reporting `switched: false`, never a
2287
2388
  * throw).
2288
2389
  *
2289
- * NO-ACTIVE RULE (the ergonomic seam): a WRITING op (write / splice / prepend / append / move /
2290
- * remove / replace) run when `manager.active` is `undefined` AUTO-CREATES + activates a default
2291
- * workspace (`manager.add()`) so the model can start writing; a pure-READ op (read / list /
2292
- * has / search) against no active workspace returns the EMPTY result (`undefined` / `[]` /
2390
+ * No-active rule (the ergonomic seam): a writing op (write / splice / prepend / append / move /
2391
+ * remove / replace) run when `manager.active` is `undefined` auto-creates and activates a default
2392
+ * workspace (`manager.add()`) so the model can start writing; a pure-read op (read / list /
2393
+ * has / search) against no active workspace returns the empty result (`undefined` / `[]` /
2293
2394
  * `false`), never creating one and never throwing.
2294
2395
  *
2295
2396
  * The handler conforms to the universal tool-handler contract: it `contract.parse`s
2296
- * the args, THROWS a `TOOL` `ToolboxError` when no operation arm matched (a malformed / unknown
2297
- * operation), else `switch`es on `op.operation` and RETURNS the plain result — letting a
2397
+ * the args, throws a `TOOL` `ToolboxError` when no operation arm matched (a malformed / unknown
2398
+ * operation), else `switch`es on `op.operation` and returns the plain result — letting a
2298
2399
  * `WorkspaceError` raised by the live workspace (`MISSING` / `MODALITY` / `PATTERN` / `RANGE`)
2299
- * PROPAGATE uncaught. The range edit is the FLAT `'splice'` op: its four flat caret integers are
2400
+ * propagate uncaught. The range edit is the flat `'splice'` op: its flat caret integers are
2300
2401
  * reassembled into a `Range` (`@orkestrel/workspace`) by `rangeOf` and fed to the workspace's
2301
2402
  * ranged `write`.
2302
2403
  *
2303
- * @param options - `manager` (drive directly) OR `store` (build a manager over it); neither ⇒
2404
+ * @param options - `manager` (drive directly) or `store` (build a manager over it); neither ⇒
2304
2405
  * an in-memory-backed manager (see {@link import('./types.js').WorkspaceToolOptions})
2305
2406
  * @returns A `ToolInterface` (named {@link import('./constants.js').WORKSPACE_TOOL_NAME} by default)
2306
2407
  *
@@ -2418,8 +2519,8 @@ function createWorkspaceTool(options) {
2418
2519
  });
2419
2520
  }
2420
2521
  /**
2421
- * Builds an LLM-callable sub-agent delegation tool — resolves a live, seeded `AgentInterface`
2422
- * from `registry` and runs it to completion for ONE delegated `task`.
2522
+ * Builds an LLM-callable sub-agent delegation tool — it resolves a live, seeded `AgentInterface`
2523
+ * from `registry` and runs it to completion for one delegated `task`.
2423
2524
  *
2424
2525
  * @remarks
2425
2526
  * The universal tool-handler contract: validates the call args against
@@ -2427,10 +2528,10 @@ function createWorkspaceTool(options) {
2427
2528
  * sub-agent's conversation as a single `user` message; `provider` / `tools` / `system` fall
2428
2529
  * back to the tool's own {@link import('./types.js').AgentToolOptions} defaults), rehydrates the sub-agent through
2429
2530
  * `registry.build`, runs it with `agent.generate()`, and returns the settled
2430
- * `AgentResult.content` string (the sub-agent's final text). A missing / unresolvable `provider`, or a malformed call, THROWS a typed `TOOL`
2531
+ * `AgentResult.content` string (the sub-agent's final text). A missing / unresolvable `provider`, or a malformed call, throws a typed `TOOL`
2431
2532
  * {@link import('./errors.js').ToolboxError}; a delegation that would exceed
2432
2533
  * {@link import('./constants.js').AGENT_TOOL_DEPTH}, or re-enter an already-delegated agent (a
2433
- * cycle), THROWS a typed `DEPTH` {@link import('./errors.js').ToolboxError} — both isolated
2534
+ * cycle), throws a typed `DEPTH` {@link import('./errors.js').ToolboxError}, each isolated
2434
2535
  * by the `ToolManagerInterface` into the canonical tool result's top-level `error`.
2435
2536
  *
2436
2537
  * `AgentInterface` (`@orkestrel/agent`) exposes no teardown method — a bound sub-agent's
@@ -2502,9 +2603,8 @@ function createAgentTool(registry, options) {
2502
2603
  });
2503
2604
  }
2504
2605
  /**
2505
- * Builds an LLM-callable tool that returns the FULL `description` of another registered tool by
2506
- * name — the counterpart to the lean `summary` the other tools in this package advertise
2507
- * (`AGENT_TOOL_SUMMARY` / `WORKFLOW_TOOL_SUMMARY` / `WORKSPACE_TOOL_SUMMARY`).
2606
+ * Builds an LLM-callable tool that returns the full `description` of another registered tool by
2607
+ * name — the counterpart to the lean `summary` the other tools in this package advertise.
2508
2608
  *
2509
2609
  * @remarks
2510
2610
  * `ToolManagerInterface.definitions()` (`@orkestrel/tool`) advertises `tool.summary ??
@@ -2515,8 +2615,8 @@ function createAgentTool(registry, options) {
2515
2615
  * tool has no `description` of its own, then a placeholder when it has neither).
2516
2616
  *
2517
2617
  * The universal tool-handler contract: validates the call args against
2518
- * {@link import('./shapers.js').describeToolShape}, RETURNS the plain description string on
2519
- * success, THROWS a typed `TOOL` {@link import('./errors.js').ToolboxError} on a malformed call
2618
+ * {@link import('./shapers.js').describeToolShape}, returns the plain description string on
2619
+ * success, throws a typed `TOOL` {@link import('./errors.js').ToolboxError} on a malformed call
2520
2620
  * or an unknown tool name.
2521
2621
  *
2522
2622
  * @param tools - The `ToolManagerInterface` (`@orkestrel/tool`) whose registered tools this
@@ -2553,20 +2653,23 @@ function createDescribeTool(tools) {
2553
2653
  });
2554
2654
  }
2555
2655
  /**
2556
- * Builds an LLM-callable form tool — the ASK side of the terminal seam. Asks
2557
- * a multi-field form and BLOCKS until it answers, returning the resolved values record.
2656
+ * Builds an LLM-callable form tool — the ask side of the terminal seam. It asks a multi-field form
2657
+ * and blocks until the addressed terminal answers, returning the resolved values record.
2558
2658
  *
2559
2659
  * @remarks
2560
2660
  * The universal tool-handler contract: validates the call args against
2561
2661
  * {@link import('./shapers.js').promptToolShape}, parses the call's schema through
2562
2662
  * `@orkestrel/form`, constructs the live form, and passes it to `TerminalManagerInterface.ask`.
2563
- * `from` is FIXED at construction
2663
+ * `from` is fixed at construction
2564
2664
  * ({@link import('./types.js').PromptToolOptions.from}) — never read from the model-supplied
2565
- * args — so a model cannot spoof which terminal is asking. A form CYCLE rejects with
2665
+ * args — so a model cannot spoof which terminal is asking. A form cycle rejects with
2566
2666
  * `TerminalError('DEADLOCK')`, re-surfaced as a typed `DEADLOCK`
2567
2667
  * {@link import('./errors.js').ToolboxError}; an expired form re-surfaces as `EXPIRE`; an
2568
2668
  * unknown `to` (or any other `TerminalError`) re-surfaces as `TOOL`, naming the unknown terminal
2569
- * and how many brokers the manager holds (`manager.count`).
2669
+ * and how many brokers the manager holds (`manager.count`). A schema `parseForm` refuses — an
2670
+ * unknown control, a duplicate field name, a `'select'` or `'checkbox'` field without usable
2671
+ * `choices` — throws a typed `TOOL` error up front, so a malformed schema never parks as a form
2672
+ * nobody can answer.
2570
2673
  *
2571
2674
  * @param options - The live manager, the fixed `from` identity, and advertised overrides (see
2572
2675
  * {@link import('./types.js').PromptToolOptions})
@@ -2624,9 +2727,8 @@ function createPromptTool(options) {
2624
2727
  });
2625
2728
  }
2626
2729
  /**
2627
- * Builds an LLM-callable answer tool — the ANSWER side of the terminal seam. Lists the forms
2628
- * addressed to {@link import('./types.js').AnswerToolOptions.to}, or answers one of
2629
- * them by id.
2730
+ * Builds an LLM-callable answer tool — the answer side of the terminal seam. It lists the forms
2731
+ * addressed to {@link import('./types.js').AnswerToolOptions.to}, or answers one of them by id.
2630
2732
  *
2631
2733
  * @remarks
2632
2734
  * The universal tool-handler contract: validates the call args against
@@ -2636,10 +2738,10 @@ function createPromptTool(options) {
2636
2738
  * and applies it through
2637
2739
  * `TerminalManagerInterface.answer` — a rejected / unknown / unresolvable outcome
2638
2740
  * (`TerminalAnswerResult.error`) re-surfaces as a typed `ANSWER` `ToolboxError`; success returns
2639
- * `{ answered: id }`. `to` is FIXED at construction
2741
+ * `{ answered: id }`. `to` is fixed at construction
2640
2742
  * ({@link import('./types.js').AnswerToolOptions.to}) — never read from the model-supplied args —
2641
2743
  * so a model cannot spoof which terminal it is answering for. Concurrent answerers racing on one
2642
- * endpoint are FIRST-WRITE-WINS — a late answer to an already-settled form returns a typed
2744
+ * endpoint are first-write-wins — a late answer to an already-settled form returns a typed
2643
2745
  * `ANSWER` `ToolboxError` (surfaced as a 422 over HTTP).
2644
2746
  *
2645
2747
  * @param options - The live manager, the fixed `to` identity, and advertised overrides (see
@@ -2692,8 +2794,8 @@ function createAnswerTool(options) {
2692
2794
  }
2693
2795
  /**
2694
2796
  * Creates the in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of database
2695
- * definitions, the DEFAULT store the database and relation tools persist their
2696
- * `DatabaseDefinition` configs through.
2797
+ * definitions, the default store the database and relation tools persist their `DatabaseDefinition`
2798
+ * configs through.
2697
2799
  *
2698
2800
  * @returns A {@link DefinitionStoreInterface}
2699
2801
  *
@@ -2740,7 +2842,7 @@ function createDatabaseDefinitionStore(driver = createMemoryDriver()) {
2740
2842
  * @remarks
2741
2843
  * The universal tool-handler contract: validates the call args against
2742
2844
  * {@link import('./shapers.js').databaseToolShape}, dispatches to the matching operation, and
2743
- * RETURNS a plain result on success. A database is resolved lazily and cached for the tool's
2845
+ * returns a plain result on success. A database is resolved lazily and cached for the tool's
2744
2846
  * lifetime — `'create'` mints one from `tables` ({@link import('./compilers.js').expandTables}) and
2745
2847
  * a registered `driver` key ({@link import('./types.js').DatabaseToolOptions.drivers}, default
2746
2848
  * `{ memory: () => createMemoryDriver() }`); any other operation addressing an uncached id falls
@@ -2765,7 +2867,7 @@ function createDatabaseDefinitionStore(driver = createMemoryDriver()) {
2765
2867
  * ({@link import('./helpers.js').inferDatabaseCode}); an `ToolboxError` thrown by this tool's own
2766
2868
  * guards passes through unwrapped.
2767
2869
  *
2768
- * A lazily re-minted database over the DEFAULT in-memory driver yields an EMPTY database — only
2870
+ * A lazily re-minted database over the default in-memory driver yields an empty database — only
2769
2871
  * the {@link import('./types.js').DatabaseDefinition} schema persists in `store`, never rows;
2770
2872
  * durable rows need a persistent driver factory registered in
2771
2873
  * {@link import('./types.js').DatabaseToolOptions.drivers}. `'destroy'` closes whatever handle is
@@ -2773,7 +2875,7 @@ function createDatabaseDefinitionStore(driver = createMemoryDriver()) {
2773
2875
  * {@link import('./types.js').DatabaseToolOptions.databases} handle — the embedder relinquishes
2774
2876
  * that handle's lifecycle to this tool for any id it wires in. This tool assumes the
2775
2877
  * single-writer, non-reentrant model `@orkestrel/database` itself assumes — concurrent calls
2776
- * against one id are NOT serialized by this tool. `'get'` is uncapped by
2878
+ * against one id are not serialized by this tool. `'get'` is uncapped by
2777
2879
  * {@link import('./types.js').DatabaseToolOptions.limit} (bounded only by the caller's `key` array
2778
2880
  * size), unlike `'records'` / `'find'` / `'links'`.
2779
2881
  *
@@ -2785,11 +2887,14 @@ function createDatabaseDefinitionStore(driver = createMemoryDriver()) {
2785
2887
  * import { createDatabaseTool } from '@src/core'
2786
2888
  *
2787
2889
  * const tool = createDatabaseTool()
2788
- * await tool.execute({
2789
- * operation: 'create',
2790
- * id: 'shop',
2791
- * tables: { products: { columns: { name: 'string', price: 'number' } } },
2792
- * })
2890
+ * await tool.execute(
2891
+ * {
2892
+ * operation: 'create',
2893
+ * id: 'shop',
2894
+ * tables: { products: { columns: { name: 'string', price: 'number' } } },
2895
+ * },
2896
+ * { signal: new AbortController().signal },
2897
+ * )
2793
2898
  * ```
2794
2899
  */
2795
2900
  function createDatabaseTool(options = {}) {
@@ -2949,14 +3054,14 @@ function createDatabaseTool(options = {}) {
2949
3054
  * The universal tool-handler contract: validates the call args against
2950
3055
  * {@link import('./shapers.js').relationToolShape}, resolves the addressed
2951
3056
  * {@link import('@orkestrel/relation').RelationManagerInterface} — an explicit `manager` field
2952
- * must match a key of {@link import('./types.js').RelationToolOptions.managers}, an OMITTED one
2953
- * resolves to the SOLE registered manager, either miss throwing a typed `TOOL`
3057
+ * must match a key of {@link import('./types.js').RelationToolOptions.managers}, an omitted one
3058
+ * resolves to the sole registered manager, either miss throwing a typed `TOOL`
2954
3059
  * {@link import('./errors.js').ToolboxError}
2955
3060
  * ({@link import('./helpers.js').resolveRelationManager}) — then resolves `model` against it
2956
3061
  * ({@link import('./helpers.js').resolveRelationModel}, same typed-`TOOL`-on-miss shape), and
2957
- * dispatches to the matched operation, RETURNING a plain result on success.
3062
+ * dispatches to the matched operation, returning a plain result on success.
2958
3063
  *
2959
- * `'load'` / `'find'` expand the call's FLAT dot-path `include` list into a live
3064
+ * `'load'` / `'find'` expand the call's flat dot-path `include` list into a live
2960
3065
  * `@orkestrel/relation` `Include` tree through {@link import('./helpers.js').expandInclude}, capped
2961
3066
  * at {@link import('./types.js').RelationToolOptions.depth} (default
2962
3067
  * {@link import('./constants.js').RELATION_TOOL_DEPTH}) — a path exceeding the cap, or carrying an
@@ -2966,7 +3071,7 @@ function createDatabaseTool(options = {}) {
2966
3071
  * result to {@link import('./types.js').RelationToolOptions.limit} (default
2967
3072
  * {@link import('./constants.js').RELATION_TOOL_LIMIT}), taken through
2968
3073
  * {@link import('./helpers.js').resolveLimit} — `'find'` probes one row past the effective limit to
2969
- * report `truncated`; `'links'` (which has no upstream pagination) fetches the FULL linked-key
3074
+ * report `truncated`; `'links'` (which has no upstream pagination) fetches the full linked-key
2970
3075
  * list and slices/truncates it the same way. `'link'` / `'unlink'` write / remove one `through` junction
2971
3076
  * row.
2972
3077
  *
@@ -2985,7 +3090,10 @@ function createDatabaseTool(options = {}) {
2985
3090
  * import { createRelationTool } from '@src/core'
2986
3091
  *
2987
3092
  * const tool = createRelationTool({ managers: { shop: manager } })
2988
- * await tool.execute({ operation: 'load', model: 'accounts', key: 'acc1', include: ['contacts'] })
3093
+ * await tool.execute(
3094
+ * { operation: 'load', model: 'accounts', key: 'acc1', include: ['contacts'] },
3095
+ * { signal: new AbortController().signal },
3096
+ * )
2989
3097
  * ```
2990
3098
  */
2991
3099
  function createRelationTool(options) {
@@ -3066,44 +3174,44 @@ function createRelationTool(options) {
3066
3174
  });
3067
3175
  }
3068
3176
  /**
3069
- * Builds a standalone LLM-callable tool that infers a JSON Schema from example values — the
3070
- * utility half of the "existing API/DB → MCP tool" bridge (the other half,
3071
- * {@link createEndpointTool}, wraps one CONCRETE endpoint).
3177
+ * Builds a standalone LLM-callable tool that infers a JSON Schema from example values — the utility
3178
+ * half of the bridge from an existing API or database into an MCP tool (the other half,
3179
+ * {@link createEndpointTool}, wraps one concrete endpoint).
3072
3180
  *
3073
3181
  * @remarks
3074
3182
  * The universal tool-handler contract: validates the call args against
3075
3183
  * {@link import('./shapers.js').inferToolShape} (`samples` non-empty, `format` / `enum` optional
3076
3184
  * booleans, `candidates` an optional array), infers a schema through `@orkestrel/contract`'s
3077
3185
  * `samplesToSchema`, wraps a non-object root as `{ value: <schema> }` through `schemaToObject` (mirrors
3078
- * the tool-parameters convention every other `create*Tool` factory advertises), and RETURNS the
3186
+ * the tool-parameters convention every other `create*Tool` factory advertises), and returns the
3079
3187
  * resulting parameters record. An empty `samples` array fails `inferToolShape`'s `min: 1` bound —
3080
3188
  * `contract.parse` returns `undefined` and the handler throws a typed `TOOL`
3081
3189
  * {@link import('./errors.js').ToolboxError}.
3082
3190
  *
3083
- * When `candidates` is ABSENT, the return is the bare parameters record — unchanged from before
3084
- * this array existed. When `candidates` is PRESENT (any array, including empty), the handler
3085
- * compiles a SEPARATE per-call contract from the RAW inferred schema (through `@orkestrel/contract`'s
3086
- * `schemaToShape`, NOT the `schemaToObject`-wrapped parameters — a bare-value sample checks a
3191
+ * When `candidates` is absent, the return is the bare parameters record — unchanged from before
3192
+ * this array existed. When `candidates` is present (any array, including empty), the handler
3193
+ * compiles a separate per-call contract from the raw inferred schema (through `@orkestrel/contract`'s
3194
+ * `schemaToShape`, not the `schemaToObject`-wrapped parameters — a bare-value sample checks a
3087
3195
  * bare-value candidate) and returns `{ parameters, checks }`, one check per candidate at the same
3088
- * index. Every entry has a UNIFORM shape — `{ index, valid, coercible }`, with `faults` added ONLY
3089
- * when `valid` is `false`: `valid` is the STRICT guard verdict (`checker.is(candidate)`), the
3090
- * OPPOSITE of {@link createEndpointTool}'s enforcement, which coerces (`7` becomes `'7'` for a
3091
- * string slot) — here a conformance report answers "does this value conform AS-IS": `7` against a
3092
- * string slot is `valid: false`, full stop. `coercible` answers a SEPARATE question — "would the
3093
- * NORMALIZING parse accept this value", that is would {@link createEndpointTool}'s default enforcement
3196
+ * index. Every entry has a uniform shape — `{ index, valid, coercible }`, with `faults` added only
3197
+ * when `valid` is `false`: `valid` is the strict guard verdict (`checker.is(candidate)`), the
3198
+ * opposite of {@link createEndpointTool}'s enforcement, which coerces (`7` becomes `'7'` for a
3199
+ * string slot) — here a conformance report answers "does this value conform as-is": `7` against a
3200
+ * string slot is `valid: false`, full stop. `coercible` answers a separate question — "would the
3201
+ * normalizing parse accept this value", that is would {@link createEndpointTool}'s default enforcement
3094
3202
  * admit it (`checker.parse(candidate) !== undefined`) — computed for every candidate regardless of
3095
3203
  * `valid`; by the house parse/guard round-trip, a `valid: true` entry is
3096
- * ALWAYS also `coercible: true`. `@orkestrel/contract`'s `explain` mirrors the normalizing
3204
+ * always also `coercible: true`. `@orkestrel/contract`'s `explain` mirrors the normalizing
3097
3205
  * `parse`'s leniency, not `is`'s strictness — so a strictly-invalid but coercible candidate (`7`
3098
- * against a string slot) yields `{ valid: false, coercible: true, faults: [] }`: EMPTY faults, since
3206
+ * against a string slot) yields `{ valid: false, coercible: true, faults: [] }`: empty faults, because
3099
3207
  * the mismatch the normalizing parse would silently fix is not one `explain` reports. `faults`
3100
- * therefore only ever populates for a NON-coercible mismatch — a wrong type the parse can't coerce
3208
+ * therefore only ever populates for a non-coercible mismatch — a wrong type the parse can't coerce
3101
3209
  * (a boolean in a string slot), a missing required key, or an out-of-enum value — where
3102
3210
  * `coercible: false`. `checker.is` / `.parse` / `.explain` are all total over JSON-safe input — a
3103
- * JSON-safe hostile candidate (a `__proto__`-carrying object, deeply nested data) reaches all three
3104
- * and yields a bounded, non-throwing per-candidate verdict; a NON-JSON-safe candidate (for example a
3105
- * throwing-getter `Proxy`) never reaches the checker at all — it fails the OUTER `args` parse
3106
- * against {@link import('./shapers.js').inferToolShape} and rejects the WHOLE call with the same
3211
+ * JSON-safe hostile candidate (a `__proto__`-carrying object, deeply nested data) reaches each of them
3212
+ * and yields a bounded, non-throwing per-candidate verdict; a non-JSON-safe candidate (for example a
3213
+ * throwing-getter `Proxy`) never reaches the checker at all — it fails the outer `args` parse
3214
+ * against {@link import('./shapers.js').inferToolShape} and rejects the whole call with the same
3107
3215
  * `TOOL` {@link import('./errors.js').ToolboxError} a malformed `samples`/`format`/`enum` throws,
3108
3216
  * with no per-candidate verdict produced.
3109
3217
  *
@@ -3182,36 +3290,38 @@ function createInferTool(options) {
3182
3290
  });
3183
3291
  }
3184
3292
  /**
3185
- * Wraps one CONCRETE endpoint ({@link import('./types.js').EndpointDefinition}) as an LLM-callable
3186
- * `ToolInterface` — the endpoint half of the "existing API/DB → MCP tool" bridge (the other half,
3187
- * {@link createInferTool}, is a standalone inference utility).
3293
+ * Wraps one concrete endpoint ({@link import('./types.js').EndpointDefinition}) as an LLM-callable
3294
+ * `ToolInterface` — the endpoint half of the bridge from an existing API or database into an MCP
3295
+ * tool (the other half, {@link createInferTool}, is a standalone inference utility).
3188
3296
  *
3189
3297
  * @remarks
3190
- * `parameters` is inferred ONCE at construction from `definition.samples` through
3298
+ * `parameters` is inferred once at construction from `definition.samples` through
3191
3299
  * `@orkestrel/contract`'s `samplesToSchema` (tuned by {@link import('./types.js').EndpointToolOptions}'s
3192
3300
  * `format` / `enum`), wrapping a non-object root as `{ value: <schema> }` through `schemaToObject` —
3193
- * the SAME object-rooted schema is both the ADVERTISED `parameters` and, by default
3194
- * ({@link import('./types.js').EndpointToolOptions.validate} `true`), the ENFORCED contract:
3195
- * `@orkestrel/contract`'s `schemaToShape` compiles it ONCE (through `createContract`) into a
3301
+ * the same object-rooted schema is both the advertised `parameters` and, by default
3302
+ * ({@link import('./types.js').EndpointToolOptions.validate} `true`), the enforced contract:
3303
+ * `@orkestrel/contract`'s `schemaToShape` compiles it once (through `createContract`) into a
3196
3304
  * `ContractInterface` whose `.parse` runs on every call's `args` before `definition.execute` — a
3197
- * NORMALIZING parse, not a strict type check: a scalar is COERCED to its inferred type where the
3305
+ * normalizing parse, not a strict type check: a scalar is coerced to its inferred type where the
3198
3306
  * house parsers coerce (a number to/from a numeric string, a boolean from `'1'`/`'0'`/`'true'`/
3199
- * `'false'`/`1`/`0`), so `definition.execute` receives the COERCED value (for example `7` sent for a
3307
+ * `'false'`/`1`/`0`), so `definition.execute` receives the coerced value (for example `7` sent for a
3200
3308
  * string slot arrives as `'7'`), not the raw call value. A call whose `args` fails to parse into
3201
- * a record — a required key missing, or a value not coercible to its slot's type — THROWS a
3309
+ * a record — a required key missing, or a value not coercible to its slot's type — throws a
3202
3310
  * typed `TOOL` {@link import('./errors.js').ToolboxError} carrying the compiled contract's
3203
3311
  * structured `explain` faults, and `definition.execute` is never called. `format` annotations are
3204
- * NEVER asserted, and a key outside the closed inferred schema is SILENTLY DROPPED rather than
3312
+ * never asserted, and a key outside the closed inferred schema is silently dropped rather than
3205
3313
  * rejected (see {@link import('./types.js').EndpointToolOptions.validate}). With
3206
- * `validate: false`, the tool's `execute` PASSES THROUGH the model-supplied `args` to
3207
- * `definition.execute` WITHOUT re-validation — the raw-passthrough opt-out. Either way, the
3208
- * definition's return flows back as the tool call's plain result; a throw PROPAGATES uncaught,
3314
+ * `validate: false`, the tool's `execute` passes through the model-supplied `args` to
3315
+ * `definition.execute` without re-validation — the raw-passthrough opt-out. The execution context
3316
+ * the tool's `execute` receives reaches `definition.execute` unchanged whichever way `args` are
3317
+ * handled, so a handler that reads `context.signal` observes the caller's cancellation. Either way,
3318
+ * the definition's return flows back as the tool call's plain result; a throw propagates uncaught,
3209
3319
  * isolated by the `ToolManagerInterface` (`@orkestrel/tool`) into the canonical error envelope
3210
3320
  * — never caught or re-wrapped here.
3211
3321
  *
3212
3322
  * @param definition - The endpoint's identity, non-empty samples, and local handler (see
3213
3323
  * {@link import('./types.js').EndpointDefinition})
3214
- * @param options - Construction-time inference tuning + the validate opt-out (see
3324
+ * @param options - Construction-time inference tuning and the validate opt-out (see
3215
3325
  * {@link import('./types.js').EndpointToolOptions})
3216
3326
  * @returns A `ToolInterface` named `definition.name`
3217
3327
  *
@@ -3258,8 +3368,8 @@ function createEndpointTool(definition, options) {
3258
3368
  name: definition.name,
3259
3369
  description: definition.description,
3260
3370
  ...parameters === void 0 ? {} : { parameters },
3261
- execute(args) {
3262
- return definition.execute(args);
3371
+ execute(args, context) {
3372
+ return definition.execute(args, context);
3263
3373
  }
3264
3374
  });
3265
3375
  const contract = createContract(schemaToShape(objectSchema));
@@ -3267,13 +3377,13 @@ function createEndpointTool(definition, options) {
3267
3377
  name: definition.name,
3268
3378
  description: definition.description,
3269
3379
  ...parameters === void 0 ? {} : { parameters },
3270
- execute(args) {
3380
+ execute(args, context) {
3271
3381
  const parsed = contract.parse(args);
3272
3382
  if (parsed === void 0 || !isRecord(parsed)) throw new ToolboxError("TOOL", "malformed endpoint call arguments", {
3273
3383
  name: definition.name,
3274
3384
  faults: contract.explain(args)
3275
3385
  });
3276
- return definition.execute(parsed);
3386
+ return definition.execute(parsed, context);
3277
3387
  }
3278
3388
  });
3279
3389
  }