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