@orkestrel/toolbox 0.0.11 → 0.0.13

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,40 +10,44 @@ 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
14
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
13
+ * Holds the name {@link import('./factories.js').createAgentTool} advertises by default, `'agent'`
14
+ * — the key a 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
19
- * reach — the bound {@link import('./factories.js').createAgentTool}'s depth/cycle guard
18
+ * Holds the maximum nesting depth a delegation chain (agent tool → sub-agent → agent tool → …) may
19
+ * reach, `8` — 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
24
- * sharing one reference): the two guards bound DIFFERENT chains (workflow nesting vs. agent
23
+ * Deliberately a separate constant from {@link MAX_WORKFLOW_CHAIN} (rather than the guards
24
+ * sharing one reference): they bound different chains (workflow nesting against 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
27
27
  * by shared reference.
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}
32
- * advertises in place of {@link AGENT_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
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
35
- * {@link import('./factories.js').createDescribeTool}.
31
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
32
+ * {@link import('./factories.js').createAgentTool} advertises in place of
33
+ * {@link AGENT_TOOL_DESCRIPTION} — one sentence offering sub-agent delegation and pointing at
34
+ * `describe` for the optional overrides.
35
+ *
36
+ * @remarks
37
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
38
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
39
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
36
40
  */
37
41
  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
42
  /**
39
- * The description {@link import('./factories.js').createAgentTool} advertises — a short guide
43
+ * Holds the description {@link import('./factories.js').createAgentTool} advertises — a short guide
40
44
  * covering the required task and optional provider, tools, and system overrides.
41
45
  */
42
46
  var AGENT_TOOL_DESCRIPTION = [
43
47
  "Delegate a task to a sub-agent and return its result. Every call runs ONE sub-agent turn to completion.",
44
48
  "",
45
49
  "Required:",
46
- " task - the instructions the sub-agent should carry out.",
50
+ " task - the instructions the sub-agent carries out.",
47
51
  "Optional overrides (default to the values this tool was configured with):",
48
52
  " provider - the registry key of the model/provider the sub-agent runs against.",
49
53
  " tools - registry keys of the tools loaded into the sub-agent (replaces the default list, not merged).",
@@ -52,7 +56,7 @@ var AGENT_TOOL_DESCRIPTION = [
52
56
  JSON.stringify({ task: "Summarize the attached notes in three bullet points." })
53
57
  ].join("\n");
54
58
  /**
55
- * The maximum nesting depth a workflow → agent → workflow chain may reach — the bound
59
+ * Holds the maximum nesting depth a workflow → agent → workflow chain may reach, `8` — the bound
56
60
  * {@link import('./factories.js').createAgentFunction} and
57
61
  * {@link import('./factories.js').createWorkflowTool}'s depth/cycle guards enforce.
58
62
  *
@@ -61,42 +65,42 @@ var AGENT_TOOL_DESCRIPTION = [
61
65
  * workflows is allowed, while a ninth nested workflow is rejected with this package's typed
62
66
  * `DEPTH` `ToolboxError`.
63
67
  */
64
- var MAX_WORKFLOW_DEPTH = 8;
68
+ var MAX_WORKFLOW_CHAIN = 8;
65
69
  /**
66
- * The name {@link import('./factories.js').createWorkflowTool} advertises by default — the key a
67
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under, and the name
68
- * {@link import('./factories.js').createAgentFunction} binds the depth/cycle-aware workflow tool
69
- * under onto a wrapped agent's `context.tools`.
70
+ * Holds the name {@link import('./factories.js').createWorkflowTool} advertises by default,
71
+ * `'workflow'` — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers
72
+ * under, and the name {@link import('./factories.js').createAgentFunction} binds the
73
+ * depth/cycle-aware workflow tool under onto a wrapped agent's `context.tools`.
70
74
  *
71
75
  * @remarks
72
76
  * The propagation seam's well-known key: when
73
77
  * `createAgentFunction`'s `runner` option is supplied, it adds a `createWorkflowTool`-built tool
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}).
78
+ * under this name to the agent's `context.tools`, so it can author and run a nested workflow
79
+ * (bounded by {@link MAX_WORKFLOW_CHAIN}).
76
80
  */
77
81
  var WORKFLOW_TOOL_NAME = "workflow";
78
82
  /**
79
- * A complete FLAT authoring example — the PRIMARY way a small model authors a workflow through
80
- * {@link import('./factories.js').createWorkflowTool}: `{ name, steps: [{ name }] }`.
83
+ * Holds a complete flat authoring example — the primary way a small model authors a workflow
84
+ * through {@link import('./factories.js').createWorkflowTool}: `{ name, steps: [{ name }] }`.
81
85
  *
82
86
  * @remarks
83
87
  * Each step becomes a one-task phase, in
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
88
+ * order; a step's `name` is a registered behavior name (not a label) — the registry key its
89
+ * task's `behavior` resolves against. The tool expands this
86
90
  * ({@link import('./helpers.js').expandSteps}) into a valid `WorkflowDefinition`
87
- * (`@orkestrel/workflow`). It is embedded VERBATIM in {@link WORKFLOW_TOOL_DESCRIPTION}.
91
+ * (`@orkestrel/workflow`). It is embedded verbatim in {@link WORKFLOW_TOOL_DESCRIPTION}.
88
92
  */
89
93
  var WORKFLOW_TOOL_FLAT_EXAMPLE = Object.freeze({
90
94
  name: "release",
91
95
  steps: Object.freeze([Object.freeze({ name: "compile" }), Object.freeze({ name: "publish" })])
92
96
  });
93
97
  /**
94
- * A minimal NESTED authoring example — the ADVANCED escape-hatch form a model may use instead of
95
- * the flat shape: a full `WorkflowDefinition` (`@orkestrel/workflow`).
98
+ * Holds a minimal nested authoring example — the advanced escape-hatch form a model can use instead
99
+ * of the flat shape: a full `WorkflowDefinition` (`@orkestrel/workflow`).
96
100
  *
97
101
  * @remarks
98
- * The full four-level form, documented in
99
- * {@link WORKFLOW_TOOL_DESCRIPTION} as the advanced alternative. It is embedded VERBATIM.
102
+ * The full nested form, documented in
103
+ * {@link WORKFLOW_TOOL_DESCRIPTION} as the advanced alternative. It is embedded verbatim.
100
104
  */
101
105
  var WORKFLOW_TOOL_NESTED_EXAMPLE = Object.freeze({
102
106
  id: "release",
@@ -107,20 +111,24 @@ var WORKFLOW_TOOL_NESTED_EXAMPLE = Object.freeze({
107
111
  tasks: Object.freeze([Object.freeze({
108
112
  id: "compile",
109
113
  name: "Compile",
110
- run: "compile"
114
+ behavior: "compile"
111
115
  })])
112
116
  })])
113
117
  });
114
118
  /**
115
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createWorkflowTool}
116
- * advertises in place of {@link WORKFLOW_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
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
119
- * {@link import('./factories.js').createDescribeTool}.
119
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
120
+ * {@link import('./factories.js').createWorkflowTool} advertises in place of
121
+ * {@link WORKFLOW_TOOL_DESCRIPTION} — one sentence offering multi-phase authoring and pointing at
122
+ * `describe` for the authoring schema and its examples.
123
+ *
124
+ * @remarks
125
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
126
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
127
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
120
128
  */
121
129
  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
130
  /**
123
- * The description {@link import('./factories.js').createWorkflowTool} advertises — the flat
131
+ * Holds the description {@link import('./factories.js').createWorkflowTool} advertises — the flat
124
132
  * authoring form, its worked example, and the advanced nested definition form.
125
133
  */
126
134
  var WORKFLOW_TOOL_DESCRIPTION = [
@@ -134,18 +142,19 @@ var WORKFLOW_TOOL_DESCRIPTION = [
134
142
  "Example:",
135
143
  JSON.stringify(WORKFLOW_TOOL_FLAT_EXAMPLE),
136
144
  "",
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:",
145
+ "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
146
  JSON.stringify(WORKFLOW_TOOL_NESTED_EXAMPLE),
139
147
  "In the nested form you may omit any \"id\"/\"name\" and they are filled in positionally; a provided one is kept."
140
148
  ].join("\n");
141
149
  /**
142
- * The name {@link import('./factories.js').createWorkspaceTool} advertises by default — the key a
143
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
150
+ * Holds the name {@link import('./factories.js').createWorkspaceTool} advertises by default,
151
+ * `'workspace'` — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`)
152
+ * registers under.
144
153
  */
145
154
  var WORKSPACE_TOOL_NAME = "workspace";
146
155
  /**
147
- * A valid {@link import('./types.js').WorkspaceOperation} object — the canonical example embedded
148
- * VERBATIM in {@link WORKSPACE_TOOL_DESCRIPTION}.
156
+ * Holds a valid {@link import('./types.js').WorkspaceOperation} object — the canonical example
157
+ * embedded verbatim in {@link WORKSPACE_TOOL_DESCRIPTION}.
149
158
  *
150
159
  * @remarks
151
160
  * A `'write'` op (the most common authoring
@@ -158,15 +167,19 @@ var WORKSPACE_TOOL_EXAMPLE = Object.freeze({
158
167
  content: "hello"
159
168
  });
160
169
  /**
161
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createWorkspaceTool}
162
- * advertises in place of {@link WORKSPACE_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
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
165
- * {@link import('./factories.js').createDescribeTool}.
170
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
171
+ * {@link import('./factories.js').createWorkspaceTool} advertises in place of
172
+ * {@link WORKSPACE_TOOL_DESCRIPTION} — one sentence offering the `operation`-keyed file editing and
173
+ * pointing at `describe` for the operation list and its fields.
174
+ *
175
+ * @remarks
176
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
177
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
178
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
166
179
  */
167
180
  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
181
  /**
169
- * The description {@link import('./factories.js').createWorkspaceTool} advertises — the
182
+ * Holds the description {@link import('./factories.js').createWorkspaceTool} advertises — the
170
183
  * operation-keyed workspace protocol, all supported operations, and worked examples.
171
184
  *
172
185
  * @remarks
@@ -198,24 +211,26 @@ var WORKSPACE_TOOL_DESCRIPTION = [
198
211
  JSON.stringify(WORKSPACE_TOOL_EXAMPLE)
199
212
  ].join("\n");
200
213
  /**
201
- * The name {@link import('./factories.js').createDescribeTool} advertises by default — the key a
202
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
214
+ * Holds the name {@link import('./factories.js').createDescribeTool} advertises by default,
215
+ * `'describe'` — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers
216
+ * under.
203
217
  *
204
218
  * @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
219
+ * Pairs with the lean {@link AGENT_TOOL_SUMMARY} / {@link WORKFLOW_TOOL_SUMMARY} /
220
+ * {@link WORKSPACE_TOOL_SUMMARY} — a model that reads only the
207
221
  * advertised summary can call `describe` with that tool's registered name to get its full
208
222
  * teaching description back.
209
223
  */
210
224
  var DESCRIBE_TOOL_NAME = "describe";
211
225
  /**
212
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createDescribeTool}
226
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createDescribeTool}
213
227
  * advertises — this tool needs no teaching of its own, so its summary and description are both
214
228
  * short.
215
229
  */
216
230
  var DESCRIBE_TOOL_SUMMARY = "Return the full description of a named registered tool.";
217
231
  /**
218
- * The DESCRIPTION {@link import('./factories.js').createDescribeTool} advertises.
232
+ * Holds the description {@link import('./factories.js').createDescribeTool} advertises — the
233
+ * registered tool `name` it requires, and the full description of that tool it returns.
219
234
  *
220
235
  * @remarks
221
236
  * Deliberately short — unlike the workflow / workspace / agent tools, this one has no authoring
@@ -223,19 +238,27 @@ var DESCRIBE_TOOL_SUMMARY = "Return the full description of a named registered t
223
238
  */
224
239
  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
240
  /**
226
- * The name {@link import('./factories.js').createPromptTool} advertises by default — the key a
227
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
241
+ * Holds the name {@link import('./factories.js').createPromptTool} advertises by default, `'ask'` —
242
+ * the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
228
243
  */
229
244
  var PROMPT_TOOL_NAME = "ask";
230
245
  /**
231
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createPromptTool}
232
- * advertises in place of {@link PROMPT_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
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
235
- * {@link import('./factories.js').createDescribeTool}.
246
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
247
+ * {@link import('./factories.js').createPromptTool} advertises in place of
248
+ * {@link PROMPT_TOOL_DESCRIPTION} — one sentence offering the blocking multi-field ask and pointing
249
+ * at `describe` for the schema.
250
+ *
251
+ * @remarks
252
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
253
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
254
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
236
255
  */
237
256
  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. */
257
+ /**
258
+ * Holds the form protocol {@link import('./factories.js').createPromptTool} advertises — the
259
+ * required `to` and `schema`, how a field declares its control and its rules, and a worked
260
+ * example.
261
+ */
239
262
  var PROMPT_TOOL_DESCRIPTION = [
240
263
  "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
264
  "",
@@ -261,24 +284,32 @@ var PROMPT_TOOL_DESCRIPTION = [
261
284
  })
262
285
  ].join("\n");
263
286
  /**
264
- * The name {@link import('./factories.js').createAnswerTool} advertises by default — the key a
265
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
287
+ * Holds the name {@link import('./factories.js').createAnswerTool} advertises by default,
288
+ * `'answer'` — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers
289
+ * under.
266
290
  */
267
291
  var ANSWER_TOOL_NAME = "answer";
268
292
  /**
269
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createAnswerTool}
270
- * advertises in place of {@link ANSWER_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
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
273
- * {@link import('./factories.js').createDescribeTool}.
293
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
294
+ * {@link import('./factories.js').createAnswerTool} advertises in place of
295
+ * {@link ANSWER_TOOL_DESCRIPTION} — one sentence offering the pending listing and the answer call,
296
+ * and pointing at `describe` for the fields each takes.
297
+ *
298
+ * @remarks
299
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
300
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
301
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
274
302
  */
275
303
  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. */
304
+ /**
305
+ * Holds the protocol {@link import('./factories.js').createAnswerTool} advertises — the `pending`
306
+ * and `answer` operations and the `values` record an answer supplies, each with a worked example.
307
+ */
277
308
  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.",
309
+ "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
310
  "",
280
311
  "Operations:",
281
- "- pending { \"operation\": \"pending\" } — list every form currently addressed to this terminal (id, from, schema).",
312
+ "- pending { \"operation\": \"pending\" } — list every form addressed to this terminal (id, from, schema).",
282
313
  "- answer { \"operation\": \"answer\", \"id\": \"<form id>\", \"values\": { \"<field name>\": <field value> } } — answer every required field with the value its control accepts.",
283
314
  "Example — list pending forms:",
284
315
  JSON.stringify({ operation: "pending" }),
@@ -293,28 +324,31 @@ var ANSWER_TOOL_DESCRIPTION = [
293
324
  })
294
325
  ].join("\n");
295
326
  /**
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.
327
+ * Holds the name {@link import('./factories.js').createDatabaseTool} advertises by default,
328
+ * `'database'` — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers
329
+ * under.
303
330
  */
304
331
  var DATABASE_TOOL_NAME = "database";
305
332
  /**
306
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} the upcoming database tool
307
- * will advertise in place of {@link DATABASE_TOOL_DESCRIPTION}.
333
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
334
+ * {@link import('./factories.js').createDatabaseTool} advertises in place of
335
+ * {@link DATABASE_TOOL_DESCRIPTION} — one sentence offering the `operation`-keyed database call and
336
+ * pointing at `describe` for the operation list, the query form, and the column DSL.
337
+ *
338
+ * @remarks
339
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
340
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
341
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
308
342
  */
309
343
  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
344
  /**
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.
345
+ * Holds the description {@link import('./factories.js').createDatabaseTool} advertises — a
346
+ * multi-line guide that teaches a small model the operation list, the serialized query form, and
347
+ * the {@link import('./types.js').TableSpec} column DSL.
314
348
  *
315
349
  * @remarks
316
- * The query form is deliberately SERIALIZED (never fluent) — every condition is a flat object
317
- * `{ column, operator, values, connector? }` where `values` is ALWAYS an array, even for a
350
+ * The query form is deliberately serialized (never fluent) — every condition is a flat object
351
+ * `{ column, operator, values, connector? }` where `values` is always an array, even for a
318
352
  * single-value operator (`{ column: 'age', operator: 'from', values: [18] }`), so a small model
319
353
  * never has to chain method calls or guess whether a value is scalar or a list.
320
354
  */
@@ -322,7 +356,7 @@ var DATABASE_TOOL_DESCRIPTION = [
322
356
  "Create and query a database. Every call is ONE operation, chosen by the \"operation\" field.",
323
357
  "",
324
358
  "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.",
359
+ "- 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
360
  "- tables { \"operation\": \"tables\", \"id\": \"<database id>\" } — list a database's table names.",
327
361
  "- get { \"operation\": \"get\", \"id\": \"<database id>\", \"table\": \"<table>\", \"key\": \"<row key>\" } — fetch one row by its primary key.",
328
362
  "- records { \"operation\": \"records\", \"id\": \"<database id>\", \"table\": \"<table>\", \"query\"?: <Query> } — list rows matching a query.",
@@ -339,7 +373,7 @@ var DATABASE_TOOL_DESCRIPTION = [
339
373
  " operators: equals, not, above, below, from, to, between, like, glob, starts, ends, any, none, absent, present.",
340
374
  " \"connector\" joins this condition to the next (\"and\" | \"or\"); omit on the last condition.",
341
375
  "",
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.",
376
+ "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
377
  "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
378
  "Example — create a database:",
345
379
  JSON.stringify({
@@ -349,7 +383,7 @@ var DATABASE_TOOL_DESCRIPTION = [
349
383
  name: "string",
350
384
  price: "number",
351
385
  notes: {
352
- type: "string",
386
+ primitive: "string",
353
387
  optional: true
354
388
  }
355
389
  } } }
@@ -366,9 +400,12 @@ var DATABASE_TOOL_DESCRIPTION = [
366
400
  }] }
367
401
  })
368
402
  ].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. */
403
+ /**
404
+ * Holds the default cap on rows a `records` call returns when the caller omits `query.limit`,
405
+ * `1000` — the database tool's default row ceiling.
406
+ */
370
407
  var DATABASE_TOOL_LIMIT = 1e3;
371
- /** The runtime-frozen database-tool mutation names disabled by `DatabaseToolOptions.readonly`. */
408
+ /** Lists the runtime-frozen database-tool mutation names disabled by `DatabaseToolOptions.readonly`. */
372
409
  var DATABASE_TOOL_MUTATIONS = Object.freeze([
373
410
  "create",
374
411
  "add",
@@ -378,21 +415,30 @@ var DATABASE_TOOL_MUTATIONS = Object.freeze([
378
415
  "destroy"
379
416
  ]);
380
417
  /**
381
- * The name `createRelationTool` advertises by default — the key a model calls and the
382
- * `ToolManagerInterface` (`@orkestrel/tool`) registers under.
418
+ * Holds the name {@link import('./factories.js').createRelationTool} advertises by default,
419
+ * `'relation'` — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers
420
+ * under.
383
421
  */
384
422
  var RELATION_TOOL_NAME = "relation";
385
423
  /**
386
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} the relation tool advertises
387
- * in place of {@link RELATION_TOOL_DESCRIPTION}.
424
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
425
+ * {@link import('./factories.js').createRelationTool} advertises in place of
426
+ * {@link RELATION_TOOL_DESCRIPTION} — one sentence offering the `operation`-keyed relationship
427
+ * traversal and pointing at `describe` for the include-path syntax.
428
+ *
429
+ * @remarks
430
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
431
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
432
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
388
433
  */
389
434
  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
435
  /**
391
- * The DESCRIPTION the relation tool advertises — a multi-line guide that teaches a small model
392
- * the operation list and the flat dot-path `include` syntax.
436
+ * Holds the description {@link import('./factories.js').createRelationTool} advertises — a
437
+ * multi-line guide that teaches a small model the operation list and the flat dot-path `include`
438
+ * syntax.
393
439
  *
394
440
  * @remarks
395
- * An include path is a FLAT dot-separated string (`'contacts.account'`), never a nested object —
441
+ * An include path is a flat dot-separated string (`'contacts.account'`), never a nested object —
396
442
  * the same small-model ergonomic lever the other tools in this package use for flat args.
397
443
  */
398
444
  var RELATION_TOOL_DESCRIPTION = [
@@ -414,24 +460,38 @@ var RELATION_TOOL_DESCRIPTION = [
414
460
  include: ["contacts.account"]
415
461
  })
416
462
  ].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. */
463
+ /**
464
+ * Holds the default cap on rows a `find` or `links` call returns when the caller omits `limit`,
465
+ * `1000` — the relation tool's default row ceiling.
466
+ */
418
467
  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. */
468
+ /**
469
+ * Holds the default cap on how many `include` path segments deep a `load` or `find` call may
470
+ * traverse, `3` — the relation tool's default include-depth ceiling.
471
+ */
420
472
  var RELATION_TOOL_DEPTH = 3;
421
473
  /**
422
- * The name {@link import('./factories.js').createInferTool} advertises by default — the key a
423
- * model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
474
+ * Holds the name {@link import('./factories.js').createInferTool} advertises by default, `'infer'`
475
+ * — the key a model calls and the `ToolManagerInterface` (`@orkestrel/tool`) registers under.
424
476
  */
425
477
  var INFER_TOOL_NAME = "infer";
426
478
  /**
427
- * The lean {@link import('@orkestrel/tool').ToolInterface.summary} {@link import('./factories.js').createInferTool}
428
- * advertises in place of {@link INFER_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
429
- * (`@orkestrel/tool`) advertises `summary ?? description`, so this one-sentence text stands in
430
- * for the full teaching description; the full text stays retrievable via
431
- * {@link import('./factories.js').createDescribeTool}.
479
+ * Holds the lean {@link import('@orkestrel/tool').ToolInterface.summary}
480
+ * {@link import('./factories.js').createInferTool} advertises in place of
481
+ * {@link INFER_TOOL_DESCRIPTION} — one sentence offering schema inference from example values and
482
+ * pointing at `describe` for the fields it takes.
483
+ *
484
+ * @remarks
485
+ * A `ToolManagerInterface.definitions()` call (`@orkestrel/tool`) advertises
486
+ * `summary ?? description`, so this one-sentence text stands in for the full teaching description;
487
+ * the full text stays retrievable through {@link import('./factories.js').createDescribeTool}.
432
488
  */
433
489
  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. */
490
+ /**
491
+ * Holds the schema-inference protocol {@link import('./factories.js').createInferTool} advertises —
492
+ * the required `samples`, the optional `format`, `enum`, and `candidates` arguments, and a worked
493
+ * example of the bare return and of the `candidates`-wrapped return.
494
+ */
435
495
  var INFER_TOOL_DESCRIPTION = [
436
496
  "Infer a JSON Schema from example values, returned in the same shape a tool advertises its parameters.",
437
497
  "",
@@ -444,7 +504,7 @@ var INFER_TOOL_DESCRIPTION = [
444
504
  " is wrapped as { parameters, checks } instead of the bare parameters record, one",
445
505
  " check per candidate (same index). Every check has the uniform shape",
446
506
  " { 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",
507
+ " — for example the number 7 is NOT valid against a string slot. `coercible` answers a",
448
508
  " separate question: would the SAME value be accepted by an endpoint tool call,",
449
509
  " whose enforcement NORMALIZES args (7 coerces to '7')? So 7 against a string slot",
450
510
  " yields { valid: false, coercible: true, faults: [] } — a strict mismatch that",
@@ -524,7 +584,7 @@ var INFER_TOOL_DESCRIPTION = [
524
584
  //#endregion
525
585
  //#region src/core/errors.ts
526
586
  /**
527
- * A package-owned tool-call failure: malformed input or unresolved configuration (`TOOL`),
587
+ * Represents a package-owned tool-call failure: malformed input or unresolved configuration (`TOOL`),
528
588
  * delegation depth/cycle rejection (`DEPTH`), prompt failure (`DEADLOCK` / `EXPIRE` / `ANSWER`),
529
589
  * or a translated upstream database/relation failure (`DATABASE` / `RELATION`).
530
590
  *
@@ -556,10 +616,10 @@ var ToolboxError = class extends Error {
556
616
  }
557
617
  };
558
618
  /**
559
- * Type guard narrowing an unknown caught value to an {@link ToolboxError}.
619
+ * Narrows an unknown caught value to a {@link ToolboxError}.
560
620
  *
561
621
  * @param value - The value to test (typically a `catch` binding)
562
- * @returns `true` when `value` is an {@link ToolboxError}
622
+ * @returns True if `value` is an {@link ToolboxError}; false otherwise
563
623
  *
564
624
  * @example
565
625
  * ```ts
@@ -576,9 +636,102 @@ function isToolboxError(value) {
576
636
  return value instanceof ToolboxError;
577
637
  }
578
638
  //#endregion
639
+ //#region src/core/validators.ts
640
+ /**
641
+ * Narrows an unknown value to a valid alternating workflow lineage.
642
+ *
643
+ * @param value - The value to inspect
644
+ * @returns True if `value` is a unique, nonempty-tagged workflow/agent chain; false otherwise
645
+ */
646
+ function isWorkflowLineage(value) {
647
+ const inspected = (0, _orkestrel_contract.attempt)(() => {
648
+ if (!Array.isArray(value)) return false;
649
+ const seen = /* @__PURE__ */ new Set();
650
+ for (const [index, tag] of value.entries()) {
651
+ if (!(0, _orkestrel_contract.isString)(tag)) return false;
652
+ const prefix = index % 2 === 0 ? "workflow:" : "agent:";
653
+ if (!tag.startsWith(prefix) || tag.length === prefix.length || seen.has(tag)) return false;
654
+ seen.add(tag);
655
+ }
656
+ return true;
657
+ });
658
+ return inspected.success && inspected.value;
659
+ }
660
+ /**
661
+ * Narrows an unknown callable to Toolbox's frozen contextual agent adapter metadata.
662
+ *
663
+ * @param value - The value to inspect
664
+ * @returns True if it is a frozen {@link AgentFunction} with a frozen valid lineage; false otherwise
665
+ */
666
+ function isAgentFunction(value) {
667
+ const inspected = (0, _orkestrel_contract.attempt)(() => {
668
+ if (typeof value !== "function" || !Object.isFrozen(value)) return false;
669
+ const category = Reflect.getOwnPropertyDescriptor(value, "category");
670
+ const lineage = Reflect.getOwnPropertyDescriptor(value, "lineage");
671
+ return category?.value === "agent" && lineage !== void 0 && "value" in lineage && Object.isFrozen(lineage.value) && isWorkflowLineage(lineage.value);
672
+ });
673
+ return inspected.success && inspected.value;
674
+ }
675
+ /**
676
+ * Narrows an unknown value to a {@link ColumnSpec}.
677
+ *
678
+ * @param value - The value to inspect
679
+ * @returns True if `value` is a valid {@link ColumnPrimitive} shorthand or a `{ primitive, optional }` record with a valid `primitive`; false otherwise
680
+ */
681
+ function isColumnSpec(value) {
682
+ if (isColumnPrimitive(value)) return true;
683
+ if (!(0, _orkestrel_contract.isRecord)(value)) return false;
684
+ return isColumnPrimitive(value.primitive) && (value.optional === void 0 || typeof value.optional === "boolean");
685
+ }
686
+ /**
687
+ * Narrows an unknown value to a {@link ColumnPrimitive}.
688
+ *
689
+ * @param value - The value to inspect
690
+ * @returns True if `value` is `'string'`, `'integer'`, `'number'`, or `'boolean'`; false otherwise
691
+ */
692
+ function isColumnPrimitive(value) {
693
+ return value === "string" || value === "integer" || value === "number" || value === "boolean";
694
+ }
695
+ /**
696
+ * Narrows an unknown value to a {@link DatabaseDefinition} — a non-empty `id` and `driver`, a
697
+ * `tables` record whose every value is `{ columns: record of valid ColumnSpec }`, plus optional
698
+ * `primary`, `indexes`, and finite `version` schema configuration. The boundary guard a
699
+ * {@link import('./types.js').DefinitionStoreInterface} applies to an untrusted persisted blob
700
+ * before trusting it as a definition (never an `as`).
701
+ *
702
+ * @param value - The value to inspect
703
+ * @returns True if `value` is a complete {@link DatabaseDefinition}; false otherwise
704
+ */
705
+ function isDatabaseDefinition(value) {
706
+ if (!(0, _orkestrel_contract.isRecord)(value)) return false;
707
+ if ("keys" in value) return false;
708
+ if (!(0, _orkestrel_contract.isNonEmptyString)(value.id) || !(0, _orkestrel_contract.isNonEmptyString)(value.driver)) return false;
709
+ if (!(0, _orkestrel_contract.isRecord)(value.tables)) return false;
710
+ for (const table of Object.values(value.tables)) {
711
+ if (!(0, _orkestrel_contract.isRecord)(table) || !(0, _orkestrel_contract.isRecord)(table.columns)) return false;
712
+ for (const column of Object.values(table.columns)) if (!isColumnSpec(column)) return false;
713
+ }
714
+ if (value.primary !== void 0) {
715
+ if (!(0, _orkestrel_contract.isRecord)(value.primary)) return false;
716
+ for (const key of Object.values(value.primary)) if (!(0, _orkestrel_contract.isNonEmptyString)(key)) return false;
717
+ }
718
+ if (value.indexes !== void 0) {
719
+ if (!(0, _orkestrel_contract.isRecord)(value.indexes)) return false;
720
+ for (const groups of Object.values(value.indexes)) {
721
+ if (!Array.isArray(groups)) return false;
722
+ for (const group of groups) {
723
+ if (!Array.isArray(group) || group.length === 0) return false;
724
+ for (const column of group) if (!(0, _orkestrel_contract.isNonEmptyString)(column)) return false;
725
+ }
726
+ }
727
+ }
728
+ if (value.version !== void 0 && !(0, _orkestrel_contract.isFiniteNumber)(value.version)) return false;
729
+ return true;
730
+ }
731
+ //#endregion
579
732
  //#region src/core/shapers.ts
580
733
  /**
581
- * The shape of {@link import('./factories.js').createPromptTool}'s call arguments — `to` names the
734
+ * Describes the shape of {@link import('./factories.js').createPromptTool}'s call arguments — `to` names the
582
735
  * terminal identity and `schema` carries the complete multi-field form document.
583
736
  *
584
737
  * @remarks
@@ -593,7 +746,7 @@ var promptToolShape = (0, _orkestrel_contract.objectShape)({
593
746
  schema: (0, _orkestrel_contract.jsonShape)({ description: "The @orkestrel/form schema to ask, with form metadata and one or more typed fields." })
594
747
  });
595
748
  /**
596
- * The shape of {@link import('./factories.js').createAnswerTool}'s call arguments — discriminated
749
+ * Describes the shape of {@link import('./factories.js').createAnswerTool}'s call arguments — discriminated
597
750
  * by `operation`: `'pending'` lists the forms addressed to this tool's terminal, while `'answer'`
598
751
  * resolves one by `id` with a complete `values` record.
599
752
  *
@@ -601,7 +754,7 @@ var promptToolShape = (0, _orkestrel_contract.objectShape)({
601
754
  * `values` is first bounded to exact JSON. The handler then narrows it with the originating Form
602
755
  * package's `isFormValues` guard before the terminal manager applies it to the parked live form.
603
756
  */
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)({
757
+ 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
758
  operation: (0, _orkestrel_contract.literalShape)(["answer"], { description: "Answer one pending form by id." }),
606
759
  id: (0, _orkestrel_contract.stringShape)({
607
760
  min: 1,
@@ -610,7 +763,7 @@ var answerToolShape = (0, _orkestrel_contract.unionShape)((0, _orkestrel_contrac
610
763
  values: (0, _orkestrel_contract.jsonShape)({ description: "The form answers keyed by field name." })
611
764
  }));
612
765
  /**
613
- * The shape of {@link import('./types.js').AgentToolArguments} —
766
+ * Describes the shape of {@link import('./types.js').AgentToolArguments} —
614
767
  * {@link import('./factories.js').createAgentTool}'s advertised `parameters`.
615
768
  *
616
769
  * @remarks
@@ -620,7 +773,7 @@ var answerToolShape = (0, _orkestrel_contract.unionShape)((0, _orkestrel_contrac
620
773
  var agentToolShape = (0, _orkestrel_contract.objectShape)({
621
774
  task: (0, _orkestrel_contract.stringShape)({
622
775
  min: 1,
623
- description: "The instructions the sub-agent should carry out."
776
+ description: "The instructions the sub-agent carries out."
624
777
  }),
625
778
  provider: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
626
779
  min: 1,
@@ -630,7 +783,7 @@ var agentToolShape = (0, _orkestrel_contract.objectShape)({
630
783
  system: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({ description: "A system prompt seeding the sub-agent's context (overrides the default)." }))
631
784
  });
632
785
  /**
633
- * The shape of {@link import('./types.js').DescribeToolArguments} —
786
+ * Describes the shape of {@link import('./types.js').DescribeToolArguments} —
634
787
  * {@link import('./factories.js').createDescribeTool}'s advertised `parameters`.
635
788
  *
636
789
  * @remarks
@@ -641,8 +794,8 @@ var describeToolShape = (0, _orkestrel_contract.objectShape)({ name: (0, _orkest
641
794
  description: "The registered name of the tool whose full description to return."
642
795
  }) });
643
796
  /**
644
- * The shape of a {@link import('./types.js').TaskDraft} — identical to a strict task shape
645
- * EXCEPT `id` and `name` are OPTIONAL.
797
+ * Describes the shape of a {@link import('./types.js').TaskDraft} — identical to a strict task
798
+ * shape except that `id` and `name` are optional.
646
799
  */
647
800
  var taskDraftShape = (0, _orkestrel_contract.objectShape)({
648
801
  id: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
@@ -654,7 +807,7 @@ var taskDraftShape = (0, _orkestrel_contract.objectShape)({
654
807
  description: "Task name; defaults to the id when omitted."
655
808
  })),
656
809
  description: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({ description: "Optional task description." })),
657
- run: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
810
+ behavior: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
658
811
  min: 1,
659
812
  description: "The registered behavior name to invoke (a registry key, not a label); omitted completes with JSON null."
660
813
  })),
@@ -669,8 +822,8 @@ var taskDraftShape = (0, _orkestrel_contract.objectShape)({
669
822
  }))
670
823
  });
671
824
  /**
672
- * The shape of a PHASE in a draft workflow — identical to a strict phase shape EXCEPT `id` and
673
- * `name` are OPTIONAL, and its tasks are {@link taskDraftShape}s.
825
+ * Describes the shape of a phase in a draft workflow — identical to a strict phase shape except
826
+ * that `id` and `name` are optional and each task takes {@link taskDraftShape}.
674
827
  */
675
828
  var phaseDraftShape = (0, _orkestrel_contract.objectShape)({
676
829
  id: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
@@ -690,17 +843,17 @@ var phaseDraftShape = (0, _orkestrel_contract.objectShape)({
690
843
  bail: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.literalShape)([true, false], { description: "Per-phase failure-policy override; omitted inherits the workflow bail." }))
691
844
  });
692
845
  /**
693
- * The shape of a DRAFT workflow — identical to a strict workflow shape EXCEPT `id` and `name`
694
- * are OPTIONAL at all three levels (workflow / phase / task), so a small model can omit the six
695
- * identity strings and let the tool synthesize them positionally.
846
+ * Describes the shape of a draft workflow — identical to a strict workflow shape except that `id`
847
+ * and `name` are optional at the workflow, phase, and task levels, so a small model can omit every
848
+ * identity string and let the tool synthesize them positionally.
696
849
  *
697
850
  * @remarks
698
851
  * 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
852
+ * `behavior` stays optional like the strict form; omission is the deliberate JSON `null` no-op. A
700
853
  * provided `id` / `name` still has `minLength: 1` (so
701
- * an explicitly-empty `id: ''` is REJECTED, not auto-filled). After
854
+ * an explicitly-empty `id: ''` is rejected, not auto-filled). After
702
855
  * {@link import('./helpers.js').completeDraft} fills the missing ids/names, the result is
703
- * validated against the STRICT `createWorkflowContract` (`@orkestrel/workflow`) gate before
856
+ * validated against the strict `createWorkflowContract` (`@orkestrel/workflow`) gate before
704
857
  * running.
705
858
  */
706
859
  var workflowDraftShape = (0, _orkestrel_contract.objectShape)({
@@ -717,27 +870,29 @@ var workflowDraftShape = (0, _orkestrel_contract.objectShape)({
717
870
  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
871
  });
719
872
  /**
720
- * The shape of ONE flat step — `{ name }` — the building block of {@link workflowStepsShape}.
873
+ * Describes the shape of one flat step — `{ name }` — the building block of
874
+ * {@link workflowStepsShape}.
721
875
  *
722
876
  * @remarks
723
- * `name` is the REGISTERED behavior name the step runs (it becomes the task's `run`). The tool
877
+ * `name` is the registered behavior name the step runs (it becomes the task's `behavior`). The tool
724
878
  * expands each step into a one-task phase, in order ({@link import('./helpers.js').expandSteps}).
725
879
  */
726
880
  var stepShape = (0, _orkestrel_contract.objectShape)({ name: (0, _orkestrel_contract.stringShape)({
727
881
  min: 1,
728
- description: "The registered behavior name this step runs (becomes the task run)."
882
+ description: "The registered behavior name this step runs (becomes the task behavior)."
729
883
  }) });
730
884
  /**
731
- * The FLAT authoring shape {@link import('./factories.js').createWorkflowTool} advertises as its
732
- * `parameters` — the simplest surface a small model can fill: `{ name?, steps: [{ name }] }`.
885
+ * Describes the flat authoring shape {@link import('./factories.js').createWorkflowTool} advertises
886
+ * as its `parameters` — the simplest surface a small model can fill:
887
+ * `{ name?, steps: [{ name }] }`.
733
888
  *
734
889
  * @remarks
735
890
  * A deliberately-reduced surface: a flat ordered list of steps, each a `{ name }`. The tool
736
- * EXPANDS it ({@link import('./helpers.js').expandSteps}) into a full
891
+ * expands it ({@link import('./helpers.js').expandSteps}) into a full
737
892
  * {@link import('./types.js').WorkflowDefinition} — one one-task phase per step, in order —
738
- * then validates against the STRICT `createWorkflowContract` (`@orkestrel/workflow`) gate. The
739
- * full nested form is STILL accepted by the tool (it branches on the args' shape) and is
740
- * documented as the advanced escape-hatch in the tool's description — but THIS is what
893
+ * then validates against the strict `createWorkflowContract` (`@orkestrel/workflow`) gate. The
894
+ * full nested form is still accepted by the tool (it branches on the args' shape) and is
895
+ * documented as the advanced escape-hatch in the tool's description — but this is what
741
896
  * `parameters` advertises.
742
897
  */
743
898
  var workflowStepsShape = (0, _orkestrel_contract.objectShape)({
@@ -748,20 +903,20 @@ var workflowStepsShape = (0, _orkestrel_contract.objectShape)({
748
903
  steps: (0, _orkestrel_contract.arrayShape)(stepShape, { description: "The ordered steps to run, one after another (each becomes a one-task phase)." })
749
904
  });
750
905
  /**
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` /
906
+ * Describes the shape of a {@link import('./types.js').WorkspaceOperation} — a descriptive tagged union
907
+ * over the workspace edit, read, and navigation operations, discriminated by the `operation`
908
+ * literal (never a bare `kind`). Each variant leads with its `operation`
909
+ * discriminant then its flat fields, every field through `stringShape` / `optionalShape` /
755
910
  * `integerShape({ min: 1 })` / `booleanShape`, each carrying a strong field-level `description`.
756
911
  *
757
912
  * @remarks
758
- * The union compiles to an `anyOf` JSON Schema + a `unionOf` guard + a first-match parser
913
+ * The union compiles to an `anyOf` JSON Schema, a `unionOf` guard, and a first-match parser
759
914
  * automatically ({@link import('./factories.js').createWorkspaceTool} types the result to the
760
- * hand-written {@link import('./types.js').WorkspaceOperation}). `limit` and the four `'splice'`
761
- * caret components are POSITIVE integers (`integerShape({ min: 1 })`); `regex` / `sensitive`
762
- * are `optionalShape(booleanShape(...))`. The two REGISTRY arms — `workspaces` (list the
915
+ * hand-written {@link import('./types.js').WorkspaceOperation}). `limit` and the `'splice'`
916
+ * caret components are positive integers (`integerShape({ min: 1 })`); `regex` / `sensitive`
917
+ * are `optionalShape(booleanShape(...))`. The registry arms — `workspaces` (list the
763
918
  * workspaces the model can move between) and `switch` (re-point the active one by `id`) — let a
764
- * model DISCOVER then CHOOSE which workspace the edit / read arms target.
919
+ * model discover then choose which workspace the edit / read arms target.
765
920
  */
766
921
  var workspaceToolShape = (0, _orkestrel_contract.unionShape)((0, _orkestrel_contract.objectShape)({
767
922
  operation: (0, _orkestrel_contract.literalShape)(["read"], { description: "Read a whole text file's text by path." }),
@@ -831,27 +986,37 @@ var workspaceToolShape = (0, _orkestrel_contract.unionShape)((0, _orkestrel_cont
831
986
  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
987
  id: (0, _orkestrel_contract.stringShape)({ description: "The id of the workspace to make active (from the \"workspaces\" listing)." })
833
988
  }));
834
- /** A {@link import('./types.js').ColumnKind} literal — the leaf {@link columnSpecShape} wraps. */
835
- var columnKindShape = (0, _orkestrel_contract.literalShape)([
989
+ /** Describes a {@link import('./types.js').ColumnPrimitive} literal — the leaf {@link columnSpecShape} wraps. */
990
+ var columnPrimitiveShape = (0, _orkestrel_contract.literalShape)([
836
991
  "string",
837
992
  "integer",
838
993
  "number",
839
994
  "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,
995
+ ], { description: "A column primitive: \"string\" | \"integer\" | \"number\" | \"boolean\"." });
996
+ /** Describes a {@link import('./types.js').ColumnSpec} — a bare {@link columnPrimitiveShape}, or `{ primitive, optional }`. */
997
+ var columnSpecShape = (0, _orkestrel_contract.unionShape)(columnPrimitiveShape, (0, _orkestrel_contract.objectShape)({
998
+ primitive: columnPrimitiveShape,
844
999
  optional: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.booleanShape)({ description: "Whether the column may be absent from a row." }))
845
1000
  }));
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. */
1001
+ /** Describes a {@link import('./types.js').TableSpec} — table name to `{ columns }`, each column a {@link columnSpecShape}. */
1002
+ 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." });
1003
+ /**
1004
+ * Describes one key value for the database tool and the relation tool — a string or number; the
1005
+ * array form (multiple keys, positional) resolves first, so an array argument is read as many keys
1006
+ * rather than one.
1007
+ */
849
1008
  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. */
1009
+ /** Describes a loose row — a flat object of column name to JSON value. */
851
1010
  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. */
1011
+ /**
1012
+ * Describes one or many loose rows — the array form resolves first, so an array argument is read as
1013
+ * many rows rather than one.
1014
+ */
853
1015
  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. */
1016
+ /**
1017
+ * Describes one serialized where condition — `values` is always an array, even for a single-value
1018
+ * operator.
1019
+ */
855
1020
  var conditionShape = (0, _orkestrel_contract.objectShape)({
856
1021
  column: (0, _orkestrel_contract.stringShape)({ description: "The column this condition applies to." }),
857
1022
  operator: (0, _orkestrel_contract.literalShape)([
@@ -874,12 +1039,12 @@ var conditionShape = (0, _orkestrel_contract.objectShape)({
874
1039
  values: (0, _orkestrel_contract.arrayShape)((0, _orkestrel_contract.jsonShape)(), { description: "The operand values the operator needs (always an array, even for one value)." }),
875
1040
  connector: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.literalShape)(["and", "or"], { description: "Joins this condition to the next; omit on the last condition." }))
876
1041
  });
877
- /** One sort term. */
1042
+ /** Describes one sort term — a `column` to sort by and the `direction` to sort it in. */
878
1043
  var orderShape = (0, _orkestrel_contract.objectShape)({
879
1044
  column: (0, _orkestrel_contract.stringShape)({ description: "The column to sort by." }),
880
1045
  direction: (0, _orkestrel_contract.literalShape)(["ascending", "descending"], { description: "The sort direction." })
881
1046
  });
882
- /** The SERIALIZED query form — conditions, order, and pagination. */
1047
+ /** Describes the serialized query form — conditions, order, and pagination. */
883
1048
  var queryShape = (0, _orkestrel_contract.objectShape)({
884
1049
  conditions: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.arrayShape)(conditionShape, { description: "The WHERE conditions, folded left to right." })),
885
1050
  order: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.arrayShape)(orderShape, { description: "The sort terms, applied in order." })),
@@ -893,18 +1058,17 @@ var queryShape = (0, _orkestrel_contract.objectShape)({
893
1058
  }))
894
1059
  });
895
1060
  /**
896
- * The shape of {@link import('./factories.js').createDatabaseTool}'s call arguments —
897
- * discriminated by `operation` into the 11 database operations (`'create'` / `'tables'` /
898
- * `'get'` / `'records'` / `'count'` / `'aggregate'` / `'add'` / `'set'` / `'update'` /
899
- * `'remove'` / `'destroy'`).
1061
+ * Describes the shape of {@link import('./factories.js').createDatabaseTool}'s call arguments —
1062
+ * discriminated by `operation` into the database operations `'create'`, `'tables'`, `'get'`,
1063
+ * `'records'`, `'count'`, `'aggregate'`, `'add'`, `'set'`, `'update'`, `'remove'`, and `'destroy'`.
900
1064
  *
901
1065
  * @remarks
902
1066
  * 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`
1067
+ * {@link import('./types.js').TableSpec} column DSL, compiled through
1068
+ * {@link import('./compilers.js').expandTables}); `'get'` / `'update'` / `'remove'` carry `key`
905
1069
  * (one key or an array of keys, positional); `'add'` / `'set'` carry `row` (one row or an array of
906
1070
  * rows); `'update'` also carries `changes` (a loose partial row); `'records'` / `'count'` /
907
- * `'aggregate'` carry an optional `query` (the SERIALIZED form — `values` is ALWAYS an array,
1071
+ * `'aggregate'` carry an optional `query` (the serialized form — `values` is always an array,
908
1072
  * even for a single-value operator, so a caller never chains method calls or guesses arity).
909
1073
  */
910
1074
  var databaseToolShape = (0, _orkestrel_contract.unionShape)((0, _orkestrel_contract.objectShape)({
@@ -1037,21 +1201,19 @@ var databaseToolShape = (0, _orkestrel_contract.unionShape)((0, _orkestrel_contr
1037
1201
  description: "The database id."
1038
1202
  })
1039
1203
  }));
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. */
1204
+ /** Describes a single row key (not an array) — used by `'link'` / `'unlink'` / `'links'`, which address exactly one owning row. */
1043
1205
  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. */
1206
+ /** Describes the flat dot-path relation include list, expanded through {@link import('./helpers.js').expandInclude}. */
1207
+ 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." }));
1208
+ /** Describes which registered relation manager to address — omitted resolves to the sole registered manager. */
1047
1209
  var managerShape = (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
1048
1210
  min: 1,
1049
1211
  description: "Which registered relation manager to address."
1050
1212
  }));
1051
1213
  /**
1052
- * The shape of {@link import('./factories.js').createRelationTool}'s call arguments —
1053
- * discriminated by `operation` into the 5 relation operations (`'load'` / `'find'` / `'link'` /
1054
- * `'unlink'` / `'links'`).
1214
+ * Describes the shape of {@link import('./factories.js').createRelationTool}'s call arguments —
1215
+ * discriminated by `operation` into the relation operations `'load'`, `'find'`, `'link'`,
1216
+ * `'unlink'`, and `'links'`.
1055
1217
  *
1056
1218
  * @remarks
1057
1219
  * `'load'` fetches one or more rows (positional key/array) with `include` attached. `'find'`
@@ -1065,7 +1227,7 @@ var relationToolShape = (0, _orkestrel_contract.unionShape)((0, _orkestrel_contr
1065
1227
  min: 1,
1066
1228
  description: "The model (table) name."
1067
1229
  }),
1068
- key: relationKeyShape,
1230
+ key: keyShape,
1069
1231
  include: includeShape
1070
1232
  }), (0, _orkestrel_contract.objectShape)({
1071
1233
  operation: (0, _orkestrel_contract.literalShape)(["find"], { description: "List rows, with related rows attached." }),
@@ -1128,7 +1290,7 @@ var relationToolShape = (0, _orkestrel_contract.unionShape)((0, _orkestrel_contr
1128
1290
  })
1129
1291
  }));
1130
1292
  /**
1131
- * The shape of {@link import('./factories.js').createInferTool}'s call arguments — one or more
1293
+ * Describes the shape of {@link import('./factories.js').createInferTool}'s call arguments — one or more
1132
1294
  * example `samples` to infer a JSON Schema from, plus per-call `format` / `enum` toggles and an
1133
1295
  * optional `candidates` array to check against the inferred schema.
1134
1296
  *
@@ -1136,8 +1298,8 @@ var relationToolShape = (0, _orkestrel_contract.unionShape)((0, _orkestrel_contr
1136
1298
  * `samples` requires at least one element (`min: 1`) — an empty array parses to `undefined`,
1137
1299
  * surfaced by the handler as a typed `TOOL` {@link import('./errors.js').ToolboxError}. When
1138
1300
  * `candidates` is present (any array, including empty), the handler compiles a contract from the
1139
- * freshly inferred schema and checks each candidate against it with a STRICT guard (`.is`, no
1140
- * coercion) — the opposite of {@link import('./factories.js').createEndpointTool}'s NORMALIZING
1301
+ * freshly inferred schema and checks each candidate against it with a strict guard (`.is`, no
1302
+ * coercion) — the opposite of {@link import('./factories.js').createEndpointTool}'s normalizing
1141
1303
  * `.parse` enforcement.
1142
1304
  */
1143
1305
  var inferToolShape = (0, _orkestrel_contract.objectShape)({
@@ -1152,24 +1314,24 @@ var inferToolShape = (0, _orkestrel_contract.objectShape)({
1152
1314
  //#endregion
1153
1315
  //#region src/core/helpers.ts
1154
1316
  /**
1155
- * The ancestry identifier of a workflow in a run chain — `workflow:<id>`.
1317
+ * Returns the ancestry identifier of a workflow in a run chain — `workflow:<id>`.
1156
1318
  *
1157
1319
  * @remarks
1158
- * Namespacing keeps a workflow id and an {@link agentTag} agent name in ONE set without
1159
- * collision, so re-entering a workflow OR an agent already in the chain is a single `includes`
1320
+ * Namespacing keeps a workflow id and a {@link tagAgent} agent name in one set without
1321
+ * collision, so re-entering a workflow or an agent already in the chain is a single `includes`
1160
1322
  * check.
1161
1323
  *
1162
1324
  * @param id - The workflow definition's `id`
1163
1325
  * @returns The namespaced ancestry tag (`workflow:<id>`)
1164
1326
  */
1165
- function workflowTag(id) {
1327
+ function tagWorkflow(id) {
1166
1328
  return `workflow:${id}`;
1167
1329
  }
1168
1330
  /**
1169
- * The ancestry identifier of an agent in a run chain — `agent:<name>`.
1331
+ * Returns the ancestry identifier of an agent in a run chain — `agent:<name>`.
1170
1332
  *
1171
1333
  * @remarks
1172
- * The agent counterpart of {@link workflowTag}: {@link import('./factories.js').createAgentFunction}
1334
+ * The agent counterpart of {@link tagWorkflow}: {@link import('./factories.js').createAgentFunction}
1173
1335
  * / {@link import('./factories.js').createWorkflowTool} guard against re-entering an agent or
1174
1336
  * workflow already in the chain (this package's typed `DEPTH` `ToolboxError`). The
1175
1337
  * `agent:` namespace keeps it distinct from a same-string workflow id.
@@ -1177,88 +1339,53 @@ function workflowTag(id) {
1177
1339
  * @param name - The agent's identifier / registry name
1178
1340
  * @returns The namespaced ancestry tag (`agent:<name>`)
1179
1341
  */
1180
- function agentTag(name) {
1342
+ function tagAgent(name) {
1181
1343
  return `agent:${name}`;
1182
1344
  }
1183
1345
  /**
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.
1346
+ * Returns the canonical workflow lineage — validated, copied, and frozen.
1205
1347
  *
1206
1348
  * @param lineage - The configured chain; omitted means a direct root
1207
1349
  * @returns An immutable caller-isolated lineage
1208
1350
  */
1209
- function lineageOf(lineage = []) {
1351
+ function normalizeLineage(lineage = []) {
1210
1352
  if (!isWorkflowLineage(lineage)) throw new ToolboxError("TOOL", "workflow lineage must alternate unique workflow and agent tags");
1211
1353
  return Object.freeze([...lineage]);
1212
1354
  }
1213
1355
  /**
1214
- * Append one tag to a workflow lineage and return a frozen copy.
1356
+ * Appends one tag to a workflow lineage and returns a frozen copy.
1215
1357
  *
1216
1358
  * @param lineage - The valid chain to extend
1217
1359
  * @param tag - The workflow or agent tag to append
1218
1360
  * @returns The validated immutable extension
1219
1361
  */
1220
1362
  function extendLineage(lineage, tag) {
1221
- return lineageOf([...lineage, tag]);
1363
+ return normalizeLineage([...lineage, tag]);
1222
1364
  }
1223
1365
  /**
1224
- * Derive the zero-based workflow nesting depth from a valid lineage.
1366
+ * Derives the zero-based workflow nesting depth from a valid lineage.
1225
1367
  *
1226
1368
  * @param lineage - The workflow/agent chain
1227
1369
  * @returns Zero for an empty/root lineage, then one per nested workflow
1228
1370
  */
1229
1371
  function deriveWorkflowDepth(lineage) {
1230
- const workflows = lineageOf(lineage).filter((tag) => tag.startsWith("workflow:")).length;
1372
+ const workflows = normalizeLineage(lineage).filter((tag) => tag.startsWith("workflow:")).length;
1231
1373
  return Math.max(0, workflows - 1);
1232
1374
  }
1233
1375
  /**
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.
1376
+ * Builds the plain success summary {@link import('./factories.js').createWorkflowTool} returns on a
1377
+ * completed run — the universal tool-handler contract: return a plain value on success, appearing
1378
+ * identically over both the agent loop and MCP.
1252
1379
  *
1253
1380
  * @remarks
1254
- * The summary is LEAN: the workflow's terminal `status`, settled-task count, and exact optional
1381
+ * The summary is lean: the workflow's terminal `status`, settled-task count, and exact optional
1255
1382
  * native persistence outcome. It carries no synthetic `id` / `name`: a tool handler has no call
1256
1383
  * id; the `ToolManagerInterface` (`@orkestrel/tool`) supplies the canonical envelope's identity.
1257
1384
  *
1258
1385
  * @param result - The terminal `WorkflowResult` (`@orkestrel/workflow`) the run produced
1259
1386
  * @returns The plain success summary — `{ status, count, durable?, fault? }`
1260
1387
  */
1261
- function workflowToolSummary(result) {
1388
+ function summarizeWorkflow(result) {
1262
1389
  return {
1263
1390
  status: result.status,
1264
1391
  count: result.results.length,
@@ -1267,21 +1394,21 @@ function workflowToolSummary(result) {
1267
1394
  };
1268
1395
  }
1269
1396
  /**
1270
- * Complete a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesize any
1271
- * MISSING `id` deterministically + positionally, and default any MISSING `name` to its
1272
- * (now-resolved) `id`.
1397
+ * Completes a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesizes a
1398
+ * missing `id` deterministically and positionally, and defaults a missing `name` to its resolved
1399
+ * `id`.
1273
1400
  *
1274
1401
  * @remarks
1275
1402
  * The positional id scheme is stable and human-legible: the workflow is `wf`, phase `i` is
1276
1403
  * `phase-<i>`, and task `j` of that phase is `<phaseId>-task-<j>` (so a provided phase id flows
1277
- * into its tasks' synthesized ids). A PROVIDED `id` / `name` at any level is kept VERBATIM —
1404
+ * into its tasks' synthesized ids). A provided `id` / `name` at any level is kept verbatim —
1278
1405
  * 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
1406
+ * the other way round), so the result always carries an `id` and a `name`. `behavior`, `description`, the per-phase
1280
1407
  * `concurrency` / `bail`, the per-task `retries` / `timeout`, and the workflow `bail` carry over
1281
1408
  * unchanged. The result is a complete {@link WorkflowDefinition}; the caller still validates it
1282
- * against the STRICT contract.
1409
+ * against the strict contract.
1283
1410
  *
1284
- * @param draft - The draft workflow (id/name optional at all three levels)
1411
+ * @param draft - The draft workflow (`id` and `name` optional at the workflow, phase, and task levels)
1285
1412
  * @returns A complete {@link WorkflowDefinition} with every id/name filled
1286
1413
  */
1287
1414
  function completeDraft(draft) {
@@ -1295,7 +1422,7 @@ function completeDraft(draft) {
1295
1422
  };
1296
1423
  }
1297
1424
  /**
1298
- * Complete one {@link PhaseDraft} into a strict phase definition — the per-phase step of
1425
+ * Completes one {@link PhaseDraft} into a strict phase definition — the per-phase step of
1299
1426
  * {@link completeDraft} (phase `index` → `phase-<index>` when its id is omitted).
1300
1427
  *
1301
1428
  * @param phase - The draft phase
@@ -1314,7 +1441,7 @@ function completePhaseDraft(phase, index) {
1314
1441
  };
1315
1442
  }
1316
1443
  /**
1317
- * Complete one {@link TaskDraft} into a strict task definition — the per-task leaf step of
1444
+ * Completes one {@link TaskDraft} into a strict task definition — the per-task leaf step of
1318
1445
  * {@link completeDraft} (task `index` of phase `<phaseId>` → `<phaseId>-task-<index>` when its id
1319
1446
  * is omitted).
1320
1447
  *
@@ -1329,25 +1456,25 @@ function completeTaskDraft(task, phaseId, index) {
1329
1456
  id,
1330
1457
  name: task.name ?? id,
1331
1458
  ...task.description === void 0 ? {} : { description: task.description },
1332
- ...task.run === void 0 ? {} : { run: task.run },
1459
+ ...task.behavior === void 0 ? {} : { behavior: task.behavior },
1333
1460
  ...task.retries === void 0 ? {} : { retries: task.retries },
1334
1461
  ...task.timeout === void 0 ? {} : { timeout: task.timeout }
1335
1462
  };
1336
1463
  }
1337
1464
  /**
1338
- * Expand a flat {@link WorkflowSteps} blob into a strict {@link WorkflowDefinition} — each step
1339
- * becomes a one-task phase, IN ORDER.
1465
+ * Expands a flat {@link WorkflowSteps} blob into a strict {@link WorkflowDefinition} — each step
1466
+ * becomes a one-task phase, in order.
1340
1467
  *
1341
1468
  * @remarks
1342
- * The expansion of the tool's ADVERTISED surface: the deliberately-reduced flat form. Each
1469
+ * The expansion of the tool's advertised surface: the deliberately-reduced flat form. Each
1343
1470
  * {@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
1471
+ * `name` becomes the task's `behavior` (the behavior-registry key). Ids/names are auto-filled
1345
1472
  * positionally — it builds an ids-omitted {@link WorkflowDraft} and delegates to
1346
- * {@link completeDraft}, so the two lenient surfaces share ONE synthesis path (step `i` → phase
1473
+ * {@link completeDraft}, so the lenient surfaces share one synthesis path (step `i` → phase
1347
1474
  * `phase-<i>`, its task `phase-<i>-task-0`). The optional `name` becomes both the workflow's
1348
1475
  * deterministic id and its name, so named flat workflows retain distinct persistence keys;
1349
1476
  * omission keeps the shared draft fallback `wf`. The result is a complete definition the caller
1350
- * validates against the STRICT contract before running.
1477
+ * validates against the strict contract before running.
1351
1478
  *
1352
1479
  * @param flat - The flat steps blob (`{ name?, steps: [{ name }] }`)
1353
1480
  * @returns A complete {@link WorkflowDefinition} (one one-task phase per step)
@@ -1358,12 +1485,12 @@ function expandSteps(flat) {
1358
1485
  id: flat.name,
1359
1486
  name: flat.name
1360
1487
  },
1361
- phases: flat.steps.map((step) => ({ tasks: [{ run: step.name }] }))
1488
+ phases: flat.steps.map((step) => ({ tasks: [{ behavior: step.name }] }))
1362
1489
  });
1363
1490
  }
1364
1491
  /**
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.
1492
+ * Maps a caught error to the {@link ToolboxErrorCode} the terminal-tool factory throws with — the
1493
+ * pure classification step of that factory's error handling.
1367
1494
  *
1368
1495
  * @remarks
1369
1496
  * Narrows `error` with {@link isTerminalError} (`@orkestrel/terminal`) first: a non-`TerminalError`
@@ -1376,119 +1503,46 @@ function expandSteps(flat) {
1376
1503
  * @param error - The value caught from a terminal-manager operation (`ask` / `answer` / …)
1377
1504
  * @returns The mapped {@link ToolboxErrorCode}, or `undefined` if `error` is not a `TerminalError`
1378
1505
  */
1379
- function terminalToolCode(error) {
1506
+ function inferTerminalCode(error) {
1380
1507
  if (!(0, _orkestrel_terminal.isTerminalError)(error)) return void 0;
1381
1508
  if (error.code === "DEADLOCK") return "DEADLOCK";
1382
1509
  if (error.code === "EXPIRE") return "EXPIRE";
1383
1510
  return "TOOL";
1384
1511
  }
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
1512
  /**
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`.
1513
+ * Maps a caught error to the granular {@link DatabaseErrorCode} (`@orkestrel/database`) the code
1514
+ * {@link import('./factories.js').createDatabaseTool} throws with — the pure classification step
1515
+ * of that factory's error handling, mirroring {@link inferTerminalCode}'s idiom for
1516
+ * `@orkestrel/database`.
1464
1517
  *
1465
1518
  * @param error - The value caught from a `@orkestrel/database` table operation
1466
1519
  * @returns The granular {@link DatabaseErrorCode}, or `undefined` if `error` is not a `DatabaseError`
1467
1520
  */
1468
- function databaseToolCode(error) {
1521
+ function inferDatabaseCode(error) {
1469
1522
  return (0, _orkestrel_database.isDatabaseError)(error) ? error.code : void 0;
1470
1523
  }
1471
1524
  /**
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`.
1525
+ * Maps a caught error to the granular {@link RelationErrorCode} (`@orkestrel/relation`) the code
1526
+ * {@link import('./factories.js').createRelationTool} throws with — the pure classification step
1527
+ * of that factory's error handling, mirroring {@link inferTerminalCode}'s idiom for
1528
+ * `@orkestrel/relation`.
1475
1529
  *
1476
1530
  * @param error - The value caught from a `@orkestrel/relation` operation
1477
1531
  * @returns The granular {@link RelationErrorCode}, or `undefined` if `error` is not a `RelationError`
1478
1532
  */
1479
- function relationToolCode(error) {
1533
+ function inferRelationCode(error) {
1480
1534
  return (0, _orkestrel_relation.isRelationError)(error) ? error.code : void 0;
1481
1535
  }
1482
1536
  /**
1483
- * Expand the relation tool's FLAT dot-path `include` list into a live `@orkestrel/relation`
1537
+ * Expands the relation tool's flat dot-path `include` list into a live `@orkestrel/relation`
1484
1538
  * {@link Include} tree — the pure leaf {@link import('./factories.js').createRelationTool} calls
1485
1539
  * before a `'load'` / `'find'` call.
1486
1540
  *
1487
1541
  * @remarks
1488
1542
  * Each path splits on `'.'` into a chain of relation names, deep-merged into one nested
1489
- * `Include` object with a leaf `true`. A longer path SUBSUMES a shorter sibling's bare `true` —
1543
+ * `Include` object with a leaf `true`. A longer path subsumes a shorter sibling's bare `true` —
1490
1544
  * `'contacts'` followed by `'contacts.account'` yields `{ contacts: { account: true } }`, never
1491
- * overwriting the deeper chain. An EMPTY segment (`''`, from a leading/trailing/doubled `.`) or a
1545
+ * overwriting the deeper chain. An empty segment (`''`, from a leading/trailing/doubled `.`) or a
1492
1546
  * path whose segment count exceeds `depth` throws a typed `TOOL` {@link ToolboxError}.
1493
1547
  *
1494
1548
  * @param paths - The flat dot-path `include` list (or `undefined` — yields `{}`)
@@ -1551,20 +1605,20 @@ function expandInclude(paths, depth) {
1551
1605
  return include;
1552
1606
  }
1553
1607
  /**
1554
- * Resolve which registered {@link RelationManagerInterface} a relation-tool call addresses — the
1608
+ * Resolves which registered {@link RelationManagerInterface} a relation-tool call addresses — the
1555
1609
  * pure manager-resolution leaf {@link import('./factories.js').createRelationTool} calls on
1556
1610
  * every operation.
1557
1611
  *
1558
1612
  * @remarks
1559
1613
  * An explicit `name` must match a key of `managers` (a miss throws a typed `TOOL`
1560
- * {@link ToolboxError} naming the registered managers). An OMITTED `name` resolves to the sole
1614
+ * {@link ToolboxError} naming the registered managers). An omitted `name` resolves to the sole
1561
1615
  * registered manager when exactly one is registered, else throws the same typed error.
1562
1616
  *
1563
1617
  * @param managers - The tool's registered `RelationManagerInterface` map
1564
1618
  * @param name - The call's optional `manager` field
1565
1619
  * @returns The resolved {@link RelationManagerInterface}
1566
1620
  */
1567
- function relationManagerOf(managers, name) {
1621
+ function resolveRelationManager(managers, name) {
1568
1622
  if (name !== void 0) {
1569
1623
  const manager = managers[name];
1570
1624
  if (manager === void 0) throw new ToolboxError("TOOL", `unknown relation manager '${name}'`, {
@@ -1582,35 +1636,35 @@ function relationManagerOf(managers, name) {
1582
1636
  throw new ToolboxError("TOOL", "no relation manager resolved for the call", { managers: names });
1583
1637
  }
1584
1638
  /**
1585
- * Resolve a `model` name against a live {@link RelationManagerInterface} — the pure model-lookup
1639
+ * Resolves a `model` name against a live {@link RelationManagerInterface} — the pure model-lookup
1586
1640
  * leaf {@link import('./factories.js').createRelationTool} calls on every operation, mirroring
1587
- * {@link relationManagerOf}'s guard shape.
1641
+ * {@link resolveRelationManager}'s guard shape.
1588
1642
  *
1589
1643
  * @param manager - The resolved {@link RelationManagerInterface}
1590
1644
  * @param name - The call's `model` field
1591
1645
  * @returns The model's {@link ModelInterface}
1592
1646
  */
1593
- function relationModelOf(manager, name) {
1647
+ function resolveRelationModel(manager, name) {
1594
1648
  if (!manager.has(name)) throw new ToolboxError("TOOL", `unknown model '${name}'`, {
1595
1649
  model: name,
1596
- models: manager.models()
1650
+ models: manager.names()
1597
1651
  });
1598
1652
  return manager.model(name);
1599
1653
  }
1600
1654
  /**
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'`.
1655
+ * Returns the canonical live `@orkestrel/database` {@link QueryInput} for the database tool's
1656
+ * parsed serialized query — each condition's omitted `connector` defaults to `'and'`.
1603
1657
  *
1604
1658
  * @remarks
1605
1659
  * The wire form ({@link import('./shapers.js').databaseToolShape}) lets a caller drop `connector`
1606
- * on the last condition (it has nothing to join FORWARD to); the compiled `Condition` a live
1660
+ * on the last condition (it has nothing to join forward to); the compiled `Condition` a live
1607
1661
  * `@orkestrel/database` table call accepts always carries one, so this fills the gap. `order` /
1608
1662
  * `limit` / `offset` pass through unchanged. Pure and total.
1609
1663
  *
1610
1664
  * @param query - The parsed query (or `undefined`)
1611
1665
  * @returns The equivalent live `QueryInput`, or `undefined` when `query` is `undefined`
1612
1666
  */
1613
- function queryOf(query) {
1667
+ function normalizeQuery(query) {
1614
1668
  if (query === void 0) return void 0;
1615
1669
  const conditions = query.conditions?.map((condition) => ({
1616
1670
  ...condition,
@@ -1624,14 +1678,39 @@ function queryOf(query) {
1624
1678
  };
1625
1679
  }
1626
1680
  /**
1627
- * Clamp a `'records'` call's query to a row cap, and build the PROBE query the caller reads
1628
- * with — the pure leaf {@link import('./factories.js').createDatabaseTool}'s `'records'` operation
1629
- * uses to detect truncation without a separate `count` round trip.
1681
+ * Picks the effective row limit a tool reads with — the requested count when it sits inside the
1682
+ * cap, the cap when it exceeds it, and `0` when either falls below zero.
1630
1683
  *
1631
1684
  * @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
1634
- * requests ONE MORE row than the effective limit (`limit: effective + 1`) — if storage returns
1685
+ * The one place the database tool's `'records'` clamp ({@link clampQuery}) and the relation tool's
1686
+ * `'find'` / `'links'` truncation both take their ceiling from, so a negative construction-time
1687
+ * option can never reach a slice. Pure and total.
1688
+ *
1689
+ * @example
1690
+ * ```ts
1691
+ * import { resolveLimit } from '@src/core'
1692
+ *
1693
+ * resolveLimit(undefined, 100) // 100 — an omitted request takes the cap
1694
+ * resolveLimit(500, 100) // 100 — a request over the cap is clamped down
1695
+ * resolveLimit(-1, 100) // 0 — a negative request floors at zero
1696
+ * ```
1697
+ *
1698
+ * @param requested - The caller's requested row count (or `undefined`)
1699
+ * @param cap - The row-count ceiling
1700
+ * @returns The effective row limit, never below `0` and never above `cap`
1701
+ */
1702
+ function resolveLimit(requested, cap) {
1703
+ return Math.max(0, Math.min(requested ?? cap, cap));
1704
+ }
1705
+ /**
1706
+ * Clamps a `'records'` call's query to a row cap, and builds the probe query the caller reads with
1707
+ * — the pure leaf {@link import('./factories.js').createDatabaseTool}'s `'records'` operation uses
1708
+ * to detect truncation without a separate `count` round trip.
1709
+ *
1710
+ * @remarks
1711
+ * {@link resolveLimit} picks the effective limit, so a caller can never exceed the configured cap
1712
+ * by supplying a larger `query.limit`, and can never drive it below `0`. The returned probe query
1713
+ * requests one more row than the effective limit (`limit: effective + 1`) — if storage returns
1635
1714
  * that many, the caller knows the true result was truncated (`rows.length > effective`) and slices
1636
1715
  * back down to `effective` before returning.
1637
1716
  *
@@ -1647,10 +1726,10 @@ function queryOf(query) {
1647
1726
  *
1648
1727
  * @param query - The live query to clamp (or `undefined`)
1649
1728
  * @param cap - The row-count ceiling
1650
- * @returns The PROBE query (`limit` bumped by one) and the effective `limit`
1729
+ * @returns The probe query (`limit` bumped by one) and the effective `limit`
1651
1730
  */
1652
1731
  function clampQuery(query, cap) {
1653
- const limit = Math.max(0, Math.min(query?.limit ?? cap, cap));
1732
+ const limit = resolveLimit(query?.limit, cap);
1654
1733
  return {
1655
1734
  query: {
1656
1735
  ...query,
@@ -1660,28 +1739,77 @@ function clampQuery(query, cap) {
1660
1739
  };
1661
1740
  }
1662
1741
  //#endregion
1742
+ //#region src/core/compilers.ts
1743
+ /**
1744
+ * Compiles a {@link TableSpec} into the `@orkestrel/database` {@link TableMap} it configures —
1745
+ * each {@link ColumnSpec} maps to the matching primitive shaper (`'string'` → `stringShape()`,
1746
+ * `'integer'` → `integerShape()`, `'number'` → `numberShape()`, `'boolean'` → `booleanShape()`),
1747
+ * wrapped in `optionalShape` when the column declares `optional: true`. Total, pure.
1748
+ *
1749
+ * @param spec - The small-model-facing table layout
1750
+ * @returns The compiled `TableMap` a `@orkestrel/database` `createDatabase` call accepts
1751
+ */
1752
+ function expandTables(spec) {
1753
+ const tables = {};
1754
+ for (const [table, definition] of Object.entries(spec)) {
1755
+ const columns = {};
1756
+ for (const [column, columnSpec] of Object.entries(definition.columns)) columns[column] = compileColumn(columnSpec);
1757
+ tables[table] = columns;
1758
+ }
1759
+ return tables;
1760
+ }
1761
+ /**
1762
+ * Compiles one {@link ColumnSpec} into its `@orkestrel/database` column shape — the per-column leaf
1763
+ * {@link expandTables} maps over.
1764
+ *
1765
+ * @param spec - The column spec to compile
1766
+ * @returns The `@orkestrel/database` column shape, wrapped in `optionalShape` when the spec declares `optional: true`
1767
+ */
1768
+ function compileColumn(spec) {
1769
+ const primitive = (0, _orkestrel_contract.isString)(spec) ? spec : spec.primitive;
1770
+ const optional = !(0, _orkestrel_contract.isString)(spec) && spec.optional === true;
1771
+ const shape = compileColumnPrimitive(primitive);
1772
+ return optional ? (0, _orkestrel_contract.optionalShape)(shape) : shape;
1773
+ }
1774
+ /**
1775
+ * Compiles one {@link import('./types.js').ColumnPrimitive} into its primitive
1776
+ * `@orkestrel/database` shape — the leaf {@link compileColumn} wraps.
1777
+ *
1778
+ * @param primitive - The declared column primitive
1779
+ * @returns The matching primitive `@orkestrel/database` shape
1780
+ */
1781
+ function compileColumnPrimitive(primitive) {
1782
+ if (primitive === "string") return (0, _orkestrel_contract.stringShape)();
1783
+ if (primitive === "integer") return (0, _orkestrel_contract.integerShape)();
1784
+ if (primitive === "number") return (0, _orkestrel_contract.numberShape)();
1785
+ return (0, _orkestrel_contract.booleanShape)();
1786
+ }
1787
+ //#endregion
1663
1788
  //#region src/core/stores/MemoryDefinitionStore.ts
1664
1789
  /**
1665
- * The in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of
1666
- * {@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}.
1790
+ * Represents the in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of
1791
+ * {@link DatabaseDefinition}s keyed by database id, the default store
1792
+ * {@link import('../factories.js').createMemoryDefinitionStore} builds. It implements the same
1793
+ * {@link DefinitionStoreInterface} contract as
1794
+ * {@link import('./DatabaseDefinitionStore.js').DatabaseDefinitionStore}: this store copies on
1795
+ * write and on read; the table-backed store narrows an untrusted stored blob and reports
1796
+ * `undefined` for a malformed one.
1669
1797
  *
1670
1798
  * @remarks
1671
- * A plain `Map<string, DatabaseDefinition>` (AGENTS §21 — the definition is already pure,
1672
- * self-contained CONFIG-only JSON, so no encoding is needed for the memory tier). Values are
1673
- * structured-cloned on both write and read, keeping caller mutation outside the store. There is NO
1674
- * idle-TTL and NO eviction: a persisted definition lives until an explicit `delete`. A durable
1675
- * backend (JSON / SQLite / IndexedDB) swaps in through the SAME interface without touching a
1799
+ * A plain `Map<string, DatabaseDefinition>` (the definition is already pure,
1800
+ * self-contained config-only JSON, so no encoding is needed for the memory tier). Values are
1801
+ * structured-cloned on both write and read, keeping caller mutation outside the store. There is no
1802
+ * idle-TTL and no eviction: a persisted definition lives until an explicit `delete`. A durable
1803
+ * backend (JSON / SQLite / IndexedDB) swaps in through the same interface without touching a
1676
1804
  * consumer — its driver-pluggable twin is
1677
1805
  * {@link import('./DatabaseDefinitionStore.js').DatabaseDefinitionStore} (the definition as one
1678
1806
  * opaque JSON column).
1679
1807
  *
1680
1808
  * - **`get` resolves the persisted definition for an id**, or `undefined` if none is stored.
1681
- * - **`set` inserts / replaces under the definition's OWN `id`** (no separate id param).
1809
+ * - **`set` inserts / replaces under the definition's own `id`** (no separate id param).
1682
1810
  * - **`delete` drops a definition by id**; an absent id is a no-op (no throw).
1683
1811
  *
1684
- * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method
1812
+ * The public surface is exactly `get` / `set` / `delete` — no extra members (the method
1685
1813
  * bijection with {@link DefinitionStoreInterface}).
1686
1814
  *
1687
1815
  * @example
@@ -1696,14 +1824,32 @@ function clampQuery(query, cap) {
1696
1824
  */
1697
1825
  var MemoryDefinitionStore = class {
1698
1826
  #definitions = /* @__PURE__ */ new Map();
1827
+ /**
1828
+ * Resolves the persisted definition for `id`, copied out of the backing `Map`.
1829
+ *
1830
+ * @param id - The database id to read
1831
+ * @returns The stored {@link DatabaseDefinition}, or `undefined` when none is stored
1832
+ */
1699
1833
  get(id) {
1700
1834
  const definition = this.#definitions.get(id);
1701
1835
  return Promise.resolve(definition === void 0 ? void 0 : structuredClone(definition));
1702
1836
  }
1837
+ /**
1838
+ * Inserts or replaces a definition under its own `id`, copied into the backing `Map`.
1839
+ *
1840
+ * @param definition - The config to persist; its own `id` is the key (no separate id param)
1841
+ * @returns A promise settling after the definition is stored
1842
+ */
1703
1843
  set(definition) {
1704
1844
  this.#definitions.set(definition.id, structuredClone(definition));
1705
1845
  return Promise.resolve();
1706
1846
  }
1847
+ /**
1848
+ * Drops the definition stored under `id`.
1849
+ *
1850
+ * @param id - The database id to drop; an absent id is a no-op, never a throw
1851
+ * @returns A promise settling after no definition is stored under `id`
1852
+ */
1707
1853
  delete(id) {
1708
1854
  this.#definitions.delete(id);
1709
1855
  return Promise.resolve();
@@ -1712,34 +1858,34 @@ var MemoryDefinitionStore = class {
1712
1858
  //#endregion
1713
1859
  //#region src/core/stores/DatabaseDefinitionStore.ts
1714
1860
  /**
1715
- * A {@link DefinitionStoreInterface} backed by one table of the `@orkestrel/database` layer — a
1716
- * database's durable CONFIG state IS a row, so persistence reduces to keyed point-access
1861
+ * Represents a {@link DefinitionStoreInterface} backed by one table of the `@orkestrel/database` layer — a
1862
+ * database's durable config state is a row, so persistence reduces to keyed point-access
1717
1863
  * (`get` / `set` / `delete`) over a {@link TableInterface}, the driver-pluggable twin of the
1718
1864
  * plain-`Map` {@link import('./MemoryDefinitionStore.js').MemoryDefinitionStore}.
1719
1865
  *
1720
1866
  * @remarks
1721
1867
  * The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,
1722
1868
  * JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a JSON / SQLite /
1723
- * IndexedDB backend swaps in WITHOUT touching a consumer — the same seam as
1869
+ * IndexedDB backend swaps in without touching a consumer — the same seam as
1724
1870
  * {@link import('./MemoryDefinitionStore.js').MemoryDefinitionStore}. The driver defaults to
1725
1871
  * memory ({@link import('../factories.js').createDatabaseDefinitionStore} passes
1726
- * `createMemoryDriver()`), so it ALSO works in memory out of the box; you opt into the durable
1872
+ * `createMemoryDriver()`), so it also works in memory out of the box; you opt into the durable
1727
1873
  * plumbing by passing a JSON / SQLite / IndexedDB driver.
1728
1874
  *
1729
- * The {@link DatabaseDefinition} is stored as ONE OPAQUE JSON COLUMN — the table is a row of
1730
- * `{ id; definition }` ({@link DatabaseDefinitionRow}). The definition is already a COMPLETE,
1731
- * self-contained, pure-JSON CONFIG payload (never a live handle), so storing it whole is lossless
1732
- * AND keeps the row type flat (`definition` reads back as `unknown`).
1875
+ * The {@link DatabaseDefinition} is stored as one opaque JSON column — the table is a row of
1876
+ * `{ id; definition }` ({@link DatabaseDefinitionRow}). The definition is already a complete,
1877
+ * self-contained, pure-JSON config payload (never a live handle), so storing it whole is lossless
1878
+ * and keeps the row type flat (`definition` reads back as `unknown`).
1733
1879
  *
1734
- * - **`set(definition)` upserts under the definition's OWN `id`** (no separate id param) — it
1880
+ * - **`set(definition)` upserts under the definition's own `id`** (no separate id param) — it
1735
1881
  * writes the row `{ id: definition.id, definition }`.
1736
1882
  * - **`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
1883
+ * to a {@link DatabaseDefinition} ({@link import('../validators.js').isDatabaseDefinition} — the
1884
+ * boundary narrow for an untrusted storage read), or `undefined` if none is stored
1739
1885
  * or the stored blob is malformed.
1740
1886
  * - **`delete(id)` drops a definition by id**; an absent id is a no-op (no throw).
1741
1887
  *
1742
- * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method
1888
+ * The public surface is exactly `get` / `set` / `delete` — no extra members (the method
1743
1889
  * bijection with {@link DefinitionStoreInterface}).
1744
1890
  *
1745
1891
  * @example
@@ -1755,7 +1901,7 @@ var MemoryDefinitionStore = class {
1755
1901
  var DatabaseDefinitionStore = class {
1756
1902
  #table;
1757
1903
  /**
1758
- * Wrap a table as a definition store.
1904
+ * Wraps a table as a definition store.
1759
1905
  *
1760
1906
  * @param table - The {@link TableInterface} holding the definitions — its row is the
1761
1907
  * {@link DatabaseDefinitionRow} `{ id; definition }` shape (the definition one opaque JSON column)
@@ -1763,20 +1909,37 @@ var DatabaseDefinitionStore = class {
1763
1909
  constructor(table) {
1764
1910
  this.#table = table;
1765
1911
  }
1766
- /** Resolve the persisted definition for `id`, narrowing the opaque JSON column back to a `DatabaseDefinition`. */
1912
+ /**
1913
+ * Resolves the persisted definition for `id`, narrowing the opaque JSON column back to a
1914
+ * {@link DatabaseDefinition}.
1915
+ *
1916
+ * @param id - The database id to read
1917
+ * @returns The stored {@link DatabaseDefinition}, or `undefined` when none is stored or the
1918
+ * stored blob is malformed
1919
+ */
1767
1920
  async get(id) {
1768
1921
  const row = await this.#table.get(id);
1769
1922
  if (row === void 0) return void 0;
1770
1923
  return isDatabaseDefinition(row.definition) ? row.definition : void 0;
1771
1924
  }
1772
- /** Insert or replace under the definition's OWN `id` (no separate id param) — the row is `{ id, definition }`. */
1925
+ /**
1926
+ * Inserts or replaces a definition under its own `id` — the written row is `{ id, definition }`.
1927
+ *
1928
+ * @param definition - The config to persist; its own `id` is the row key (no separate id param)
1929
+ * @returns A promise settling after the row is written
1930
+ */
1773
1931
  async set(definition) {
1774
1932
  await this.#table.set({
1775
1933
  id: definition.id,
1776
1934
  definition
1777
1935
  });
1778
1936
  }
1779
- /** Drop a definition by id; an absent id is a no-op (no throw). */
1937
+ /**
1938
+ * Drops the definition stored under `id`.
1939
+ *
1940
+ * @param id - The database id to drop; an absent id is a no-op, never a throw
1941
+ * @returns A promise settling after no row is stored under `id`
1942
+ */
1780
1943
  async delete(id) {
1781
1944
  await this.#table.remove(id);
1782
1945
  }
@@ -1784,7 +1947,8 @@ var DatabaseDefinitionStore = class {
1784
1947
  //#endregion
1785
1948
  //#region src/core/databases/DatabaseResolver.ts
1786
1949
  /**
1787
- * Resolve database definitions into cached live handles for database tools.
1950
+ * Resolves a database definition into a cached live handle for a database tool, over the tool's
1951
+ * live handles, its stored definitions, its driver registry, and an optional key generator.
1788
1952
  *
1789
1953
  * @example
1790
1954
  * ```ts
@@ -1800,7 +1964,7 @@ var DatabaseResolver = class {
1800
1964
  #generator;
1801
1965
  #store;
1802
1966
  /**
1803
- * Create a database resolver over the tool's live state and optional definition store.
1967
+ * Creates a database resolver over the tool's live state and optional definition store.
1804
1968
  *
1805
1969
  * @param handles - Initial live database handles cached by id
1806
1970
  * @param drivers - Driver factories keyed by definition driver name
@@ -1814,16 +1978,16 @@ var DatabaseResolver = class {
1814
1978
  this.#store = store;
1815
1979
  }
1816
1980
  /**
1817
- * Determine whether a live database is cached by id.
1981
+ * Determines whether a live database is cached by id.
1818
1982
  *
1819
1983
  * @param id - Database id
1820
- * @returns Whether a live handle is cached
1984
+ * @returns True if a live handle is cached; false otherwise
1821
1985
  */
1822
1986
  has(id) {
1823
1987
  return this.#handles.has(id);
1824
1988
  }
1825
1989
  /**
1826
- * Read a cached database without consulting the definition store.
1990
+ * Reads a cached database without consulting the definition store.
1827
1991
  *
1828
1992
  * @param id - Database id
1829
1993
  * @returns The cached live database, or `undefined`
@@ -1832,7 +1996,7 @@ var DatabaseResolver = class {
1832
1996
  return this.#handles.get(id);
1833
1997
  }
1834
1998
  /**
1835
- * Cache a live database by id.
1999
+ * Caches a live database by id.
1836
2000
  *
1837
2001
  * @param id - Database id
1838
2002
  * @param database - Live database handle
@@ -1842,7 +2006,7 @@ var DatabaseResolver = class {
1842
2006
  this.#handles.set(id, database);
1843
2007
  }
1844
2008
  /**
1845
- * Remove a cached live database by id.
2009
+ * Removes a cached live database by id.
1846
2010
  *
1847
2011
  * @param id - Database id
1848
2012
  * @returns Nothing
@@ -1851,7 +2015,8 @@ var DatabaseResolver = class {
1851
2015
  this.#handles.delete(id);
1852
2016
  }
1853
2017
  /**
1854
- * Resolve a cached or stored database by id.
2018
+ * Resolves a live database by id — the cached handle when one exists, otherwise a database
2019
+ * constructed from its stored definition.
1855
2020
  *
1856
2021
  * @param id - Database definition id
1857
2022
  * @returns The cached or newly constructed live database
@@ -1886,8 +2051,8 @@ var DatabaseResolver = class {
1886
2051
  //#endregion
1887
2052
  //#region src/core/factories.ts
1888
2053
  /**
1889
- * Wrap a registered tool as a {@link WorkflowFunction} (`@orkestrel/workflow`) — the OPT-IN
1890
- * adapter that lets a `function`-form task run a `@orkestrel/tool` tool BY NAME.
2054
+ * Wraps a registered tool as a {@link WorkflowFunction} (`@orkestrel/workflow`) — the opt-in
2055
+ * adapter that lets a `function`-form task run a `@orkestrel/tool` tool by name.
1891
2056
  *
1892
2057
  * @remarks
1893
2058
  * Composes into a caller's `WorkflowOptions.functions` registry like any other behavior
@@ -1925,7 +2090,7 @@ function createToolFunction(tools, name) {
1925
2090
  };
1926
2091
  }
1927
2092
  /**
1928
- * Wrap a live `AgentInterface` (`@orkestrel/agent`) as a {@link WorkflowFunction}
2093
+ * Wraps a live `AgentInterface` (`@orkestrel/agent`) as a {@link WorkflowFunction}
1929
2094
  * (`@orkestrel/workflow`) — the opt-in adapter that runs the agent to a settled result and carries
1930
2095
  * immutable lineage metadata for contextual Toolbox composition.
1931
2096
  *
@@ -1933,7 +2098,7 @@ function createToolFunction(tools, name) {
1933
2098
  * Composes into a caller's registry like any other behavior; the pure workflow runner has no
1934
2099
  * knowledge of agents itself. A root adapter derives its workflow lineage from the controller,
1935
2100
  * 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
2101
+ * targets deeper than {@link import('./constants.js').MAX_WORKFLOW_CHAIN} are rejected before
1937
2102
  * agent or runner activity. When {@link import('./types.js').AgentFunctionOptions.runner} is
1938
2103
  * supplied, the adapter binds a recursion-safe {@link createWorkflowTool} onto the agent's
1939
2104
  * `context.tools`, propagating opaque leaves, raw agents, lineage, and the native store. The
@@ -1961,12 +2126,12 @@ function createToolFunction(tools, name) {
1961
2126
  * ```
1962
2127
  */
1963
2128
  function createAgentFunction(agent, options) {
1964
- const lineage = lineageOf(options?.lineage);
2129
+ const lineage = normalizeLineage(options?.lineage);
1965
2130
  if (lineage.length > 0 && !lineage.at(-1)?.startsWith("workflow:")) throw new ToolboxError("TOOL", "agent function lineage must end with a workflow tag");
1966
2131
  const functions = options?.functions === void 0 ? void 0 : Object.freeze({ ...options.functions });
1967
2132
  const agents = options?.agents === void 0 ? void 0 : Object.freeze({ ...options.agents });
1968
2133
  return Object.freeze(Object.assign(async (controller) => {
1969
- const workflow = workflowTag(controller.task.phase.workflow.id);
2134
+ const workflow = tagWorkflow(controller.task.phase.workflow.id);
1970
2135
  const current = lineage.length === 0 ? extendLineage(lineage, workflow) : lineage;
1971
2136
  if (current.at(-1) !== workflow) throw new ToolboxError("DEPTH", "agent function workflow does not match its lineage", {
1972
2137
  workflow,
@@ -1978,7 +2143,7 @@ function createAgentFunction(agent, options) {
1978
2143
  depth,
1979
2144
  max: 8
1980
2145
  });
1981
- const tag = agentTag(agent.id);
2146
+ const tag = tagAgent(agent.id);
1982
2147
  if (current.includes(tag)) throw new ToolboxError("DEPTH", `agent '${agent.id}' is already an ancestor (cycle)`, {
1983
2148
  agent: agent.id,
1984
2149
  lineage: [...current]
@@ -2010,7 +2175,7 @@ function createAgentFunction(agent, options) {
2010
2175
  }));
2011
2176
  }
2012
2177
  /**
2013
- * Compose opaque host functions and raw agents into one immutable workflow registry.
2178
+ * Composes opaque host functions and raw agents into one immutable workflow registry.
2014
2179
  *
2015
2180
  * @remarks
2016
2181
  * This is the target-aware composition boundary used by direct runner consumers and
@@ -2037,7 +2202,7 @@ function createAgentFunction(agent, options) {
2037
2202
  * ```
2038
2203
  */
2039
2204
  function createWorkflowFunctions(runner, options) {
2040
- const lineage = lineageOf(options?.lineage);
2205
+ const lineage = normalizeLineage(options?.lineage);
2041
2206
  if (lineage.length > 0 && !lineage.at(-1)?.startsWith("workflow:")) throw new ToolboxError("TOOL", "workflow functions lineage must end with a workflow tag");
2042
2207
  const functions = options?.functions === void 0 ? Object.freeze({}) : Object.freeze({ ...options.functions });
2043
2208
  const agents = options?.agents === void 0 ? Object.freeze({}) : Object.freeze({ ...options.agents });
@@ -2061,7 +2226,9 @@ function createWorkflowFunctions(runner, options) {
2061
2226
  return Object.freeze(composed);
2062
2227
  }
2063
2228
  /**
2064
- * Compile the lenient workflow draft contract used by {@link createWorkflowTool}.
2229
+ * Compiles the lenient workflow draft contract {@link createWorkflowTool} parses an authored tree
2230
+ * with — a `ContractInterface` over a {@link WorkflowDraft}, whose `id` and `name` are optional at
2231
+ * the workflow, phase, and task levels.
2065
2232
  *
2066
2233
  * @returns The compiled {@link import('./types.js').WorkflowDraft} contract
2067
2234
  */
@@ -2069,34 +2236,33 @@ function createWorkflowDraftContract() {
2069
2236
  return (0, _orkestrel_contract.createContract)(workflowDraftShape);
2070
2237
  }
2071
2238
  /**
2072
- * Wrap a {@link WorkflowDefinition} as an LLM-callable tool — it ADVERTISES the SIMPLE flat
2073
- * authoring shape (`{ name?, steps: [{ name }] }`) as its `parameters` so even a small model can
2074
- * author a complete tree, and its handler EXPANDS / COMPLETES the authored blob, validates it
2075
- * against the STRICT contract, and runs it through `runner`, forwarding the caller's optional
2076
- * named functions and native checkpoint store.
2239
+ * Wraps a {@link WorkflowDefinition} as an LLM-callable tool — it advertises the flat authoring
2240
+ * shape (`{ name?, steps: [{ name }] }`) as its `parameters`, and its handler completes the
2241
+ * authored blob, validates it against the strict contract, and runs it through `runner`, forwarding
2242
+ * the caller's optional named functions and native checkpoint store.
2077
2243
  *
2078
2244
  * @remarks
2079
2245
  * A plain `ToolManagerInterface`-compatible tool (`@orkestrel/tool`), reproducing
2080
2246
  * Toolbox's flat / draft / full authoring contract, strict soundness gate, and lineage guard.
2081
- * It is ALSO the propagation carrier
2247
+ * It is also the propagation carrier
2082
2248
  * {@link createAgentFunction} binds onto a wrapped agent's `context.tools`: because a tool
2083
2249
  * handler receives only the model-supplied `args`, the immutable lineage is closed over at bind
2084
2250
  * time. The authored target is appended and its zero-based depth derived from workflow tags.
2085
2251
  *
2086
- * **Widened authoring surface (additive — the canonical contract + runner stay STRICT and
2087
- * unchanged).** A 2B model reliably CALLS the tool but cannot reliably emit the full four-level
2088
- * nested {@link WorkflowDefinition} (six required `id`/`name` strings, an all-or-nothing tree).
2089
- * So the tool ACCEPTS three authoring forms and converges them on the SAME strict
2252
+ * **Widened authoring surface (additive — the canonical contract and runner stay strict and
2253
+ * unchanged).** A 2B model reliably calls the tool but cannot reliably emit the full nested
2254
+ * {@link WorkflowDefinition}, whose every `id` and `name` is required across an all-or-nothing
2255
+ * tree. So the tool accepts the authoring forms that follow and converges them on the same strict
2090
2256
  * `createWorkflowContract` gate before running (soundness preserved):
2091
- * - the FLAT shape `{ name?, steps: [{ name }] }` — the ADVERTISED `parameters` (the simplest
2257
+ * - the flat shape `{ name?, steps: [{ name }] }` — the advertised `parameters` (the simplest
2092
2258
  * form, {@link import('./helpers.js').expandSteps}'d into one one-task phase per step);
2093
- * - a nested DRAFT with any `id`/`name` OMITTED — {@link createWorkflowDraftContract}-parsed then
2259
+ * - a nested draft with any `id`/`name` omitted — {@link createWorkflowDraftContract}-parsed then
2094
2260
  * {@link import('./helpers.js').completeDraft}'d (missing ids synthesized positionally);
2095
2261
  * - the full nested {@link WorkflowDefinition} — the advanced escape-hatch, accepted as the draft
2096
2262
  * super-set.
2097
2263
  *
2098
- * The universal tool-handler contract (AGENTS §14): returns the plain run summary
2099
- * (`{ status, count, durable?, fault? }`) on success, THROWS a typed `ToolboxError` on Toolbox
2264
+ * The universal tool-handler contract: returns the plain run summary
2265
+ * (`{ status, count, durable?, fault? }`) on success, throws a typed `ToolboxError` on Toolbox
2100
2266
  * boundary failures — malformed authored args (`TOOL`), or an over-deep / cyclic nested run
2101
2267
  * (`DEPTH`) — and preserves genuine runner `WorkflowError`s. The `ToolManagerInterface` isolates every throw into the canonical tool result's
2102
2268
  * top-level `error`, so nothing escapes the run. `options.lineage` is the propagation carrier
@@ -2110,6 +2276,34 @@ function createWorkflowDraftContract() {
2110
2276
  * @returns A `ToolInterface` (named {@link import('./constants.js').WORKFLOW_TOOL_NAME}) whose
2111
2277
  * `parameters` advertise the flat authoring schema
2112
2278
  *
2279
+ * @example Authoring and running a workflow through the tool with a real ToolManager
2280
+ * ```ts
2281
+ * import { createWorkflowTool } from '@orkestrel/toolbox'
2282
+ * import { createToolManager } from '@orkestrel/tool'
2283
+ * import { createWorkflowRunner } from '@orkestrel/workflow'
2284
+ * import type { WorkflowDefinition } from '@orkestrel/workflow'
2285
+ *
2286
+ * const definition: WorkflowDefinition = { id: 'release', name: 'Release', phases: [] }
2287
+ * const runner = createWorkflowRunner()
2288
+ * const functions = {
2289
+ * compile: () => 'compiled',
2290
+ * publish: () => 'published',
2291
+ * }
2292
+ * const tool = createWorkflowTool(definition, runner, { functions })
2293
+ *
2294
+ * const tools = createToolManager()
2295
+ * tools.add(tool)
2296
+ *
2297
+ * // A small model authors the simple flat shape — no ids/names required.
2298
+ * const result = await tools.execute({
2299
+ * id: 'call-1',
2300
+ * name: 'workflow',
2301
+ * arguments: { name: 'release', steps: [{ name: 'compile' }, { name: 'publish' }] },
2302
+ * })
2303
+ * if (!result.success) throw new Error(result.error)
2304
+ * result.value // { status: 'completed', count: 2 } — the single-level envelope; no nested { id, name, value }
2305
+ * ```
2306
+ *
2113
2307
  * @example
2114
2308
  * ```ts
2115
2309
  * import { createWorkflowTool } from '@src/core'
@@ -2127,7 +2321,7 @@ function createWorkflowTool(definition, runner, options) {
2127
2321
  const strict = (0, _orkestrel_workflow.createWorkflowContract)();
2128
2322
  const draft = createWorkflowDraftContract();
2129
2323
  const steps = (0, _orkestrel_contract.createContract)(workflowStepsShape);
2130
- const lineage = lineageOf(options?.lineage);
2324
+ const lineage = normalizeLineage(options?.lineage);
2131
2325
  if (lineage.length > 0 && !lineage.at(-1)?.startsWith("agent:")) throw new ToolboxError("TOOL", "workflow tool lineage must end with an agent tag");
2132
2326
  const functions = options?.functions === void 0 ? void 0 : Object.freeze({ ...options.functions });
2133
2327
  const agents = options?.agents === void 0 ? void 0 : Object.freeze({ ...options.agents });
@@ -2152,7 +2346,7 @@ function createWorkflowTool(definition, runner, options) {
2152
2346
  target = parsed === void 0 ? void 0 : completeDraft(parsed);
2153
2347
  }
2154
2348
  if (target === void 0 || !strict.is(target)) throw new ToolboxError("TOOL", "malformed workflow definition", { workflow: definition.id });
2155
- const tag = workflowTag(target.id);
2349
+ const tag = tagWorkflow(target.id);
2156
2350
  if (lineage.includes(tag)) throw new ToolboxError("DEPTH", `workflow '${target.id}' is already an ancestor (cycle)`, {
2157
2351
  workflow: target.id,
2158
2352
  lineage: [...lineage]
@@ -2170,7 +2364,7 @@ function createWorkflowTool(definition, runner, options) {
2170
2364
  ...agents === void 0 ? {} : { agents },
2171
2365
  ...store === void 0 ? {} : { store }
2172
2366
  });
2173
- return workflowToolSummary(await runner.execute(target, {
2367
+ return summarizeWorkflow(await runner.execute(target, {
2174
2368
  ...registry === void 0 ? {} : { functions: registry },
2175
2369
  ...store === void 0 ? {} : { store }
2176
2370
  }));
@@ -2178,42 +2372,35 @@ function createWorkflowTool(definition, runner, options) {
2178
2372
  });
2179
2373
  }
2180
2374
  /**
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
2183
- * handler PARSES the model-supplied args against that contract and DISPATCHES the matched
2184
- * operation against the manager's ACTIVE workspace (the registry ops drive the manager itself),
2185
- * returning the plain result. A malformed operation throws this package's `ToolboxError`; a
2186
- * genuine workspace-domain failure propagates `@orkestrel/workspace`'s typed `WorkspaceError`.
2187
- * EITHER drives a caller-supplied {@link WorkspaceToolOptions.manager} directly, OR
2188
- * constructs a fresh `WorkspaceManagerInterface` (`@orkestrel/workspace`) over
2189
- * {@link import('./types.js').WorkspaceToolOptions.store} (via `@orkestrel/workspace`'s
2190
- * `createWorkspaceManager`); neither given constructs a manager backed by
2191
- * `@orkestrel/workspace`'s in-memory store default.
2375
+ * Builds an LLM-callable workspace-editing tool — it advertises the `operation`-discriminated union
2376
+ * ({@link import('./shapers.js').workspaceToolShape}) as its `parameters`, and its handler parses
2377
+ * the model-supplied args against that contract and dispatches the matched operation against the
2378
+ * manager's active workspace, returning the plain result.
2192
2379
  *
2193
2380
  * @remarks
2194
- * MANAGER-DRIVEN: every edit / read op (read / list / has / search / replace / write / splice /
2381
+ * Manager-driven: every edit / read op (read / list / has / search / replace / write / splice /
2195
2382
  * prepend / append / move / remove) targets `manager.active`, so the model edits whichever
2196
2383
  * workspace is active and a host can re-point it (`WorkspaceManagerInterface.switch`) between
2197
- * turns. Two REGISTRY ops make the model self-sufficient: `workspaces` LISTS the registered
2384
+ * turns. The registry ops make the model self-sufficient: `workspaces` lists the registered
2198
2385
  * workspaces (each `{ id, files, active }`) so it can discover an id, and `switch` re-points the
2199
2386
  * active workspace by id (lenient — an unknown id is a no-op reporting `switched: false`, never a
2200
2387
  * throw).
2201
2388
  *
2202
- * NO-ACTIVE RULE (the ergonomic seam): a WRITING op (write / splice / prepend / append / move /
2203
- * 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 /
2205
- * has / search) against no active workspace returns the EMPTY result (`undefined` / `[]` /
2389
+ * No-active rule (the ergonomic seam): a writing op (write / splice / prepend / append / move /
2390
+ * remove / replace) run when `manager.active` is `undefined` auto-creates and activates a default
2391
+ * workspace (`manager.add()`) so the model can start writing; a pure-read op (read / list /
2392
+ * has / search) against no active workspace returns the empty result (`undefined` / `[]` /
2206
2393
  * `false`), never creating one and never throwing.
2207
2394
  *
2208
- * The handler conforms to the universal tool-handler contract (AGENTS §14): it `contract.parse`s
2209
- * the args, THROWS a `TOOL` `ToolboxError` when no operation arm matched (a malformed / unknown
2210
- * 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
2395
+ * The handler conforms to the universal tool-handler contract: it `contract.parse`s
2396
+ * the args, throws a `TOOL` `ToolboxError` when no operation arm matched (a malformed / unknown
2397
+ * operation), else `switch`es on `op.operation` and returns the plain result — letting a
2398
+ * `WorkspaceError` raised by the live workspace (`MISSING` / `MODALITY` / `PATTERN` / `RANGE`)
2399
+ * propagate uncaught. The range edit is the flat `'splice'` op: its flat caret integers are
2213
2400
  * reassembled into a `Range` (`@orkestrel/workspace`) by `rangeOf` and fed to the workspace's
2214
2401
  * ranged `write`.
2215
2402
  *
2216
- * @param options - `manager` (drive directly) OR `store` (build a manager over it); neither ⇒
2403
+ * @param options - `manager` (drive directly) or `store` (build a manager over it); neither ⇒
2217
2404
  * an in-memory-backed manager (see {@link import('./types.js').WorkspaceToolOptions})
2218
2405
  * @returns A `ToolInterface` (named {@link import('./constants.js').WORKSPACE_TOOL_NAME} by default)
2219
2406
  *
@@ -2331,19 +2518,19 @@ function createWorkspaceTool(options) {
2331
2518
  });
2332
2519
  }
2333
2520
  /**
2334
- * Build an LLM-callable sub-agent delegation tool — resolves a live, seeded `AgentInterface`
2335
- * from `registry` and runs it to completion for ONE delegated `task`.
2521
+ * Builds an LLM-callable sub-agent delegation tool — it resolves a live, seeded `AgentInterface`
2522
+ * from `registry` and runs it to completion for one delegated `task`.
2336
2523
  *
2337
2524
  * @remarks
2338
- * The universal tool-handler contract (AGENTS §14): validates the call args against
2525
+ * The universal tool-handler contract: validates the call args against
2339
2526
  * {@link import('./shapers.js').agentToolShape}, assembles an `AgentJobInput` (`task` seeds the
2340
2527
  * 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
2528
+ * back to the tool's own {@link import('./types.js').AgentToolOptions} defaults), rehydrates the sub-agent through
2342
2529
  * `registry.build`, runs it with `agent.generate()`, and returns the settled
2343
- * `AgentResult.content` string (the sub-agent's final text). A missing / unresolvable `provider`, or a malformed call, THROWS a typed `TOOL`
2530
+ * `AgentResult.content` string (the sub-agent's final text). A missing / unresolvable `provider`, or a malformed call, throws a typed `TOOL`
2344
2531
  * {@link import('./errors.js').ToolboxError}; a delegation that would exceed
2345
2532
  * {@link import('./constants.js').AGENT_TOOL_DEPTH}, or re-enter an already-delegated agent (a
2346
- * cycle), THROWS a typed `DEPTH` {@link import('./errors.js').ToolboxError} — both isolated
2533
+ * cycle), throws a typed `DEPTH` {@link import('./errors.js').ToolboxError}, each isolated
2347
2534
  * by the `ToolManagerInterface` into the canonical tool result's top-level `error`.
2348
2535
  *
2349
2536
  * `AgentInterface` (`@orkestrel/agent`) exposes no teardown method — a bound sub-agent's
@@ -2389,7 +2576,7 @@ function createAgentTool(registry, options) {
2389
2576
  depth,
2390
2577
  max: 8
2391
2578
  });
2392
- const tag = agentTag(provider);
2579
+ const tag = tagAgent(provider);
2393
2580
  if (ancestry.includes(tag)) throw new ToolboxError("DEPTH", `agent '${provider}' is already an ancestor (cycle)`, {
2394
2581
  provider,
2395
2582
  ancestry: [...ancestry]
@@ -2415,21 +2602,20 @@ function createAgentTool(registry, options) {
2415
2602
  });
2416
2603
  }
2417
2604
  /**
2418
- * Build an LLM-callable tool that returns the FULL `description` of another registered tool by
2419
- * name — the counterpart to the lean `summary` the other tools in this package advertise
2420
- * (`AGENT_TOOL_SUMMARY` / `WORKFLOW_TOOL_SUMMARY` / `WORKSPACE_TOOL_SUMMARY`).
2605
+ * Builds an LLM-callable tool that returns the full `description` of another registered tool by
2606
+ * name — the counterpart to the lean `summary` the other tools in this package advertise.
2421
2607
  *
2422
2608
  * @remarks
2423
2609
  * `ToolManagerInterface.definitions()` (`@orkestrel/tool`) advertises `tool.summary ??
2424
2610
  * tool.description` — a lean one-sentence summary stands in for a tool's full teaching
2425
2611
  * description when `summary` is set, keeping the advertised tool list compact for a small model.
2426
2612
  * 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
2613
+ * up through `tools.tool(name)` and returns its full `description` (falling back to `summary` when a
2428
2614
  * tool has no `description` of its own, then a placeholder when it has neither).
2429
2615
  *
2430
- * The universal tool-handler contract (AGENTS §14): validates the call args against
2431
- * {@link import('./shapers.js').describeToolShape}, RETURNS the plain description string on
2432
- * success, THROWS a typed `TOOL` {@link import('./errors.js').ToolboxError} on a malformed call
2616
+ * The universal tool-handler contract: validates the call args against
2617
+ * {@link import('./shapers.js').describeToolShape}, returns the plain description string on
2618
+ * success, throws a typed `TOOL` {@link import('./errors.js').ToolboxError} on a malformed call
2433
2619
  * or an unknown tool name.
2434
2620
  *
2435
2621
  * @param tools - The `ToolManagerInterface` (`@orkestrel/tool`) whose registered tools this
@@ -2466,20 +2652,23 @@ function createDescribeTool(tools) {
2466
2652
  });
2467
2653
  }
2468
2654
  /**
2469
- * Build an LLM-callable form tool — the ASK side of the terminal seam. Asks
2470
- * a multi-field form and BLOCKS until it answers, returning the resolved values record.
2655
+ * Builds an LLM-callable form tool — the ask side of the terminal seam. It asks a multi-field form
2656
+ * and blocks until the addressed terminal answers, returning the resolved values record.
2471
2657
  *
2472
2658
  * @remarks
2473
- * The universal tool-handler contract (AGENTS §14): validates the call args against
2659
+ * The universal tool-handler contract: validates the call args against
2474
2660
  * {@link import('./shapers.js').promptToolShape}, parses the call's schema through
2475
2661
  * `@orkestrel/form`, constructs the live form, and passes it to `TerminalManagerInterface.ask`.
2476
- * `from` is FIXED at construction
2662
+ * `from` is fixed at construction
2477
2663
  * ({@link import('./types.js').PromptToolOptions.from}) — never read from the model-supplied
2478
- * args — so a model cannot spoof which terminal is asking. A form CYCLE rejects with
2664
+ * args — so a model cannot spoof which terminal is asking. A form cycle rejects with
2479
2665
  * `TerminalError('DEADLOCK')`, re-surfaced as a typed `DEADLOCK`
2480
2666
  * {@link import('./errors.js').ToolboxError}; an expired form re-surfaces as `EXPIRE`; an
2481
2667
  * unknown `to` (or any other `TerminalError`) re-surfaces as `TOOL`, naming the unknown terminal
2482
- * plus the known ones (`manager.terminals()`).
2668
+ * and how many brokers the manager holds (`manager.count`). A schema `parseForm` refuses — an
2669
+ * unknown control, a duplicate field name, a `'select'` or `'checkbox'` field without usable
2670
+ * `choices` — throws a typed `TOOL` error up front, so a malformed schema never parks as a form
2671
+ * nobody can answer.
2483
2672
  *
2484
2673
  * @param options - The live manager, the fixed `from` identity, and advertised overrides (see
2485
2674
  * {@link import('./types.js').PromptToolOptions})
@@ -2520,7 +2709,7 @@ function createPromptTool(options) {
2520
2709
  return await options.manager.ask(options.from, call.to, (0, _orkestrel_form.createForm)(schema));
2521
2710
  } catch (error) {
2522
2711
  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);
2712
+ const code = inferTerminalCode(error);
2524
2713
  if (code === void 0) throw error;
2525
2714
  if (code === "DEADLOCK") throw new ToolboxError("DEADLOCK", `asking '${call.to}' would create a form cycle`, (0, _orkestrel_terminal.isTerminalError)(error) ? error.context : {
2526
2715
  from: options.from,
@@ -2529,7 +2718,7 @@ function createPromptTool(options) {
2529
2718
  if (code === "EXPIRE") throw new ToolboxError("EXPIRE", `form to '${call.to}' expired before it was answered`, { to: call.to });
2530
2719
  if ((0, _orkestrel_terminal.isTerminalError)(error) && error.code === "TARGET") throw new ToolboxError("TOOL", `unknown terminal '${call.to}'`, {
2531
2720
  to: call.to,
2532
- known: options.manager.terminals()
2721
+ count: options.manager.count
2533
2722
  });
2534
2723
  throw new ToolboxError("TOOL", `asking '${call.to}' failed`, { to: call.to });
2535
2724
  }
@@ -2537,22 +2726,21 @@ function createPromptTool(options) {
2537
2726
  });
2538
2727
  }
2539
2728
  /**
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
2542
- * them by id.
2729
+ * Builds an LLM-callable answer tool — the answer side of the terminal seam. It lists the forms
2730
+ * addressed to {@link import('./types.js').AnswerToolOptions.to}, or answers one of them by id.
2543
2731
  *
2544
2732
  * @remarks
2545
- * The universal tool-handler contract (AGENTS §14): validates the call args against
2733
+ * The universal tool-handler contract: validates the call args against
2546
2734
  * {@link import('./shapers.js').answerToolShape} (discriminated by `operation`). `'pending'`
2547
- * returns a compact list (`{ id, from, schema }`) of every form currently addressed to `to`.
2735
+ * returns a compact list (`{ id, from, schema }`) of every form addressed to `to`.
2548
2736
  * `'answer'` looks the form up by `id`, narrows the supplied `values` through `@orkestrel/form`,
2549
- * and applies it via
2737
+ * and applies it through
2550
2738
  * `TerminalManagerInterface.answer` — a rejected / unknown / unresolvable outcome
2551
2739
  * (`TerminalAnswerResult.error`) re-surfaces as a typed `ANSWER` `ToolboxError`; success returns
2552
- * `{ answered: id }`. `to` is FIXED at construction
2740
+ * `{ answered: id }`. `to` is fixed at construction
2553
2741
  * ({@link import('./types.js').AnswerToolOptions.to}) — never read from the model-supplied args —
2554
2742
  * so a model cannot spoof which terminal it is answering for. Concurrent answerers racing on one
2555
- * endpoint are FIRST-WRITE-WINS — a late answer to an already-settled form returns a typed
2743
+ * endpoint are first-write-wins — a late answer to an already-settled form returns a typed
2556
2744
  * `ANSWER` `ToolboxError` (surfaced as a 422 over HTTP).
2557
2745
  *
2558
2746
  * @param options - The live manager, the fixed `to` identity, and advertised overrides (see
@@ -2604,9 +2792,9 @@ function createAnswerTool(options) {
2604
2792
  });
2605
2793
  }
2606
2794
  /**
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
2609
- * `DatabaseDefinition` configs through.
2795
+ * Creates the in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of database
2796
+ * definitions, the default store the database and relation tools persist their `DatabaseDefinition`
2797
+ * configs through.
2610
2798
  *
2611
2799
  * @returns A {@link DefinitionStoreInterface}
2612
2800
  *
@@ -2621,7 +2809,7 @@ function createMemoryDefinitionStore() {
2621
2809
  return new MemoryDefinitionStore();
2622
2810
  }
2623
2811
  /**
2624
- * Create a {@link DefinitionStoreInterface} backed by one table of the `@orkestrel/database`
2812
+ * Creates a {@link DefinitionStoreInterface} backed by one table of the `@orkestrel/database`
2625
2813
  * layer — the driver-pluggable twin of {@link createMemoryDefinitionStore}, storing each
2626
2814
  * database's definition as one opaque JSON column.
2627
2815
  *
@@ -2646,15 +2834,15 @@ function createDatabaseDefinitionStore(driver = (0, _orkestrel_database.createMe
2646
2834
  }).table("definitions"));
2647
2835
  }
2648
2836
  /**
2649
- * Build an LLM-callable database tool — create, query, and mutate `@orkestrel/database`
2650
- * databases through one `operation`-discriminated call (AGENTS §14, matching
2837
+ * Builds an LLM-callable database tool — it creates, queries, and mutates `@orkestrel/database`
2838
+ * databases through one `operation`-discriminated call (matching
2651
2839
  * {@link createWorkspaceTool}'s single-tool-many-operations shape).
2652
2840
  *
2653
2841
  * @remarks
2654
- * The universal tool-handler contract (AGENTS §14): validates the call args against
2842
+ * The universal tool-handler contract: validates the call args against
2655
2843
  * {@link import('./shapers.js').databaseToolShape}, dispatches to the matching operation, and
2656
- * 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
2844
+ * returns a plain result on success. A database is resolved lazily and cached for the tool's
2845
+ * lifetime — `'create'` mints one from `tables` ({@link import('./compilers.js').expandTables}) and
2658
2846
  * a registered `driver` key ({@link import('./types.js').DatabaseToolOptions.drivers}, default
2659
2847
  * `{ memory: () => createMemoryDriver() }`); any other operation addressing an uncached id falls
2660
2848
  * back to {@link import('./types.js').DatabaseToolOptions.store} (an unknown id throws a typed
@@ -2663,10 +2851,10 @@ function createDatabaseDefinitionStore(driver = (0, _orkestrel_database.createMe
2663
2851
  *
2664
2852
  * `'records'` clamps its `query` to
2665
2853
  * {@link import('./types.js').DatabaseToolOptions.limit} (default
2666
- * {@link import('./constants.js').DATABASE_TOOL_LIMIT}) via
2854
+ * {@link import('./constants.js').DATABASE_TOOL_LIMIT}) through
2667
2855
  * {@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'`).
2856
+ * than the cap. Every operation's `query` is normalized through
2857
+ * {@link import('./helpers.js').normalizeQuery} (defaults an omitted condition `connector` to `'and'`).
2670
2858
  * When {@link import('./types.js').DatabaseToolOptions.readonly} is `true`, every mutating
2671
2859
  * operation throws a typed `TOOL` `ToolboxError` before doing anything. A configured
2672
2860
  * {@link import('./types.js').DatabaseToolOptions.timeout} is passed as a fresh
@@ -2675,10 +2863,10 @@ function createDatabaseDefinitionStore(driver = (0, _orkestrel_database.createMe
2675
2863
  * not an outer deadline for resolution, construction, schema inspection, `get`, or `close`. A typed `@orkestrel/database`
2676
2864
  * failure (`DatabaseError`) re-surfaces as a typed `DATABASE` `ToolboxError` carrying the
2677
2865
  * original {@link import('@orkestrel/database').DatabaseErrorCode} in `context.code`
2678
- * ({@link import('./helpers.js').databaseToolCode}); an `ToolboxError` thrown by this tool's own
2866
+ * ({@link import('./helpers.js').inferDatabaseCode}); an `ToolboxError` thrown by this tool's own
2679
2867
  * guards passes through unwrapped.
2680
2868
  *
2681
- * A lazily re-minted database over the DEFAULT in-memory driver yields an EMPTY database — only
2869
+ * A lazily re-minted database over the default in-memory driver yields an empty database — only
2682
2870
  * the {@link import('./types.js').DatabaseDefinition} schema persists in `store`, never rows;
2683
2871
  * durable rows need a persistent driver factory registered in
2684
2872
  * {@link import('./types.js').DatabaseToolOptions.drivers}. `'destroy'` closes whatever handle is
@@ -2686,7 +2874,7 @@ function createDatabaseDefinitionStore(driver = (0, _orkestrel_database.createMe
2686
2874
  * {@link import('./types.js').DatabaseToolOptions.databases} handle — the embedder relinquishes
2687
2875
  * that handle's lifecycle to this tool for any id it wires in. This tool assumes the
2688
2876
  * single-writer, non-reentrant model `@orkestrel/database` itself assumes — concurrent calls
2689
- * against one id are NOT serialized by this tool. `'get'` is uncapped by
2877
+ * against one id are not serialized by this tool. `'get'` is uncapped by
2690
2878
  * {@link import('./types.js').DatabaseToolOptions.limit} (bounded only by the caller's `key` array
2691
2879
  * size), unlike `'records'` / `'find'` / `'links'`.
2692
2880
  *
@@ -2783,7 +2971,7 @@ function createDatabaseTool(options = {}) {
2783
2971
  }
2784
2972
  case "records": {
2785
2973
  const table = (await resolver.resolve(call.id)).table(call.table);
2786
- const { query: probe, limit } = clampQuery(queryOf(call.query), cap);
2974
+ const { query: probe, limit } = clampQuery(normalizeQuery(call.query), cap);
2787
2975
  const rows = await table.records(probe, read);
2788
2976
  const truncated = rows.length > limit;
2789
2977
  const sliced = rows.slice(0, limit);
@@ -2794,8 +2982,8 @@ function createDatabaseTool(options = {}) {
2794
2982
  limit
2795
2983
  };
2796
2984
  }
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) };
2985
+ case "count": return { count: await (await resolver.resolve(call.id)).table(call.table).count(normalizeQuery(call.query), read) };
2986
+ case "aggregate": return { value: await (await resolver.resolve(call.id)).table(call.table).aggregate(call.function, call.column, normalizeQuery(call.query), read) };
2799
2987
  case "add": {
2800
2988
  const table = (await resolver.resolve(call.id)).table(call.table);
2801
2989
  const many = Array.isArray(call.row);
@@ -2841,7 +3029,7 @@ function createDatabaseTool(options = {}) {
2841
3029
  }
2842
3030
  } catch (error) {
2843
3031
  if (isToolboxError(error)) throw error;
2844
- const code = databaseToolCode(error);
3032
+ const code = inferDatabaseCode(error);
2845
3033
  if (code === void 0) throw error;
2846
3034
  throw new ToolboxError("DATABASE", error instanceof Error ? error.message : String(error), {
2847
3035
  code,
@@ -2854,32 +3042,33 @@ function createDatabaseTool(options = {}) {
2854
3042
  });
2855
3043
  }
2856
3044
  /**
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
3045
+ * Builds an LLM-callable relation tool — it traverses and edits `@orkestrel/relation` relationships
3046
+ * through one `operation`-discriminated call (matching {@link createDatabaseTool}'s
2859
3047
  * single-tool-many-operations shape).
2860
3048
  *
2861
3049
  * @remarks
2862
- * The universal tool-handler contract (AGENTS §14): validates the call args against
3050
+ * The universal tool-handler contract: validates the call args against
2863
3051
  * {@link import('./shapers.js').relationToolShape}, resolves the addressed
2864
3052
  * {@link import('@orkestrel/relation').RelationManagerInterface} — an explicit `manager` field
2865
- * must match a key of {@link import('./types.js').RelationToolOptions.managers}, an OMITTED one
2866
- * resolves to the SOLE registered manager, either miss throwing a typed `TOOL`
3053
+ * must match a key of {@link import('./types.js').RelationToolOptions.managers}, an omitted one
3054
+ * resolves to the sole registered manager, either miss throwing a typed `TOOL`
2867
3055
  * {@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
2870
- * dispatches to the matched operation, RETURNING a plain result on success.
3056
+ * ({@link import('./helpers.js').resolveRelationManager}) — then resolves `model` against it
3057
+ * ({@link import('./helpers.js').resolveRelationModel}, same typed-`TOOL`-on-miss shape), and
3058
+ * dispatches to the matched operation, returning a plain result on success.
2871
3059
  *
2872
- * `'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
3060
+ * `'load'` / `'find'` expand the call's flat dot-path `include` list into a live
3061
+ * `@orkestrel/relation` `Include` tree through {@link import('./helpers.js').expandInclude}, capped
2874
3062
  * at {@link import('./types.js').RelationToolOptions.depth} (default
2875
3063
  * {@link import('./constants.js').RELATION_TOOL_DEPTH}) — a path exceeding the cap, or carrying an
2876
3064
  * 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
3065
+ * (positional many-key form — an array key is read as many keys rather than one) or a single key.
3066
+ * `'find'` and `'links'` clamp their
2878
3067
  * 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
3068
+ * {@link import('./constants.js').RELATION_TOOL_LIMIT}), taken through
3069
+ * {@link import('./helpers.js').resolveLimit} — `'find'` probes one row past the effective limit to
3070
+ * report `truncated`; `'links'` (which has no upstream pagination) fetches the full linked-key
3071
+ * list and slices/truncates it the same way. `'link'` / `'unlink'` write / remove one `through` junction
2883
3072
  * row.
2884
3073
  *
2885
3074
  * A typed `@orkestrel/relation` failure (`RelationError`) re-surfaces as a typed `RELATION`
@@ -2914,7 +3103,7 @@ function createRelationTool(options) {
2914
3103
  const call = contract.parse(args);
2915
3104
  if (call === void 0) throw new ToolboxError("TOOL", "malformed relation call", { args });
2916
3105
  try {
2917
- const model = relationModelOf(relationManagerOf(options.managers, call.manager), call.model);
3106
+ const model = resolveRelationModel(resolveRelationManager(options.managers, call.manager), call.model);
2918
3107
  switch (call.operation) {
2919
3108
  case "load": {
2920
3109
  const include = expandInclude(call.include, depth);
@@ -2923,7 +3112,7 @@ function createRelationTool(options) {
2923
3112
  }
2924
3113
  case "find": {
2925
3114
  const include = expandInclude(call.include, depth);
2926
- const effective = Math.min(call.limit ?? cap, cap);
3115
+ const effective = resolveLimit(call.limit, cap);
2927
3116
  const rows = await model.find(include, {
2928
3117
  limit: effective + 1,
2929
3118
  ...call.offset === void 0 ? {} : { offset: call.offset },
@@ -2946,27 +3135,28 @@ function createRelationTool(options) {
2946
3135
  await model.unlink(call.key, call.relation, call.target);
2947
3136
  return { unlinked: true };
2948
3137
  case "links": {
3138
+ const effective = resolveLimit(void 0, cap);
2949
3139
  const keys = await model.links(call.key, call.relation);
2950
- const truncated = keys.length > cap;
2951
- const sliced = keys.slice(0, cap);
3140
+ const truncated = keys.length > effective;
3141
+ const sliced = keys.slice(0, effective);
2952
3142
  return {
2953
3143
  keys: sliced,
2954
3144
  count: sliced.length,
2955
3145
  truncated,
2956
- limit: cap
3146
+ limit: effective
2957
3147
  };
2958
3148
  }
2959
3149
  }
2960
3150
  } catch (error) {
2961
3151
  if (isToolboxError(error)) throw error;
2962
- const relation = relationToolCode(error);
3152
+ const relation = inferRelationCode(error);
2963
3153
  if (relation !== void 0) throw new ToolboxError("RELATION", error instanceof Error ? error.message : String(error), {
2964
3154
  code: relation,
2965
3155
  operation: call.operation,
2966
3156
  model: call.model,
2967
3157
  ..."relation" in call ? { relation: call.relation } : {}
2968
3158
  });
2969
- const database = databaseToolCode(error);
3159
+ const database = inferDatabaseCode(error);
2970
3160
  if (database === void 0) throw error;
2971
3161
  throw new ToolboxError("DATABASE", error instanceof Error ? error.message : String(error), {
2972
3162
  code: database,
@@ -2977,44 +3167,44 @@ function createRelationTool(options) {
2977
3167
  });
2978
3168
  }
2979
3169
  /**
2980
- * Build a standalone LLM-callable tool that infers a JSON Schema from example values — the
2981
- * utility half of the "existing API/DB → MCP tool" bridge (the other half,
2982
- * {@link createEndpointTool}, wraps one CONCRETE endpoint).
3170
+ * Builds a standalone LLM-callable tool that infers a JSON Schema from example values — the utility
3171
+ * half of the bridge from an existing API or database into an MCP tool (the other half,
3172
+ * {@link createEndpointTool}, wraps one concrete endpoint).
2983
3173
  *
2984
3174
  * @remarks
2985
- * The universal tool-handler contract (AGENTS §14): validates the call args against
3175
+ * The universal tool-handler contract: validates the call args against
2986
3176
  * {@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
2989
- * the tool-parameters convention every other `create*Tool` factory advertises), and RETURNS the
3177
+ * booleans, `candidates` an optional array), infers a schema through `@orkestrel/contract`'s
3178
+ * `samplesToSchema`, wraps a non-object root as `{ value: <schema> }` through `schemaToObject` (mirrors
3179
+ * the tool-parameters convention every other `create*Tool` factory advertises), and returns the
2990
3180
  * resulting parameters record. An empty `samples` array fails `inferToolShape`'s `min: 1` bound —
2991
3181
  * `contract.parse` returns `undefined` and the handler throws a typed `TOOL`
2992
3182
  * {@link import('./errors.js').ToolboxError}.
2993
3183
  *
2994
- * When `candidates` is ABSENT, the return is the bare parameters record — unchanged from before
2995
- * 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
2997
- * `schemaToShape`, NOT the `schemaToObject`-wrapped parameters — a bare-value sample checks a
3184
+ * When `candidates` is absent, the return is the bare parameters record — unchanged from before
3185
+ * this array existed. When `candidates` is present (any array, including empty), the handler
3186
+ * compiles a separate per-call contract from the raw inferred schema (through `@orkestrel/contract`'s
3187
+ * `schemaToShape`, not the `schemaToObject`-wrapped parameters — a bare-value sample checks a
2998
3188
  * bare-value candidate) and returns `{ parameters, checks }`, one check per candidate at the same
2999
- * index. Every entry has a UNIFORM shape — `{ index, valid, coercible }`, with `faults` added ONLY
3000
- * when `valid` is `false`: `valid` is the STRICT guard verdict (`checker.is(candidate)`), the
3001
- * OPPOSITE of {@link createEndpointTool}'s enforcement, which coerces (`7` becomes `'7'` for a
3002
- * string slot) — here a conformance report answers "does this value conform AS-IS": `7` against a
3003
- * 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
3189
+ * index. Every entry has a uniform shape — `{ index, valid, coercible }`, with `faults` added only
3190
+ * when `valid` is `false`: `valid` is the strict guard verdict (`checker.is(candidate)`), the
3191
+ * opposite of {@link createEndpointTool}'s enforcement, which coerces (`7` becomes `'7'` for a
3192
+ * string slot) — here a conformance report answers "does this value conform as-is": `7` against a
3193
+ * string slot is `valid: false`, full stop. `coercible` answers a separate question — "would the
3194
+ * normalizing parse accept this value", that is would {@link createEndpointTool}'s default enforcement
3005
3195
  * 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
3196
+ * `valid`; by the house parse/guard round-trip, a `valid: true` entry is
3197
+ * always also `coercible: true`. `@orkestrel/contract`'s `explain` mirrors the normalizing
3008
3198
  * `parse`'s leniency, not `is`'s strictness — so a strictly-invalid but coercible candidate (`7`
3009
- * against a string slot) yields `{ valid: false, coercible: true, faults: [] }`: EMPTY faults, since
3199
+ * against a string slot) yields `{ valid: false, coercible: true, faults: [] }`: empty faults, because
3010
3200
  * the mismatch the normalizing parse would silently fix is not one `explain` reports. `faults`
3011
- * therefore only ever populates for a NON-coercible mismatch — a wrong type the parse can't coerce
3201
+ * therefore only ever populates for a non-coercible mismatch — a wrong type the parse can't coerce
3012
3202
  * (a boolean in a string slot), a missing required key, or an out-of-enum value — where
3013
3203
  * `coercible: false`. `checker.is` / `.parse` / `.explain` are all total over JSON-safe input — a
3014
- * 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
3016
- * throwing-getter `Proxy`) never reaches the checker at all — it fails the OUTER `args` parse
3017
- * against {@link import('./shapers.js').inferToolShape} and rejects the WHOLE call with the same
3204
+ * JSON-safe hostile candidate (a `__proto__`-carrying object, deeply nested data) reaches each of them
3205
+ * and yields a bounded, non-throwing per-candidate verdict; a non-JSON-safe candidate (for example a
3206
+ * throwing-getter `Proxy`) never reaches the checker at all — it fails the outer `args` parse
3207
+ * against {@link import('./shapers.js').inferToolShape} and rejects the whole call with the same
3018
3208
  * `TOOL` {@link import('./errors.js').ToolboxError} a malformed `samples`/`format`/`enum` throws,
3019
3209
  * with no per-candidate verdict produced.
3020
3210
  *
@@ -3093,36 +3283,36 @@ function createInferTool(options) {
3093
3283
  });
3094
3284
  }
3095
3285
  /**
3096
- * Wrap one CONCRETE endpoint ({@link import('./types.js').EndpointDefinition}) as an LLM-callable
3097
- * `ToolInterface` — the endpoint half of the "existing API/DB → MCP tool" bridge (the other half,
3098
- * {@link createInferTool}, is a standalone inference utility).
3286
+ * Wraps one concrete endpoint ({@link import('./types.js').EndpointDefinition}) as an LLM-callable
3287
+ * `ToolInterface` — the endpoint half of the bridge from an existing API or database into an MCP
3288
+ * tool (the other half, {@link createInferTool}, is a standalone inference utility).
3099
3289
  *
3100
3290
  * @remarks
3101
- * `parameters` is inferred ONCE at construction from `definition.samples` via
3291
+ * `parameters` is inferred once at construction from `definition.samples` through
3102
3292
  * `@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` —
3104
- * the SAME object-rooted schema is both the ADVERTISED `parameters` and, by default
3105
- * ({@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
3108
- * NORMALIZING parse, not a strict type check: a scalar is COERCED to its inferred type where the
3293
+ * `format` / `enum`), wrapping a non-object root as `{ value: <schema> }` through `schemaToObject` —
3294
+ * the same object-rooted schema is both the advertised `parameters` and, by default
3295
+ * ({@link import('./types.js').EndpointToolOptions.validate} `true`), the enforced contract:
3296
+ * `@orkestrel/contract`'s `schemaToShape` compiles it once (through `createContract`) into a
3297
+ * `ContractInterface` whose `.parse` runs on every call's `args` before `definition.execute` — a
3298
+ * normalizing parse, not a strict type check: a scalar is coerced to its inferred type where the
3109
3299
  * 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
3300
+ * `'false'`/`1`/`0`), so `definition.execute` receives the coerced value (for example `7` sent for a
3111
3301
  * string slot arrives as `'7'`), not the raw call value. A call whose `args` fails to parse into
3112
- * a record — a required key missing, or a value not coercible to its slot's type — THROWS a
3302
+ * a record — a required key missing, or a value not coercible to its slot's type — throws a
3113
3303
  * 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
3115
- * NEVER asserted, and a key outside the closed inferred schema is SILENTLY DROPPED rather than
3304
+ * structured `explain` faults, and `definition.execute` is never called. `format` annotations are
3305
+ * never asserted, and a key outside the closed inferred schema is silently dropped rather than
3116
3306
  * 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,
3307
+ * `validate: false`, the tool's `execute` passes through the model-supplied `args` to
3308
+ * `definition.execute` without re-validation — the raw-passthrough opt-out. Either way, the
3309
+ * definition's return flows back as the tool call's plain result; a throw propagates uncaught,
3120
3310
  * isolated by the `ToolManagerInterface` (`@orkestrel/tool`) into the canonical error envelope
3121
- * (AGENTS §14) — never caught or re-wrapped here.
3311
+ * — never caught or re-wrapped here.
3122
3312
  *
3123
3313
  * @param definition - The endpoint's identity, non-empty samples, and local handler (see
3124
3314
  * {@link import('./types.js').EndpointDefinition})
3125
- * @param options - Construction-time inference tuning + the validate opt-out (see
3315
+ * @param options - Construction-time inference tuning and the validate opt-out (see
3126
3316
  * {@link import('./types.js').EndpointToolOptions})
3127
3317
  * @returns A `ToolInterface` named `definition.name`
3128
3318
  *
@@ -3135,12 +3325,12 @@ function createInferTool(options) {
3135
3325
  * name: 'lookupUser',
3136
3326
  * description: 'Look up a user by id.',
3137
3327
  * samples: [{ id: '1', name: 'Ada' }, { id: '2', name: 'Bob' }],
3138
- * invoke: (args) => ({ id: args.id, name: 'Ada' }),
3328
+ * execute: (args) => ({ id: args.id, name: 'Ada' }),
3139
3329
  * })
3140
3330
  * const tools = createToolManager()
3141
3331
  * tools.add(tool)
3142
3332
  *
3143
- * // conforming args (all required keys present) parse and reach `invoke`
3333
+ * // conforming args (all required keys present) parse and reach the definition's `execute`
3144
3334
  * const result = await tools.execute({
3145
3335
  * id: 'call-1',
3146
3336
  * name: 'lookupUser',
@@ -3149,7 +3339,7 @@ function createInferTool(options) {
3149
3339
  * // result.value -> { id: '1', name: 'Ada' }
3150
3340
  *
3151
3341
  * // a nonconforming call (id is not coercible to the required string) is rejected before
3152
- * // `invoke` runs
3342
+ * // the definition's `execute` runs
3153
3343
  * const rejected = await tools.execute({
3154
3344
  * id: 'call-2',
3155
3345
  * name: 'lookupUser',
@@ -3170,7 +3360,7 @@ function createEndpointTool(definition, options) {
3170
3360
  description: definition.description,
3171
3361
  ...parameters === void 0 ? {} : { parameters },
3172
3362
  execute(args) {
3173
- return definition.invoke(args);
3363
+ return definition.execute(args);
3174
3364
  }
3175
3365
  });
3176
3366
  const contract = (0, _orkestrel_contract.createContract)((0, _orkestrel_contract.schemaToShape)(objectSchema));
@@ -3184,7 +3374,7 @@ function createEndpointTool(definition, options) {
3184
3374
  name: definition.name,
3185
3375
  faults: contract.explain(args)
3186
3376
  });
3187
- return definition.invoke(parsed);
3377
+ return definition.execute(parsed);
3188
3378
  }
3189
3379
  });
3190
3380
  }
@@ -3209,7 +3399,7 @@ exports.DatabaseResolver = DatabaseResolver;
3209
3399
  exports.INFER_TOOL_DESCRIPTION = INFER_TOOL_DESCRIPTION;
3210
3400
  exports.INFER_TOOL_NAME = INFER_TOOL_NAME;
3211
3401
  exports.INFER_TOOL_SUMMARY = INFER_TOOL_SUMMARY;
3212
- exports.MAX_WORKFLOW_DEPTH = MAX_WORKFLOW_DEPTH;
3402
+ exports.MAX_WORKFLOW_CHAIN = MAX_WORKFLOW_CHAIN;
3213
3403
  exports.MemoryDefinitionStore = MemoryDefinitionStore;
3214
3404
  exports.PROMPT_TOOL_DESCRIPTION = PROMPT_TOOL_DESCRIPTION;
3215
3405
  exports.PROMPT_TOOL_NAME = PROMPT_TOOL_NAME;
@@ -3229,13 +3419,13 @@ exports.WORKSPACE_TOOL_DESCRIPTION = WORKSPACE_TOOL_DESCRIPTION;
3229
3419
  exports.WORKSPACE_TOOL_EXAMPLE = WORKSPACE_TOOL_EXAMPLE;
3230
3420
  exports.WORKSPACE_TOOL_NAME = WORKSPACE_TOOL_NAME;
3231
3421
  exports.WORKSPACE_TOOL_SUMMARY = WORKSPACE_TOOL_SUMMARY;
3232
- exports.agentTag = agentTag;
3233
3422
  exports.agentToolShape = agentToolShape;
3234
3423
  exports.answerToolShape = answerToolShape;
3235
3424
  exports.clampQuery = clampQuery;
3236
- exports.columnKindShape = columnKindShape;
3237
- exports.columnShape = columnShape;
3425
+ exports.columnPrimitiveShape = columnPrimitiveShape;
3238
3426
  exports.columnSpecShape = columnSpecShape;
3427
+ exports.compileColumn = compileColumn;
3428
+ exports.compileColumnPrimitive = compileColumnPrimitive;
3239
3429
  exports.completeDraft = completeDraft;
3240
3430
  exports.completePhaseDraft = completePhaseDraft;
3241
3431
  exports.completeTaskDraft = completeTaskDraft;
@@ -3256,7 +3446,6 @@ exports.createWorkflowDraftContract = createWorkflowDraftContract;
3256
3446
  exports.createWorkflowFunctions = createWorkflowFunctions;
3257
3447
  exports.createWorkflowTool = createWorkflowTool;
3258
3448
  exports.createWorkspaceTool = createWorkspaceTool;
3259
- exports.databaseToolCode = databaseToolCode;
3260
3449
  exports.databaseToolShape = databaseToolShape;
3261
3450
  exports.deriveWorkflowDepth = deriveWorkflowDepth;
3262
3451
  exports.describeToolShape = describeToolShape;
@@ -3265,38 +3454,39 @@ exports.expandSteps = expandSteps;
3265
3454
  exports.expandTables = expandTables;
3266
3455
  exports.extendLineage = extendLineage;
3267
3456
  exports.includeShape = includeShape;
3457
+ exports.inferDatabaseCode = inferDatabaseCode;
3458
+ exports.inferRelationCode = inferRelationCode;
3459
+ exports.inferTerminalCode = inferTerminalCode;
3268
3460
  exports.inferToolShape = inferToolShape;
3269
3461
  exports.isAgentFunction = isAgentFunction;
3270
- exports.isColumnKind = isColumnKind;
3462
+ exports.isColumnPrimitive = isColumnPrimitive;
3271
3463
  exports.isColumnSpec = isColumnSpec;
3272
3464
  exports.isDatabaseDefinition = isDatabaseDefinition;
3273
3465
  exports.isToolboxError = isToolboxError;
3274
3466
  exports.isWorkflowLineage = isWorkflowLineage;
3275
3467
  exports.keyShape = keyShape;
3276
- exports.kindShape = kindShape;
3277
- exports.lineageOf = lineageOf;
3278
3468
  exports.managerShape = managerShape;
3469
+ exports.normalizeLineage = normalizeLineage;
3470
+ exports.normalizeQuery = normalizeQuery;
3279
3471
  exports.orderShape = orderShape;
3280
3472
  exports.phaseDraftShape = phaseDraftShape;
3281
3473
  exports.promptToolShape = promptToolShape;
3282
- exports.queryOf = queryOf;
3283
3474
  exports.queryShape = queryShape;
3284
- exports.relationKeyShape = relationKeyShape;
3285
- exports.relationManagerOf = relationManagerOf;
3286
- exports.relationModelOf = relationModelOf;
3287
- exports.relationToolCode = relationToolCode;
3288
3475
  exports.relationToolShape = relationToolShape;
3476
+ exports.resolveLimit = resolveLimit;
3477
+ exports.resolveRelationManager = resolveRelationManager;
3478
+ exports.resolveRelationModel = resolveRelationModel;
3289
3479
  exports.rowShape = rowShape;
3290
3480
  exports.rowsShape = rowsShape;
3291
3481
  exports.singleKeyShape = singleKeyShape;
3292
3482
  exports.stepShape = stepShape;
3483
+ exports.summarizeWorkflow = summarizeWorkflow;
3293
3484
  exports.tableSpecShape = tableSpecShape;
3485
+ exports.tagAgent = tagAgent;
3486
+ exports.tagWorkflow = tagWorkflow;
3294
3487
  exports.taskDraftShape = taskDraftShape;
3295
- exports.terminalToolCode = terminalToolCode;
3296
3488
  exports.workflowDraftShape = workflowDraftShape;
3297
3489
  exports.workflowStepsShape = workflowStepsShape;
3298
- exports.workflowTag = workflowTag;
3299
- exports.workflowToolSummary = workflowToolSummary;
3300
3490
  exports.workspaceToolShape = workspaceToolShape;
3301
3491
 
3302
3492
  //# sourceMappingURL=index.cjs.map