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