@orkestrel/toolbox 0.0.11 → 0.0.12

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,17 +9,17 @@ 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
- * The name {@link import('./factories.js').createAgentTool} advertises by default — the key a
12
+ * Holds the name {@link import('./factories.js').createAgentTool} advertises by default — the key a
13
13
  * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
14
14
  */
15
15
  var AGENT_TOOL_NAME = "agent";
16
16
  /**
17
- * The maximum nesting depth a delegation chain (agent tool → sub-agent → agent tool → …) may
17
+ * Holds the maximum nesting depth a delegation chain (agent tool → sub-agent → agent tool → …) may
18
18
  * reach — 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_DEPTH} (rather than the two guards
22
+ * Deliberately a SEPARATE constant from {@link MAX_WORKFLOW_CHAIN} (rather than the two guards
23
23
  * sharing one reference): the two guards bound DIFFERENT chains (workflow nesting vs. 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
@@ -27,22 +27,22 @@ var AGENT_TOOL_NAME = "agent";
27
27
  */
28
28
  var AGENT_TOOL_DEPTH = 8;
29
29
  /**
30
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createAgentTool}
30
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createAgentTool}
31
31
  * advertises in place of {@link AGENT_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
32
32
  * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
33
- * for the full teaching description; the full text stays retrievable via
33
+ * for the full teaching description; the full text stays retrievable through
34
34
  * {@link import('./factories.js').createDescribeTool}.
35
35
  */
36
36
  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
37
  /**
38
- * The description {@link import('./factories.js').createAgentTool} advertises — a short guide
38
+ * Holds the description {@link import('./factories.js').createAgentTool} advertises — a short guide
39
39
  * covering the required task and optional provider, tools, and system overrides.
40
40
  */
41
41
  var AGENT_TOOL_DESCRIPTION = [
42
42
  "Delegate a task to a sub-agent and return its result. Every call runs ONE sub-agent turn to completion.",
43
43
  "",
44
44
  "Required:",
45
- " task - the instructions the sub-agent should carry out.",
45
+ " task - the instructions the sub-agent carries out.",
46
46
  "Optional overrides (default to the values this tool was configured with):",
47
47
  " provider - the registry key of the model/provider the sub-agent runs against.",
48
48
  " tools - registry keys of the tools loaded into the sub-agent (replaces the default list, not merged).",
@@ -51,7 +51,7 @@ var AGENT_TOOL_DESCRIPTION = [
51
51
  JSON.stringify({ task: "Summarize the attached notes in three bullet points." })
52
52
  ].join("\n");
53
53
  /**
54
- * The maximum nesting depth a workflow → agent → workflow chain may reach — the bound
54
+ * Holds the maximum nesting depth a workflow → agent → workflow chain may reach — the bound
55
55
  * {@link import('./factories.js').createAgentFunction} and
56
56
  * {@link import('./factories.js').createWorkflowTool}'s depth/cycle guards enforce.
57
57
  *
@@ -60,9 +60,9 @@ var AGENT_TOOL_DESCRIPTION = [
60
60
  * workflows is allowed, while a ninth nested workflow is rejected with this package's typed
61
61
  * `DEPTH` `ToolboxError`.
62
62
  */
63
- var MAX_WORKFLOW_DEPTH = 8;
63
+ var MAX_WORKFLOW_CHAIN = 8;
64
64
  /**
65
- * The name {@link import('./factories.js').createWorkflowTool} advertises by default — the key a
65
+ * Holds the name {@link import('./factories.js').createWorkflowTool} advertises by default — the key a
66
66
  * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under, and the name
67
67
  * {@link import('./factories.js').createAgentFunction} binds the depth/cycle-aware workflow tool
68
68
  * under onto a wrapped agent's `context.tools`.
@@ -71,17 +71,17 @@ var MAX_WORKFLOW_DEPTH = 8;
71
71
  * The propagation seam's well-known key: when
72
72
  * `createAgentFunction`'s `runner` option is supplied, it adds a `createWorkflowTool`-built tool
73
73
  * under this name to the agent's `context.tools`, so it can author + run a NESTED workflow
74
- * (bounded by {@link MAX_WORKFLOW_DEPTH}).
74
+ * (bounded by {@link MAX_WORKFLOW_CHAIN}).
75
75
  */
76
76
  var WORKFLOW_TOOL_NAME = "workflow";
77
77
  /**
78
- * A complete FLAT authoring example — the PRIMARY way a small model authors a workflow through
78
+ * Holds a complete FLAT authoring example — the PRIMARY way a small model authors a workflow through
79
79
  * {@link import('./factories.js').createWorkflowTool}: `{ name, steps: [{ name }] }`.
80
80
  *
81
81
  * @remarks
82
82
  * Each step becomes a one-task phase, in
83
83
  * order; a step's `name` is a REGISTERED behavior name (not a label) — the registry key its
84
- * task's `run` resolves against. The tool expands this
84
+ * task's `behavior` resolves against. The tool expands this
85
85
  * ({@link import('./helpers.js').expandSteps}) into a valid `WorkflowDefinition`
86
86
  * (`@orkestrel/workflow`). It is embedded VERBATIM in {@link WORKFLOW_TOOL_DESCRIPTION}.
87
87
  */
@@ -90,7 +90,7 @@ var WORKFLOW_TOOL_FLAT_EXAMPLE = Object.freeze({
90
90
  steps: Object.freeze([Object.freeze({ name: "compile" }), Object.freeze({ name: "publish" })])
91
91
  });
92
92
  /**
93
- * A minimal NESTED authoring example — the ADVANCED escape-hatch form a model may use instead of
93
+ * Holds a minimal NESTED authoring example — the ADVANCED escape-hatch form a model may use instead of
94
94
  * the flat shape: a full `WorkflowDefinition` (`@orkestrel/workflow`).
95
95
  *
96
96
  * @remarks
@@ -106,20 +106,20 @@ var WORKFLOW_TOOL_NESTED_EXAMPLE = Object.freeze({
106
106
  tasks: Object.freeze([Object.freeze({
107
107
  id: "compile",
108
108
  name: "Compile",
109
- run: "compile"
109
+ behavior: "compile"
110
110
  })])
111
111
  })])
112
112
  });
113
113
  /**
114
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createWorkflowTool}
114
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createWorkflowTool}
115
115
  * advertises in place of {@link WORKFLOW_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
116
116
  * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
117
- * for the full teaching description; the full text stays retrievable via
117
+ * for the full teaching description; the full text stays retrievable through
118
118
  * {@link import('./factories.js').createDescribeTool}.
119
119
  */
120
120
  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
121
  /**
122
- * The description {@link import('./factories.js').createWorkflowTool} advertises — the flat
122
+ * Holds the description {@link import('./factories.js').createWorkflowTool} advertises — the flat
123
123
  * authoring form, its worked example, and the advanced nested definition form.
124
124
  */
125
125
  var WORKFLOW_TOOL_DESCRIPTION = [
@@ -133,17 +133,17 @@ var WORKFLOW_TOOL_DESCRIPTION = [
133
133
  "Example:",
134
134
  JSON.stringify(WORKFLOW_TOOL_FLAT_EXAMPLE),
135
135
  "",
136
- "ADVANCED — the full nested form, for multi-task phases or explicit ids. A workflow has phases; a phase has tasks; a task may have a \"run\" (a registered behavior name); omitting it creates a JSON-null no-op:",
136
+ "ADVANCED — the full nested form, for multi-task phases or explicit ids. A workflow has phases; a phase has tasks; a task may have a \"behavior\" (a registered behavior name); omitting it creates a JSON-null no-op:",
137
137
  JSON.stringify(WORKFLOW_TOOL_NESTED_EXAMPLE),
138
138
  "In the nested form you may omit any \"id\"/\"name\" and they are filled in positionally; a provided one is kept."
139
139
  ].join("\n");
140
140
  /**
141
- * The name {@link import('./factories.js').createWorkspaceTool} advertises by default — the key a
141
+ * Holds the name {@link import('./factories.js').createWorkspaceTool} advertises by default — the key a
142
142
  * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
143
143
  */
144
144
  var WORKSPACE_TOOL_NAME = "workspace";
145
145
  /**
146
- * A valid {@link import('./types.js').WorkspaceOperation} object — the canonical example embedded
146
+ * Holds a valid {@link import('./types.js').WorkspaceOperation} object — the canonical example embedded
147
147
  * VERBATIM in {@link WORKSPACE_TOOL_DESCRIPTION}.
148
148
  *
149
149
  * @remarks
@@ -157,15 +157,15 @@ var WORKSPACE_TOOL_EXAMPLE = Object.freeze({
157
157
  content: "hello"
158
158
  });
159
159
  /**
160
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createWorkspaceTool}
160
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createWorkspaceTool}
161
161
  * advertises in place of {@link WORKSPACE_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
162
162
  * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
163
- * for the full teaching description; the full text stays retrievable via
163
+ * for the full teaching description; the full text stays retrievable through
164
164
  * {@link import('./factories.js').createDescribeTool}.
165
165
  */
166
166
  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
167
  /**
168
- * The description {@link import('./factories.js').createWorkspaceTool} advertises — the
168
+ * Holds the description {@link import('./factories.js').createWorkspaceTool} advertises — the
169
169
  * operation-keyed workspace protocol, all supported operations, and worked examples.
170
170
  *
171
171
  * @remarks
@@ -197,24 +197,24 @@ var WORKSPACE_TOOL_DESCRIPTION = [
197
197
  JSON.stringify(WORKSPACE_TOOL_EXAMPLE)
198
198
  ].join("\n");
199
199
  /**
200
- * The name {@link import('./factories.js').createDescribeTool} advertises by default — the key a
200
+ * Holds the name {@link import('./factories.js').createDescribeTool} advertises by default — the key a
201
201
  * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
202
202
  *
203
203
  * @remarks
204
- * Net-new: pairs with the other three tools' lean {@link AGENT_TOOL_SUMMARY} /
205
- * {@link WORKFLOW_TOOL_SUMMARY} / {@link WORKSPACE_TOOL_SUMMARY} — a model that reads only the
204
+ * Pairs with the lean {@link AGENT_TOOL_SUMMARY} / {@link WORKFLOW_TOOL_SUMMARY} /
205
+ * {@link WORKSPACE_TOOL_SUMMARY} — a model that reads only the
206
206
  * advertised summary can call `describe` with that tool's registered name to get its full
207
207
  * teaching description back.
208
208
  */
209
209
  var DESCRIBE_TOOL_NAME = "describe";
210
210
  /**
211
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createDescribeTool}
211
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createDescribeTool}
212
212
  * advertises — this tool needs no teaching of its own, so its summary and description are both
213
213
  * short.
214
214
  */
215
215
  var DESCRIBE_TOOL_SUMMARY = "Return the full description of a named registered tool.";
216
216
  /**
217
- * The DESCRIPTION {@link import('./factories.js').createDescribeTool} advertises.
217
+ * Holds the DESCRIPTION {@link import('./factories.js').createDescribeTool} advertises.
218
218
  *
219
219
  * @remarks
220
220
  * Deliberately short — unlike the workflow / workspace / agent tools, this one has no authoring
@@ -222,19 +222,19 @@ var DESCRIBE_TOOL_SUMMARY = "Return the full description of a named registered t
222
222
  */
223
223
  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
224
  /**
225
- * The name {@link import('./factories.js').createPromptTool} advertises by default — the key a
225
+ * Holds the name {@link import('./factories.js').createPromptTool} advertises by default — the key a
226
226
  * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
227
227
  */
228
228
  var PROMPT_TOOL_NAME = "ask";
229
229
  /**
230
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createPromptTool}
230
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createPromptTool}
231
231
  * advertises in place of {@link PROMPT_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
232
232
  * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
233
- * for the full teaching description; the full text stays retrievable via
233
+ * for the full teaching description; the full text stays retrievable through
234
234
  * {@link import('./factories.js').createDescribeTool}.
235
235
  */
236
236
  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
- /** The full form protocol {@link import('./factories.js').createPromptTool} advertises. */
237
+ /** Holds the full form protocol {@link import('./factories.js').createPromptTool} advertises. */
238
238
  var PROMPT_TOOL_DESCRIPTION = [
239
239
  "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
240
  "",
@@ -260,24 +260,24 @@ var PROMPT_TOOL_DESCRIPTION = [
260
260
  })
261
261
  ].join("\n");
262
262
  /**
263
- * The name {@link import('./factories.js').createAnswerTool} advertises by default — the key a
263
+ * Holds the name {@link import('./factories.js').createAnswerTool} advertises by default — the key a
264
264
  * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
265
265
  */
266
266
  var ANSWER_TOOL_NAME = "answer";
267
267
  /**
268
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createAnswerTool}
268
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createAnswerTool}
269
269
  * advertises in place of {@link ANSWER_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
270
270
  * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
271
- * for the full teaching description; the full text stays retrievable via
271
+ * for the full teaching description; the full text stays retrievable through
272
272
  * {@link import('./factories.js').createDescribeTool}.
273
273
  */
274
274
  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
- /** The pending/answer protocol {@link import('./factories.js').createAnswerTool} advertises. */
275
+ /** Holds the pending/answer protocol {@link import('./factories.js').createAnswerTool} advertises. */
276
276
  var ANSWER_TOOL_DESCRIPTION = [
277
- "List the forms currently addressed to this terminal, or answer one of them by id. Every call is ONE operation, chosen by the \"operation\" field.",
277
+ "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
278
  "",
279
279
  "Operations:",
280
- "- pending { \"operation\": \"pending\" } — list every form currently addressed to this terminal (id, from, schema).",
280
+ "- pending { \"operation\": \"pending\" } — list every form addressed to this terminal (id, from, schema).",
281
281
  "- answer { \"operation\": \"answer\", \"id\": \"<form id>\", \"values\": { \"<field name>\": <field value> } } — answer every required field with the value its control accepts.",
282
282
  "Example — list pending forms:",
283
283
  JSON.stringify({ operation: "pending" }),
@@ -292,24 +292,20 @@ var ANSWER_TOOL_DESCRIPTION = [
292
292
  })
293
293
  ].join("\n");
294
294
  /**
295
- * The name the upcoming `createDatabaseTool` factory will advertise by default — the key a model
296
- * calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
297
- *
298
- * @remarks
299
- * SRC-1 of a 3-unit spine: this unit lands the persistence + schema foundation
300
- * ({@link import('./types.js').DatabaseDefinition}, {@link import('./types.js').DefinitionStoreInterface},
301
- * {@link import('./helpers.js').expandTables}); `createDatabaseTool` itself is built in a later unit.
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.
302
297
  */
303
298
  var DATABASE_TOOL_NAME = "database";
304
299
  /**
305
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} the upcoming database tool
306
- * will advertise in place of {@link DATABASE_TOOL_DESCRIPTION}.
300
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
301
+ * {@link import('./factories.js').createDatabaseTool} advertises in place of
302
+ * {@link DATABASE_TOOL_DESCRIPTION}.
307
303
  */
308
304
  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.";
309
305
  /**
310
- * The DESCRIPTION the upcoming database tool will advertise — a multi-line guide that teaches a
311
- * small model the operation list, the SERIALIZED query form, and the {@link import('./types.js').TableSpec}
312
- * column DSL.
306
+ * 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
308
+ * the {@link import('./types.js').TableSpec} column DSL.
313
309
  *
314
310
  * @remarks
315
311
  * The query form is deliberately SERIALIZED (never fluent) — every condition is a flat object
@@ -321,7 +317,7 @@ var DATABASE_TOOL_DESCRIPTION = [
321
317
  "Create and query a database. Every call is ONE operation, chosen by the \"operation\" field.",
322
318
  "",
323
319
  "Operations (each takes the fields listed):",
324
- "- create { \"operation\": \"create\", \"id\": \"<database id>\", \"tables\": { \"<table>\": { \"columns\": { \"<column>\": \"string\" | \"integer\" | \"number\" | \"boolean\" | { \"type\": \"string\", \"optional\": true } } } }, \"primary\"?: { \"<table>\": \"<column>\" }, \"indexes\"?: { \"<table>\": [[\"<column>\"]] }, \"version\"?: <number> } — define a new database.",
320
+ "- create { \"operation\": \"create\", \"id\": \"<database id>\", \"tables\": { \"<table>\": { \"columns\": { \"<column>\": \"string\" | \"integer\" | \"number\" | \"boolean\" | { \"primitive\": \"string\", \"optional\": true } } } }, \"primary\"?: { \"<table>\": \"<column>\" }, \"indexes\"?: { \"<table>\": [[\"<column>\"]] }, \"version\"?: <number> } — define a new database.",
325
321
  "- tables { \"operation\": \"tables\", \"id\": \"<database id>\" } — list a database's table names.",
326
322
  "- get { \"operation\": \"get\", \"id\": \"<database id>\", \"table\": \"<table>\", \"key\": \"<row key>\" } — fetch one row by its primary key.",
327
323
  "- records { \"operation\": \"records\", \"id\": \"<database id>\", \"table\": \"<table>\", \"query\"?: <Query> } — list rows matching a query.",
@@ -338,7 +334,7 @@ var DATABASE_TOOL_DESCRIPTION = [
338
334
  " operators: equals, not, above, below, from, to, between, like, glob, starts, ends, any, none, absent, present.",
339
335
  " \"connector\" joins this condition to the next (\"and\" | \"or\"); omit on the last condition.",
340
336
  "",
341
- "Column DSL (used by \"create\" \"tables\"): a column is either a bare type string (\"string\" | \"integer\" | \"number\" | \"boolean\"), or { \"type\": \"<type>\", \"optional\": true } when the column may be absent from a row.",
337
+ "Column DSL (used by \"create\" \"tables\"): a column is either a bare primitive string (\"string\" | \"integer\" | \"number\" | \"boolean\"), or { \"primitive\": \"<primitive>\", \"optional\": true } when the column may be absent from a row.",
342
338
  "Schema configuration is creation-time only. Evolve a schema by opening a newly configured target-version database over a versioned persistent driver; reconciliation requires paired metadata/stamp capabilities.",
343
339
  "Example — create a database:",
344
340
  JSON.stringify({
@@ -348,7 +344,7 @@ var DATABASE_TOOL_DESCRIPTION = [
348
344
  name: "string",
349
345
  price: "number",
350
346
  notes: {
351
- type: "string",
347
+ primitive: "string",
352
348
  optional: true
353
349
  }
354
350
  } } }
@@ -365,9 +361,9 @@ var DATABASE_TOOL_DESCRIPTION = [
365
361
  }] }
366
362
  })
367
363
  ].join("\n");
368
- /** The default cap on rows a `records` call returns when the caller omits `query.limit` — the upcoming database tool's default row ceiling. */
364
+ /** Holds the default cap on rows a `records` call returns when the caller omits `query.limit` — the database tool's default row ceiling. */
369
365
  var DATABASE_TOOL_LIMIT = 1e3;
370
- /** The runtime-frozen database-tool mutation names disabled by `DatabaseToolOptions.readonly`. */
366
+ /** Lists the runtime-frozen database-tool mutation names disabled by `DatabaseToolOptions.readonly`. */
371
367
  var DATABASE_TOOL_MUTATIONS = Object.freeze([
372
368
  "create",
373
369
  "add",
@@ -377,17 +373,17 @@ var DATABASE_TOOL_MUTATIONS = Object.freeze([
377
373
  "destroy"
378
374
  ]);
379
375
  /**
380
- * The name `createRelationTool` advertises by default — the key a model calls and the
376
+ * Holds the name `createRelationTool` advertises by default — the key a model calls and the
381
377
  * `ToolManagerInterface` (`@orkestrel/tool`) registers under.
382
378
  */
383
379
  var RELATION_TOOL_NAME = "relation";
384
380
  /**
385
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} the relation tool advertises
381
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} the relation tool advertises
386
382
  * in place of {@link RELATION_TOOL_DESCRIPTION}.
387
383
  */
388
384
  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.";
389
385
  /**
390
- * The DESCRIPTION the relation tool advertises — a multi-line guide that teaches a small model
386
+ * Holds the DESCRIPTION the relation tool advertises — a multi-line guide that teaches a small model
391
387
  * the operation list and the flat dot-path `include` syntax.
392
388
  *
393
389
  * @remarks
@@ -413,24 +409,24 @@ var RELATION_TOOL_DESCRIPTION = [
413
409
  include: ["contacts.account"]
414
410
  })
415
411
  ].join("\n");
416
- /** The default cap on rows a `find` / `links` call returns when the caller omits `limit` — the relation tool's default row ceiling. */
412
+ /** Holds the default cap on rows a `find` / `links` call returns when the caller omits `limit` — the relation tool's default row ceiling. */
417
413
  var RELATION_TOOL_LIMIT = 1e3;
418
- /** The default cap on how many `include` path segments deep a `load` / `find` call may traverse — the relation tool's default include-depth ceiling. */
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. */
419
415
  var RELATION_TOOL_DEPTH = 3;
420
416
  /**
421
- * The name {@link import('./factories.js').createInferTool} advertises by default — the key a
417
+ * Holds the name {@link import('./factories.js').createInferTool} advertises by default — the key a
422
418
  * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
423
419
  */
424
420
  var INFER_TOOL_NAME = "infer";
425
421
  /**
426
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createInferTool}
422
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createInferTool}
427
423
  * advertises in place of {@link INFER_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
428
424
  * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
429
- * for the full teaching description; the full text stays retrievable via
425
+ * for the full teaching description; the full text stays retrievable through
430
426
  * {@link import('./factories.js').createDescribeTool}.
431
427
  */
432
428
  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.";
433
- /** The schema-inference protocol {@link import('./factories.js').createInferTool} advertises. */
429
+ /** Holds the schema-inference protocol {@link import('./factories.js').createInferTool} advertises. */
434
430
  var INFER_TOOL_DESCRIPTION = [
435
431
  "Infer a JSON Schema from example values, returned in the same shape a tool advertises its parameters.",
436
432
  "",
@@ -443,7 +439,7 @@ var INFER_TOOL_DESCRIPTION = [
443
439
  " is wrapped as { parameters, checks } instead of the bare parameters record, one",
444
440
  " check per candidate (same index). Every check has the uniform shape",
445
441
  " { index, valid, coercible, faults? }. `valid` is a STRICT verdict (no coercion)",
446
- " — e.g. the number 7 is NOT valid against a string slot. `coercible` answers a",
442
+ " — for example the number 7 is NOT valid against a string slot. `coercible` answers a",
447
443
  " separate question: would the SAME value be accepted by an endpoint tool call,",
448
444
  " whose enforcement NORMALIZES args (7 coerces to '7')? So 7 against a string slot",
449
445
  " yields { valid: false, coercible: true, faults: [] } — a strict mismatch that",
@@ -523,7 +519,7 @@ var INFER_TOOL_DESCRIPTION = [
523
519
  //#endregion
524
520
  //#region src/core/errors.ts
525
521
  /**
526
- * A package-owned tool-call failure: malformed input or unresolved configuration (`TOOL`),
522
+ * Represents a package-owned tool-call failure: malformed input or unresolved configuration (`TOOL`),
527
523
  * delegation depth/cycle rejection (`DEPTH`), prompt failure (`DEADLOCK` / `EXPIRE` / `ANSWER`),
528
524
  * or a translated upstream database/relation failure (`DATABASE` / `RELATION`).
529
525
  *
@@ -555,10 +551,10 @@ var ToolboxError = class extends Error {
555
551
  }
556
552
  };
557
553
  /**
558
- * Type guard narrowing an unknown caught value to an {@link ToolboxError}.
554
+ * Narrows an unknown caught value to an {@link ToolboxError}.
559
555
  *
560
556
  * @param value - The value to test (typically a `catch` binding)
561
- * @returns `true` when `value` is an {@link ToolboxError}
557
+ * @returns True if `value` is an {@link ToolboxError}; false otherwise
562
558
  *
563
559
  * @example
564
560
  * ```ts
@@ -575,9 +571,102 @@ function isToolboxError(value) {
575
571
  return value instanceof ToolboxError;
576
572
  }
577
573
  //#endregion
574
+ //#region src/core/validators.ts
575
+ /**
576
+ * Narrows an unknown value to a valid alternating workflow lineage.
577
+ *
578
+ * @param value - The value to inspect
579
+ * @returns True if `value` is a unique, nonempty-tagged workflow/agent chain; false otherwise
580
+ */
581
+ function isWorkflowLineage(value) {
582
+ const inspected = attempt(() => {
583
+ if (!Array.isArray(value)) return false;
584
+ const seen = /* @__PURE__ */ new Set();
585
+ for (const [index, tag] of value.entries()) {
586
+ if (!isString(tag)) return false;
587
+ const prefix = index % 2 === 0 ? "workflow:" : "agent:";
588
+ if (!tag.startsWith(prefix) || tag.length === prefix.length || seen.has(tag)) return false;
589
+ seen.add(tag);
590
+ }
591
+ return true;
592
+ });
593
+ return inspected.success && inspected.value;
594
+ }
595
+ /**
596
+ * Narrows an unknown callable to Toolbox's frozen contextual agent adapter metadata.
597
+ *
598
+ * @param value - The value to inspect
599
+ * @returns True if it is a frozen {@link AgentFunction} with a frozen valid lineage; false otherwise
600
+ */
601
+ function isAgentFunction(value) {
602
+ const inspected = attempt(() => {
603
+ if (typeof value !== "function" || !Object.isFrozen(value)) return false;
604
+ const category = Reflect.getOwnPropertyDescriptor(value, "category");
605
+ const lineage = Reflect.getOwnPropertyDescriptor(value, "lineage");
606
+ return category?.value === "agent" && lineage !== void 0 && "value" in lineage && Object.isFrozen(lineage.value) && isWorkflowLineage(lineage.value);
607
+ });
608
+ return inspected.success && inspected.value;
609
+ }
610
+ /**
611
+ * Narrows an unknown value to a {@link ColumnSpec}.
612
+ *
613
+ * @param value - The value to inspect
614
+ * @returns True if `value` is a valid {@link ColumnPrimitive} shorthand or a `{ primitive, optional }` record with a valid `primitive`; false otherwise
615
+ */
616
+ function isColumnSpec(value) {
617
+ if (isColumnPrimitive(value)) return true;
618
+ if (!isRecord(value)) return false;
619
+ return isColumnPrimitive(value.primitive) && (value.optional === void 0 || typeof value.optional === "boolean");
620
+ }
621
+ /**
622
+ * Narrows an unknown value to a {@link ColumnPrimitive}.
623
+ *
624
+ * @param value - The value to inspect
625
+ * @returns True if `value` is `'string'`, `'integer'`, `'number'`, or `'boolean'`; false otherwise
626
+ */
627
+ function isColumnPrimitive(value) {
628
+ return value === "string" || value === "integer" || value === "number" || value === "boolean";
629
+ }
630
+ /**
631
+ * Narrows an unknown value to a {@link DatabaseDefinition} — a non-empty `id` + `driver`, a
632
+ * `tables` record whose every value is `{ columns: record of valid ColumnSpec }`, plus optional
633
+ * `primary`, `indexes`, and finite `version` schema configuration. The boundary guard a
634
+ * {@link import('./types.js').DefinitionStoreInterface} applies to an untrusted persisted blob
635
+ * before trusting it as a definition (never an `as`).
636
+ *
637
+ * @param value - The value to inspect
638
+ * @returns True if `value` is a complete {@link DatabaseDefinition}; false otherwise
639
+ */
640
+ function isDatabaseDefinition(value) {
641
+ if (!isRecord(value)) return false;
642
+ if ("keys" in value) return false;
643
+ if (!isNonEmptyString(value.id) || !isNonEmptyString(value.driver)) return false;
644
+ if (!isRecord(value.tables)) return false;
645
+ for (const table of Object.values(value.tables)) {
646
+ if (!isRecord(table) || !isRecord(table.columns)) return false;
647
+ for (const column of Object.values(table.columns)) if (!isColumnSpec(column)) return false;
648
+ }
649
+ if (value.primary !== void 0) {
650
+ if (!isRecord(value.primary)) return false;
651
+ for (const key of Object.values(value.primary)) if (!isNonEmptyString(key)) return false;
652
+ }
653
+ if (value.indexes !== void 0) {
654
+ if (!isRecord(value.indexes)) return false;
655
+ for (const groups of Object.values(value.indexes)) {
656
+ if (!Array.isArray(groups)) return false;
657
+ for (const group of groups) {
658
+ if (!Array.isArray(group) || group.length === 0) return false;
659
+ for (const column of group) if (!isNonEmptyString(column)) return false;
660
+ }
661
+ }
662
+ }
663
+ if (value.version !== void 0 && !isFiniteNumber(value.version)) return false;
664
+ return true;
665
+ }
666
+ //#endregion
578
667
  //#region src/core/shapers.ts
579
668
  /**
580
- * The shape of {@link import('./factories.js').createPromptTool}'s call arguments — `to` names the
669
+ * Describes the shape of {@link import('./factories.js').createPromptTool}'s call arguments — `to` names the
581
670
  * terminal identity and `schema` carries the complete multi-field form document.
582
671
  *
583
672
  * @remarks
@@ -592,7 +681,7 @@ var promptToolShape = objectShape({
592
681
  schema: jsonShape({ description: "The @orkestrel/form schema to ask, with form metadata and one or more typed fields." })
593
682
  });
594
683
  /**
595
- * The shape of {@link import('./factories.js').createAnswerTool}'s call arguments — discriminated
684
+ * Describes the shape of {@link import('./factories.js').createAnswerTool}'s call arguments — discriminated
596
685
  * by `operation`: `'pending'` lists the forms addressed to this tool's terminal, while `'answer'`
597
686
  * resolves one by `id` with a complete `values` record.
598
687
  *
@@ -600,7 +689,7 @@ var promptToolShape = objectShape({
600
689
  * `values` is first bounded to exact JSON. The handler then narrows it with the originating Form
601
690
  * package's `isFormValues` guard before the terminal manager applies it to the parked live form.
602
691
  */
603
- var answerToolShape = unionShape(objectShape({ operation: literalShape(["pending"], { description: "List the forms currently addressed to this terminal." }) }), objectShape({
692
+ var answerToolShape = unionShape(objectShape({ operation: literalShape(["pending"], { description: "List the forms addressed to this terminal." }) }), objectShape({
604
693
  operation: literalShape(["answer"], { description: "Answer one pending form by id." }),
605
694
  id: stringShape({
606
695
  min: 1,
@@ -609,7 +698,7 @@ var answerToolShape = unionShape(objectShape({ operation: literalShape(["pending
609
698
  values: jsonShape({ description: "The form answers keyed by field name." })
610
699
  }));
611
700
  /**
612
- * The shape of {@link import('./types.js').AgentToolArguments} —
701
+ * Describes the shape of {@link import('./types.js').AgentToolArguments} —
613
702
  * {@link import('./factories.js').createAgentTool}'s advertised `parameters`.
614
703
  *
615
704
  * @remarks
@@ -619,7 +708,7 @@ var answerToolShape = unionShape(objectShape({ operation: literalShape(["pending
619
708
  var agentToolShape = objectShape({
620
709
  task: stringShape({
621
710
  min: 1,
622
- description: "The instructions the sub-agent should carry out."
711
+ description: "The instructions the sub-agent carries out."
623
712
  }),
624
713
  provider: optionalShape(stringShape({
625
714
  min: 1,
@@ -629,7 +718,7 @@ var agentToolShape = objectShape({
629
718
  system: optionalShape(stringShape({ description: "A system prompt seeding the sub-agent's context (overrides the default)." }))
630
719
  });
631
720
  /**
632
- * The shape of {@link import('./types.js').DescribeToolArguments} —
721
+ * Describes the shape of {@link import('./types.js').DescribeToolArguments} —
633
722
  * {@link import('./factories.js').createDescribeTool}'s advertised `parameters`.
634
723
  *
635
724
  * @remarks
@@ -640,7 +729,7 @@ var describeToolShape = objectShape({ name: stringShape({
640
729
  description: "The registered name of the tool whose full description to return."
641
730
  }) });
642
731
  /**
643
- * The shape of a {@link import('./types.js').TaskDraft} — identical to a strict task shape
732
+ * Describes the shape of a {@link import('./types.js').TaskDraft} — identical to a strict task shape
644
733
  * EXCEPT `id` and `name` are OPTIONAL.
645
734
  */
646
735
  var taskDraftShape = objectShape({
@@ -653,7 +742,7 @@ var taskDraftShape = objectShape({
653
742
  description: "Task name; defaults to the id when omitted."
654
743
  })),
655
744
  description: optionalShape(stringShape({ description: "Optional task description." })),
656
- run: optionalShape(stringShape({
745
+ behavior: optionalShape(stringShape({
657
746
  min: 1,
658
747
  description: "The registered behavior name to invoke (a registry key, not a label); omitted completes with JSON null."
659
748
  })),
@@ -668,7 +757,7 @@ var taskDraftShape = objectShape({
668
757
  }))
669
758
  });
670
759
  /**
671
- * The shape of a PHASE in a draft workflow — identical to a strict phase shape EXCEPT `id` and
760
+ * Describes the shape of a PHASE in a draft workflow — identical to a strict phase shape EXCEPT `id` and
672
761
  * `name` are OPTIONAL, and its tasks are {@link taskDraftShape}s.
673
762
  */
674
763
  var phaseDraftShape = objectShape({
@@ -689,13 +778,13 @@ var phaseDraftShape = objectShape({
689
778
  bail: optionalShape(literalShape([true, false], { description: "Per-phase failure-policy override; omitted inherits the workflow bail." }))
690
779
  });
691
780
  /**
692
- * The shape of a DRAFT workflow — identical to a strict workflow shape EXCEPT `id` and `name`
781
+ * Describes the shape of a DRAFT workflow — identical to a strict workflow shape EXCEPT `id` and `name`
693
782
  * are OPTIONAL at all three levels (workflow / phase / task), so a small model can omit the six
694
783
  * identity strings and let the tool synthesize them positionally.
695
784
  *
696
785
  * @remarks
697
786
  * The lenient counterpart {@link import('./factories.js').createWorkflowDraftContract} compiles.
698
- * `run` stays optional like the strict form; omission is the deliberate JSON `null` no-op. A
787
+ * `behavior` stays optional like the strict form; omission is the deliberate JSON `null` no-op. A
699
788
  * provided `id` / `name` still has `minLength: 1` (so
700
789
  * an explicitly-empty `id: ''` is REJECTED, not auto-filled). After
701
790
  * {@link import('./helpers.js').completeDraft} fills the missing ids/names, the result is
@@ -716,18 +805,18 @@ var workflowDraftShape = objectShape({
716
805
  bail: optionalShape(literalShape([true, false], { description: "Failure policy: false (default) continues gracefully, true halts on the first failure." }))
717
806
  });
718
807
  /**
719
- * The shape of ONE flat step — `{ name }` — the building block of {@link workflowStepsShape}.
808
+ * Describes the shape of ONE flat step — `{ name }` — the building block of {@link workflowStepsShape}.
720
809
  *
721
810
  * @remarks
722
- * `name` is the REGISTERED behavior name the step runs (it becomes the task's `run`). The tool
811
+ * `name` is the REGISTERED behavior name the step runs (it becomes the task's `behavior`). The tool
723
812
  * expands each step into a one-task phase, in order ({@link import('./helpers.js').expandSteps}).
724
813
  */
725
814
  var stepShape = objectShape({ name: stringShape({
726
815
  min: 1,
727
- description: "The registered behavior name this step runs (becomes the task run)."
816
+ description: "The registered behavior name this step runs (becomes the task behavior)."
728
817
  }) });
729
818
  /**
730
- * The FLAT authoring shape {@link import('./factories.js').createWorkflowTool} advertises as its
819
+ * Describes the FLAT authoring shape {@link import('./factories.js').createWorkflowTool} advertises as its
731
820
  * `parameters` — the simplest surface a small model can fill: `{ name?, steps: [{ name }] }`.
732
821
  *
733
822
  * @remarks
@@ -747,10 +836,10 @@ var workflowStepsShape = objectShape({
747
836
  steps: arrayShape(stepShape, { description: "The ordered steps to run, one after another (each becomes a one-task phase)." })
748
837
  });
749
838
  /**
750
- * The shape of a {@link import('./types.js').WorkspaceOperation} — a descriptive tagged union
751
- * over the 13 workspace edit / read / navigation operations, discriminated by the `operation`
752
- * literal (never a bare `kind`; AGENTS §4.4). Each variant leads with its `operation`
753
- * discriminant then its FLAT fields, every field via `stringShape` / `optionalShape` /
839
+ * Describes the shape of a {@link import('./types.js').WorkspaceOperation} — a descriptive tagged union
840
+ * over the workspace edit, read, and navigation operations, discriminated by the `operation`
841
+ * literal (never a bare `kind`). Each variant leads with its `operation`
842
+ * discriminant then its FLAT fields, every field through `stringShape` / `optionalShape` /
754
843
  * `integerShape({ min: 1 })` / `booleanShape`, each carrying a strong field-level `description`.
755
844
  *
756
845
  * @remarks
@@ -830,27 +919,27 @@ var workspaceToolShape = unionShape(objectShape({
830
919
  operation: literalShape(["switch"], { description: "Switch the active workspace to the one with this id (get ids from the \"workspaces\" operation). Edit and read operations then target it." }),
831
920
  id: stringShape({ description: "The id of the workspace to make active (from the \"workspaces\" listing)." })
832
921
  }));
833
- /** A {@link import('./types.js').ColumnKind} literal — the leaf {@link columnSpecShape} wraps. */
834
- var columnKindShape = literalShape([
922
+ /** Describes a {@link import('./types.js').ColumnPrimitive} literal — the leaf {@link columnSpecShape} wraps. */
923
+ var columnPrimitiveShape = literalShape([
835
924
  "string",
836
925
  "integer",
837
926
  "number",
838
927
  "boolean"
839
- ], { description: "A column type: \"string\" | \"integer\" | \"number\" | \"boolean\"." });
840
- /** A {@link import('./types.js').ColumnSpec} — a bare {@link columnKindShape}, or `{ type, optional }`. */
841
- var columnSpecShape = unionShape(columnKindShape, objectShape({
842
- type: columnKindShape,
928
+ ], { description: "A column primitive: \"string\" | \"integer\" | \"number\" | \"boolean\"." });
929
+ /** Describes a {@link import('./types.js').ColumnSpec} — a bare {@link columnPrimitiveShape}, or `{ primitive, optional }`. */
930
+ var columnSpecShape = unionShape(columnPrimitiveShape, objectShape({
931
+ primitive: columnPrimitiveShape,
843
932
  optional: optionalShape(booleanShape({ description: "Whether the column may be absent from a row." }))
844
933
  }));
845
- /** A {@link import('./types.js').TableSpec} — table name to `{ columns }`, each column a {@link columnSpecShape}. */
846
- var tableSpecShape = recordShape(objectShape({ columns: recordShape(columnSpecShape, { description: "Column name to its type." }) }), { description: "Table name to its column layout." });
847
- /** One key value — a string or number; the array form (multiple keys, positional) resolves FIRST per AGENTS §9.2. */
934
+ /** Describes a {@link import('./types.js').TableSpec} — table name to `{ columns }`, each column a {@link columnSpecShape}. */
935
+ 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. */
848
937
  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." }));
849
- /** A loose row — a flat object of column name to JSON value; the array form (multiple rows) resolves FIRST per AGENTS §9.2. */
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. */
850
939
  var rowShape = recordShape(jsonShape(), { description: "A row as a flat object of column name to value." });
851
- /** One or many loose rows — the array form resolves FIRST per AGENTS §9.2. */
940
+ /** Describes one or many loose rows — the array form resolves FIRST, so an array argument is read as many rows rather than one. */
852
941
  var rowsShape = unionShape(arrayShape(rowShape, { description: "Multiple rows." }), rowShape);
853
- /** One SERIALIZED WHERE condition — `values` is ALWAYS an array, even for a single-value operator. */
942
+ /** Describes one SERIALIZED WHERE condition — `values` is ALWAYS an array, even for a single-value operator. */
854
943
  var conditionShape = objectShape({
855
944
  column: stringShape({ description: "The column this condition applies to." }),
856
945
  operator: literalShape([
@@ -873,12 +962,12 @@ var conditionShape = objectShape({
873
962
  values: arrayShape(jsonShape(), { description: "The operand values the operator needs (always an array, even for one value)." }),
874
963
  connector: optionalShape(literalShape(["and", "or"], { description: "Joins this condition to the next; omit on the last condition." }))
875
964
  });
876
- /** One sort term. */
965
+ /** Describes one sort term. */
877
966
  var orderShape = objectShape({
878
967
  column: stringShape({ description: "The column to sort by." }),
879
968
  direction: literalShape(["ascending", "descending"], { description: "The sort direction." })
880
969
  });
881
- /** The SERIALIZED query form — conditions, order, and pagination. */
970
+ /** Describes the SERIALIZED query form — conditions, order, and pagination. */
882
971
  var queryShape = objectShape({
883
972
  conditions: optionalShape(arrayShape(conditionShape, { description: "The WHERE conditions, folded left to right." })),
884
973
  order: optionalShape(arrayShape(orderShape, { description: "The sort terms, applied in order." })),
@@ -892,15 +981,15 @@ var queryShape = objectShape({
892
981
  }))
893
982
  });
894
983
  /**
895
- * The shape of {@link import('./factories.js').createDatabaseTool}'s call arguments —
984
+ * Describes the shape of {@link import('./factories.js').createDatabaseTool}'s call arguments —
896
985
  * discriminated by `operation` into the 11 database operations (`'create'` / `'tables'` /
897
986
  * `'get'` / `'records'` / `'count'` / `'aggregate'` / `'add'` / `'set'` / `'update'` /
898
987
  * `'remove'` / `'destroy'`).
899
988
  *
900
989
  * @remarks
901
990
  * Every arm carries `id` (the database id). `'create'` carries `tables` (the
902
- * {@link import('./types.js').TableSpec} column DSL, compiled via
903
- * {@link import('./helpers.js').expandTables}); `'get'` / `'update'` / `'remove'` carry `key`
991
+ * {@link import('./types.js').TableSpec} column DSL, compiled through
992
+ * {@link import('./compilers.js').expandTables}); `'get'` / `'update'` / `'remove'` carry `key`
904
993
  * (one key or an array of keys, positional); `'add'` / `'set'` carry `row` (one row or an array of
905
994
  * rows); `'update'` also carries `changes` (a loose partial row); `'records'` / `'count'` /
906
995
  * `'aggregate'` carry an optional `query` (the SERIALIZED form — `values` is ALWAYS an array,
@@ -1036,19 +1125,17 @@ var databaseToolShape = unionShape(objectShape({
1036
1125
  description: "The database id."
1037
1126
  })
1038
1127
  }));
1039
- /** One key value — a string or number; the array form (multiple keys, positional) resolves FIRST per AGENTS §9.2. */
1040
- var relationKeyShape = 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." }));
1041
- /** A single row key (not an array) — used by `'link'` / `'unlink'` / `'links'`, which address exactly one owning row. */
1128
+ /** Describes a single row key (not an array) — used by `'link'` / `'unlink'` / `'links'`, which address exactly one owning row. */
1042
1129
  var singleKeyShape = unionShape(stringShape({ description: "The owning row key." }), numberShape({ description: "The owning row key." }));
1043
- /** Flat dot-path relation include list, expanded via {@link import('./helpers.js').expandInclude}. */
1044
- var includeShape = optionalShape(arrayShape(stringShape({ description: "A dot-separated chain of relation names, e.g. \"contacts.account\"." }), { description: "Which relations to attach, as flat dot-paths." }));
1045
- /** Which registered relation manager to address — omitted resolves to the sole registered manager. */
1130
+ /** Describes the flat dot-path relation include list, expanded through {@link import('./helpers.js').expandInclude}. */
1131
+ var includeShape = optionalShape(arrayShape(stringShape({ description: "A dot-separated chain of relation names, for example \"contacts.account\"." }), { description: "Which relations to attach, as flat dot-paths." }));
1132
+ /** Describes which registered relation manager to address — omitted resolves to the sole registered manager. */
1046
1133
  var managerShape = optionalShape(stringShape({
1047
1134
  min: 1,
1048
1135
  description: "Which registered relation manager to address."
1049
1136
  }));
1050
1137
  /**
1051
- * The shape of {@link import('./factories.js').createRelationTool}'s call arguments —
1138
+ * Describes the shape of {@link import('./factories.js').createRelationTool}'s call arguments —
1052
1139
  * discriminated by `operation` into the 5 relation operations (`'load'` / `'find'` / `'link'` /
1053
1140
  * `'unlink'` / `'links'`).
1054
1141
  *
@@ -1064,7 +1151,7 @@ var relationToolShape = unionShape(objectShape({
1064
1151
  min: 1,
1065
1152
  description: "The model (table) name."
1066
1153
  }),
1067
- key: relationKeyShape,
1154
+ key: keyShape,
1068
1155
  include: includeShape
1069
1156
  }), objectShape({
1070
1157
  operation: literalShape(["find"], { description: "List rows, with related rows attached." }),
@@ -1127,7 +1214,7 @@ var relationToolShape = unionShape(objectShape({
1127
1214
  })
1128
1215
  }));
1129
1216
  /**
1130
- * The shape of {@link import('./factories.js').createInferTool}'s call arguments — one or more
1217
+ * Describes the shape of {@link import('./factories.js').createInferTool}'s call arguments — one or more
1131
1218
  * example `samples` to infer a JSON Schema from, plus per-call `format` / `enum` toggles and an
1132
1219
  * optional `candidates` array to check against the inferred schema.
1133
1220
  *
@@ -1151,24 +1238,24 @@ var inferToolShape = objectShape({
1151
1238
  //#endregion
1152
1239
  //#region src/core/helpers.ts
1153
1240
  /**
1154
- * The ancestry identifier of a workflow in a run chain — `workflow:<id>`.
1241
+ * Returns the ancestry identifier of a workflow in a run chain — `workflow:<id>`.
1155
1242
  *
1156
1243
  * @remarks
1157
- * Namespacing keeps a workflow id and an {@link agentTag} agent name in ONE set without
1244
+ * Namespacing keeps a workflow id and a {@link tagAgent} agent name in ONE set without
1158
1245
  * collision, so re-entering a workflow OR an agent already in the chain is a single `includes`
1159
1246
  * check.
1160
1247
  *
1161
1248
  * @param id - The workflow definition's `id`
1162
1249
  * @returns The namespaced ancestry tag (`workflow:<id>`)
1163
1250
  */
1164
- function workflowTag(id) {
1251
+ function tagWorkflow(id) {
1165
1252
  return `workflow:${id}`;
1166
1253
  }
1167
1254
  /**
1168
- * The ancestry identifier of an agent in a run chain — `agent:<name>`.
1255
+ * Returns the ancestry identifier of an agent in a run chain — `agent:<name>`.
1169
1256
  *
1170
1257
  * @remarks
1171
- * The agent counterpart of {@link workflowTag}: {@link import('./factories.js').createAgentFunction}
1258
+ * The agent counterpart of {@link tagWorkflow}: {@link import('./factories.js').createAgentFunction}
1172
1259
  * / {@link import('./factories.js').createWorkflowTool} guard against re-entering an agent or
1173
1260
  * workflow already in the chain (this package's typed `DEPTH` `ToolboxError`). The
1174
1261
  * `agent:` namespace keeps it distinct from a same-string workflow id.
@@ -1176,78 +1263,43 @@ function workflowTag(id) {
1176
1263
  * @param name - The agent's identifier / registry name
1177
1264
  * @returns The namespaced ancestry tag (`agent:<name>`)
1178
1265
  */
1179
- function agentTag(name) {
1266
+ function tagAgent(name) {
1180
1267
  return `agent:${name}`;
1181
1268
  }
1182
1269
  /**
1183
- * Narrow an unknown value to a valid alternating workflow lineage.
1184
- *
1185
- * @param value - The value to inspect
1186
- * @returns Whether `value` is a unique, nonempty-tagged workflow/agent chain
1187
- */
1188
- function isWorkflowLineage(value) {
1189
- const inspected = attempt(() => {
1190
- if (!Array.isArray(value)) return false;
1191
- const seen = /* @__PURE__ */ new Set();
1192
- for (const [index, tag] of value.entries()) {
1193
- if (!isString(tag)) return false;
1194
- const prefix = index % 2 === 0 ? "workflow:" : "agent:";
1195
- if (!tag.startsWith(prefix) || tag.length === prefix.length || seen.has(tag)) return false;
1196
- seen.add(tag);
1197
- }
1198
- return true;
1199
- });
1200
- return inspected.success && inspected.value;
1201
- }
1202
- /**
1203
- * Build a validated, copied, and frozen workflow lineage value.
1270
+ * Returns the canonical workflow lineage — validated, copied, and frozen.
1204
1271
  *
1205
1272
  * @param lineage - The configured chain; omitted means a direct root
1206
1273
  * @returns An immutable caller-isolated lineage
1207
1274
  */
1208
- function lineageOf(lineage = []) {
1275
+ function normalizeLineage(lineage = []) {
1209
1276
  if (!isWorkflowLineage(lineage)) throw new ToolboxError("TOOL", "workflow lineage must alternate unique workflow and agent tags");
1210
1277
  return Object.freeze([...lineage]);
1211
1278
  }
1212
1279
  /**
1213
- * Append one tag to a workflow lineage and return a frozen copy.
1280
+ * Appends one tag to a workflow lineage and returns a frozen copy.
1214
1281
  *
1215
1282
  * @param lineage - The valid chain to extend
1216
1283
  * @param tag - The workflow or agent tag to append
1217
1284
  * @returns The validated immutable extension
1218
1285
  */
1219
1286
  function extendLineage(lineage, tag) {
1220
- return lineageOf([...lineage, tag]);
1287
+ return normalizeLineage([...lineage, tag]);
1221
1288
  }
1222
1289
  /**
1223
- * Derive the zero-based workflow nesting depth from a valid lineage.
1290
+ * Derives the zero-based workflow nesting depth from a valid lineage.
1224
1291
  *
1225
1292
  * @param lineage - The workflow/agent chain
1226
1293
  * @returns Zero for an empty/root lineage, then one per nested workflow
1227
1294
  */
1228
1295
  function deriveWorkflowDepth(lineage) {
1229
- const workflows = lineageOf(lineage).filter((tag) => tag.startsWith("workflow:")).length;
1296
+ const workflows = normalizeLineage(lineage).filter((tag) => tag.startsWith("workflow:")).length;
1230
1297
  return Math.max(0, workflows - 1);
1231
1298
  }
1232
1299
  /**
1233
- * Narrow an unknown callable to Toolbox's frozen contextual agent adapter metadata.
1234
- *
1235
- * @param value - The value to inspect
1236
- * @returns Whether it is a frozen {@link AgentFunction} with a frozen valid lineage
1237
- */
1238
- function isAgentFunction(value) {
1239
- const inspected = attempt(() => {
1240
- if (typeof value !== "function" || !Object.isFrozen(value)) return false;
1241
- const category = Reflect.getOwnPropertyDescriptor(value, "category");
1242
- const lineage = Reflect.getOwnPropertyDescriptor(value, "lineage");
1243
- return category?.value === "agent" && lineage !== void 0 && "value" in lineage && Object.isFrozen(lineage.value) && isWorkflowLineage(lineage.value);
1244
- });
1245
- return inspected.success && inspected.value;
1246
- }
1247
- /**
1248
- * Build the plain success summary {@link import('./factories.js').createWorkflowTool} returns on
1249
- * a completed run — the universal tool-handler contract (AGENTS §14): return a plain value on
1250
- * success, appearing identically over BOTH the agent loop and MCP.
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.
1251
1303
  *
1252
1304
  * @remarks
1253
1305
  * The summary is LEAN: the workflow's terminal `status`, settled-task count, and exact optional
@@ -1257,7 +1309,7 @@ function isAgentFunction(value) {
1257
1309
  * @param result - The terminal `WorkflowResult` (`@orkestrel/workflow`) the run produced
1258
1310
  * @returns The plain success summary — `{ status, count, durable?, fault? }`
1259
1311
  */
1260
- function workflowToolSummary(result) {
1312
+ function summarizeWorkflow(result) {
1261
1313
  return {
1262
1314
  status: result.status,
1263
1315
  count: result.results.length,
@@ -1266,8 +1318,8 @@ function workflowToolSummary(result) {
1266
1318
  };
1267
1319
  }
1268
1320
  /**
1269
- * Complete a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesize any
1270
- * MISSING `id` deterministically + positionally, and default any MISSING `name` to its
1321
+ * Completes a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesizes any
1322
+ * MISSING `id` deterministically + positionally, and defaults any MISSING `name` to its
1271
1323
  * (now-resolved) `id`.
1272
1324
  *
1273
1325
  * @remarks
@@ -1275,7 +1327,7 @@ function workflowToolSummary(result) {
1275
1327
  * `phase-<i>`, and task `j` of that phase is `<phaseId>-task-<j>` (so a provided phase id flows
1276
1328
  * into its tasks' synthesized ids). A PROVIDED `id` / `name` at any level is kept VERBATIM —
1277
1329
  * synthesis touches only the omitted ones. A missing `name` defaults to the resolved `id` (never
1278
- * the other way round), so the result always has both. `run`, `description`, the per-phase
1330
+ * the other way round), so the result always has both. `behavior`, `description`, the per-phase
1279
1331
  * `concurrency` / `bail`, the per-task `retries` / `timeout`, and the workflow `bail` carry over
1280
1332
  * unchanged. The result is a complete {@link WorkflowDefinition}; the caller still validates it
1281
1333
  * against the STRICT contract.
@@ -1294,7 +1346,7 @@ function completeDraft(draft) {
1294
1346
  };
1295
1347
  }
1296
1348
  /**
1297
- * Complete one {@link PhaseDraft} into a strict phase definition — the per-phase step of
1349
+ * Completes one {@link PhaseDraft} into a strict phase definition — the per-phase step of
1298
1350
  * {@link completeDraft} (phase `index` → `phase-<index>` when its id is omitted).
1299
1351
  *
1300
1352
  * @param phase - The draft phase
@@ -1313,7 +1365,7 @@ function completePhaseDraft(phase, index) {
1313
1365
  };
1314
1366
  }
1315
1367
  /**
1316
- * Complete one {@link TaskDraft} into a strict task definition — the per-task leaf step of
1368
+ * Completes one {@link TaskDraft} into a strict task definition — the per-task leaf step of
1317
1369
  * {@link completeDraft} (task `index` of phase `<phaseId>` → `<phaseId>-task-<index>` when its id
1318
1370
  * is omitted).
1319
1371
  *
@@ -1328,19 +1380,19 @@ function completeTaskDraft(task, phaseId, index) {
1328
1380
  id,
1329
1381
  name: task.name ?? id,
1330
1382
  ...task.description === void 0 ? {} : { description: task.description },
1331
- ...task.run === void 0 ? {} : { run: task.run },
1383
+ ...task.behavior === void 0 ? {} : { behavior: task.behavior },
1332
1384
  ...task.retries === void 0 ? {} : { retries: task.retries },
1333
1385
  ...task.timeout === void 0 ? {} : { timeout: task.timeout }
1334
1386
  };
1335
1387
  }
1336
1388
  /**
1337
- * Expand a flat {@link WorkflowSteps} blob into a strict {@link WorkflowDefinition} — each step
1389
+ * Expands a flat {@link WorkflowSteps} blob into a strict {@link WorkflowDefinition} — each step
1338
1390
  * becomes a one-task phase, IN ORDER.
1339
1391
  *
1340
1392
  * @remarks
1341
1393
  * The expansion of the tool's ADVERTISED surface: the deliberately-reduced flat form. Each
1342
1394
  * {@link import('./types.js').WorkflowStep} maps to a phase holding exactly one task: the step's
1343
- * `name` becomes the task's `run` (the behavior-registry key). Ids/names are auto-filled
1395
+ * `name` becomes the task's `behavior` (the behavior-registry key). Ids/names are auto-filled
1344
1396
  * positionally — it builds an ids-omitted {@link WorkflowDraft} and delegates to
1345
1397
  * {@link completeDraft}, so the two lenient surfaces share ONE synthesis path (step `i` → phase
1346
1398
  * `phase-<i>`, its task `phase-<i>-task-0`). The optional `name` becomes both the workflow's
@@ -1357,12 +1409,12 @@ function expandSteps(flat) {
1357
1409
  id: flat.name,
1358
1410
  name: flat.name
1359
1411
  },
1360
- phases: flat.steps.map((step) => ({ tasks: [{ run: step.name }] }))
1412
+ phases: flat.steps.map((step) => ({ tasks: [{ behavior: step.name }] }))
1361
1413
  });
1362
1414
  }
1363
1415
  /**
1364
- * Map a caught error to the {@link ToolboxErrorCode} the terminal-tool factory should throw
1365
- * with — the pure classification step of that factory's error handling.
1416
+ * Maps a caught error to the {@link ToolboxErrorCode} the terminal-tool factory throws with — the
1417
+ * pure classification step of that factory's error handling.
1366
1418
  *
1367
1419
  * @remarks
1368
1420
  * Narrows `error` with {@link isTerminalError} (`@orkestrel/terminal`) first: a non-`TerminalError`
@@ -1375,111 +1427,38 @@ function expandSteps(flat) {
1375
1427
  * @param error - The value caught from a terminal-manager operation (`ask` / `answer` / …)
1376
1428
  * @returns The mapped {@link ToolboxErrorCode}, or `undefined` if `error` is not a `TerminalError`
1377
1429
  */
1378
- function terminalToolCode(error) {
1430
+ function inferTerminalCode(error) {
1379
1431
  if (!isTerminalError(error)) return void 0;
1380
1432
  if (error.code === "DEADLOCK") return "DEADLOCK";
1381
1433
  if (error.code === "EXPIRE") return "EXPIRE";
1382
1434
  return "TOOL";
1383
1435
  }
1384
- /** Narrow an unknown value to a {@link ColumnSpec} — a valid {@link import('./types.js').ColumnKind} shorthand, or `{ type, optional }` with a valid `type`. */
1385
- function isColumnSpec(value) {
1386
- if (isColumnKind(value)) return true;
1387
- if (!isRecord(value)) return false;
1388
- return isColumnKind(value.type) && (value.optional === void 0 || typeof value.optional === "boolean");
1389
- }
1390
- /** Narrow an unknown value to a {@link import('./types.js').ColumnKind}. */
1391
- function isColumnKind(value) {
1392
- return value === "string" || value === "integer" || value === "number" || value === "boolean";
1393
- }
1394
- /**
1395
- * Compile a {@link TableSpec} into the `@orkestrel/database` {@link TableMap} it configures —
1396
- * each {@link ColumnSpec} maps to the matching primitive shaper (`'string'` → `stringShape()`,
1397
- * `'integer'` → `integerShape()`, `'number'` → `numberShape()`, `'boolean'` → `booleanShape()`),
1398
- * wrapped in `optionalShape` when the column declares `optional: true`. Total, pure.
1399
- *
1400
- * @param spec - The small-model-facing table layout
1401
- * @returns The compiled `TableMap` a `@orkestrel/database` `createDatabase` call accepts
1402
- */
1403
- function expandTables(spec) {
1404
- const tables = {};
1405
- for (const [table, definition] of Object.entries(spec)) {
1406
- const columns = {};
1407
- for (const [column, kind] of Object.entries(definition.columns)) columns[column] = columnShape(kind);
1408
- tables[table] = columns;
1409
- }
1410
- return tables;
1411
- }
1412
- /** Compile one {@link ColumnSpec} into its `@orkestrel/database` column shape — the per-column leaf {@link expandTables} maps over. */
1413
- function columnShape(spec) {
1414
- const kind = isString(spec) ? spec : spec.type;
1415
- const optional = !isString(spec) && spec.optional === true;
1416
- const shape = kindShape(kind);
1417
- return optional ? optionalShape(shape) : shape;
1418
- }
1419
- /** Map one {@link import('./types.js').ColumnKind} to its primitive `@orkestrel/database` shape — the leaf {@link columnShape} wraps. */
1420
- function kindShape(kind) {
1421
- if (kind === "string") return stringShape();
1422
- if (kind === "integer") return integerShape();
1423
- if (kind === "number") return numberShape();
1424
- return booleanShape();
1425
- }
1426
- /**
1427
- * Narrow an unknown value to a {@link DatabaseDefinition} — a non-empty `id` + `driver`, a
1428
- * `tables` record whose every value is `{ columns: record of valid ColumnSpec }`, plus optional
1429
- * `primary`, `indexes`, and finite `version` schema configuration. The boundary guard a
1430
- * {@link import('./types.js').DefinitionStoreInterface} applies to an untrusted persisted blob
1431
- * before trusting it as a definition (never an `as`).
1432
- */
1433
- function isDatabaseDefinition(value) {
1434
- if (!isRecord(value)) return false;
1435
- if ("keys" in value) return false;
1436
- if (!isNonEmptyString(value.id) || !isNonEmptyString(value.driver)) return false;
1437
- if (!isRecord(value.tables)) return false;
1438
- for (const table of Object.values(value.tables)) {
1439
- if (!isRecord(table) || !isRecord(table.columns)) return false;
1440
- for (const column of Object.values(table.columns)) if (!isColumnSpec(column)) return false;
1441
- }
1442
- if (value.primary !== void 0) {
1443
- if (!isRecord(value.primary)) return false;
1444
- for (const key of Object.values(value.primary)) if (!isNonEmptyString(key)) return false;
1445
- }
1446
- if (value.indexes !== void 0) {
1447
- if (!isRecord(value.indexes)) return false;
1448
- for (const groups of Object.values(value.indexes)) {
1449
- if (!Array.isArray(groups)) return false;
1450
- for (const group of groups) {
1451
- if (!Array.isArray(group) || group.length === 0) return false;
1452
- for (const column of group) if (!isNonEmptyString(column)) return false;
1453
- }
1454
- }
1455
- }
1456
- if (value.version !== void 0 && !isFiniteNumber(value.version)) return false;
1457
- return true;
1458
- }
1459
1436
  /**
1460
- * Map a caught error to the {@link ToolboxErrorCode} the upcoming database tool should throw
1461
- * with — the pure classification step of that factory's error handling, mirroring
1462
- * {@link terminalToolCode}'s idiom for `@orkestrel/database`.
1437
+ * Maps a caught error to the granular {@link DatabaseErrorCode} (`@orkestrel/database`) the code
1438
+ * {@link import('./factories.js').createDatabaseTool} throws with — the pure classification step
1439
+ * of that factory's error handling, mirroring {@link inferTerminalCode}'s idiom for
1440
+ * `@orkestrel/database`.
1463
1441
  *
1464
1442
  * @param error - The value caught from a `@orkestrel/database` table operation
1465
1443
  * @returns The granular {@link DatabaseErrorCode}, or `undefined` if `error` is not a `DatabaseError`
1466
1444
  */
1467
- function databaseToolCode(error) {
1445
+ function inferDatabaseCode(error) {
1468
1446
  return isDatabaseError(error) ? error.code : void 0;
1469
1447
  }
1470
1448
  /**
1471
- * Map a caught error to the {@link ToolboxErrorCode} the upcoming relation tool should throw
1472
- * with — the pure classification step of that factory's error handling, mirroring
1473
- * {@link terminalToolCode}'s idiom for `@orkestrel/relation`.
1449
+ * Maps a caught error to the granular {@link RelationErrorCode} (`@orkestrel/relation`) the code
1450
+ * {@link import('./factories.js').createRelationTool} throws with — the pure classification step
1451
+ * of that factory's error handling, mirroring {@link inferTerminalCode}'s idiom for
1452
+ * `@orkestrel/relation`.
1474
1453
  *
1475
1454
  * @param error - The value caught from a `@orkestrel/relation` operation
1476
1455
  * @returns The granular {@link RelationErrorCode}, or `undefined` if `error` is not a `RelationError`
1477
1456
  */
1478
- function relationToolCode(error) {
1457
+ function inferRelationCode(error) {
1479
1458
  return isRelationError(error) ? error.code : void 0;
1480
1459
  }
1481
1460
  /**
1482
- * Expand the relation tool's FLAT dot-path `include` list into a live `@orkestrel/relation`
1461
+ * Expands the relation tool's FLAT dot-path `include` list into a live `@orkestrel/relation`
1483
1462
  * {@link Include} tree — the pure leaf {@link import('./factories.js').createRelationTool} calls
1484
1463
  * before a `'load'` / `'find'` call.
1485
1464
  *
@@ -1550,7 +1529,7 @@ function expandInclude(paths, depth) {
1550
1529
  return include;
1551
1530
  }
1552
1531
  /**
1553
- * Resolve which registered {@link RelationManagerInterface} a relation-tool call addresses — the
1532
+ * Resolves which registered {@link RelationManagerInterface} a relation-tool call addresses — the
1554
1533
  * pure manager-resolution leaf {@link import('./factories.js').createRelationTool} calls on
1555
1534
  * every operation.
1556
1535
  *
@@ -1563,7 +1542,7 @@ function expandInclude(paths, depth) {
1563
1542
  * @param name - The call's optional `manager` field
1564
1543
  * @returns The resolved {@link RelationManagerInterface}
1565
1544
  */
1566
- function relationManagerOf(managers, name) {
1545
+ function resolveRelationManager(managers, name) {
1567
1546
  if (name !== void 0) {
1568
1547
  const manager = managers[name];
1569
1548
  if (manager === void 0) throw new ToolboxError("TOOL", `unknown relation manager '${name}'`, {
@@ -1581,24 +1560,24 @@ function relationManagerOf(managers, name) {
1581
1560
  throw new ToolboxError("TOOL", "no relation manager resolved for the call", { managers: names });
1582
1561
  }
1583
1562
  /**
1584
- * Resolve a `model` name against a live {@link RelationManagerInterface} — the pure model-lookup
1563
+ * Resolves a `model` name against a live {@link RelationManagerInterface} — the pure model-lookup
1585
1564
  * leaf {@link import('./factories.js').createRelationTool} calls on every operation, mirroring
1586
- * {@link relationManagerOf}'s guard shape.
1565
+ * {@link resolveRelationManager}'s guard shape.
1587
1566
  *
1588
1567
  * @param manager - The resolved {@link RelationManagerInterface}
1589
1568
  * @param name - The call's `model` field
1590
1569
  * @returns The model's {@link ModelInterface}
1591
1570
  */
1592
- function relationModelOf(manager, name) {
1571
+ function resolveRelationModel(manager, name) {
1593
1572
  if (!manager.has(name)) throw new ToolboxError("TOOL", `unknown model '${name}'`, {
1594
1573
  model: name,
1595
- models: manager.models()
1574
+ models: manager.names()
1596
1575
  });
1597
1576
  return manager.model(name);
1598
1577
  }
1599
1578
  /**
1600
- * Normalize the database tool's parsed SERIALIZED query into a live `@orkestrel/database`
1601
- * {@link QueryInput} — default each condition's OMITTED `connector` to `'and'`.
1579
+ * 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'`.
1602
1581
  *
1603
1582
  * @remarks
1604
1583
  * The wire form ({@link import('./shapers.js').databaseToolShape}) lets a caller drop `connector`
@@ -1609,7 +1588,7 @@ function relationModelOf(manager, name) {
1609
1588
  * @param query - The parsed query (or `undefined`)
1610
1589
  * @returns The equivalent live `QueryInput`, or `undefined` when `query` is `undefined`
1611
1590
  */
1612
- function queryOf(query) {
1591
+ function normalizeQuery(query) {
1613
1592
  if (query === void 0) return void 0;
1614
1593
  const conditions = query.conditions?.map((condition) => ({
1615
1594
  ...condition,
@@ -1623,13 +1602,38 @@ function queryOf(query) {
1623
1602
  };
1624
1603
  }
1625
1604
  /**
1626
- * Clamp a `'records'` call's query to a row cap, and build the PROBE query the caller reads
1605
+ * Picks the effective row limit a tool reads with — the requested count when it sits inside the
1606
+ * cap, the cap when it exceeds it, and `0` when either falls below zero.
1607
+ *
1608
+ * @remarks
1609
+ * The one place the database tool's `'records'` clamp ({@link clampQuery}) and the relation tool's
1610
+ * `'find'` / `'links'` truncation both take their ceiling from, so a negative construction-time
1611
+ * option can never reach a slice. Pure and total.
1612
+ *
1613
+ * @example
1614
+ * ```ts
1615
+ * import { resolveLimit } from '@src/core'
1616
+ *
1617
+ * resolveLimit(undefined, 100) // 100 — an omitted request takes the cap
1618
+ * resolveLimit(500, 100) // 100 — a request over the cap is clamped down
1619
+ * resolveLimit(-1, 100) // 0 — a negative request floors at zero
1620
+ * ```
1621
+ *
1622
+ * @param requested - The caller's requested row count (or `undefined`)
1623
+ * @param cap - The row-count ceiling
1624
+ * @returns The effective row limit, never below `0` and never above `cap`
1625
+ */
1626
+ function resolveLimit(requested, cap) {
1627
+ return Math.max(0, Math.min(requested ?? cap, cap));
1628
+ }
1629
+ /**
1630
+ * Clamps a `'records'` call's query to a row cap, and builds the PROBE query the caller reads
1627
1631
  * with — the pure leaf {@link import('./factories.js').createDatabaseTool}'s `'records'` operation
1628
1632
  * uses to detect truncation without a separate `count` round trip.
1629
1633
  *
1630
1634
  * @remarks
1631
- * The effective limit is `min(query?.limit ?? cap, cap)`, floored at `0` (so a caller can never
1632
- * exceed the configured cap by supplying a larger `query.limit`). The returned probe query
1635
+ * {@link resolveLimit} picks the effective limit, so a caller can never exceed the configured cap
1636
+ * by supplying a larger `query.limit`, and can never drive it below `0`. The returned probe query
1633
1637
  * requests ONE MORE row than the effective limit (`limit: effective + 1`) — if storage returns
1634
1638
  * that many, the caller knows the true result was truncated (`rows.length > effective`) and slices
1635
1639
  * back down to `effective` before returning.
@@ -1649,7 +1653,7 @@ function queryOf(query) {
1649
1653
  * @returns The PROBE query (`limit` bumped by one) and the effective `limit`
1650
1654
  */
1651
1655
  function clampQuery(query, cap) {
1652
- const limit = Math.max(0, Math.min(query?.limit ?? cap, cap));
1656
+ const limit = resolveLimit(query?.limit, cap);
1653
1657
  return {
1654
1658
  query: {
1655
1659
  ...query,
@@ -1659,15 +1663,64 @@ function clampQuery(query, cap) {
1659
1663
  };
1660
1664
  }
1661
1665
  //#endregion
1666
+ //#region src/core/compilers.ts
1667
+ /**
1668
+ * Compiles a {@link TableSpec} into the `@orkestrel/database` {@link TableMap} it configures —
1669
+ * each {@link ColumnSpec} maps to the matching primitive shaper (`'string'` → `stringShape()`,
1670
+ * `'integer'` → `integerShape()`, `'number'` → `numberShape()`, `'boolean'` → `booleanShape()`),
1671
+ * wrapped in `optionalShape` when the column declares `optional: true`. Total, pure.
1672
+ *
1673
+ * @param spec - The small-model-facing table layout
1674
+ * @returns The compiled `TableMap` a `@orkestrel/database` `createDatabase` call accepts
1675
+ */
1676
+ function expandTables(spec) {
1677
+ const tables = {};
1678
+ for (const [table, definition] of Object.entries(spec)) {
1679
+ const columns = {};
1680
+ for (const [column, columnSpec] of Object.entries(definition.columns)) columns[column] = compileColumn(columnSpec);
1681
+ tables[table] = columns;
1682
+ }
1683
+ return tables;
1684
+ }
1685
+ /**
1686
+ * Compiles one {@link ColumnSpec} into its `@orkestrel/database` column shape — the per-column leaf
1687
+ * {@link expandTables} maps over.
1688
+ *
1689
+ * @param spec - The column spec to compile
1690
+ * @returns The `@orkestrel/database` column shape, wrapped in `optionalShape` when the spec declares `optional: true`
1691
+ */
1692
+ function compileColumn(spec) {
1693
+ const primitive = isString(spec) ? spec : spec.primitive;
1694
+ const optional = !isString(spec) && spec.optional === true;
1695
+ const shape = compileColumnPrimitive(primitive);
1696
+ return optional ? optionalShape(shape) : shape;
1697
+ }
1698
+ /**
1699
+ * Compiles one {@link import('./types.js').ColumnPrimitive} into its primitive
1700
+ * `@orkestrel/database` shape — the leaf {@link compileColumn} wraps.
1701
+ *
1702
+ * @param primitive - The declared column primitive
1703
+ * @returns The matching primitive `@orkestrel/database` shape
1704
+ */
1705
+ function compileColumnPrimitive(primitive) {
1706
+ if (primitive === "string") return stringShape();
1707
+ if (primitive === "integer") return integerShape();
1708
+ if (primitive === "number") return numberShape();
1709
+ return booleanShape();
1710
+ }
1711
+ //#endregion
1662
1712
  //#region src/core/stores/MemoryDefinitionStore.ts
1663
1713
  /**
1664
- * The in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of
1714
+ * Represents the in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of
1665
1715
  * {@link DatabaseDefinition}s keyed by database id, the DEFAULT store
1666
- * {@link import('../factories.js').createMemoryDefinitionStore} builds. The EXACT twin of
1667
- * {@link import('./DatabaseDefinitionStore.js').DatabaseDefinitionStore}.
1716
+ * {@link import('../factories.js').createMemoryDefinitionStore} builds. It implements the same
1717
+ * {@link DefinitionStoreInterface} contract as
1718
+ * {@link import('./DatabaseDefinitionStore.js').DatabaseDefinitionStore}: this store copies on
1719
+ * write and on read; the table-backed store narrows an untrusted stored blob and reports
1720
+ * `undefined` for a malformed one.
1668
1721
  *
1669
1722
  * @remarks
1670
- * A plain `Map<string, DatabaseDefinition>` (AGENTS §21 — the definition is already pure,
1723
+ * A plain `Map<string, DatabaseDefinition>` (the definition is already pure,
1671
1724
  * self-contained CONFIG-only JSON, so no encoding is needed for the memory tier). Values are
1672
1725
  * structured-cloned on both write and read, keeping caller mutation outside the store. There is NO
1673
1726
  * idle-TTL and NO eviction: a persisted definition lives until an explicit `delete`. A durable
@@ -1680,7 +1733,7 @@ function clampQuery(query, cap) {
1680
1733
  * - **`set` inserts / replaces under the definition's OWN `id`** (no separate id param).
1681
1734
  * - **`delete` drops a definition by id**; an absent id is a no-op (no throw).
1682
1735
  *
1683
- * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method
1736
+ * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the method
1684
1737
  * bijection with {@link DefinitionStoreInterface}).
1685
1738
  *
1686
1739
  * @example
@@ -1695,14 +1748,32 @@ function clampQuery(query, cap) {
1695
1748
  */
1696
1749
  var MemoryDefinitionStore = class {
1697
1750
  #definitions = /* @__PURE__ */ new Map();
1751
+ /**
1752
+ * Resolves the persisted definition for `id`, copied out of the backing `Map`.
1753
+ *
1754
+ * @param id - The database id to read
1755
+ * @returns The stored {@link DatabaseDefinition}, or `undefined` when none is stored
1756
+ */
1698
1757
  get(id) {
1699
1758
  const definition = this.#definitions.get(id);
1700
1759
  return Promise.resolve(definition === void 0 ? void 0 : structuredClone(definition));
1701
1760
  }
1761
+ /**
1762
+ * Inserts or replaces a definition under its OWN `id`, copied into the backing `Map`.
1763
+ *
1764
+ * @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
1766
+ */
1702
1767
  set(definition) {
1703
1768
  this.#definitions.set(definition.id, structuredClone(definition));
1704
1769
  return Promise.resolve();
1705
1770
  }
1771
+ /**
1772
+ * Drops the definition stored under `id`.
1773
+ *
1774
+ * @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`
1776
+ */
1706
1777
  delete(id) {
1707
1778
  this.#definitions.delete(id);
1708
1779
  return Promise.resolve();
@@ -1711,7 +1782,7 @@ var MemoryDefinitionStore = class {
1711
1782
  //#endregion
1712
1783
  //#region src/core/stores/DatabaseDefinitionStore.ts
1713
1784
  /**
1714
- * A {@link DefinitionStoreInterface} backed by one table of the `@orkestrel/database` layer — a
1785
+ * Represents a {@link DefinitionStoreInterface} backed by one table of the `@orkestrel/database` layer — a
1715
1786
  * database's durable CONFIG state IS a row, so persistence reduces to keyed point-access
1716
1787
  * (`get` / `set` / `delete`) over a {@link TableInterface}, the driver-pluggable twin of the
1717
1788
  * plain-`Map` {@link import('./MemoryDefinitionStore.js').MemoryDefinitionStore}.
@@ -1733,12 +1804,12 @@ var MemoryDefinitionStore = class {
1733
1804
  * - **`set(definition)` upserts under the definition's OWN `id`** (no separate id param) — it
1734
1805
  * writes the row `{ id: definition.id, definition }`.
1735
1806
  * - **`get(id)` resolves the stored definition for an id**, narrowing the opaque JSON column back
1736
- * to a {@link DatabaseDefinition} ({@link import('../helpers.js').isDatabaseDefinition} — the
1737
- * AGENTS §14 boundary narrow for an untrusted storage read), or `undefined` if none is stored
1807
+ * to a {@link DatabaseDefinition} ({@link import('../validators.js').isDatabaseDefinition} — the
1808
+ * boundary narrow for an untrusted storage read), or `undefined` if none is stored
1738
1809
  * or the stored blob is malformed.
1739
1810
  * - **`delete(id)` drops a definition by id**; an absent id is a no-op (no throw).
1740
1811
  *
1741
- * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method
1812
+ * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the method
1742
1813
  * bijection with {@link DefinitionStoreInterface}).
1743
1814
  *
1744
1815
  * @example
@@ -1754,7 +1825,7 @@ var MemoryDefinitionStore = class {
1754
1825
  var DatabaseDefinitionStore = class {
1755
1826
  #table;
1756
1827
  /**
1757
- * Wrap a table as a definition store.
1828
+ * Wraps a table as a definition store.
1758
1829
  *
1759
1830
  * @param table - The {@link TableInterface} holding the definitions — its row is the
1760
1831
  * {@link DatabaseDefinitionRow} `{ id; definition }` shape (the definition one opaque JSON column)
@@ -1762,20 +1833,37 @@ var DatabaseDefinitionStore = class {
1762
1833
  constructor(table) {
1763
1834
  this.#table = table;
1764
1835
  }
1765
- /** Resolve the persisted definition for `id`, narrowing the opaque JSON column back to a `DatabaseDefinition`. */
1836
+ /**
1837
+ * Resolves the persisted definition for `id`, narrowing the opaque JSON column back to a
1838
+ * {@link DatabaseDefinition}.
1839
+ *
1840
+ * @param id - The database id to read
1841
+ * @returns The stored {@link DatabaseDefinition}, or `undefined` when none is stored or the
1842
+ * stored blob is malformed
1843
+ */
1766
1844
  async get(id) {
1767
1845
  const row = await this.#table.get(id);
1768
1846
  if (row === void 0) return void 0;
1769
1847
  return isDatabaseDefinition(row.definition) ? row.definition : void 0;
1770
1848
  }
1771
- /** Insert or replace under the definition's OWN `id` (no separate id param) — the row is `{ id, definition }`. */
1849
+ /**
1850
+ * Inserts or replaces a definition under its OWN `id` — the written row is `{ id, definition }`.
1851
+ *
1852
+ * @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
1854
+ */
1772
1855
  async set(definition) {
1773
1856
  await this.#table.set({
1774
1857
  id: definition.id,
1775
1858
  definition
1776
1859
  });
1777
1860
  }
1778
- /** Drop a definition by id; an absent id is a no-op (no throw). */
1861
+ /**
1862
+ * Drops the definition stored under `id`.
1863
+ *
1864
+ * @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`
1866
+ */
1779
1867
  async delete(id) {
1780
1868
  await this.#table.remove(id);
1781
1869
  }
@@ -1783,7 +1871,7 @@ var DatabaseDefinitionStore = class {
1783
1871
  //#endregion
1784
1872
  //#region src/core/databases/DatabaseResolver.ts
1785
1873
  /**
1786
- * Resolve database definitions into cached live handles for database tools.
1874
+ * Resolves database definitions into cached live handles for database tools.
1787
1875
  *
1788
1876
  * @example
1789
1877
  * ```ts
@@ -1799,7 +1887,7 @@ var DatabaseResolver = class {
1799
1887
  #generator;
1800
1888
  #store;
1801
1889
  /**
1802
- * Create a database resolver over the tool's live state and optional definition store.
1890
+ * Creates a database resolver over the tool's live state and optional definition store.
1803
1891
  *
1804
1892
  * @param handles - Initial live database handles cached by id
1805
1893
  * @param drivers - Driver factories keyed by definition driver name
@@ -1813,16 +1901,16 @@ var DatabaseResolver = class {
1813
1901
  this.#store = store;
1814
1902
  }
1815
1903
  /**
1816
- * Determine whether a live database is cached by id.
1904
+ * Determines whether a live database is cached by id.
1817
1905
  *
1818
1906
  * @param id - Database id
1819
- * @returns Whether a live handle is cached
1907
+ * @returns True if a live handle is cached; false otherwise
1820
1908
  */
1821
1909
  has(id) {
1822
1910
  return this.#handles.has(id);
1823
1911
  }
1824
1912
  /**
1825
- * Read a cached database without consulting the definition store.
1913
+ * Reads a cached database without consulting the definition store.
1826
1914
  *
1827
1915
  * @param id - Database id
1828
1916
  * @returns The cached live database, or `undefined`
@@ -1831,7 +1919,7 @@ var DatabaseResolver = class {
1831
1919
  return this.#handles.get(id);
1832
1920
  }
1833
1921
  /**
1834
- * Cache a live database by id.
1922
+ * Caches a live database by id.
1835
1923
  *
1836
1924
  * @param id - Database id
1837
1925
  * @param database - Live database handle
@@ -1841,7 +1929,7 @@ var DatabaseResolver = class {
1841
1929
  this.#handles.set(id, database);
1842
1930
  }
1843
1931
  /**
1844
- * Remove a cached live database by id.
1932
+ * Removes a cached live database by id.
1845
1933
  *
1846
1934
  * @param id - Database id
1847
1935
  * @returns Nothing
@@ -1850,7 +1938,7 @@ var DatabaseResolver = class {
1850
1938
  this.#handles.delete(id);
1851
1939
  }
1852
1940
  /**
1853
- * Resolve a cached or stored database by id.
1941
+ * Resolves a cached or stored database by id.
1854
1942
  *
1855
1943
  * @param id - Database definition id
1856
1944
  * @returns The cached or newly constructed live database
@@ -1885,7 +1973,7 @@ var DatabaseResolver = class {
1885
1973
  //#endregion
1886
1974
  //#region src/core/factories.ts
1887
1975
  /**
1888
- * Wrap a registered tool as a {@link WorkflowFunction} (`@orkestrel/workflow`) — the OPT-IN
1976
+ * Wraps a registered tool as a {@link WorkflowFunction} (`@orkestrel/workflow`) — the OPT-IN
1889
1977
  * adapter that lets a `function`-form task run a `@orkestrel/tool` tool BY NAME.
1890
1978
  *
1891
1979
  * @remarks
@@ -1924,7 +2012,7 @@ function createToolFunction(tools, name) {
1924
2012
  };
1925
2013
  }
1926
2014
  /**
1927
- * Wrap a live `AgentInterface` (`@orkestrel/agent`) as a {@link WorkflowFunction}
2015
+ * Wraps a live `AgentInterface` (`@orkestrel/agent`) as a {@link WorkflowFunction}
1928
2016
  * (`@orkestrel/workflow`) — the opt-in adapter that runs the agent to a settled result and carries
1929
2017
  * immutable lineage metadata for contextual Toolbox composition.
1930
2018
  *
@@ -1932,7 +2020,7 @@ function createToolFunction(tools, name) {
1932
2020
  * Composes into a caller's registry like any other behavior; the pure workflow runner has no
1933
2021
  * knowledge of agents itself. A root adapter derives its workflow lineage from the controller,
1934
2022
  * while a contextual adapter requires an exact match. Repeated agents, repeated workflows, and
1935
- * targets deeper than {@link import('./constants.js').MAX_WORKFLOW_DEPTH} are rejected before
2023
+ * targets deeper than {@link import('./constants.js').MAX_WORKFLOW_CHAIN} are rejected before
1936
2024
  * agent or runner activity. When {@link import('./types.js').AgentFunctionOptions.runner} is
1937
2025
  * supplied, the adapter binds a recursion-safe {@link createWorkflowTool} onto the agent's
1938
2026
  * `context.tools`, propagating opaque leaves, raw agents, lineage, and the native store. The
@@ -1960,12 +2048,12 @@ function createToolFunction(tools, name) {
1960
2048
  * ```
1961
2049
  */
1962
2050
  function createAgentFunction(agent, options) {
1963
- const lineage = lineageOf(options?.lineage);
2051
+ const lineage = normalizeLineage(options?.lineage);
1964
2052
  if (lineage.length > 0 && !lineage.at(-1)?.startsWith("workflow:")) throw new ToolboxError("TOOL", "agent function lineage must end with a workflow tag");
1965
2053
  const functions = options?.functions === void 0 ? void 0 : Object.freeze({ ...options.functions });
1966
2054
  const agents = options?.agents === void 0 ? void 0 : Object.freeze({ ...options.agents });
1967
2055
  return Object.freeze(Object.assign(async (controller) => {
1968
- const workflow = workflowTag(controller.task.phase.workflow.id);
2056
+ const workflow = tagWorkflow(controller.task.phase.workflow.id);
1969
2057
  const current = lineage.length === 0 ? extendLineage(lineage, workflow) : lineage;
1970
2058
  if (current.at(-1) !== workflow) throw new ToolboxError("DEPTH", "agent function workflow does not match its lineage", {
1971
2059
  workflow,
@@ -1977,7 +2065,7 @@ function createAgentFunction(agent, options) {
1977
2065
  depth,
1978
2066
  max: 8
1979
2067
  });
1980
- const tag = agentTag(agent.id);
2068
+ const tag = tagAgent(agent.id);
1981
2069
  if (current.includes(tag)) throw new ToolboxError("DEPTH", `agent '${agent.id}' is already an ancestor (cycle)`, {
1982
2070
  agent: agent.id,
1983
2071
  lineage: [...current]
@@ -2009,7 +2097,7 @@ function createAgentFunction(agent, options) {
2009
2097
  }));
2010
2098
  }
2011
2099
  /**
2012
- * Compose opaque host functions and raw agents into one immutable workflow registry.
2100
+ * Composes opaque host functions and raw agents into one immutable workflow registry.
2013
2101
  *
2014
2102
  * @remarks
2015
2103
  * This is the target-aware composition boundary used by direct runner consumers and
@@ -2036,7 +2124,7 @@ function createAgentFunction(agent, options) {
2036
2124
  * ```
2037
2125
  */
2038
2126
  function createWorkflowFunctions(runner, options) {
2039
- const lineage = lineageOf(options?.lineage);
2127
+ const lineage = normalizeLineage(options?.lineage);
2040
2128
  if (lineage.length > 0 && !lineage.at(-1)?.startsWith("workflow:")) throw new ToolboxError("TOOL", "workflow functions lineage must end with a workflow tag");
2041
2129
  const functions = options?.functions === void 0 ? Object.freeze({}) : Object.freeze({ ...options.functions });
2042
2130
  const agents = options?.agents === void 0 ? Object.freeze({}) : Object.freeze({ ...options.agents });
@@ -2060,7 +2148,7 @@ function createWorkflowFunctions(runner, options) {
2060
2148
  return Object.freeze(composed);
2061
2149
  }
2062
2150
  /**
2063
- * Compile the lenient workflow draft contract used by {@link createWorkflowTool}.
2151
+ * Compiles the lenient workflow draft contract used by {@link createWorkflowTool}.
2064
2152
  *
2065
2153
  * @returns The compiled {@link import('./types.js').WorkflowDraft} contract
2066
2154
  */
@@ -2068,7 +2156,7 @@ function createWorkflowDraftContract() {
2068
2156
  return createContract(workflowDraftShape);
2069
2157
  }
2070
2158
  /**
2071
- * Wrap a {@link WorkflowDefinition} as an LLM-callable tool — it ADVERTISES the SIMPLE flat
2159
+ * Wraps a {@link WorkflowDefinition} as an LLM-callable tool — it ADVERTISES the SIMPLE flat
2072
2160
  * authoring shape (`{ name?, steps: [{ name }] }`) as its `parameters` so even a small model can
2073
2161
  * author a complete tree, and its handler EXPANDS / COMPLETES the authored blob, validates it
2074
2162
  * against the STRICT contract, and runs it through `runner`, forwarding the caller's optional
@@ -2094,7 +2182,7 @@ function createWorkflowDraftContract() {
2094
2182
  * - the full nested {@link WorkflowDefinition} — the advanced escape-hatch, accepted as the draft
2095
2183
  * super-set.
2096
2184
  *
2097
- * The universal tool-handler contract (AGENTS §14): returns the plain run summary
2185
+ * The universal tool-handler contract: returns the plain run summary
2098
2186
  * (`{ status, count, durable?, fault? }`) on success, THROWS a typed `ToolboxError` on Toolbox
2099
2187
  * boundary failures — malformed authored args (`TOOL`), or an over-deep / cyclic nested run
2100
2188
  * (`DEPTH`) — and preserves genuine runner `WorkflowError`s. The `ToolManagerInterface` isolates every throw into the canonical tool result's
@@ -2126,7 +2214,7 @@ function createWorkflowTool(definition, runner, options) {
2126
2214
  const strict = createWorkflowContract();
2127
2215
  const draft = createWorkflowDraftContract();
2128
2216
  const steps = createContract(workflowStepsShape);
2129
- const lineage = lineageOf(options?.lineage);
2217
+ const lineage = normalizeLineage(options?.lineage);
2130
2218
  if (lineage.length > 0 && !lineage.at(-1)?.startsWith("agent:")) throw new ToolboxError("TOOL", "workflow tool lineage must end with an agent tag");
2131
2219
  const functions = options?.functions === void 0 ? void 0 : Object.freeze({ ...options.functions });
2132
2220
  const agents = options?.agents === void 0 ? void 0 : Object.freeze({ ...options.agents });
@@ -2151,7 +2239,7 @@ function createWorkflowTool(definition, runner, options) {
2151
2239
  target = parsed === void 0 ? void 0 : completeDraft(parsed);
2152
2240
  }
2153
2241
  if (target === void 0 || !strict.is(target)) throw new ToolboxError("TOOL", "malformed workflow definition", { workflow: definition.id });
2154
- const tag = workflowTag(target.id);
2242
+ const tag = tagWorkflow(target.id);
2155
2243
  if (lineage.includes(tag)) throw new ToolboxError("DEPTH", `workflow '${target.id}' is already an ancestor (cycle)`, {
2156
2244
  workflow: target.id,
2157
2245
  lineage: [...lineage]
@@ -2169,7 +2257,7 @@ function createWorkflowTool(definition, runner, options) {
2169
2257
  ...agents === void 0 ? {} : { agents },
2170
2258
  ...store === void 0 ? {} : { store }
2171
2259
  });
2172
- return workflowToolSummary(await runner.execute(target, {
2260
+ return summarizeWorkflow(await runner.execute(target, {
2173
2261
  ...registry === void 0 ? {} : { functions: registry },
2174
2262
  ...store === void 0 ? {} : { store }
2175
2263
  }));
@@ -2177,15 +2265,15 @@ function createWorkflowTool(definition, runner, options) {
2177
2265
  });
2178
2266
  }
2179
2267
  /**
2180
- * Build an LLM-callable workspace-editing tool — it ADVERTISES the `operation`-discriminated
2181
- * 13-op union ({@link import('./shapers.js').workspaceToolShape}) as its `parameters`, and its
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
2182
2270
  * handler PARSES the model-supplied args against that contract and DISPATCHES the matched
2183
2271
  * operation against the manager's ACTIVE workspace (the registry ops drive the manager itself),
2184
2272
  * returning the plain result. A malformed operation throws this package's `ToolboxError`; a
2185
2273
  * genuine workspace-domain failure propagates `@orkestrel/workspace`'s typed `WorkspaceError`.
2186
2274
  * EITHER drives a caller-supplied {@link WorkspaceToolOptions.manager} directly, OR
2187
2275
  * constructs a fresh `WorkspaceManagerInterface` (`@orkestrel/workspace`) over
2188
- * {@link import('./types.js').WorkspaceToolOptions.store} (via `@orkestrel/workspace`'s
2276
+ * {@link import('./types.js').WorkspaceToolOptions.store} (through `@orkestrel/workspace`'s
2189
2277
  * `createWorkspaceManager`); neither given constructs a manager backed by
2190
2278
  * `@orkestrel/workspace`'s in-memory store default.
2191
2279
  *
@@ -2200,15 +2288,15 @@ function createWorkflowTool(definition, runner, options) {
2200
2288
  *
2201
2289
  * NO-ACTIVE RULE (the ergonomic seam): a WRITING op (write / splice / prepend / append / move /
2202
2290
  * remove / replace) run when `manager.active` is `undefined` AUTO-CREATES + activates a default
2203
- * workspace (`manager.add()`) so the model can just start writing; a pure-READ op (read / list /
2291
+ * workspace (`manager.add()`) so the model can start writing; a pure-READ op (read / list /
2204
2292
  * has / search) against no active workspace returns the EMPTY result (`undefined` / `[]` /
2205
2293
  * `false`), never creating one and never throwing.
2206
2294
  *
2207
- * The handler conforms to the universal tool-handler contract (AGENTS §14): it `contract.parse`s
2295
+ * The handler conforms to the universal tool-handler contract: it `contract.parse`s
2208
2296
  * the args, THROWS a `TOOL` `ToolboxError` when no operation arm matched (a malformed / unknown
2209
2297
  * operation), else `switch`es on `op.operation` and RETURNS the plain result — letting a
2210
- * `WorkspaceError` raised by the live workspace (`MODALITY` / `PATTERN` / `RANGE`) PROPAGATE
2211
- * uncaught. The range edit is the FLAT `'splice'` op: its four flat caret integers are
2298
+ * `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
2212
2300
  * reassembled into a `Range` (`@orkestrel/workspace`) by `rangeOf` and fed to the workspace's
2213
2301
  * ranged `write`.
2214
2302
  *
@@ -2330,14 +2418,14 @@ function createWorkspaceTool(options) {
2330
2418
  });
2331
2419
  }
2332
2420
  /**
2333
- * Build an LLM-callable sub-agent delegation tool — resolves a live, seeded `AgentInterface`
2421
+ * Builds an LLM-callable sub-agent delegation tool — resolves a live, seeded `AgentInterface`
2334
2422
  * from `registry` and runs it to completion for ONE delegated `task`.
2335
2423
  *
2336
2424
  * @remarks
2337
- * The universal tool-handler contract (AGENTS §14): validates the call args against
2425
+ * The universal tool-handler contract: validates the call args against
2338
2426
  * {@link import('./shapers.js').agentToolShape}, assembles an `AgentJobInput` (`task` seeds the
2339
2427
  * sub-agent's conversation as a single `user` message; `provider` / `tools` / `system` fall
2340
- * back to the tool's own {@link import('./types.js').AgentToolOptions} defaults), rehydrates the sub-agent via
2428
+ * back to the tool's own {@link import('./types.js').AgentToolOptions} defaults), rehydrates the sub-agent through
2341
2429
  * `registry.build`, runs it with `agent.generate()`, and returns the settled
2342
2430
  * `AgentResult.content` string (the sub-agent's final text). A missing / unresolvable `provider`, or a malformed call, THROWS a typed `TOOL`
2343
2431
  * {@link import('./errors.js').ToolboxError}; a delegation that would exceed
@@ -2388,7 +2476,7 @@ function createAgentTool(registry, options) {
2388
2476
  depth,
2389
2477
  max: 8
2390
2478
  });
2391
- const tag = agentTag(provider);
2479
+ const tag = tagAgent(provider);
2392
2480
  if (ancestry.includes(tag)) throw new ToolboxError("DEPTH", `agent '${provider}' is already an ancestor (cycle)`, {
2393
2481
  provider,
2394
2482
  ancestry: [...ancestry]
@@ -2414,7 +2502,7 @@ function createAgentTool(registry, options) {
2414
2502
  });
2415
2503
  }
2416
2504
  /**
2417
- * Build an LLM-callable tool that returns the FULL `description` of another registered tool by
2505
+ * Builds an LLM-callable tool that returns the FULL `description` of another registered tool by
2418
2506
  * name — the counterpart to the lean `summary` the other tools in this package advertise
2419
2507
  * (`AGENT_TOOL_SUMMARY` / `WORKFLOW_TOOL_SUMMARY` / `WORKSPACE_TOOL_SUMMARY`).
2420
2508
  *
@@ -2423,10 +2511,10 @@ function createAgentTool(registry, options) {
2423
2511
  * tool.description` — a lean one-sentence summary stands in for a tool's full teaching
2424
2512
  * description when `summary` is set, keeping the advertised tool list compact for a small model.
2425
2513
  * This tool is the on-demand expansion seam: given a registered tool's `name`, it looks the tool
2426
- * up via `tools.tool(name)` and returns its full `description` (falling back to `summary` when a
2514
+ * up through `tools.tool(name)` and returns its full `description` (falling back to `summary` when a
2427
2515
  * tool has no `description` of its own, then a placeholder when it has neither).
2428
2516
  *
2429
- * The universal tool-handler contract (AGENTS §14): validates the call args against
2517
+ * The universal tool-handler contract: validates the call args against
2430
2518
  * {@link import('./shapers.js').describeToolShape}, RETURNS the plain description string on
2431
2519
  * success, THROWS a typed `TOOL` {@link import('./errors.js').ToolboxError} on a malformed call
2432
2520
  * or an unknown tool name.
@@ -2465,11 +2553,11 @@ function createDescribeTool(tools) {
2465
2553
  });
2466
2554
  }
2467
2555
  /**
2468
- * Build an LLM-callable form tool — the ASK side of the terminal seam. Asks
2556
+ * Builds an LLM-callable form tool — the ASK side of the terminal seam. Asks
2469
2557
  * a multi-field form and BLOCKS until it answers, returning the resolved values record.
2470
2558
  *
2471
2559
  * @remarks
2472
- * The universal tool-handler contract (AGENTS §14): validates the call args against
2560
+ * The universal tool-handler contract: validates the call args against
2473
2561
  * {@link import('./shapers.js').promptToolShape}, parses the call's schema through
2474
2562
  * `@orkestrel/form`, constructs the live form, and passes it to `TerminalManagerInterface.ask`.
2475
2563
  * `from` is FIXED at construction
@@ -2478,7 +2566,7 @@ function createDescribeTool(tools) {
2478
2566
  * `TerminalError('DEADLOCK')`, re-surfaced as a typed `DEADLOCK`
2479
2567
  * {@link import('./errors.js').ToolboxError}; an expired form re-surfaces as `EXPIRE`; an
2480
2568
  * unknown `to` (or any other `TerminalError`) re-surfaces as `TOOL`, naming the unknown terminal
2481
- * plus the known ones (`manager.terminals()`).
2569
+ * and how many brokers the manager holds (`manager.count`).
2482
2570
  *
2483
2571
  * @param options - The live manager, the fixed `from` identity, and advertised overrides (see
2484
2572
  * {@link import('./types.js').PromptToolOptions})
@@ -2519,7 +2607,7 @@ function createPromptTool(options) {
2519
2607
  return await options.manager.ask(options.from, call.to, createForm(schema));
2520
2608
  } catch (error) {
2521
2609
  if (isFormError(error) && error.code === "ABANDONED") throw new ToolboxError("EXPIRE", `form to '${call.to}' expired before it was answered`, { to: call.to });
2522
- const code = terminalToolCode(error);
2610
+ const code = inferTerminalCode(error);
2523
2611
  if (code === void 0) throw error;
2524
2612
  if (code === "DEADLOCK") throw new ToolboxError("DEADLOCK", `asking '${call.to}' would create a form cycle`, isTerminalError(error) ? error.context : {
2525
2613
  from: options.from,
@@ -2528,7 +2616,7 @@ function createPromptTool(options) {
2528
2616
  if (code === "EXPIRE") throw new ToolboxError("EXPIRE", `form to '${call.to}' expired before it was answered`, { to: call.to });
2529
2617
  if (isTerminalError(error) && error.code === "TARGET") throw new ToolboxError("TOOL", `unknown terminal '${call.to}'`, {
2530
2618
  to: call.to,
2531
- known: options.manager.terminals()
2619
+ count: options.manager.count
2532
2620
  });
2533
2621
  throw new ToolboxError("TOOL", `asking '${call.to}' failed`, { to: call.to });
2534
2622
  }
@@ -2536,16 +2624,16 @@ function createPromptTool(options) {
2536
2624
  });
2537
2625
  }
2538
2626
  /**
2539
- * Build an LLM-callable answer tool — the ANSWER side of the terminal seam. Lists the forms
2540
- * currently addressed to {@link import('./types.js').AnswerToolOptions.to}, or answers one of
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
2541
2629
  * them by id.
2542
2630
  *
2543
2631
  * @remarks
2544
- * The universal tool-handler contract (AGENTS §14): validates the call args against
2632
+ * The universal tool-handler contract: validates the call args against
2545
2633
  * {@link import('./shapers.js').answerToolShape} (discriminated by `operation`). `'pending'`
2546
- * returns a compact list (`{ id, from, schema }`) of every form currently addressed to `to`.
2634
+ * returns a compact list (`{ id, from, schema }`) of every form addressed to `to`.
2547
2635
  * `'answer'` looks the form up by `id`, narrows the supplied `values` through `@orkestrel/form`,
2548
- * and applies it via
2636
+ * and applies it through
2549
2637
  * `TerminalManagerInterface.answer` — a rejected / unknown / unresolvable outcome
2550
2638
  * (`TerminalAnswerResult.error`) re-surfaces as a typed `ANSWER` `ToolboxError`; success returns
2551
2639
  * `{ answered: id }`. `to` is FIXED at construction
@@ -2603,8 +2691,8 @@ function createAnswerTool(options) {
2603
2691
  });
2604
2692
  }
2605
2693
  /**
2606
- * Create the in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of database
2607
- * definitions, the DEFAULT store the upcoming database / relation tools will persist their
2694
+ * Creates the in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of database
2695
+ * definitions, the DEFAULT store the database and relation tools persist their
2608
2696
  * `DatabaseDefinition` configs through.
2609
2697
  *
2610
2698
  * @returns A {@link DefinitionStoreInterface}
@@ -2620,7 +2708,7 @@ function createMemoryDefinitionStore() {
2620
2708
  return new MemoryDefinitionStore();
2621
2709
  }
2622
2710
  /**
2623
- * Create a {@link DefinitionStoreInterface} backed by one table of the `@orkestrel/database`
2711
+ * Creates a {@link DefinitionStoreInterface} backed by one table of the `@orkestrel/database`
2624
2712
  * layer — the driver-pluggable twin of {@link createMemoryDefinitionStore}, storing each
2625
2713
  * database's definition as one opaque JSON column.
2626
2714
  *
@@ -2645,15 +2733,15 @@ function createDatabaseDefinitionStore(driver = createMemoryDriver()) {
2645
2733
  }).table("definitions"));
2646
2734
  }
2647
2735
  /**
2648
- * Build an LLM-callable database tool — create, query, and mutate `@orkestrel/database`
2649
- * databases through one `operation`-discriminated call (AGENTS §14, matching
2736
+ * Builds an LLM-callable database tool — it creates, queries, and mutates `@orkestrel/database`
2737
+ * databases through one `operation`-discriminated call (matching
2650
2738
  * {@link createWorkspaceTool}'s single-tool-many-operations shape).
2651
2739
  *
2652
2740
  * @remarks
2653
- * The universal tool-handler contract (AGENTS §14): validates the call args against
2741
+ * The universal tool-handler contract: validates the call args against
2654
2742
  * {@link import('./shapers.js').databaseToolShape}, dispatches to the matching operation, and
2655
2743
  * RETURNS a plain result on success. A database is resolved lazily and cached for the tool's
2656
- * lifetime — `'create'` mints one from `tables` ({@link import('./helpers.js').expandTables}) and
2744
+ * lifetime — `'create'` mints one from `tables` ({@link import('./compilers.js').expandTables}) and
2657
2745
  * a registered `driver` key ({@link import('./types.js').DatabaseToolOptions.drivers}, default
2658
2746
  * `{ memory: () => createMemoryDriver() }`); any other operation addressing an uncached id falls
2659
2747
  * back to {@link import('./types.js').DatabaseToolOptions.store} (an unknown id throws a typed
@@ -2662,10 +2750,10 @@ function createDatabaseDefinitionStore(driver = createMemoryDriver()) {
2662
2750
  *
2663
2751
  * `'records'` clamps its `query` to
2664
2752
  * {@link import('./types.js').DatabaseToolOptions.limit} (default
2665
- * {@link import('./constants.js').DATABASE_TOOL_LIMIT}) via
2753
+ * {@link import('./constants.js').DATABASE_TOOL_LIMIT}) through
2666
2754
  * {@link import('./helpers.js').clampQuery}, reporting `truncated` when storage held more rows
2667
- * than the cap. Every operation's `query` is normalized via
2668
- * {@link import('./helpers.js').queryOf} (defaults an omitted condition `connector` to `'and'`).
2755
+ * than the cap. Every operation's `query` is normalized through
2756
+ * {@link import('./helpers.js').normalizeQuery} (defaults an omitted condition `connector` to `'and'`).
2669
2757
  * When {@link import('./types.js').DatabaseToolOptions.readonly} is `true`, every mutating
2670
2758
  * operation throws a typed `TOOL` `ToolboxError` before doing anything. A configured
2671
2759
  * {@link import('./types.js').DatabaseToolOptions.timeout} is passed as a fresh
@@ -2674,7 +2762,7 @@ function createDatabaseDefinitionStore(driver = createMemoryDriver()) {
2674
2762
  * not an outer deadline for resolution, construction, schema inspection, `get`, or `close`. A typed `@orkestrel/database`
2675
2763
  * failure (`DatabaseError`) re-surfaces as a typed `DATABASE` `ToolboxError` carrying the
2676
2764
  * original {@link import('@orkestrel/database').DatabaseErrorCode} in `context.code`
2677
- * ({@link import('./helpers.js').databaseToolCode}); an `ToolboxError` thrown by this tool's own
2765
+ * ({@link import('./helpers.js').inferDatabaseCode}); an `ToolboxError` thrown by this tool's own
2678
2766
  * guards passes through unwrapped.
2679
2767
  *
2680
2768
  * A lazily re-minted database over the DEFAULT in-memory driver yields an EMPTY database — only
@@ -2782,7 +2870,7 @@ function createDatabaseTool(options = {}) {
2782
2870
  }
2783
2871
  case "records": {
2784
2872
  const table = (await resolver.resolve(call.id)).table(call.table);
2785
- const { query: probe, limit } = clampQuery(queryOf(call.query), cap);
2873
+ const { query: probe, limit } = clampQuery(normalizeQuery(call.query), cap);
2786
2874
  const rows = await table.records(probe, read);
2787
2875
  const truncated = rows.length > limit;
2788
2876
  const sliced = rows.slice(0, limit);
@@ -2793,8 +2881,8 @@ function createDatabaseTool(options = {}) {
2793
2881
  limit
2794
2882
  };
2795
2883
  }
2796
- case "count": return { count: await (await resolver.resolve(call.id)).table(call.table).count(queryOf(call.query), read) };
2797
- case "aggregate": return { value: await (await resolver.resolve(call.id)).table(call.table).aggregate(call.function, call.column, queryOf(call.query), read) };
2884
+ case "count": return { count: await (await resolver.resolve(call.id)).table(call.table).count(normalizeQuery(call.query), read) };
2885
+ case "aggregate": return { value: await (await resolver.resolve(call.id)).table(call.table).aggregate(call.function, call.column, normalizeQuery(call.query), read) };
2798
2886
  case "add": {
2799
2887
  const table = (await resolver.resolve(call.id)).table(call.table);
2800
2888
  const many = Array.isArray(call.row);
@@ -2840,7 +2928,7 @@ function createDatabaseTool(options = {}) {
2840
2928
  }
2841
2929
  } catch (error) {
2842
2930
  if (isToolboxError(error)) throw error;
2843
- const code = databaseToolCode(error);
2931
+ const code = inferDatabaseCode(error);
2844
2932
  if (code === void 0) throw error;
2845
2933
  throw new ToolboxError("DATABASE", error instanceof Error ? error.message : String(error), {
2846
2934
  code,
@@ -2853,32 +2941,33 @@ function createDatabaseTool(options = {}) {
2853
2941
  });
2854
2942
  }
2855
2943
  /**
2856
- * Build an LLM-callable relation tool — traverse and edit `@orkestrel/relation` relationships
2857
- * through one `operation`-discriminated call (AGENTS §14, matching {@link createDatabaseTool}'s
2944
+ * Builds an LLM-callable relation tool — it traverses and edits `@orkestrel/relation` relationships
2945
+ * through one `operation`-discriminated call (matching {@link createDatabaseTool}'s
2858
2946
  * single-tool-many-operations shape).
2859
2947
  *
2860
2948
  * @remarks
2861
- * The universal tool-handler contract (AGENTS §14): validates the call args against
2949
+ * The universal tool-handler contract: validates the call args against
2862
2950
  * {@link import('./shapers.js').relationToolShape}, resolves the addressed
2863
2951
  * {@link import('@orkestrel/relation').RelationManagerInterface} — an explicit `manager` field
2864
2952
  * must match a key of {@link import('./types.js').RelationToolOptions.managers}, an OMITTED one
2865
2953
  * resolves to the SOLE registered manager, either miss throwing a typed `TOOL`
2866
2954
  * {@link import('./errors.js').ToolboxError}
2867
- * ({@link import('./helpers.js').relationManagerOf}) — then resolves `model` against it
2868
- * ({@link import('./helpers.js').relationModelOf}, same typed-`TOOL`-on-miss shape), and
2955
+ * ({@link import('./helpers.js').resolveRelationManager}) — then resolves `model` against it
2956
+ * ({@link import('./helpers.js').resolveRelationModel}, same typed-`TOOL`-on-miss shape), and
2869
2957
  * dispatches to the matched operation, RETURNING a plain result on success.
2870
2958
  *
2871
2959
  * `'load'` / `'find'` expand the call's FLAT dot-path `include` list into a live
2872
- * `@orkestrel/relation` `Include` tree via {@link import('./helpers.js').expandInclude}, capped
2960
+ * `@orkestrel/relation` `Include` tree through {@link import('./helpers.js').expandInclude}, capped
2873
2961
  * at {@link import('./types.js').RelationToolOptions.depth} (default
2874
2962
  * {@link import('./constants.js').RELATION_TOOL_DEPTH}) — a path exceeding the cap, or carrying an
2875
2963
  * empty segment, throws a typed `TOOL` error. `'load'` dispatches on whether `key` is an array
2876
- * (positional many-key form, AGENTS §9.2) or a single key. `'find'` and `'links'` clamp their
2964
+ * (positional many-key form — an array key is read as many keys rather than one) or a single key.
2965
+ * `'find'` and `'links'` clamp their
2877
2966
  * result to {@link import('./types.js').RelationToolOptions.limit} (default
2878
- * {@link import('./constants.js').RELATION_TOOL_LIMIT}) — `'find'` probes one row past the
2879
- * effective limit (mirroring {@link import('./helpers.js').clampQuery}'s idiom) to report
2880
- * `truncated`; `'links'` (which has no upstream pagination) fetches the FULL linked-key list and
2881
- * slices/truncates it the same way. `'link'` / `'unlink'` write / remove one `through` junction
2967
+ * {@link import('./constants.js').RELATION_TOOL_LIMIT}), taken through
2968
+ * {@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
2970
+ * list and slices/truncates it the same way. `'link'` / `'unlink'` write / remove one `through` junction
2882
2971
  * row.
2883
2972
  *
2884
2973
  * A typed `@orkestrel/relation` failure (`RelationError`) re-surfaces as a typed `RELATION`
@@ -2913,7 +3002,7 @@ function createRelationTool(options) {
2913
3002
  const call = contract.parse(args);
2914
3003
  if (call === void 0) throw new ToolboxError("TOOL", "malformed relation call", { args });
2915
3004
  try {
2916
- const model = relationModelOf(relationManagerOf(options.managers, call.manager), call.model);
3005
+ const model = resolveRelationModel(resolveRelationManager(options.managers, call.manager), call.model);
2917
3006
  switch (call.operation) {
2918
3007
  case "load": {
2919
3008
  const include = expandInclude(call.include, depth);
@@ -2922,7 +3011,7 @@ function createRelationTool(options) {
2922
3011
  }
2923
3012
  case "find": {
2924
3013
  const include = expandInclude(call.include, depth);
2925
- const effective = Math.min(call.limit ?? cap, cap);
3014
+ const effective = resolveLimit(call.limit, cap);
2926
3015
  const rows = await model.find(include, {
2927
3016
  limit: effective + 1,
2928
3017
  ...call.offset === void 0 ? {} : { offset: call.offset },
@@ -2945,27 +3034,28 @@ function createRelationTool(options) {
2945
3034
  await model.unlink(call.key, call.relation, call.target);
2946
3035
  return { unlinked: true };
2947
3036
  case "links": {
3037
+ const effective = resolveLimit(void 0, cap);
2948
3038
  const keys = await model.links(call.key, call.relation);
2949
- const truncated = keys.length > cap;
2950
- const sliced = keys.slice(0, cap);
3039
+ const truncated = keys.length > effective;
3040
+ const sliced = keys.slice(0, effective);
2951
3041
  return {
2952
3042
  keys: sliced,
2953
3043
  count: sliced.length,
2954
3044
  truncated,
2955
- limit: cap
3045
+ limit: effective
2956
3046
  };
2957
3047
  }
2958
3048
  }
2959
3049
  } catch (error) {
2960
3050
  if (isToolboxError(error)) throw error;
2961
- const relation = relationToolCode(error);
3051
+ const relation = inferRelationCode(error);
2962
3052
  if (relation !== void 0) throw new ToolboxError("RELATION", error instanceof Error ? error.message : String(error), {
2963
3053
  code: relation,
2964
3054
  operation: call.operation,
2965
3055
  model: call.model,
2966
3056
  ..."relation" in call ? { relation: call.relation } : {}
2967
3057
  });
2968
- const database = databaseToolCode(error);
3058
+ const database = inferDatabaseCode(error);
2969
3059
  if (database === void 0) throw error;
2970
3060
  throw new ToolboxError("DATABASE", error instanceof Error ? error.message : String(error), {
2971
3061
  code: database,
@@ -2976,15 +3066,15 @@ function createRelationTool(options) {
2976
3066
  });
2977
3067
  }
2978
3068
  /**
2979
- * Build a standalone LLM-callable tool that infers a JSON Schema from example values — the
3069
+ * Builds a standalone LLM-callable tool that infers a JSON Schema from example values — the
2980
3070
  * utility half of the "existing API/DB → MCP tool" bridge (the other half,
2981
3071
  * {@link createEndpointTool}, wraps one CONCRETE endpoint).
2982
3072
  *
2983
3073
  * @remarks
2984
- * The universal tool-handler contract (AGENTS §14): validates the call args against
3074
+ * The universal tool-handler contract: validates the call args against
2985
3075
  * {@link import('./shapers.js').inferToolShape} (`samples` non-empty, `format` / `enum` optional
2986
- * booleans, `candidates` an optional array), infers a schema via `@orkestrel/contract`'s
2987
- * `samplesToSchema`, wraps a non-object root as `{ value: <schema> }` via `schemaToObject` (mirrors
3076
+ * booleans, `candidates` an optional array), infers a schema through `@orkestrel/contract`'s
3077
+ * `samplesToSchema`, wraps a non-object root as `{ value: <schema> }` through `schemaToObject` (mirrors
2988
3078
  * the tool-parameters convention every other `create*Tool` factory advertises), and RETURNS the
2989
3079
  * resulting parameters record. An empty `samples` array fails `inferToolShape`'s `min: 1` bound —
2990
3080
  * `contract.parse` returns `undefined` and the handler throws a typed `TOOL`
@@ -2992,7 +3082,7 @@ function createRelationTool(options) {
2992
3082
  *
2993
3083
  * When `candidates` is ABSENT, the return is the bare parameters record — unchanged from before
2994
3084
  * this array existed. When `candidates` is PRESENT (any array, including empty), the handler
2995
- * compiles a SEPARATE per-call contract from the RAW inferred schema (via `@orkestrel/contract`'s
3085
+ * compiles a SEPARATE per-call contract from the RAW inferred schema (through `@orkestrel/contract`'s
2996
3086
  * `schemaToShape`, NOT the `schemaToObject`-wrapped parameters — a bare-value sample checks a
2997
3087
  * bare-value candidate) and returns `{ parameters, checks }`, one check per candidate at the same
2998
3088
  * index. Every entry has a UNIFORM shape — `{ index, valid, coercible }`, with `faults` added ONLY
@@ -3000,10 +3090,10 @@ function createRelationTool(options) {
3000
3090
  * OPPOSITE of {@link createEndpointTool}'s enforcement, which coerces (`7` becomes `'7'` for a
3001
3091
  * string slot) — here a conformance report answers "does this value conform AS-IS": `7` against a
3002
3092
  * string slot is `valid: false`, full stop. `coercible` answers a SEPARATE question — "would the
3003
- * NORMALIZING parse accept this value", i.e. would {@link createEndpointTool}'s default enforcement
3093
+ * NORMALIZING parse accept this value", that is would {@link createEndpointTool}'s default enforcement
3004
3094
  * admit it (`checker.parse(candidate) !== undefined`) — computed for every candidate regardless of
3005
- * `valid`; by the house parse/guard round-trip guarantee (AGENTS §14), a `valid: true` entry is
3006
- * ALWAYS also `coercible: true`. `@orkestrel/contract` 0.0.7's `explain` mirrors the normalizing
3095
+ * `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
3007
3097
  * `parse`'s leniency, not `is`'s strictness — so a strictly-invalid but coercible candidate (`7`
3008
3098
  * against a string slot) yields `{ valid: false, coercible: true, faults: [] }`: EMPTY faults, since
3009
3099
  * the mismatch the normalizing parse would silently fix is not one `explain` reports. `faults`
@@ -3011,7 +3101,7 @@ function createRelationTool(options) {
3011
3101
  * (a boolean in a string slot), a missing required key, or an out-of-enum value — where
3012
3102
  * `coercible: false`. `checker.is` / `.parse` / `.explain` are all total over JSON-safe input — a
3013
3103
  * JSON-safe hostile candidate (a `__proto__`-carrying object, deeply nested data) reaches all three
3014
- * and yields a bounded, non-throwing per-candidate verdict; a NON-JSON-safe candidate (e.g. a
3104
+ * and yields a bounded, non-throwing per-candidate verdict; a NON-JSON-safe candidate (for example a
3015
3105
  * throwing-getter `Proxy`) never reaches the checker at all — it fails the OUTER `args` parse
3016
3106
  * against {@link import('./shapers.js').inferToolShape} and rejects the WHOLE call with the same
3017
3107
  * `TOOL` {@link import('./errors.js').ToolboxError} a malformed `samples`/`format`/`enum` throws,
@@ -3092,32 +3182,32 @@ function createInferTool(options) {
3092
3182
  });
3093
3183
  }
3094
3184
  /**
3095
- * Wrap one CONCRETE endpoint ({@link import('./types.js').EndpointDefinition}) as an LLM-callable
3185
+ * Wraps one CONCRETE endpoint ({@link import('./types.js').EndpointDefinition}) as an LLM-callable
3096
3186
  * `ToolInterface` — the endpoint half of the "existing API/DB → MCP tool" bridge (the other half,
3097
3187
  * {@link createInferTool}, is a standalone inference utility).
3098
3188
  *
3099
3189
  * @remarks
3100
- * `parameters` is inferred ONCE at construction from `definition.samples` via
3190
+ * `parameters` is inferred ONCE at construction from `definition.samples` through
3101
3191
  * `@orkestrel/contract`'s `samplesToSchema` (tuned by {@link import('./types.js').EndpointToolOptions}'s
3102
- * `format` / `enum`), wrapping a non-object root as `{ value: <schema> }` via `schemaToObject` —
3192
+ * `format` / `enum`), wrapping a non-object root as `{ value: <schema> }` through `schemaToObject` —
3103
3193
  * the SAME object-rooted schema is both the ADVERTISED `parameters` and, by default
3104
3194
  * ({@link import('./types.js').EndpointToolOptions.validate} `true`), the ENFORCED contract:
3105
- * `@orkestrel/contract` 0.0.7's `schemaToShape` compiles it ONCE (via `createContract`) into a
3106
- * `ContractInterface` whose `.parse` runs on every call's `args` before `definition.invoke` — a
3195
+ * `@orkestrel/contract`'s `schemaToShape` compiles it ONCE (through `createContract`) into a
3196
+ * `ContractInterface` whose `.parse` runs on every call's `args` before `definition.execute` — a
3107
3197
  * NORMALIZING parse, not a strict type check: a scalar is COERCED to its inferred type where the
3108
3198
  * house parsers coerce (a number to/from a numeric string, a boolean from `'1'`/`'0'`/`'true'`/
3109
- * `'false'`/`1`/`0`), so `definition.invoke` receives the COERCED value (e.g. `7` sent for a
3199
+ * `'false'`/`1`/`0`), so `definition.execute` receives the COERCED value (for example `7` sent for a
3110
3200
  * string slot arrives as `'7'`), not the raw call value. A call whose `args` fails to parse into
3111
3201
  * a record — a required key missing, or a value not coercible to its slot's type — THROWS a
3112
3202
  * typed `TOOL` {@link import('./errors.js').ToolboxError} carrying the compiled contract's
3113
- * structured `explain` faults, and `definition.invoke` is never called. `format` annotations are
3203
+ * structured `explain` faults, and `definition.execute` is never called. `format` annotations are
3114
3204
  * NEVER asserted, and a key outside the closed inferred schema is SILENTLY DROPPED rather than
3115
3205
  * rejected (see {@link import('./types.js').EndpointToolOptions.validate}). With
3116
- * `validate: false`, `execute` PASSES THROUGH the model-supplied `args` to `definition.invoke`
3117
- * WITHOUT re-validation — the pre-0.0.7 behavior, preserved as an explicit opt-out. Either way,
3118
- * `invoke`'s return flows back as the tool call's plain result; a throw PROPAGATES uncaught,
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,
3119
3209
  * isolated by the `ToolManagerInterface` (`@orkestrel/tool`) into the canonical error envelope
3120
- * (AGENTS §14) — never caught or re-wrapped here.
3210
+ * — never caught or re-wrapped here.
3121
3211
  *
3122
3212
  * @param definition - The endpoint's identity, non-empty samples, and local handler (see
3123
3213
  * {@link import('./types.js').EndpointDefinition})
@@ -3134,12 +3224,12 @@ function createInferTool(options) {
3134
3224
  * name: 'lookupUser',
3135
3225
  * description: 'Look up a user by id.',
3136
3226
  * samples: [{ id: '1', name: 'Ada' }, { id: '2', name: 'Bob' }],
3137
- * invoke: (args) => ({ id: args.id, name: 'Ada' }),
3227
+ * execute: (args) => ({ id: args.id, name: 'Ada' }),
3138
3228
  * })
3139
3229
  * const tools = createToolManager()
3140
3230
  * tools.add(tool)
3141
3231
  *
3142
- * // conforming args (all required keys present) parse and reach `invoke`
3232
+ * // conforming args (all required keys present) parse and reach the definition's `execute`
3143
3233
  * const result = await tools.execute({
3144
3234
  * id: 'call-1',
3145
3235
  * name: 'lookupUser',
@@ -3148,7 +3238,7 @@ function createInferTool(options) {
3148
3238
  * // result.value -> { id: '1', name: 'Ada' }
3149
3239
  *
3150
3240
  * // a nonconforming call (id is not coercible to the required string) is rejected before
3151
- * // `invoke` runs
3241
+ * // the definition's `execute` runs
3152
3242
  * const rejected = await tools.execute({
3153
3243
  * id: 'call-2',
3154
3244
  * name: 'lookupUser',
@@ -3169,7 +3259,7 @@ function createEndpointTool(definition, options) {
3169
3259
  description: definition.description,
3170
3260
  ...parameters === void 0 ? {} : { parameters },
3171
3261
  execute(args) {
3172
- return definition.invoke(args);
3262
+ return definition.execute(args);
3173
3263
  }
3174
3264
  });
3175
3265
  const contract = createContract(schemaToShape(objectSchema));
@@ -3183,11 +3273,11 @@ function createEndpointTool(definition, options) {
3183
3273
  name: definition.name,
3184
3274
  faults: contract.explain(args)
3185
3275
  });
3186
- return definition.invoke(parsed);
3276
+ return definition.execute(parsed);
3187
3277
  }
3188
3278
  });
3189
3279
  }
3190
3280
  //#endregion
3191
- export { AGENT_TOOL_DEPTH, AGENT_TOOL_DESCRIPTION, AGENT_TOOL_NAME, AGENT_TOOL_SUMMARY, ANSWER_TOOL_DESCRIPTION, ANSWER_TOOL_NAME, ANSWER_TOOL_SUMMARY, DATABASE_TOOL_DESCRIPTION, DATABASE_TOOL_LIMIT, DATABASE_TOOL_MUTATIONS, DATABASE_TOOL_NAME, DATABASE_TOOL_SUMMARY, DESCRIBE_TOOL_DESCRIPTION, DESCRIBE_TOOL_NAME, DESCRIBE_TOOL_SUMMARY, DatabaseDefinitionStore, DatabaseResolver, INFER_TOOL_DESCRIPTION, INFER_TOOL_NAME, INFER_TOOL_SUMMARY, MAX_WORKFLOW_DEPTH, MemoryDefinitionStore, PROMPT_TOOL_DESCRIPTION, PROMPT_TOOL_NAME, PROMPT_TOOL_SUMMARY, RELATION_TOOL_DEPTH, RELATION_TOOL_DESCRIPTION, RELATION_TOOL_LIMIT, RELATION_TOOL_NAME, RELATION_TOOL_SUMMARY, ToolboxError, WORKFLOW_TOOL_DESCRIPTION, WORKFLOW_TOOL_FLAT_EXAMPLE, WORKFLOW_TOOL_NAME, WORKFLOW_TOOL_NESTED_EXAMPLE, WORKFLOW_TOOL_SUMMARY, WORKSPACE_TOOL_DESCRIPTION, WORKSPACE_TOOL_EXAMPLE, WORKSPACE_TOOL_NAME, WORKSPACE_TOOL_SUMMARY, agentTag, agentToolShape, answerToolShape, clampQuery, columnKindShape, columnShape, columnSpecShape, completeDraft, completePhaseDraft, completeTaskDraft, conditionShape, createAgentFunction, createAgentTool, createAnswerTool, createDatabaseDefinitionStore, createDatabaseTool, createDescribeTool, createEndpointTool, createInferTool, createMemoryDefinitionStore, createPromptTool, createRelationTool, createToolFunction, createWorkflowDraftContract, createWorkflowFunctions, createWorkflowTool, createWorkspaceTool, databaseToolCode, databaseToolShape, deriveWorkflowDepth, describeToolShape, expandInclude, expandSteps, expandTables, extendLineage, includeShape, inferToolShape, isAgentFunction, isColumnKind, isColumnSpec, isDatabaseDefinition, isToolboxError, isWorkflowLineage, keyShape, kindShape, lineageOf, managerShape, orderShape, phaseDraftShape, promptToolShape, queryOf, queryShape, relationKeyShape, relationManagerOf, relationModelOf, relationToolCode, relationToolShape, rowShape, rowsShape, singleKeyShape, stepShape, tableSpecShape, taskDraftShape, terminalToolCode, workflowDraftShape, workflowStepsShape, workflowTag, workflowToolSummary, workspaceToolShape };
3281
+ export { AGENT_TOOL_DEPTH, AGENT_TOOL_DESCRIPTION, AGENT_TOOL_NAME, AGENT_TOOL_SUMMARY, ANSWER_TOOL_DESCRIPTION, ANSWER_TOOL_NAME, ANSWER_TOOL_SUMMARY, DATABASE_TOOL_DESCRIPTION, DATABASE_TOOL_LIMIT, DATABASE_TOOL_MUTATIONS, DATABASE_TOOL_NAME, DATABASE_TOOL_SUMMARY, DESCRIBE_TOOL_DESCRIPTION, DESCRIBE_TOOL_NAME, DESCRIBE_TOOL_SUMMARY, DatabaseDefinitionStore, DatabaseResolver, INFER_TOOL_DESCRIPTION, INFER_TOOL_NAME, INFER_TOOL_SUMMARY, MAX_WORKFLOW_CHAIN, MemoryDefinitionStore, PROMPT_TOOL_DESCRIPTION, PROMPT_TOOL_NAME, PROMPT_TOOL_SUMMARY, RELATION_TOOL_DEPTH, RELATION_TOOL_DESCRIPTION, RELATION_TOOL_LIMIT, RELATION_TOOL_NAME, RELATION_TOOL_SUMMARY, ToolboxError, WORKFLOW_TOOL_DESCRIPTION, WORKFLOW_TOOL_FLAT_EXAMPLE, WORKFLOW_TOOL_NAME, WORKFLOW_TOOL_NESTED_EXAMPLE, WORKFLOW_TOOL_SUMMARY, WORKSPACE_TOOL_DESCRIPTION, WORKSPACE_TOOL_EXAMPLE, WORKSPACE_TOOL_NAME, WORKSPACE_TOOL_SUMMARY, agentToolShape, answerToolShape, clampQuery, columnPrimitiveShape, columnSpecShape, compileColumn, compileColumnPrimitive, completeDraft, completePhaseDraft, completeTaskDraft, conditionShape, createAgentFunction, createAgentTool, createAnswerTool, createDatabaseDefinitionStore, createDatabaseTool, createDescribeTool, createEndpointTool, createInferTool, createMemoryDefinitionStore, createPromptTool, createRelationTool, createToolFunction, createWorkflowDraftContract, createWorkflowFunctions, createWorkflowTool, createWorkspaceTool, databaseToolShape, deriveWorkflowDepth, describeToolShape, expandInclude, expandSteps, expandTables, extendLineage, includeShape, inferDatabaseCode, inferRelationCode, inferTerminalCode, inferToolShape, isAgentFunction, isColumnPrimitive, isColumnSpec, isDatabaseDefinition, isToolboxError, isWorkflowLineage, keyShape, managerShape, normalizeLineage, normalizeQuery, orderShape, phaseDraftShape, promptToolShape, queryShape, relationToolShape, resolveLimit, resolveRelationManager, resolveRelationModel, rowShape, rowsShape, singleKeyShape, stepShape, summarizeWorkflow, tableSpecShape, tagAgent, tagWorkflow, taskDraftShape, workflowDraftShape, workflowStepsShape, workspaceToolShape };
3192
3282
 
3193
3283
  //# sourceMappingURL=index.js.map