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