@orkestrel/tool 0.0.6 → 0.0.8

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.
@@ -1,2649 +1,327 @@
1
- import { AgentInterface } from '@orkestrel/agent';
2
- import { AgentRegistryInterface } from '@orkestrel/agent';
3
- import { ArrayShape } from '@orkestrel/contract';
4
- import { BooleanShape } from '@orkestrel/contract';
5
- import { ColumnSchema } from '@orkestrel/database';
6
- import { Condition } from '@orkestrel/database';
7
- import { Connector } from '@orkestrel/database';
8
- import { ContractInterface } from '@orkestrel/contract';
9
- import { ContractShape } from '@orkestrel/contract';
10
- import { ConversationStoreInterface } from '@orkestrel/agent';
11
- import { Criteria } from '@orkestrel/database';
12
- import { DatabaseErrorCode } from '@orkestrel/database';
13
- import { DatabaseInterface } from '@orkestrel/database';
14
- import { Direction } from '@orkestrel/database';
15
- import { DriverInterface } from '@orkestrel/database';
16
- import { Include } from '@orkestrel/relation';
17
- import { JSONShape } from '@orkestrel/contract';
18
- import { KeyFunction } from '@orkestrel/database';
19
- import { LiteralShape } from '@orkestrel/contract';
20
- import { ModelInterface } from '@orkestrel/relation';
21
- import { NumberShape } from '@orkestrel/contract';
22
- import { ObjectShape } from '@orkestrel/contract';
23
- import { OptionalShape } from '@orkestrel/contract';
24
- import { PromptType } from '@orkestrel/terminal';
25
- import { RelationErrorCode } from '@orkestrel/relation';
26
- import { RelationManagerInterface } from '@orkestrel/relation';
27
- import { StringShape } from '@orkestrel/contract';
28
- import { TableInterface } from '@orkestrel/database';
29
- import { TableSchema } from '@orkestrel/database';
30
- import { TablesShape } from '@orkestrel/database';
31
- import { TerminalManagerInterface } from '@orkestrel/terminal';
32
- import { ToolInterface } from '@orkestrel/agent';
33
- import { ToolManagerInterface } from '@orkestrel/agent';
34
- import { UnionShape } from '@orkestrel/contract';
35
- import { WorkflowDefinition } from '@orkestrel/workflow';
36
- import { WorkflowFunction } from '@orkestrel/workflow';
37
- import { WorkflowResult } from '@orkestrel/workflow';
38
- import { WorkflowRunnerInterface } from '@orkestrel/workflow';
39
- import { WorkflowStatus } from '@orkestrel/workflow';
40
- import { WorkflowStoreInterface } from '@orkestrel/workflow';
41
- import { WorkspaceManagerInterface } from '@orkestrel/agent';
42
- import { WorkspaceStoreInterface } from '@orkestrel/agent';
1
+ import { Failure } from '@orkestrel/contract';
2
+ import { Success } from '@orkestrel/contract';
43
3
 
44
4
  /**
45
- * The maximum nesting depth a delegation chain (agent tool → sub-agent → agent tool → …) may
46
- * reach — the bound {@link import('./factories.js').createAgentTool}'s depth/cycle guard
47
- * enforces.
5
+ * Create an executable tool.
48
6
  *
49
- * @remarks
50
- * Deliberately a SEPARATE constant from {@link MAX_WORKFLOW_DEPTH} (rather than the two guards
51
- * sharing one reference): the two guards bound DIFFERENT chains (workflow nesting vs. agent
52
- * delegation) that happen to share a value today, and keeping this bound decoupled means a
53
- * future change to one never silently shifts the other. Same numeric value by convention, not
54
- * by shared reference.
55
- */
56
- export declare const AGENT_TOOL_DEPTH = 8;
57
-
58
- export declare const AGENT_TOOL_DESCRIPTION: string;
59
-
60
- /**
61
- * The name {@link import('./factories.js').createAgentTool} advertises by default — the key a
62
- * model calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under.
63
- */
64
- export declare const AGENT_TOOL_NAME = "agent";
65
-
66
- /**
67
- * The lean {@link import('@orkestrel/agent').ToolInterface.summary} {@link import('./factories.js').createAgentTool}
68
- * advertises in place of {@link AGENT_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
69
- * (`@orkestrel/agent`) advertises `summary ?? description`, so this one-sentence text stands in
70
- * for the full teaching description; the full text stays retrievable via
71
- * {@link import('./factories.js').createDescribeTool}.
72
- */
73
- export declare const 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.";
74
-
75
- /**
76
- * Options for {@link import('./factories.js').createAgentFunction} — the OPT-IN adapter that
77
- * wraps a live `AgentInterface` (`@orkestrel/agent`) as a `WorkflowFunction`
78
- * (`@orkestrel/workflow`), folding a nested workflow-authoring depth / cycle guard into its
79
- * closure.
80
- *
81
- * @remarks
82
- * All fields are optional: omitted entirely, the adapter runs the agent with no nested workflow
83
- * tool bound and no depth/cycle bound (depth `0`, empty ancestry).
84
- * - `runner` — when supplied, the adapter BINDS a depth/cycle-aware
85
- * {@link import('./factories.js').createWorkflowTool} onto the agent's `context.tools` (the
86
- * propagation seam), so the agent can author + run a NESTED workflow through it. Omitted ⇒ the
87
- * agent runs with no workflow tool bound.
88
- * - `depth` — this invocation's nesting depth (default `0`); the bound workflow tool runs its
89
- * nested workflow at `depth + 1`, bounded by
90
- * {@link import('./constants.js').MAX_WORKFLOW_DEPTH}.
91
- * - `ancestry` — the workflow / agent identifiers already in this run chain (default empty); a
92
- * cycle (this agent already present) is rejected with a typed `DEPTH` `WorkflowError`
93
- * (`@orkestrel/workflow`).
94
- */
95
- export declare interface AgentFunctionOptions {
96
- readonly runner?: WorkflowRunnerInterface;
97
- readonly depth?: number;
98
- readonly ancestry?: readonly string[];
99
- }
100
-
101
- /**
102
- * The ancestry identifier of an agent in a run chain — `agent:<name>`.
103
- *
104
- * @remarks
105
- * The agent counterpart of {@link workflowTag}: {@link import('./factories.js').createAgentFunction}
106
- * / {@link import('./factories.js').createWorkflowTool} guard against re-entering an agent or
107
- * workflow already in the chain (a typed `DEPTH` `WorkflowError`, `@orkestrel/workflow`). The
108
- * `agent:` namespace keeps it distinct from a same-string workflow id.
109
- *
110
- * @param name - The agent's identifier / registry name
111
- * @returns The namespaced ancestry tag (`agent:<name>`)
112
- */
113
- export declare function agentTag(name: string): string;
114
-
115
- /**
116
- * The FLAT args {@link import('./factories.js').createAgentTool} accepts — a delegated `task`
117
- * plus the minimal optional `AgentJobInput` (`@orkestrel/agent`) fields a caller may override
118
- * per-call.
119
- *
120
- * @remarks
121
- * `task` becomes the seed user message in the sub-agent's rehydrated conversation
122
- * (`AgentJobInput.messages`). `provider` / `tools` / `system` shadow the tool's own
123
- * {@link AgentToolOptions} defaults for this ONE call when supplied.
124
- */
125
- export declare interface AgentToolArguments {
126
- readonly task: string;
127
- readonly provider?: string;
128
- readonly tools?: readonly string[];
129
- readonly system?: string;
130
- }
131
-
132
- /**
133
- * Thrown by {@link import('./factories.js').createAgentTool}'s and
134
- * {@link import('./factories.js').createDescribeTool}'s handlers on every failure path — a
135
- * malformed / unresolvable call or an unknown tool name (`TOOL`), a delegation that would
136
- * exceed the configured depth bound or re-enter an ancestor (`DEPTH`), a prompt cycle
137
- * (`DEADLOCK`), a prompt that expired before it was answered (`EXPIRE`), or an answer that
138
- * failed to apply (`ANSWER`) — the last three thrown by
139
- * {@link import('./factories.js').createPromptTool} / {@link import('./factories.js').createAnswerTool}.
140
- * The upcoming database / relation tools (SRC-1's later units) will throw it too: a typed
141
- * `@orkestrel/database` failure re-surfaces as `DATABASE`, a typed `@orkestrel/relation` failure
142
- * as `RELATION` — each carrying the package's own granular error code in `context`.
143
- *
144
- * @remarks
145
- * Carries a machine-readable `code` (see {@link import('./types.js').AgentToolErrorCode}) and
146
- * an optional `context` bag for structured diagnostics. The `ToolManagerInterface`
147
- * (`@orkestrel/agent`) isolates every throw into the canonical tool result's top-level `error`
148
- * (AGENTS §14) — nothing escapes the run.
149
- *
150
- * @example
151
- * ```ts
152
- * import { AgentToolError, isAgentToolError } from '@src/core'
153
- *
154
- * try {
155
- * throw new AgentToolError('TOOL', 'task is required')
156
- * } catch (error) {
157
- * if (isAgentToolError(error)) console.log(error.code) // 'TOOL'
158
- * }
159
- * ```
160
- */
161
- export declare class AgentToolError extends Error {
162
- readonly code: AgentToolErrorCode;
163
- readonly context?: Readonly<Record<string, unknown>>;
164
- constructor(code: AgentToolErrorCode, message: string, context?: Readonly<Record<string, unknown>>);
165
- }
166
-
167
- /**
168
- * The error CODE a thrown {@link import('./errors.js').AgentToolError} carries — the SAME
169
- * two-code shape `@orkestrel/workflow`'s `WorkflowError` uses for its own tool guard, kept
170
- * distinct per package (AGENTS §14: a thrown, typed, code-bearing error, never a `{ error }`
171
- * return).
172
- *
173
- * @remarks
174
- * `TOOL` — malformed / unresolvable call args (a missing `task`, no resolvable `provider`).
175
- * `DEPTH` — the delegation would exceed {@link import('./constants.js').AGENT_TOOL_DEPTH}, or
176
- * the resolved agent is already an ancestor (a cycle).
177
- * `DEADLOCK` — an `ask` call ({@link import('./factories.js').createPromptTool}) would form a
178
- * prompt cycle (`TerminalManagerInterface.ask`, `@orkestrel/terminal`, rejects with its own
179
- * `TerminalError('DEADLOCK')`, re-surfaced here).
180
- * `EXPIRE` — the addressed prompt expired before it was answered.
181
- * `ANSWER` — {@link import('./factories.js').createAnswerTool}'s answer call failed to apply
182
- * (an unknown prompt id, a rejected value, or the terminal itself unknown —
183
- * `TerminalAnswerResult.error`, `@orkestrel/terminal`).
184
- * `DATABASE` — a typed `@orkestrel/database` failure (`DatabaseError`), re-surfaced with the
185
- * granular {@link import('@orkestrel/database').DatabaseErrorCode} carried in `context`.
186
- * `RELATION` — a typed `@orkestrel/relation` failure (`RelationError`), re-surfaced with the
187
- * granular {@link import('@orkestrel/relation').RelationErrorCode} carried in `context`.
188
- */
189
- export declare type AgentToolErrorCode = 'TOOL' | 'DEPTH' | 'DEADLOCK' | 'EXPIRE' | 'ANSWER' | 'DATABASE' | 'RELATION';
190
-
191
- /**
192
- * Options for {@link import('./factories.js').createAgentTool} — the sub-agent delegation
193
- * defaults, the nesting-depth / cycle guard bookkeeping, and the advertised tool overrides.
194
- *
195
- * @remarks
196
- * - `name` / `description` — advertised tool overrides; default to
197
- * {@link import('./constants.js').AGENT_TOOL_NAME} / {@link import('./constants.js').AGENT_TOOL_DESCRIPTION}.
198
- * - `provider` — the DEFAULT registry provider key used when a call omits `provider`; a call
199
- * that supplies its own `provider` overrides this. One of `provider` (here or per-call) MUST
200
- * resolve, or the handler throws a typed `TOOL` {@link import('./errors.js').AgentToolError}.
201
- * - `tools` — the DEFAULT registry tool-name list loaded into the delegated sub-agent; a
202
- * per-call `tools` list overrides (never merges with) this default.
203
- * - `system` — the DEFAULT system prompt seeding the sub-agent's context; a per-call `system`
204
- * overrides this.
205
- * - `depth` — this invocation's nesting depth (default `0`); a delegated sub-agent that itself
206
- * calls this tool again runs at `depth + 1`, bounded by
207
- * {@link import('./constants.js').AGENT_TOOL_DEPTH}.
208
- * - `ancestry` — the sub-agent identifiers already in this delegation chain (default empty); a
209
- * cycle (the resolved agent already present) is rejected with a typed `DEPTH`
210
- * {@link import('./errors.js').AgentToolError}.
211
- * - `store` — this package's ADDITION: when supplied, the handler persists the delegated
212
- * sub-agent's active conversation snapshot (`store.set(agent.context.conversations.active.snapshot())`)
213
- * once `agent.generate()` settles successfully, before returning — one snapshot per delegation
214
- * (each `registry.build` mints a fresh conversation id, so a shared store accumulates an
215
- * audit log rather than colliding). Omitted ⇒ no persistence from this tool.
216
- *
217
- * Conversation persistence for a delegated sub-agent has TWO independent seams, composable
218
- * together: this `store` slot persists EACH delegation's conversation individually, and/or an
219
- * `AgentRegistryInterface` built with `AgentRegistryOptions.store` (`@orkestrel/agent`) backs
220
- * EVERY agent it builds — including ones built through this tool — with a store-backed
221
- * `ConversationManagerInterface` of its own. Neither is required; either or both may be used.
222
- */
223
- export declare interface AgentToolOptions {
224
- readonly name?: string;
225
- readonly description?: string;
226
- readonly provider?: string;
227
- readonly tools?: readonly string[];
228
- readonly system?: string;
229
- readonly depth?: number;
230
- readonly ancestry?: readonly string[];
231
- readonly store?: ConversationStoreInterface;
232
- }
233
-
234
- /**
235
- * The shape of {@link import('./types.js').AgentToolArguments} —
236
- * {@link import('./factories.js').createAgentTool}'s advertised `parameters`.
237
- *
238
- * @remarks
239
- * `task` is the only required field (a non-empty string); `provider` / `tools` / `system`
240
- * are per-call overrides of the tool's own configured defaults.
241
- */
242
- export declare const agentToolShape: ObjectShape<{
243
- task: StringShape;
244
- provider: OptionalShape<StringShape>;
245
- tools: OptionalShape<ArrayShape<StringShape>>;
246
- system: OptionalShape<StringShape>;
247
- }, false>;
248
-
249
- export declare const ANSWER_TOOL_DESCRIPTION: string;
250
-
251
- /**
252
- * The name {@link import('./factories.js').createAnswerTool} advertises by default — the key a
253
- * model calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under.
254
- */
255
- export declare const ANSWER_TOOL_NAME = "answer";
256
-
257
- /**
258
- * The lean {@link import('@orkestrel/agent').ToolInterface.summary} {@link import('./factories.js').createAnswerTool}
259
- * advertises in place of {@link ANSWER_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
260
- * (`@orkestrel/agent`) advertises `summary ?? description`, so this one-sentence text stands in
261
- * for the full teaching description; the full text stays retrievable via
262
- * {@link import('./factories.js').createDescribeTool}.
263
- */
264
- export declare const ANSWER_TOOL_SUMMARY = "List prompts addressed to this terminal, or answer one by id. Call describe('answer') for the required fields.";
265
-
266
- /**
267
- * Options for {@link import('./factories.js').createAnswerTool} — the live
268
- * {@link TerminalManagerInterface} (`@orkestrel/terminal`) to list / answer prompts through, the
269
- * terminal name `to`, and the advertised tool overrides.
270
- *
271
- * @remarks
272
- * - `manager` — the terminal manager whose `pending(to)` / `answer(to, id, value)` the tool's
273
- * handler calls — `pending` lists the prompts currently addressed to `to`, `answer` resolves
274
- * one by `id`. A failed `answer` (`TerminalAnswerResult.error`) re-surfaces as a typed
275
- * `ANSWER` {@link import('./errors.js').AgentToolError}.
276
- * - `to` — the terminal identity this tool lists / answers prompts FOR.
277
- * - `name` / `description` — advertised tool overrides; default to
278
- * {@link import('./constants.js').ANSWER_TOOL_NAME} / {@link import('./constants.js').ANSWER_TOOL_DESCRIPTION}.
279
- */
280
- export declare interface AnswerToolOptions {
281
- readonly manager: TerminalManagerInterface;
282
- readonly to: string;
283
- readonly name?: string;
284
- readonly description?: string;
285
- }
286
-
287
- /**
288
- * The shape of {@link import('./factories.js').createAnswerTool}'s call arguments — discriminated
289
- * by `operation`: `'pending'` lists the prompts addressed to this tool's terminal, `'answer'`
290
- * resolves one by `id` with a `value`.
291
- *
292
- * @remarks
293
- * `value`'s type varies by the ORIGINAL prompt's form (`string` for `'input'` / `'password'` /
294
- * `'select'` / `'editor'`, `boolean` for `'confirm'`, `readonly string[]` for `'checkbox'`) —
295
- * `unionShape(stringShape(), booleanShape(), arrayShape(stringShape()))` expresses that
296
- * union directly, so `value` is typed as the full `string | boolean | readonly string[]` union
297
- * here (no lossy string-only fallback needed).
298
- */
299
- export declare const answerToolShape: UnionShape<readonly [ ObjectShape<{
300
- operation: LiteralShape<readonly ["pending"]>;
301
- }, false>, ObjectShape<{
302
- operation: LiteralShape<readonly ["answer"]>;
303
- id: StringShape;
304
- value: UnionShape<readonly [ StringShape, BooleanShape, ArrayShape<StringShape>]>;
305
- }, false>]>;
306
-
307
- /**
308
- * Clamp a `'records'` call's criteria to a row cap, and build the PROBE criteria the caller reads
309
- * with — the pure leaf {@link import('./factories.js').createDatabaseTool}'s `'records'` operation
310
- * uses to detect truncation without a separate `count` round trip.
311
- *
312
- * @remarks
313
- * The effective limit is `min(criteria?.limit ?? cap, cap)`, floored at `0` (so a caller can never
314
- * exceed the configured cap by supplying a larger `criteria.limit`). The returned probe criteria
315
- * requests ONE MORE row than the effective limit (`limit: effective + 1`) — if storage returns
316
- * that many, the caller knows the true result was truncated (`rows.length > effective`) and slices
317
- * back down to `effective` before returning.
318
- *
319
- * @example
320
- * ```ts
321
- * import { clampCriteria } from '@src/core'
322
- *
323
- * const { criteria, limit } = clampCriteria(undefined, 100)
324
- * // limit === 100, criteria.limit === 101 — a probe fetching one extra row
325
- * const rows = await table.records(criteria)
326
- * const truncated = rows.length > limit // true when storage had more than `limit` rows
327
- * ```
328
- *
329
- * @param criteria - The live criteria to clamp (or `undefined`)
330
- * @param cap - The row-count ceiling
331
- * @returns The PROBE criteria (`limit` bumped by one) and the effective `limit`
332
- */
333
- export declare function clampCriteria(criteria: Criteria | undefined, cap: number): Readonly<{
334
- criteria: Criteria;
335
- limit: number;
336
- }>;
337
-
338
- /**
339
- * Normalize an LLM-supplied answer `value` to the type {@link PromptType} `form` expects, so a
340
- * caller that only ever emits strings can still answer a typed prompt.
341
- *
342
- * @remarks
343
- * `'confirm'` coerces to a `boolean` — a `boolean` passes through, and the strings `'true'` /
344
- * `'false'` (case-insensitively) map to it; any other string is truthy-coerced via
345
- * `Boolean(value)`. `'checkbox'` coerces to `readonly string[]` — an array passes through
346
- * (stringifying each entry), a comma-separated string splits + trims into one, and any other
347
- * single (non-comma) string becomes a one-item array. Every other form (`'input'` / `'password'`
348
- * / `'select'` / `'editor'`) coerces to a plain `string` — a string passes through verbatim; a
349
- * non-string, non-object scalar (`number` / `boolean`) stringifies via `String(value)`; an
350
- * object or array (no lossless string form) falls back to `''` rather than serializing garbage.
351
- * Pure and total — never throws.
352
- *
353
- * @param form - The {@link PromptType} the answer is being coerced FOR
354
- * @param value - The raw, LLM-supplied answer value
355
- * @returns The coerced answer — `boolean` for `'confirm'`, `readonly string[]` for `'checkbox'`,
356
- * `string` otherwise
357
- */
358
- export declare function coerceAnswer(form: PromptType, value: unknown): string | boolean | readonly string[];
359
-
360
- /** One column's declared type — a primitive shorthand, or `integer` for a whole-number `number`. */
361
- export declare type ColumnKind = 'string' | 'integer' | 'number' | 'boolean';
362
-
363
- /** A {@link import('./types.js').ColumnKind} literal — the leaf {@link columnSpecShape} wraps. */
364
- export declare const columnKindShape: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
365
-
366
- /** Map a column NAME + its live `@orkestrel/database` `ContractShape` to a {@link ColumnSchema} — the leaf {@link tableSchema} maps over. */
367
- export declare function columnSchema(name: string, shape: ContractShape): ColumnSchema;
368
-
369
- /** Compile one {@link ColumnSpec} into its `@orkestrel/database` column shape — the per-column leaf {@link expandTables} maps over. */
370
- export declare function columnShape(spec: ColumnSpec): ContractShape;
371
-
372
- /**
373
- * One table column's spec — either a bare {@link ColumnKind} shorthand, or `{ type, optional }`
374
- * when the column may be absent from a row.
375
- */
376
- export declare type ColumnSpec = ColumnKind | Readonly<{
377
- type: ColumnKind;
378
- optional?: boolean;
379
- }>;
380
-
381
- /** A {@link import('./types.js').ColumnSpec} — a bare {@link columnKindShape}, or `{ type, optional }`. */
382
- export declare const columnSpecShape: UnionShape<readonly [ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
383
- type: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
384
- optional: OptionalShape<BooleanShape>;
385
- }, false>]>;
386
-
387
- /**
388
- * Complete a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesize any
389
- * MISSING `id` deterministically + positionally, and default any MISSING `name` to its
390
- * (now-resolved) `id`.
391
- *
392
- * @remarks
393
- * The positional id scheme is stable and human-legible: the workflow is `wf`, phase `i` is
394
- * `phase-<i>`, and task `j` of that phase is `<phaseId>-task-<j>` (so a provided phase id flows
395
- * into its tasks' synthesized ids). A PROVIDED `id` / `name` at any level is kept VERBATIM —
396
- * synthesis touches only the omitted ones. A missing `name` defaults to the resolved `id` (never
397
- * the other way round), so the result always has both. `run`, `description`, the per-phase
398
- * `concurrency` / `bail`, the per-task `retries` / `timeout`, and the workflow `bail` carry over
399
- * unchanged. The result is a complete {@link WorkflowDefinition}; the caller still validates it
400
- * against the STRICT contract.
401
- *
402
- * @param draft - The draft workflow (id/name optional at all three levels)
403
- * @returns A complete {@link WorkflowDefinition} with every id/name filled
404
- */
405
- export declare function completeDraft(draft: WorkflowDraft): WorkflowDefinition;
406
-
407
- /**
408
- * Complete one {@link PhaseDraft} into a strict phase definition — the per-phase step of
409
- * {@link completeDraft} (phase `index` → `phase-<index>` when its id is omitted).
410
- *
411
- * @param phase - The draft phase
412
- * @param index - The phase's positional index in the workflow
413
- * @returns A complete phase definition
414
- */
415
- export declare function completePhaseDraft(phase: PhaseDraft, index: number): WorkflowDefinition['phases'][number];
416
-
417
- /**
418
- * Complete one {@link TaskDraft} into a strict task definition — the per-task leaf step of
419
- * {@link completeDraft} (task `index` of phase `<phaseId>` → `<phaseId>-task-<index>` when its id
420
- * is omitted).
421
- *
422
- * @param task - The draft task
423
- * @param phaseId - The (resolved) parent phase id, so the synthesized task id nests under it
424
- * @param index - The task's positional index within its phase
425
- * @returns A complete task definition
426
- */
427
- export declare function completeTaskDraft(task: TaskDraft, phaseId: string, index: number): WorkflowDefinition['phases'][number]['tasks'][number];
428
-
429
- /** One SERIALIZED WHERE condition — `values` is ALWAYS an array, even for a single-value operator. */
430
- export declare const conditionShape: ObjectShape<{
431
- column: StringShape;
432
- operator: LiteralShape<readonly ["equals", "not", "above", "below", "from", "to", "between", "like", "glob", "starts", "ends", "any", "none", "absent", "present"]>;
433
- values: ArrayShape<JSONShape>;
434
- connector: OptionalShape<LiteralShape<readonly ["and", "or"]>>;
435
- }, false>;
436
-
437
- /**
438
- * Wrap a live `AgentInterface` (`@orkestrel/agent`) as a {@link WorkflowFunction}
439
- * (`@orkestrel/workflow`) — the OPT-IN adapter that runs the agent to a settled result, folding
440
- * a nested workflow-authoring depth / cycle guard into its own closure.
441
- *
442
- * @remarks
443
- * OWNED here now (ported from `@orkestrel/workflow`). Composes into a caller's
444
- * `WorkflowOptions.functions` registry like any other behavior; the pure workflow runner has no
445
- * knowledge of agents itself. Before running the agent, the depth/cycle guard REJECTS the call
446
- * (a THROWN typed `DEPTH` `WorkflowError`, which the leaf `fail`s) when running it would push a
447
- * nested chain past {@link import('./constants.js').MAX_WORKFLOW_DEPTH}, OR when this agent is
448
- * already an ancestor (a cycle). When {@link import('./types.js').AgentFunctionOptions.runner}
449
- * is supplied, the adapter BINDS a depth/cycle-aware {@link createWorkflowTool} onto the agent's
450
- * `context.tools` (the propagation seam) — closed over `depth` and the extended ancestry (the
451
- * tool itself computes `depth + 1` internally) — so the agent can author + run a NESTED workflow
452
- * through it; the wrapped default is the CURRENT task's own workflow id (used only on a no-args
453
- * tool call). The task's cancellation folds into the agent run: an already-aborted
454
- * `controller.signal` cancels the agent up front; otherwise a one-shot listener fires
455
- * `agent.abort(reason)` when the task cancels, removed in `finally`. `agent.generate()` resolves
456
- * a partial `AgentResult` on a cancel (never rejects), returned as the task's completed value.
457
- *
458
- * A bound agent is effectively SINGLE-RUN: `context.tools.add` binds one `ToolInterface` under
459
- * the fixed {@link import('./constants.js').WORKFLOW_TOOL_NAME}, and `agent.generate()` /
460
- * `agent.abort()` are per-agent state. Two CONCURRENT tasks sharing the SAME `agent` instance
461
- * race on that one tool binding (last-write-wins) and on generate/abort — give each concurrent
462
- * task its OWN agent instance.
463
- *
464
- * @param agent - The live `AgentInterface` to run
465
- * @param options - The nested-workflow binding + depth/cycle bookkeeping (see {@link import('./types.js').AgentFunctionOptions})
466
- * @returns A {@link WorkflowFunction} that runs `agent` to its settled result
467
- *
468
- * @example
469
- * ```ts
470
- * import { createAgentFunction } from '@src/core'
471
- * import { createWorkflowRunner } from '@orkestrel/workflow'
472
- *
473
- * const runner = createWorkflowRunner()
474
- * const review = createAgentFunction(myAgent, { runner })
475
- * await runner.execute(definition, { functions: { review } })
476
- * ```
477
- */
478
- export declare function createAgentFunction(agent: AgentInterface, options?: AgentFunctionOptions): WorkflowFunction;
479
-
480
- /**
481
- * Build an LLM-callable sub-agent delegation tool — resolves a live, seeded `AgentInterface`
482
- * from `registry` and runs it to completion for ONE delegated `task`.
483
- *
484
- * @remarks
485
- * The universal tool-handler contract (AGENTS §14): validates the call args against
486
- * {@link import('./shapers.js').agentToolShape}, assembles an `AgentJobInput` (`task` seeds the
487
- * sub-agent's conversation as a single `user` message; `provider` / `tools` / `system` fall
488
- * back to the tool's own {@link import('./types.js').AgentToolOptions} defaults), rehydrates the sub-agent via
489
- * `registry.build`, runs it with `agent.generate()`, and returns the settled
490
- * `AgentResult.content` string (the sub-agent's final text). A missing / unresolvable `provider`, or a malformed call, THROWS a typed `TOOL`
491
- * {@link import('./errors.js').AgentToolError}; a delegation that would exceed
492
- * {@link import('./constants.js').AGENT_TOOL_DEPTH}, or re-enter an already-delegated agent (a
493
- * cycle), THROWS a typed `DEPTH` {@link import('./errors.js').AgentToolError} — both isolated
494
- * by the `ToolManagerInterface` into the canonical tool result's top-level `error`.
495
- *
496
- * `AgentInterface` (`@orkestrel/agent`) exposes no teardown method — a bound sub-agent's
497
- * lifetime is the single `generate()` call this handler awaits; there is nothing to release
498
- * afterwards (unlike a store-backed resource, its state lives entirely in the resolved
499
- * `AgentContextInterface`, owned by the caller's registry).
500
- *
501
- * @param registry - The `AgentRegistryInterface` a delegated job resolves against (providers,
502
- * tools, authorities, schedulers, and the `build` rehydration seam)
503
- * @param options - Delegation defaults, depth/ancestry bookkeeping, and advertised overrides
504
- * (see {@link import('./types.js').AgentToolOptions})
505
- * @returns A `ToolInterface` (named {@link import('./constants.js').AGENT_TOOL_NAME} by default)
506
- *
507
- * @example
508
- * ```ts
509
- * import { createAgentTool } from '@src/core'
510
- * import { createAgentRegistry, createToolManager } from '@orkestrel/agent'
511
- *
512
- * const registry = createAgentRegistry({ providers: { openai: myProvider } })
513
- * const tool = createAgentTool(registry, { provider: 'openai' })
514
- * const tools = createToolManager()
515
- * tools.add(tool) // a model can now delegate a task to a sub-agent
516
- * ```
517
- */
518
- export declare function createAgentTool(registry: AgentRegistryInterface, options?: AgentToolOptions): ToolInterface;
519
-
520
- /**
521
- * Build an LLM-callable answer tool — the ANSWER side of the terminal seam. Lists the prompts
522
- * currently addressed to {@link import('./types.js').AnswerToolOptions.to}, or answers one of
523
- * them by id.
524
- *
525
- * @remarks
526
- * The universal tool-handler contract (AGENTS §14): validates the call args against
527
- * {@link import('./shapers.js').answerToolShape} (discriminated by `operation`). `'pending'`
528
- * returns a compact list (`{ id, from, form, message }`) of every prompt currently addressed to
529
- * `to` (`TerminalManagerInterface.pending`, `@orkestrel/terminal`). `'answer'` looks the prompt
530
- * up by `id` (an unknown id throws a typed `ANSWER` {@link import('./errors.js').AgentToolError}),
531
- * normalizes the model-supplied `value` to the prompt's own form
532
- * ({@link import('./helpers.js').coerceAnswer}), and applies it via
533
- * `TerminalManagerInterface.answer` — a rejected / unknown / unresolvable outcome
534
- * (`TerminalAnswerResult.error`) re-surfaces as a typed `ANSWER` `AgentToolError`; success returns
535
- * `{ answered: id }`. `to` is FIXED at construction
536
- * ({@link import('./types.js').AnswerToolOptions.to}) — never read from the model-supplied args —
537
- * so a model cannot spoof which terminal it is answering for. Concurrent answerers racing on one
538
- * endpoint are FIRST-WRITE-WINS — a late answer to an already-settled prompt returns a typed
539
- * `ANSWER` `AgentToolError` (surfaced as a 422 over HTTP).
540
- *
541
- * @param options - The live manager, the fixed `to` identity, and advertised overrides (see
542
- * {@link import('./types.js').AnswerToolOptions})
543
- * @returns A `ToolInterface` (named {@link import('./constants.js').ANSWER_TOOL_NAME} by default)
544
- *
545
- * @example
546
- * ```ts
547
- * import { createAnswerTool } from '@src/core'
548
- * import { createTerminalManager, createToolManager } from '@orkestrel/terminal'
549
- *
550
- * const manager = createTerminalManager()
551
- * manager.add('reviewer')
552
- * const tool = createAnswerTool({ manager, to: 'reviewer' })
553
- * const tools = createToolManager()
554
- * tools.add(tool) // the reviewer terminal can now list/answer prompts addressed to it
555
- * ```
556
- */
557
- export declare function createAnswerTool(options: AnswerToolOptions): ToolInterface;
558
-
559
- /**
560
- * Create a {@link DefinitionStoreInterface} backed by one table of the `@orkestrel/database`
561
- * layer — the driver-pluggable twin of {@link createMemoryDefinitionStore}, storing each
562
- * database's definition as one opaque JSON column.
563
- *
564
- * @param driver - The {@link DriverInterface} backing the table (default an in-memory driver)
565
- * @returns A {@link DefinitionStoreInterface}
566
- *
567
- * @example
568
- * ```ts
569
- * import { createDatabaseDefinitionStore } from '@src/core'
570
- *
571
- * const store = createDatabaseDefinitionStore() // in-memory by default
572
- * ```
573
- */
574
- export declare function createDatabaseDefinitionStore(driver?: DriverInterface): DefinitionStoreInterface;
575
-
576
- /**
577
- * Build an LLM-callable database tool — create, query, and mutate `@orkestrel/database`
578
- * databases through one `operation`-discriminated call (AGENTS §14, matching
579
- * {@link createWorkspaceTool}'s single-tool-many-operations shape).
580
- *
581
- * @remarks
582
- * The universal tool-handler contract (AGENTS §14): validates the call args against
583
- * {@link import('./shapers.js').databaseToolShape}, dispatches to the matching operation, and
584
- * RETURNS a plain result on success. A database is resolved lazily and cached for the tool's
585
- * lifetime — `'create'` mints one from `tables` ({@link import('./helpers.js').expandTables}) and
586
- * a registered `driver` key ({@link import('./types.js').DatabaseToolOptions.drivers}, default
587
- * `{ memory: () => createMemoryDriver() }`); any other operation addressing an uncached id falls
588
- * back to {@link import('./types.js').DatabaseToolOptions.store} (an unknown id throws a typed
589
- * `TOOL` {@link import('./errors.js').AgentToolError}). When a `store` is configured, `'create'`
590
- * persists the new {@link import('./types.js').DatabaseDefinition} and `'destroy'` deletes it.
591
- *
592
- * `'migrate'` re-declares a LIVE handle's tables via `DatabaseInterface.import` (the SAME driver
593
- * and storage, a NEW typed view) and calls its `migrate` against the OLD deployed schema —
594
- * derived from the handle's OWN `export()` (via {@link import('./helpers.js').tableSchema}), so it
595
- * works for any handle, config-tracked or caller-supplied via
596
- * {@link import('./types.js').DatabaseToolOptions.databases}. `'records'` clamps its `criteria` to
597
- * {@link import('./types.js').DatabaseToolOptions.limit} (default
598
- * {@link import('./constants.js').DATABASE_TOOL_LIMIT}) via
599
- * {@link import('./helpers.js').clampCriteria}, reporting `truncated` when storage held more rows
600
- * than the cap. Every operation's `criteria` is normalized via
601
- * {@link import('./helpers.js').criteriaOf} (defaults an omitted condition `connector` to `'and'`).
602
- * When {@link import('./types.js').DatabaseToolOptions.readonly} is `true`, every mutating
603
- * operation throws a typed `TOOL` `AgentToolError` before doing anything. When
604
- * {@link import('./types.js').DatabaseToolOptions.timeout} is set, every `@orkestrel/database` call
605
- * this tool makes is given a fresh `AbortSignal.timeout(timeout)`. A typed `@orkestrel/database`
606
- * failure (`DatabaseError`) re-surfaces as a typed `DATABASE` `AgentToolError` carrying the
607
- * original {@link import('@orkestrel/database').DatabaseErrorCode} in `context.code`
608
- * ({@link import('./helpers.js').databaseToolCode}); an `AgentToolError` thrown by this tool's own
609
- * guards passes through unwrapped.
610
- *
611
- * A lazily re-minted database over the DEFAULT in-memory driver yields an EMPTY database — only
612
- * the {@link import('./types.js').DatabaseDefinition} schema persists in `store`, never rows;
613
- * durable rows need a persistent driver factory registered in
614
- * {@link import('./types.js').DatabaseToolOptions.drivers}. `'destroy'` closes whatever handle is
615
- * cached for the id, including an embedder-supplied
616
- * {@link import('./types.js').DatabaseToolOptions.databases} handle — the embedder relinquishes
617
- * that handle's lifecycle to this tool for any id it wires in. This tool assumes the
618
- * single-writer, non-reentrant model `@orkestrel/database` itself assumes — concurrent calls
619
- * against one id are NOT serialized by this tool. `'get'` is uncapped by
620
- * {@link import('./types.js').DatabaseToolOptions.limit} (bounded only by the caller's `key` array
621
- * size), unlike `'records'` / `'find'` / `'links'`.
622
- *
623
- * @param options - The tool's configuration (see {@link import('./types.js').DatabaseToolOptions})
624
- * @returns A `ToolInterface` (named {@link import('./constants.js').DATABASE_TOOL_NAME} by default)
625
- *
626
- * @example
627
- * ```ts
628
- * import { createDatabaseTool } from '@src/core'
629
- *
630
- * const tool = createDatabaseTool()
631
- * await tool.execute({
632
- * operation: 'create',
633
- * id: 'shop',
634
- * tables: { products: { columns: { name: 'string', price: 'number' } } },
635
- * })
636
- * ```
637
- */
638
- export declare function createDatabaseTool(options?: DatabaseToolOptions): ToolInterface;
639
-
640
- /**
641
- * Build an LLM-callable tool that returns the FULL `description` of another registered tool by
642
- * name — the counterpart to the lean `summary` the other tools in this package advertise
643
- * (`AGENT_TOOL_SUMMARY` / `WORKFLOW_TOOL_SUMMARY` / `WORKSPACE_TOOL_SUMMARY`).
644
- *
645
- * @remarks
646
- * `ToolManagerInterface.definitions()` (`@orkestrel/agent`) advertises `tool.summary ??
647
- * tool.description` — a lean one-sentence summary stands in for a tool's full teaching
648
- * description when `summary` is set, keeping the advertised tool list compact for a small model.
649
- * This tool is the on-demand expansion seam: given a registered tool's `name`, it looks the tool
650
- * up via `tools.tool(name)` and returns its full `description` (falling back to `summary` when a
651
- * tool has no `description` of its own, then a placeholder when it has neither).
652
- *
653
- * The universal tool-handler contract (AGENTS §14): validates the call args against
654
- * {@link import('./shapers.js').describeToolShape}, RETURNS the plain description string on
655
- * success, THROWS a typed `TOOL` {@link import('./errors.js').AgentToolError} on a malformed call
656
- * or an unknown tool name.
657
- *
658
- * @param tools - The `ToolManagerInterface` (`@orkestrel/agent`) whose registered tools this
659
- * tool can describe
660
- * @returns A `ToolInterface` (named {@link import('./constants.js').DESCRIBE_TOOL_NAME})
661
- *
662
- * @example
663
- * ```ts
664
- * import { createDescribeTool, createWorkflowTool } from '@src/core'
665
- * import { createToolManager } from '@orkestrel/agent'
666
- *
667
- * const tools = createToolManager()
668
- * tools.add(createWorkflowTool(definition, runner))
669
- * tools.add(createDescribeTool(tools))
670
- * const full = await tools.execute({ id: '1', name: 'describe', arguments: { name: 'workflow' } })
671
- * full.value // the workflow tool's full teaching description
672
- * ```
673
- */
674
- export declare function createDescribeTool(tools: ToolManagerInterface): ToolInterface;
675
-
676
- /**
677
- * Wrap one CONCRETE endpoint ({@link import('./types.js').EndpointDefinition}) as an LLM-callable
678
- * `ToolInterface` — the endpoint half of the "existing API/DB → MCP tool" bridge (the other half,
679
- * {@link createInferTool}, is a standalone inference utility).
680
- *
681
- * @remarks
682
- * `parameters` is inferred ONCE at construction from `definition.samples` via
683
- * `@orkestrel/contract`'s `samplesToSchema` (tuned by {@link import('./types.js').EndpointToolOptions}'s
684
- * `format` / `enum`), wrapping a non-object root as `{ value: <schema> }` via `schemaToObject` —
685
- * the SAME object-rooted schema is both the ADVERTISED `parameters` and, by default
686
- * ({@link import('./types.js').EndpointToolOptions.validate} `true`), the ENFORCED contract:
687
- * `@orkestrel/contract` 0.0.7's `schemaToShape` compiles it ONCE (via `createContract`) into a
688
- * `ContractInterface` whose `.parse` runs on every call's `args` before `definition.invoke` — a
689
- * NORMALIZING parse, not a strict type check: a scalar is COERCED to its inferred type where the
690
- * house parsers coerce (a number to/from a numeric string, a boolean from `'1'`/`'0'`/`'true'`/
691
- * `'false'`/`1`/`0`), so `definition.invoke` receives the COERCED value (e.g. `7` sent for a
692
- * string slot arrives as `'7'`), not the raw call value. A call whose `args` fails to parse into
693
- * a record — a required key missing, or a value not coercible to its slot's type — THROWS a
694
- * typed `TOOL` {@link import('./errors.js').AgentToolError} carrying the compiled contract's
695
- * structured `explain` faults, and `definition.invoke` is never called. `format` annotations are
696
- * NEVER asserted, and a key outside the closed inferred schema is SILENTLY DROPPED rather than
697
- * rejected (see {@link import('./types.js').EndpointToolOptions.validate}). With
698
- * `validate: false`, `execute` PASSES THROUGH the model-supplied `args` to `definition.invoke`
699
- * WITHOUT re-validation — the pre-0.0.7 behavior, preserved as an explicit opt-out. Either way,
700
- * `invoke`'s return flows back as the tool call's plain result; a throw PROPAGATES uncaught,
701
- * isolated by the `ToolManagerInterface` (`@orkestrel/agent`) into the canonical error envelope
702
- * (AGENTS §14) — never caught or re-wrapped here.
703
- *
704
- * @param definition - The endpoint's identity, non-empty samples, and local handler (see
705
- * {@link import('./types.js').EndpointDefinition})
706
- * @param options - Construction-time inference tuning + the validate opt-out (see
707
- * {@link import('./types.js').EndpointToolOptions})
708
- * @returns A `ToolInterface` named `definition.name`
709
- *
710
- * @example
711
- * ```ts
712
- * import { createEndpointTool } from '@src/core'
713
- * import { createToolManager } from '@orkestrel/agent'
714
- *
715
- * const tool = createEndpointTool({
716
- * name: 'lookupUser',
717
- * description: 'Look up a user by id.',
718
- * samples: [{ id: '1', name: 'Ada' }, { id: '2', name: 'Bob' }],
719
- * invoke: (args) => ({ id: args.id, name: 'Ada' }),
720
- * })
721
- * const tools = createToolManager()
722
- * tools.add(tool)
723
- *
724
- * // conforming args (all required keys present) parse and reach `invoke`
725
- * const result = await tools.execute({
726
- * id: 'call-1',
727
- * name: 'lookupUser',
728
- * arguments: { id: '1', name: 'Ada' },
729
- * })
730
- * // result.value -> { id: '1', name: 'Ada' }
731
- *
732
- * // a nonconforming call (id is not coercible to the required string) is rejected before
733
- * // `invoke` runs
734
- * const rejected = await tools.execute({
735
- * id: 'call-2',
736
- * name: 'lookupUser',
737
- * arguments: { id: true, name: 'Ada' },
738
- * })
739
- * // rejected.error -> the TOOL AgentToolError message
740
- * ```
741
- */
742
- export declare function createEndpointTool(definition: EndpointDefinition, options?: EndpointToolOptions): ToolInterface;
743
-
744
- /**
745
- * Build a standalone LLM-callable tool that infers a JSON Schema from example values — the
746
- * utility half of the "existing API/DB → MCP tool" bridge (the other half,
747
- * {@link createEndpointTool}, wraps one CONCRETE endpoint).
748
- *
749
- * @remarks
750
- * The universal tool-handler contract (AGENTS §14): validates the call args against
751
- * {@link import('./shapers.js').inferToolShape} (`samples` non-empty, `format` / `enum` optional
752
- * booleans, `candidates` an optional array), infers a schema via `@orkestrel/contract`'s
753
- * `samplesToSchema`, wraps a non-object root as `{ value: <schema> }` via `schemaToObject` (mirrors
754
- * the tool-parameters convention every other `create*Tool` factory advertises), and RETURNS the
755
- * resulting parameters record. An empty `samples` array fails `inferToolShape`'s `min: 1` bound —
756
- * `contract.parse` returns `undefined` and the handler throws a typed `TOOL`
757
- * {@link import('./errors.js').AgentToolError}.
758
- *
759
- * When `candidates` is ABSENT, the return is the bare parameters record — unchanged from before
760
- * this array existed. When `candidates` is PRESENT (any array, including empty), the handler
761
- * compiles a SEPARATE per-call contract from the RAW inferred schema (via `@orkestrel/contract`'s
762
- * `schemaToShape`, NOT the `schemaToObject`-wrapped parameters — a bare-value sample checks a
763
- * bare-value candidate) and returns `{ parameters, checks }`, one check per candidate at the same
764
- * index. Every entry has a UNIFORM shape — `{ index, valid, coercible }`, with `faults` added ONLY
765
- * when `valid` is `false`: `valid` is the STRICT guard verdict (`checker.is(candidate)`), the
766
- * OPPOSITE of {@link createEndpointTool}'s enforcement, which coerces (`7` becomes `'7'` for a
767
- * string slot) — here a conformance report answers "does this value conform AS-IS": `7` against a
768
- * string slot is `valid: false`, full stop. `coercible` answers a SEPARATE question — "would the
769
- * NORMALIZING parse accept this value", i.e. would {@link createEndpointTool}'s default enforcement
770
- * admit it (`checker.parse(candidate) !== undefined`) — computed for every candidate regardless of
771
- * `valid`; by the house parse/guard round-trip guarantee (AGENTS §14), a `valid: true` entry is
772
- * ALWAYS also `coercible: true`. `@orkestrel/contract` 0.0.7's `explain` mirrors the normalizing
773
- * `parse`'s leniency, not `is`'s strictness — so a strictly-invalid but coercible candidate (`7`
774
- * against a string slot) yields `{ valid: false, coercible: true, faults: [] }`: EMPTY faults, since
775
- * the mismatch the normalizing parse would silently fix is not one `explain` reports. `faults`
776
- * therefore only ever populates for a NON-coercible mismatch — a wrong type the parse can't coerce
777
- * (a boolean in a string slot), a missing required key, or an out-of-enum value — where
778
- * `coercible: false`. `checker.is` / `.parse` / `.explain` are all total over JSON-safe input — a
779
- * JSON-safe hostile candidate (a `__proto__`-carrying object, deeply nested data) reaches all three
780
- * and yields a bounded, non-throwing per-candidate verdict; a NON-JSON-safe candidate (e.g. a
781
- * throwing-getter `Proxy`) never reaches the checker at all — it fails the OUTER `args` parse
782
- * against {@link import('./shapers.js').inferToolShape} and rejects the WHOLE call with the same
783
- * `TOOL` {@link import('./errors.js').AgentToolError} a malformed `samples`/`format`/`enum` throws,
784
- * with no per-candidate verdict produced.
785
- *
786
- * @param options - Advertised `name` / `description` overrides (see
787
- * {@link import('./types.js').InferToolOptions})
788
- * @returns A `ToolInterface` (named {@link import('./constants.js').INFER_TOOL_NAME} by default)
789
- *
790
- * @example
791
- * ```ts
792
- * import { createInferTool } from '@src/core'
793
- * import { createToolManager } from '@orkestrel/agent'
794
- *
795
- * const tool = createInferTool()
796
- * const tools = createToolManager()
797
- * tools.add(tool)
798
- *
799
- * const result = await tools.execute({
800
- * id: 'call-1',
801
- * name: 'infer',
802
- * arguments: { samples: [{ id: 1, name: 'Ada' }, { id: 2, name: 'Bob' }] },
803
- * })
804
- * // result.value -> { type: 'object', properties: { id: {...}, name: {...} }, ... }
805
- *
806
- * // with candidates, the result is wrapped with per-candidate verdicts
807
- * const checked = await tools.execute({
808
- * id: 'call-2',
809
- * name: 'infer',
810
- * arguments: {
811
- * samples: [{ id: 1, name: 'Ada' }],
812
- * candidates: [{ id: 2, name: 'Bob' }, { id: 'x', name: 'Cy' }],
813
- * },
814
- * })
815
- * // checked.value -> { parameters: {...}, checks: [
816
- * // { index: 0, valid: true, coercible: true },
817
- * // { index: 1, valid: false, coercible: false, faults: [...] },
818
- * // ] }
819
- * ```
820
- */
821
- export declare function createInferTool(options?: InferToolOptions): ToolInterface;
822
-
823
- /**
824
- * Create the in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of database
825
- * definitions, the DEFAULT store the upcoming database / relation tools will persist their
826
- * `DatabaseDefinition` configs through.
827
- *
828
- * @returns A {@link DefinitionStoreInterface}
829
- *
830
- * @example
831
- * ```ts
832
- * import { createMemoryDefinitionStore } from '@src/core'
833
- *
834
- * const store = createMemoryDefinitionStore()
835
- * ```
836
- */
837
- export declare function createMemoryDefinitionStore(): DefinitionStoreInterface;
838
-
839
- /**
840
- * Build an LLM-callable prompt tool — the ASK side of the terminal seam. Asks
841
- * {@link import('./types.js').PromptToolOptions.to} a question and BLOCKS until it answers,
842
- * returning the resolved answer value.
843
- *
844
- * @remarks
845
- * The universal tool-handler contract (AGENTS §14): validates the call args against
846
- * {@link import('./shapers.js').promptToolShape}, dispatches to the matching
847
- * `TerminalManagerInterface.ask` overload (`@orkestrel/terminal`) for the call's `form`, and
848
- * RETURNS the resolved answer on success. `from` is FIXED at construction
849
- * ({@link import('./types.js').PromptToolOptions.from}) — never read from the model-supplied
850
- * args — so a model cannot spoof which terminal is asking. A prompt CYCLE rejects with
851
- * `TerminalError('DEADLOCK')`, re-surfaced as a typed `DEADLOCK`
852
- * {@link import('./errors.js').AgentToolError}; an expired prompt re-surfaces as `EXPIRE`; an
853
- * unknown `to` (or any other `TerminalError`) re-surfaces as `TOOL`, naming the unknown terminal
854
- * plus the known ones (`manager.terminals()`).
855
- *
856
- * @param options - The live manager, the fixed `from` identity, and advertised overrides (see
857
- * {@link import('./types.js').PromptToolOptions})
858
- * @returns A `ToolInterface` (named {@link import('./constants.js').PROMPT_TOOL_NAME} by default)
859
- *
860
- * @example
861
- * ```ts
862
- * import { createPromptTool } from '@src/core'
863
- * import { createTerminalManager, createToolManager } from '@orkestrel/terminal'
864
- *
865
- * const manager = createTerminalManager()
866
- * manager.add('agent')
867
- * manager.add('reviewer')
868
- * const tool = createPromptTool({ manager, from: 'agent' })
869
- * const tools = createToolManager()
870
- * tools.add(tool) // the agent can now ask 'reviewer' and block for the answer
871
- * ```
872
- */
873
- export declare function createPromptTool(options: PromptToolOptions): ToolInterface;
874
-
875
- /**
876
- * Build an LLM-callable relation tool — traverse and edit `@orkestrel/relation` relationships
877
- * through one `operation`-discriminated call (AGENTS §14, matching {@link createDatabaseTool}'s
878
- * single-tool-many-operations shape).
879
- *
880
- * @remarks
881
- * The universal tool-handler contract (AGENTS §14): validates the call args against
882
- * {@link import('./shapers.js').relationToolShape}, resolves the addressed
883
- * {@link import('@orkestrel/relation').RelationManagerInterface} — an explicit `manager` field
884
- * must match a key of {@link import('./types.js').RelationToolOptions.managers}, an OMITTED one
885
- * resolves to the SOLE registered manager, either miss throwing a typed `TOOL`
886
- * {@link import('./errors.js').AgentToolError}
887
- * ({@link import('./helpers.js').relationManagerOf}) — then resolves `model` against it
888
- * ({@link import('./helpers.js').relationModelOf}, same typed-`TOOL`-on-miss shape), and
889
- * dispatches to the matched operation, RETURNING a plain result on success.
890
- *
891
- * `'load'` / `'find'` expand the call's FLAT dot-path `include` list into a live
892
- * `@orkestrel/relation` `Include` tree via {@link import('./helpers.js').expandInclude}, capped
893
- * at {@link import('./types.js').RelationToolOptions.depth} (default
894
- * {@link import('./constants.js').RELATION_TOOL_DEPTH}) — a path exceeding the cap, or carrying an
895
- * empty segment, throws a typed `TOOL` error. `'load'` dispatches on whether `key` is an array
896
- * (positional many-key form, AGENTS §9.2) or a single key. `'find'` and `'links'` clamp their
897
- * result to {@link import('./types.js').RelationToolOptions.limit} (default
898
- * {@link import('./constants.js').RELATION_TOOL_LIMIT}) — `'find'` probes one row past the
899
- * effective limit (mirroring {@link import('./helpers.js').clampCriteria}'s idiom) to report
900
- * `truncated`; `'links'` (which has no upstream pagination) fetches the FULL linked-key list and
901
- * slices/truncates it the same way. `'link'` / `'unlink'` write / remove one `through` junction
902
- * row.
903
- *
904
- * A typed `@orkestrel/relation` failure (`RelationError`) re-surfaces as a typed `RELATION`
905
- * `AgentToolError` carrying the original {@link import('@orkestrel/relation').RelationErrorCode}
906
- * in `context.code`; a typed `@orkestrel/database` failure underneath it (`DatabaseError`)
907
- * re-surfaces as a typed `DATABASE` `AgentToolError`, mirroring {@link createDatabaseTool}'s error
908
- * mapping; an `AgentToolError` thrown by this tool's own guards (malformed args, an unknown
909
- * manager/model) passes through unwrapped.
910
- *
911
- * @param options - The tool's configuration (see {@link import('./types.js').RelationToolOptions})
912
- * @returns A `ToolInterface` (named {@link import('./constants.js').RELATION_TOOL_NAME} by default)
913
- *
914
- * @example
915
- * ```ts
916
- * import { createRelationTool } from '@src/core'
917
- *
918
- * const tool = createRelationTool({ managers: { shop: manager } })
919
- * await tool.execute({ operation: 'load', model: 'accounts', key: 'acc1', include: ['contacts'] })
920
- * ```
921
- */
922
- export declare function createRelationTool(options: RelationToolOptions): ToolInterface;
923
-
924
- /**
925
- * Wrap a registered tool as a {@link WorkflowFunction} (`@orkestrel/workflow`) — the OPT-IN
926
- * adapter that lets a `function`-form task run a `@orkestrel/agent` tool BY NAME.
927
- *
928
- * @remarks
929
- * OWNED here now (ported from `@orkestrel/workflow`). Composes into a caller's
930
- * `WorkflowOptions.functions` registry like any other behavior
931
- * (`{ publish: createToolFunction(tools, 'publish') }`); the pure workflow runner has no
932
- * knowledge of tools itself. The returned function executes `name` against `tools` with the
933
- * task's `controller.input` as the call arguments, id-correlated to the task's own id. A
934
- * `ToolManagerInterface.execute` (`@orkestrel/agent`) NEVER throws (a handler throw is isolated
935
- * into `result.error`), so a failing tool is surfaced here as a THROWN `Error` carrying the
936
- * original message as `cause` — the leaf `fail`s, honouring `bail`. An UNREGISTERED tool name is
937
- * a programmer error (an explicit binding to a name that doesn't exist) — unlike the engine's
938
- * own silent auto-complete of an unresolved task handler, this THROWS a typed `TOOL`
939
- * `WorkflowError` (`@orkestrel/workflow`).
940
- *
941
- * @param tools - The `ToolManagerInterface` (`@orkestrel/agent`) the named tool is registered on
942
- * @param name - The registered tool's name
943
- * @returns A {@link WorkflowFunction} that runs the named tool
944
- *
945
- * @example
946
- * ```ts
947
- * import { createToolFunction } from '@src/core'
948
- * import { createToolManager } from '@orkestrel/agent'
949
- * import { createWorkflowRunner } from '@orkestrel/workflow'
950
- *
951
- * const tools = createToolManager()
952
- * tools.add(myPublishTool)
953
- * const runner = createWorkflowRunner()
954
- * await runner.execute(definition, { functions: { publish: createToolFunction(tools, 'publish') } })
955
- * ```
956
- */
957
- export declare function createToolFunction(tools: ToolManagerInterface, name: string): WorkflowFunction;
958
-
959
- /**
960
- * Compile the LENIENT workflow DRAFT contract — identical to `createWorkflowContract`
961
- * (`@orkestrel/workflow`) EXCEPT `id` and `name` are OPTIONAL at all three levels (workflow /
962
- * phase / task), so a small model can omit the six identity strings.
963
- *
964
- * @remarks
965
- * The widened authoring surface {@link createWorkflowTool} parses an authored blob through
966
- * before {@link import('./helpers.js').completeDraft} fills the missing ids/names. It does NOT
967
- * relax the canonical contract — `createWorkflowContract` (`@orkestrel/workflow`) stays
968
- * byte-for-byte unchanged and STRICT, and the completed draft is re-validated against THAT
969
- * strict gate before running (soundness preserved). A PROVIDED `id` / `name` still carries
970
- * `minLength: 1`, so an explicitly-empty `id: ''` is REJECTED (parses to `undefined`), never
971
- * auto-filled — keeping "garbage" distinct from "omitted". `run` stays optional (a plain name
972
- * string).
973
- *
974
- * @returns The compiled {@link import('./types.js').WorkflowDraft} contract
975
- *
976
- * @example
977
- * ```ts
978
- * import { createWorkflowDraftContract, completeDraft } from '@src/core'
979
- *
980
- * const draft = createWorkflowDraftContract()
981
- * const parsed = draft.parse({ phases: [{ tasks: [{ run: 'compile' }] }] })
982
- * const definition = parsed && completeDraft(parsed) // ids/names filled positionally
983
- * draft.parse({ id: '', phases: [] }) // undefined — an explicit empty id is rejected
984
- * ```
985
- */
986
- export declare function createWorkflowDraftContract(): ContractInterface<WorkflowDraft>;
987
-
988
- /**
989
- * Wrap a {@link WorkflowDefinition} as an LLM-callable tool — it ADVERTISES the SIMPLE flat
990
- * authoring shape (`{ name?, steps: [{ name }] }`) as its `parameters` so even a small model can
991
- * author a complete tree, and its handler EXPANDS / COMPLETES the authored blob, validates it
992
- * against the STRICT contract, runs it through `runner`, and, when
993
- * {@link import('./types.js').WorkflowToolOptions.store} is supplied, PERSISTS each executed
994
- * workflow's final snapshot after the run settles.
995
- *
996
- * @remarks
997
- * A plain `ToolManagerInterface`-compatible tool (`@orkestrel/agent`), reproducing
998
- * `@orkestrel/workflow`'s former call contract exactly (flat / draft / full authoring forms, the
999
- * strict soundness gate, the depth/cycle guard). It is ALSO the propagation carrier
1000
- * {@link createAgentFunction} binds onto a wrapped agent's `context.tools`: because a tool
1001
- * handler receives ONLY the model-supplied `args` (no ambient context, no signal), the run's
1002
- * depth + ancestry are CLOSED OVER at bind time via {@link import('./types.js').WorkflowToolOptions},
1003
- * and the handler enforces the SAME depth / cycle guard itself before running the nested
1004
- * workflow at `depth + 1` with the extended ancestry.
1005
- *
1006
- * **Widened authoring surface (additive — the canonical contract + runner stay STRICT and
1007
- * unchanged).** A 2B model reliably CALLS the tool but cannot reliably emit the full four-level
1008
- * nested {@link WorkflowDefinition} (six required `id`/`name` strings, an all-or-nothing tree).
1009
- * So the tool ACCEPTS three authoring forms and converges them on the SAME strict
1010
- * `createWorkflowContract` gate before running (soundness preserved):
1011
- * - the FLAT shape `{ name?, steps: [{ name }] }` — the ADVERTISED `parameters` (the simplest
1012
- * form, {@link import('./helpers.js').expandSteps}'d into one one-task phase per step);
1013
- * - a nested DRAFT with any `id`/`name` OMITTED — {@link createWorkflowDraftContract}-parsed then
1014
- * {@link import('./helpers.js').completeDraft}'d (missing ids synthesized positionally);
1015
- * - the full nested {@link WorkflowDefinition} — the advanced escape-hatch, accepted as the draft
1016
- * super-set.
1017
- *
1018
- * The universal tool-handler contract (AGENTS §14): returns the plain run summary
1019
- * (`{ status, count }`) on success, THROWS a typed `WorkflowError` (`@orkestrel/workflow`) on
1020
- * every failure path — malformed authored args (`TOOL`), or an over-deep / cyclic nested run
1021
- * (`DEPTH`). The `ToolManagerInterface` isolates every throw into the canonical tool result's
1022
- * top-level `error`, so nothing escapes the run. `options.depth` / `options.ancestry` are the
1023
- * propagation carrier across a workflow → agent → workflow chain; `options.store` is this
1024
- * package's ADDITION — the persisted snapshot is retrievable via the store afterwards (a caller
1025
- * restores it through `@orkestrel/workflow`'s own `Workflow.restore` / store-backed factories).
1026
- *
1027
- * @param definition - The workflow the tool runs when called with no authored args
1028
- * @param runner - The `WorkflowRunnerInterface` (`@orkestrel/workflow`) that executes the (nested) workflow
1029
- * @param options - Depth/ancestry bookkeeping plus the optional durable store (see {@link import('./types.js').WorkflowToolOptions})
1030
- * @returns A `ToolInterface` (named {@link import('./constants.js').WORKFLOW_TOOL_NAME}) whose
1031
- * `parameters` advertise the flat authoring schema
1032
- *
1033
- * @example
1034
- * ```ts
1035
- * import { createWorkflowTool } from '@src/core'
1036
- * import { createWorkflowRunner, createMemoryWorkflowStore } from '@orkestrel/workflow'
1037
- * import { createToolManager } from '@orkestrel/agent'
1038
- *
1039
- * const runner = createWorkflowRunner()
1040
- * const store = createMemoryWorkflowStore()
1041
- * const tool = createWorkflowTool(definition, runner, { store })
1042
- * const tools = createToolManager()
1043
- * tools.add(tool) // authored runs are now persisted to `store` on settle
1044
- * ```
1045
- */
1046
- export declare function createWorkflowTool(definition: WorkflowDefinition, runner: WorkflowRunnerInterface, options?: WorkflowToolOptions): ToolInterface;
1047
-
1048
- /**
1049
- * Build an LLM-callable workspace-editing tool — it ADVERTISES the `operation`-discriminated
1050
- * 13-op union ({@link import('./shapers.js').workspaceToolShape}) as its `parameters`, and its
1051
- * handler PARSES the model-supplied args against that contract and DISPATCHES the matched
1052
- * operation against the manager's ACTIVE workspace (the registry ops drive the manager itself),
1053
- * returning the plain result (throwing a typed `WorkspaceError`, `@orkestrel/agent`, on
1054
- * failure). EITHER drives a caller-supplied {@link WorkspaceToolOptions.manager} directly, OR
1055
- * constructs a fresh `WorkspaceManagerInterface` (`@orkestrel/agent`) over
1056
- * {@link import('./types.js').WorkspaceToolOptions.store} (via `@orkestrel/agent`'s
1057
- * `createWorkspaceManager`); neither given constructs a manager backed by `@orkestrel/agent`'s
1058
- * in-memory store default.
1059
- *
1060
- * @remarks
1061
- * MANAGER-DRIVEN: every edit / read op (read / list / has / search / replace / write / splice /
1062
- * prepend / append / move / remove) targets `manager.active`, so the model edits whichever
1063
- * workspace is active and a host can re-point it (`WorkspaceManagerInterface.switch`) between
1064
- * turns. Two REGISTRY ops make the model self-sufficient: `workspaces` LISTS the registered
1065
- * workspaces (each `{ id, files, active }`) so it can discover an id, and `switch` re-points the
1066
- * active workspace by id (lenient — an unknown id is a no-op reporting `switched: false`, never a
1067
- * throw).
1068
- *
1069
- * NO-ACTIVE RULE (the ergonomic seam): a WRITING op (write / splice / prepend / append / move /
1070
- * remove / replace) run when `manager.active` is `undefined` AUTO-CREATES + activates a default
1071
- * workspace (`manager.add()`) so the model can just start writing; a pure-READ op (read / list /
1072
- * has / search) against no active workspace returns the EMPTY result (`undefined` / `[]` /
1073
- * `false`), never creating one and never throwing.
1074
- *
1075
- * The handler conforms to the universal tool-handler contract (AGENTS §14): it `contract.parse`s
1076
- * the args, THROWS a `TOOL` `WorkspaceError` when no operation arm matched (a malformed / unknown
1077
- * operation), else `switch`es on `op.operation` and RETURNS the plain result — letting a
1078
- * `WorkspaceError` raised by the live workspace (`MODALITY` / `PATTERN` / `RANGE`) PROPAGATE
1079
- * uncaught. The range edit is the FLAT `'splice'` op: its four flat caret integers are
1080
- * reassembled into a `Range` (`@orkestrel/agent`) by `rangeOf` and fed to the workspace's ranged
1081
- * `write`.
1082
- *
1083
- * @param options - `manager` (drive directly) OR `store` (build a manager over it); neither ⇒
1084
- * an in-memory-backed manager (see {@link import('./types.js').WorkspaceToolOptions})
1085
- * @returns A `ToolInterface` (named {@link import('./constants.js').WORKSPACE_TOOL_NAME} by default)
1086
- *
1087
- * @example
1088
- * ```ts
1089
- * import { createWorkspaceTool } from '@src/core'
1090
- * import { createToolManager } from '@orkestrel/agent'
1091
- *
1092
- * const tool = createWorkspaceTool() // in-memory workspace, no persistence
1093
- * const tools = createToolManager()
1094
- * tools.add(tool)
1095
- * ```
1096
- */
1097
- export declare function createWorkspaceTool(options?: WorkspaceToolOptions): ToolInterface;
1098
-
1099
- /**
1100
- * Normalize the database tool's parsed SERIALIZED criteria into a live `@orkestrel/database`
1101
- * {@link Criteria} — default each condition's OMITTED `connector` to `'and'`.
1102
- *
1103
- * @remarks
1104
- * The wire form ({@link import('./shapers.js').databaseToolShape}) lets a caller drop `connector`
1105
- * on the last condition (it has nothing to join FORWARD to); the compiled `Condition` a live
1106
- * `@orkestrel/database` table call accepts always carries one, so this fills the gap. `order` /
1107
- * `limit` / `offset` pass through unchanged. Pure and total.
1108
- *
1109
- * @param criteria - The parsed criteria (or `undefined`)
1110
- * @returns The equivalent live `Criteria`, or `undefined` when `criteria` is `undefined`
1111
- */
1112
- export declare function criteriaOf(criteria: Readonly<{
1113
- conditions?: readonly Readonly<{
1114
- column: string;
1115
- operator: Condition['operator'];
1116
- values: readonly unknown[];
1117
- connector?: Connector;
1118
- }>[];
1119
- order?: readonly Readonly<{
1120
- column: string;
1121
- direction: Direction;
1122
- }>[];
1123
- limit?: number;
1124
- offset?: number;
1125
- }> | undefined): Criteria | undefined;
1126
-
1127
- /** The SERIALIZED criteria form — conditions, order, and pagination. */
1128
- export declare const criteriaShape: ObjectShape<{
1129
- conditions: OptionalShape<ArrayShape<ObjectShape<{
1130
- column: StringShape;
1131
- operator: LiteralShape<readonly ["equals", "not", "above", "below", "from", "to", "between", "like", "glob", "starts", "ends", "any", "none", "absent", "present"]>;
1132
- values: ArrayShape<JSONShape>;
1133
- connector: OptionalShape<LiteralShape<readonly ["and", "or"]>>;
1134
- }, false>>>;
1135
- order: OptionalShape<ArrayShape<ObjectShape<{
1136
- column: StringShape;
1137
- direction: LiteralShape<readonly ["ascending", "descending"]>;
1138
- }, false>>>;
1139
- limit: OptionalShape<NumberShape>;
1140
- offset: OptionalShape<NumberShape>;
1141
- }, false>;
1142
-
1143
- /**
1144
- * The DESCRIPTION the upcoming database tool will advertise — a multi-line guide that teaches a
1145
- * small model the operation list, the SERIALIZED criteria form, and the {@link import('./types.js').TableSpec}
1146
- * column DSL.
1147
- *
1148
- * @remarks
1149
- * The criteria form is deliberately SERIALIZED (never fluent) — every condition is a flat object
1150
- * `{ column, operator, values, connector? }` where `values` is ALWAYS an array, even for a
1151
- * single-value operator (`{ column: 'age', operator: 'from', values: [18] }`), so a small model
1152
- * never has to chain method calls or guess whether a value is scalar or a list.
1153
- */
1154
- export declare const DATABASE_TOOL_DESCRIPTION: string;
1155
-
1156
- /** The default cap on rows a `records` / `remove` call returns (or acts on) when the caller omits `criteria.limit` — the upcoming database tool's default row ceiling. */
1157
- export declare const DATABASE_TOOL_LIMIT = 1000;
1158
-
1159
- /** The database tool's mutating operations — disabled by `DatabaseToolOptions.readonly`. */
1160
- export declare const DATABASE_TOOL_MUTATIONS: Set<string>;
1161
-
1162
- /**
1163
- * The name the upcoming `createDatabaseTool` factory will advertise by default — the key a model
1164
- * calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under.
1165
- *
1166
- * @remarks
1167
- * SRC-1 of a 3-unit spine: this unit lands the persistence + schema foundation
1168
- * ({@link import('./types.js').DatabaseDefinition}, {@link import('./types.js').DefinitionStoreInterface},
1169
- * {@link import('./helpers.js').expandTables}); `createDatabaseTool` itself is built in a later unit.
1170
- */
1171
- export declare const DATABASE_TOOL_NAME = "database";
1172
-
1173
- /**
1174
- * The lean {@link import('@orkestrel/agent').ToolInterface.summary} the upcoming database tool
1175
- * will advertise in place of {@link DATABASE_TOOL_DESCRIPTION}.
1176
- */
1177
- export declare const DATABASE_TOOL_SUMMARY = "Create and query a database \u2014 one operation per call (create, tables, get, records, count, aggregate, add, set, update, remove, migrate, destroy), chosen by the 'operation' field. Call describe('database') for the full operation list, the criteria form, and the column DSL.";
1178
-
1179
- /**
1180
- * One database's CONFIG-ONLY definition — `id` + `driver` + {@link TableSpec} (+ optional `keys`),
1181
- * the pure-JSON blueprint the upcoming database / relation tools build a live database from.
1182
- *
1183
- * @remarks
1184
- * A `DatabaseDefinition` is NEVER a live handle — it is the durable, serializable config a
1185
- * {@link DefinitionStoreInterface} persists and a tool factory turns into a real
1186
- * `@orkestrel/database` `DatabaseInterface` (via `createDatabase` + {@link import('./helpers.js').expandTables})
1187
- * on demand. `keys`, when present, maps a table name to its primary-key column (omitted ⇒ the
1188
- * driver's default primary key).
1189
- */
1190
- export declare interface DatabaseDefinition {
1191
- readonly id: string;
1192
- readonly driver: string;
1193
- readonly tables: TableSpec;
1194
- readonly keys?: Readonly<Record<string, string>>;
1195
- }
1196
-
1197
- /** One opaque persisted row — the shape a `TableInterface<DatabaseDefinitionRow>`-backed store reads/writes; `definition` is narrowed with {@link import('./helpers.js').isDatabaseDefinition} on read. */
1198
- export declare interface DatabaseDefinitionRow {
1199
- readonly id: string;
1200
- readonly definition: unknown;
1201
- }
1202
-
1203
- /**
1204
- * A {@link DefinitionStoreInterface} backed by one table of the `@orkestrel/database` layer — a
1205
- * database's durable CONFIG state IS a row, so persistence reduces to keyed point-access
1206
- * (`get` / `set` / `delete`) over a {@link TableInterface}, the driver-pluggable twin of the
1207
- * plain-`Map` {@link import('./MemoryDefinitionStore.js').MemoryDefinitionStore}.
1208
- *
1209
- * @remarks
1210
- * The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,
1211
- * JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a JSON / SQLite /
1212
- * IndexedDB backend swaps in WITHOUT touching a consumer — the same seam as
1213
- * {@link import('./MemoryDefinitionStore.js').MemoryDefinitionStore}. The driver defaults to
1214
- * memory ({@link import('../factories.js').createDatabaseDefinitionStore} passes
1215
- * `createMemoryDriver()`), so it ALSO works in memory out of the box; you opt into the durable
1216
- * plumbing by passing a JSON / SQLite / IndexedDB driver.
1217
- *
1218
- * The {@link DatabaseDefinition} is stored as ONE OPAQUE JSON COLUMN — the table is a row of
1219
- * `{ id; definition }` ({@link DatabaseDefinitionRow}). The definition is already a COMPLETE,
1220
- * self-contained, pure-JSON CONFIG payload (never a live handle), so storing it whole is lossless
1221
- * AND keeps the row type flat (`definition` reads back as `unknown`).
1222
- *
1223
- * - **`set(definition)` upserts under the definition's OWN `id`** (no separate id param) — it
1224
- * writes the row `{ id: definition.id, definition }`.
1225
- * - **`get(id)` resolves the stored definition for an id**, narrowing the opaque JSON column back
1226
- * to a {@link DatabaseDefinition} ({@link import('../helpers.js').isDatabaseDefinition} — the
1227
- * AGENTS §14 boundary narrow for an untrusted storage read), or `undefined` if none is stored
1228
- * or the stored blob is malformed.
1229
- * - **`delete(id)` drops a definition by id**; an absent id is a no-op (no throw).
1230
- *
1231
- * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method
1232
- * bijection with {@link DefinitionStoreInterface}).
1233
- *
1234
- * @example
1235
- * ```ts
1236
- * import { createDatabaseDefinitionStore, createMemoryDriver } from '@src/core'
1237
- *
1238
- * const store = createDatabaseDefinitionStore(createMemoryDriver()) // a durable driver swaps in here
1239
- * await store.set({ id: 'shop', driver: 'memory', tables: {} }) // persist the config (one JSON column)
1240
- * const definition = await store.get('shop')
1241
- * await store.delete('shop')
1242
- * ```
1243
- */
1244
- export declare class DatabaseDefinitionStore implements DefinitionStoreInterface {
1245
- #private;
1246
- /**
1247
- * Wrap a table as a definition store.
1248
- *
1249
- * @param table - The {@link TableInterface} holding the definitions — its row is the
1250
- * {@link DatabaseDefinitionRow} `{ id; definition }` shape (the definition one opaque JSON column)
1251
- */
1252
- constructor(table: TableInterface<DatabaseDefinitionRow>);
1253
- /** Resolve the persisted definition for `id`, narrowing the opaque JSON column back to a `DatabaseDefinition`. */
1254
- get(id: string): Promise<DatabaseDefinition | undefined>;
1255
- /** Insert or replace under the definition's OWN `id` (no separate id param) — the row is `{ id, definition }`. */
1256
- set(definition: DatabaseDefinition): Promise<void>;
1257
- /** Drop a definition by id; an absent id is a no-op (no throw). */
1258
- delete(id: string): Promise<void>;
1259
- }
1260
-
1261
- /**
1262
- * Resolve database definitions into cached live handles for database tools.
1263
- *
1264
- * @example
1265
- * ```ts
1266
- * import { DatabaseResolver } from '@orkestrel/tool'
1267
- *
1268
- * const resolver = new DatabaseResolver(handles, drivers, key, store)
1269
- * const database = await resolver.resolve('shop')
1270
- * ```
1271
- */
1272
- export declare class DatabaseResolver {
1273
- #private;
1274
- /**
1275
- * Create a database resolver over the tool's live state and optional definition store.
1276
- *
1277
- * @param handles - Initial live database handles cached by id
1278
- * @param drivers - Driver factories keyed by definition driver name
1279
- * @param key - Key generator supplied to newly created databases
1280
- * @param store - Optional persistent definition store
1281
- */
1282
- constructor(handles: ReadonlyMap<string, DatabaseInterface>, drivers: Readonly<Record<string, () => DriverInterface>>, key: KeyFunction, store?: DefinitionStoreInterface);
1283
- /**
1284
- * Determine whether a live database is cached by id.
1285
- *
1286
- * @param id - Database id
1287
- * @returns Whether a live handle is cached
1288
- */
1289
- has(id: string): boolean;
1290
- /**
1291
- * Read a cached database without consulting the definition store.
1292
- *
1293
- * @param id - Database id
1294
- * @returns The cached live database, or `undefined`
1295
- */
1296
- get(id: string): DatabaseInterface | undefined;
1297
- /**
1298
- * Cache a live database by id.
1299
- *
1300
- * @param id - Database id
1301
- * @param database - Live database handle
1302
- * @returns Nothing
1303
- */
1304
- set(id: string, database: DatabaseInterface): void;
1305
- /**
1306
- * Remove a cached live database by id.
1307
- *
1308
- * @param id - Database id
1309
- * @returns Nothing
1310
- */
1311
- delete(id: string): void;
1312
- /**
1313
- * Resolve a cached or stored database by id.
1314
- *
1315
- * @param id - Database definition id
1316
- * @returns The cached or newly constructed live database
1317
- */
1318
- resolve(id: string): Promise<DatabaseInterface>;
1319
- }
1320
-
1321
- /**
1322
- * Map a caught error to the {@link AgentToolErrorCode} the upcoming database tool should throw
1323
- * with — the pure classification step of that factory's error handling, mirroring
1324
- * {@link terminalToolCode}'s idiom for `@orkestrel/database`.
1325
- *
1326
- * @param error - The value caught from a `@orkestrel/database` table operation
1327
- * @returns The granular {@link DatabaseErrorCode}, or `undefined` if `error` is not a `DatabaseError`
1328
- */
1329
- export declare function databaseToolCode(error: unknown): DatabaseErrorCode | undefined;
1330
-
1331
- /**
1332
- * Options for {@link import('./factories.js').createDatabaseTool} — SRC-2 of the 3-unit database
1333
- * / relation spine, built over the SRC-1 foundation ({@link DatabaseDefinition},
1334
- * {@link DefinitionStoreInterface}, {@link import('./helpers.js').expandTables}).
1335
- *
1336
- * @remarks
1337
- * - `databases` — live `DatabaseInterface` handles to seed the tool's cache with (e.g. a
1338
- * caller-constructed database it should manage alongside store-backed ones); keyed by the id a
1339
- * call's `id` field addresses.
1340
- * - `store` — the {@link DefinitionStoreInterface} the `'create'` / `'migrate'` operations persist
1341
- * their {@link DatabaseDefinition} CONFIG through, and `'destroy'` deletes from; also the source
1342
- * `'get'`/every other operation resolves an id from when it isn't already cached. Omitted means
1343
- * no persistence — a database created without a store lives only for the tool's lifetime.
1344
- * - `drivers` — registry of driver-name to `() => DriverInterface` factories a `'create'` call's
1345
- * `driver` field (or a persisted definition's `driver`) resolves against. Defaults to
1346
- * `{ memory: () => createMemoryDriver() }` (`@orkestrel/database`).
1347
- * - `key` — the `KeyFunction` (`@orkestrel/database`) every minted database is constructed with,
1348
- * used when a written row lacks its primary key. Defaults to `generateUUID`.
1349
- * - `limit` — the row cap `'records'` / `'remove'` — via {@link import('./helpers.js').clampCriteria}
1350
- * — enforce when a call's `criteria.limit` is omitted or exceeds it. Defaults to
1351
- * {@link import('./constants.js').DATABASE_TOOL_LIMIT}.
1352
- * - `timeout` — milliseconds; when set, every `@orkestrel/database` call this tool makes is given
1353
- * a fresh `AbortSignal.timeout(timeout)` per tool call.
1354
- * - `readonly` — when `true`, every mutating operation (`'create'` / `'add'` / `'set'` /
1355
- * `'update'` / `'remove'` / `'migrate'` / `'destroy'`) throws a typed `TOOL`
1356
- * {@link import('./errors.js').AgentToolError} before doing anything.
1357
- * - `name` / `description` — advertised tool overrides; default to
1358
- * {@link import('./constants.js').DATABASE_TOOL_NAME} / {@link import('./constants.js').DATABASE_TOOL_DESCRIPTION}.
1359
- */
1360
- export declare interface DatabaseToolOptions {
1361
- readonly name?: string;
1362
- readonly description?: string;
1363
- readonly databases?: Readonly<Record<string, DatabaseInterface>>;
1364
- readonly store?: DefinitionStoreInterface;
1365
- readonly drivers?: Readonly<Record<string, () => DriverInterface>>;
1366
- readonly key?: KeyFunction;
1367
- readonly limit?: number;
1368
- readonly timeout?: number;
1369
- readonly readonly?: boolean;
1370
- }
1371
-
1372
- /**
1373
- * The shape of {@link import('./factories.js').createDatabaseTool}'s call arguments —
1374
- * discriminated by `operation` into the 12 database operations (`'create'` / `'tables'` /
1375
- * `'get'` / `'records'` / `'count'` / `'aggregate'` / `'add'` / `'set'` / `'update'` /
1376
- * `'remove'` / `'migrate'` / `'destroy'`).
1377
- *
1378
- * @remarks
1379
- * Every arm carries `id` (the database id). `'create'` / `'migrate'` carry `tables` (the
1380
- * {@link import('./types.js').TableSpec} column DSL, compiled via
1381
- * {@link import('./helpers.js').expandTables}); `'get'` / `'update'` / `'remove'` carry `key`
1382
- * (one key or an array of keys, positional); `'add'` / `'set'` carry `row` (one row or an array of
1383
- * rows); `'update'` also carries `changes` (a loose partial row); `'records'` / `'count'` /
1384
- * `'aggregate'` carry an optional `criteria` (the SERIALIZED form — `values` is ALWAYS an array,
1385
- * even for a single-value operator, so a caller never chains method calls or guesses arity).
1386
- */
1387
- export declare const databaseToolShape: UnionShape<readonly [ ObjectShape<{
1388
- operation: LiteralShape<readonly ["create"]>;
1389
- id: StringShape;
1390
- tables: ObjectShape<Record<never, never>, ObjectShape<{
1391
- columns: ObjectShape<Record<never, never>, UnionShape<readonly [ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
1392
- type: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
1393
- optional: OptionalShape<BooleanShape>;
1394
- }, false>]>>;
1395
- }, false>>;
1396
- driver: OptionalShape<StringShape>;
1397
- keys: OptionalShape<ObjectShape<Record<never, never>, StringShape>>;
1398
- }, false>, ObjectShape<{
1399
- operation: LiteralShape<readonly ["tables"]>;
1400
- id: StringShape;
1401
- }, false>, ObjectShape<{
1402
- operation: LiteralShape<readonly ["get"]>;
1403
- id: StringShape;
1404
- table: StringShape;
1405
- key: UnionShape<readonly [ ArrayShape<UnionShape<readonly [ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1406
- }, false>, ObjectShape<{
1407
- operation: LiteralShape<readonly ["records"]>;
1408
- id: StringShape;
1409
- table: StringShape;
1410
- criteria: OptionalShape<ObjectShape<{
1411
- conditions: OptionalShape<ArrayShape<ObjectShape<{
1412
- column: StringShape;
1413
- operator: LiteralShape<readonly ["equals", "not", "above", "below", "from", "to", "between", "like", "glob", "starts", "ends", "any", "none", "absent", "present"]>;
1414
- values: ArrayShape<JSONShape>;
1415
- connector: OptionalShape<LiteralShape<readonly ["and", "or"]>>;
1416
- }, false>>>;
1417
- order: OptionalShape<ArrayShape<ObjectShape<{
1418
- column: StringShape;
1419
- direction: LiteralShape<readonly ["ascending", "descending"]>;
1420
- }, false>>>;
1421
- limit: OptionalShape<NumberShape>;
1422
- offset: OptionalShape<NumberShape>;
1423
- }, false>>;
1424
- }, false>, ObjectShape<{
1425
- operation: LiteralShape<readonly ["count"]>;
1426
- id: StringShape;
1427
- table: StringShape;
1428
- criteria: OptionalShape<ObjectShape<{
1429
- conditions: OptionalShape<ArrayShape<ObjectShape<{
1430
- column: StringShape;
1431
- operator: LiteralShape<readonly ["equals", "not", "above", "below", "from", "to", "between", "like", "glob", "starts", "ends", "any", "none", "absent", "present"]>;
1432
- values: ArrayShape<JSONShape>;
1433
- connector: OptionalShape<LiteralShape<readonly ["and", "or"]>>;
1434
- }, false>>>;
1435
- order: OptionalShape<ArrayShape<ObjectShape<{
1436
- column: StringShape;
1437
- direction: LiteralShape<readonly ["ascending", "descending"]>;
1438
- }, false>>>;
1439
- limit: OptionalShape<NumberShape>;
1440
- offset: OptionalShape<NumberShape>;
1441
- }, false>>;
1442
- }, false>, ObjectShape<{
1443
- operation: LiteralShape<readonly ["aggregate"]>;
1444
- id: StringShape;
1445
- table: StringShape;
1446
- function: LiteralShape<readonly ["count", "sum", "average", "minimum", "maximum"]>;
1447
- column: StringShape;
1448
- criteria: OptionalShape<ObjectShape<{
1449
- conditions: OptionalShape<ArrayShape<ObjectShape<{
1450
- column: StringShape;
1451
- operator: LiteralShape<readonly ["equals", "not", "above", "below", "from", "to", "between", "like", "glob", "starts", "ends", "any", "none", "absent", "present"]>;
1452
- values: ArrayShape<JSONShape>;
1453
- connector: OptionalShape<LiteralShape<readonly ["and", "or"]>>;
1454
- }, false>>>;
1455
- order: OptionalShape<ArrayShape<ObjectShape<{
1456
- column: StringShape;
1457
- direction: LiteralShape<readonly ["ascending", "descending"]>;
1458
- }, false>>>;
1459
- limit: OptionalShape<NumberShape>;
1460
- offset: OptionalShape<NumberShape>;
1461
- }, false>>;
1462
- }, false>, ObjectShape<{
1463
- operation: LiteralShape<readonly ["add"]>;
1464
- id: StringShape;
1465
- table: StringShape;
1466
- row: UnionShape<readonly [ ArrayShape<ObjectShape<Record<never, never>, JSONShape>>, ObjectShape<Record<never, never>, JSONShape>]>;
1467
- }, false>, ObjectShape<{
1468
- operation: LiteralShape<readonly ["set"]>;
1469
- id: StringShape;
1470
- table: StringShape;
1471
- row: UnionShape<readonly [ ArrayShape<ObjectShape<Record<never, never>, JSONShape>>, ObjectShape<Record<never, never>, JSONShape>]>;
1472
- }, false>, ObjectShape<{
1473
- operation: LiteralShape<readonly ["update"]>;
1474
- id: StringShape;
1475
- table: StringShape;
1476
- key: UnionShape<readonly [ ArrayShape<UnionShape<readonly [ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1477
- changes: ObjectShape<Record<never, never>, JSONShape>;
1478
- }, false>, ObjectShape<{
1479
- operation: LiteralShape<readonly ["remove"]>;
1480
- id: StringShape;
1481
- table: StringShape;
1482
- key: UnionShape<readonly [ ArrayShape<UnionShape<readonly [ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1483
- }, false>, ObjectShape<{
1484
- operation: LiteralShape<readonly ["migrate"]>;
1485
- id: StringShape;
1486
- tables: ObjectShape<Record<never, never>, ObjectShape<{
1487
- columns: ObjectShape<Record<never, never>, UnionShape<readonly [ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
1488
- type: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
1489
- optional: OptionalShape<BooleanShape>;
1490
- }, false>]>>;
1491
- }, false>>;
1492
- }, false>, ObjectShape<{
1493
- operation: LiteralShape<readonly ["destroy"]>;
1494
- id: StringShape;
1495
- }, false>]>;
1496
-
1497
- /**
1498
- * The point-access persistence seam (AGENTS §5 — Stores) for {@link DatabaseDefinition} configs —
1499
- * the twin of `@orkestrel/terminal`'s `TerminalStoreInterface`, storing a database's CONFIG-ONLY
1500
- * blueprint (never a live handle). Every primitive is async; `delete` of an absent id is a no-op.
1501
- */
1502
- export declare interface DefinitionStoreInterface {
1503
- get(id: string): Promise<DatabaseDefinition | undefined>;
1504
- set(definition: DatabaseDefinition): Promise<void>;
1505
- delete(id: string): Promise<void>;
1506
- }
1507
-
1508
- /**
1509
- * The DESCRIPTION {@link import('./factories.js').createDescribeTool} advertises.
1510
- *
1511
- * @remarks
1512
- * Deliberately short — unlike the workflow / workspace / agent tools, this one has no authoring
1513
- * schema or multi-step protocol to teach.
1514
- */
1515
- export declare const 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).";
1516
-
1517
- /**
1518
- * The name {@link import('./factories.js').createDescribeTool} advertises by default — the key a
1519
- * model calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under.
1520
- *
1521
- * @remarks
1522
- * Net-new: pairs with the other three tools' lean {@link AGENT_TOOL_SUMMARY} /
1523
- * {@link WORKFLOW_TOOL_SUMMARY} / {@link WORKSPACE_TOOL_SUMMARY} — a model that reads only the
1524
- * advertised summary can call `describe` with that tool's registered name to get its full
1525
- * teaching description back.
1526
- */
1527
- export declare const DESCRIBE_TOOL_NAME = "describe";
1528
-
1529
- /**
1530
- * The lean {@link import('@orkestrel/agent').ToolInterface.summary} {@link import('./factories.js').createDescribeTool}
1531
- * advertises — this tool needs no teaching of its own, so its summary and description are both
1532
- * short.
1533
- */
1534
- export declare const DESCRIBE_TOOL_SUMMARY = "Return the full description of a named registered tool.";
1535
-
1536
- /**
1537
- * The FLAT args {@link import('./factories.js').createDescribeTool} accepts — the registered
1538
- * tool `name` whose full `description` a model wants back.
1539
- *
1540
- * @remarks
1541
- * `name` must match a tool registered on the {@link import('@orkestrel/agent').ToolManagerInterface}
1542
- * the describe tool was built over — it is looked up via `tools.tool(name)`.
1543
- */
1544
- export declare interface DescribeToolArguments {
1545
- readonly name: string;
1546
- }
1547
-
1548
- /**
1549
- * The shape of {@link import('./types.js').DescribeToolArguments} —
1550
- * {@link import('./factories.js').createDescribeTool}'s advertised `parameters`.
1551
- *
1552
- * @remarks
1553
- * `name` is the only field (a non-empty string) — the registered tool name to look up.
1554
- */
1555
- export declare const describeToolShape: ObjectShape<{
1556
- name: StringShape;
1557
- }, false>;
1558
-
1559
- /**
1560
- * One concrete endpoint {@link import('./factories.js').createEndpointTool} wraps as an
1561
- * LLM-callable `ToolInterface` — the advertised identity, a non-empty set of example values its
1562
- * `parameters` are inferred from, and the local handler that runs a call.
1563
- *
1564
- * @remarks
1565
- * `samples` MUST be non-empty — {@link import('./factories.js').createEndpointTool} throws a
1566
- * typed `TOOL` {@link import('./errors.js').AgentToolError} at CONSTRUCTION when it is empty,
1567
- * since an empty sample set cannot infer a schema. By DEFAULT ({@link EndpointToolOptions.validate}
1568
- * `true`) `invoke` receives the PARSED, NORMALIZED args record — a copy of the model-supplied
1569
- * `args` with each scalar coerced to its inferred type (e.g. a number sent for a string slot
1570
- * arrives coerced to a string), checked against the same schema advertised as `parameters` — and
1571
- * a call with a missing required key or a non-coercible value never reaches `invoke` at all (see
1572
- * {@link EndpointToolOptions.validate}). With
1573
- * `validate: false`, `invoke` receives the model-supplied `args` VERBATIM (raw passthrough, never
1574
- * checked against the inferred schema). Either way `invoke`'s return flows back as the tool
1575
- * call's result; a throw PROPAGATES uncaught, isolated by the `ToolManagerInterface`
1576
- * (`@orkestrel/agent`) into the canonical error envelope. When `samples` are non-object values,
1577
- * the advertised schema wraps them under a single required `value` property, so `invoke` receives
1578
- * an `args` record of the shape `{ value: ... }` — never the bare value.
1579
- */
1580
- export declare interface EndpointDefinition {
1581
- readonly name: string;
1582
- readonly description: string;
1583
- readonly samples: readonly unknown[];
1584
- readonly invoke: EndpointHandler;
1585
- }
1586
-
1587
- /**
1588
- * The handler {@link import('./types.js').EndpointDefinition.invoke} implements — mirrors
1589
- * `@orkestrel/agent`'s `ToolOptions.execute` signature EXACTLY (same `Readonly<Record<string,
1590
- * unknown>>` argument, same `Promise<unknown> | unknown` return) so
1591
- * `execute: (args) => definition.invoke(args)` typechecks with zero assertions in
1592
- * {@link import('./factories.js').createEndpointTool}.
1593
- */
1594
- export declare type EndpointHandler = (args: Readonly<Record<string, unknown>>) => Promise<unknown> | unknown;
1595
-
1596
- /**
1597
- * Construction-time tuning for {@link import('./factories.js').createEndpointTool} — the
1598
- * inferred `parameters` schema's `format` / `enum` constraints, and whether that same schema is
1599
- * ENFORCED at `execute` time.
1600
- *
1601
- * @remarks
1602
- * `format` / `enum` default to `false`, matching `@orkestrel/contract`'s own
1603
- * `ValueToSchemaOptions` defaults. `validate` defaults to `true`: the schema
1604
- * `createEndpointTool` advertises as `parameters` (`samplesToSchema` + `schemaToObject`) is
1605
- * compiled ONCE at construction (via `@orkestrel/contract` 0.0.7's `schemaToShape`) into a
1606
- * `ContractInterface` used to `parse` every call's `args` before `invoke` runs — a NORMALIZING
1607
- * parse: a scalar value is COERCED to its inferred type where the house parsers coerce (a number
1608
- * to/from a numeric string, a boolean from `'1'`/`'0'`/`'true'`/`'false'`/`1`/`0`), so `invoke`
1609
- * receives the COERCED values (e.g. `7` sent for a string slot arrives at `invoke` as `'7'`), not
1610
- * the raw call args. A call whose `args` fails to parse — a required key missing, or a value not
1611
- * coercible to its slot's type — THROWS a typed `TOOL` {@link import('./errors.js').AgentToolError}
1612
- * carrying the structured `explain` faults, and `invoke` is never called. Beyond that coercion,
1613
- * enforcement is STRUCTURAL — required keys, `enum` membership, and numeric bounds — `format`
1614
- * annotations (`email`, `date-time`, `uuid`, `uri`, ...) are NEVER asserted, mirroring
1615
- * `@orkestrel/contract`'s own widening-only law for `schemaToShape`: a `format: true`-tuned
1616
- * endpoint still ACCEPTS a non-conforming string in a format-tagged slot. A key NOT present in
1617
- * the inferred (closed, `additionalProperties: false`) schema is NEVER a rejection either — it is
1618
- * SILENTLY DROPPED before `invoke` runs (the same leniency `@orkestrel/contract`'s own `parse`
1619
- * grants a closed object generally), so `invoke` may see fewer keys than the caller sent. Set
1620
- * `validate: false` to restore the PRE-0.0.7 behavior exactly — `execute` passes the
1621
- * model-supplied `args` straight to `invoke` UNCHANGED, unchecked and unstripped.
1622
- */
1623
- export declare interface EndpointToolOptions {
1624
- readonly format?: boolean;
1625
- readonly enum?: boolean;
1626
- readonly validate?: boolean;
1627
- }
1628
-
1629
- /**
1630
- * Expand the relation tool's FLAT dot-path `include` list into a live `@orkestrel/relation`
1631
- * {@link Include} tree — the pure leaf {@link import('./factories.js').createRelationTool} calls
1632
- * before a `'load'` / `'find'` call.
1633
- *
1634
- * @remarks
1635
- * Each path splits on `'.'` into a chain of relation names, deep-merged into one nested
1636
- * `Include` object with a leaf `true`. A longer path SUBSUMES a shorter sibling's bare `true` —
1637
- * `'contacts'` followed by `'contacts.account'` yields `{ contacts: { account: true } }`, never
1638
- * overwriting the deeper chain. An EMPTY segment (`''`, from a leading/trailing/doubled `.`) or a
1639
- * path whose segment count exceeds `depth` throws a typed `TOOL` {@link AgentToolError}.
1640
- *
1641
- * @param paths - The flat dot-path `include` list (or `undefined` — yields `{}`)
1642
- * @param depth - The max segment count a single path may reach
1643
- * @returns The equivalent nested {@link Include}
7
+ * @param options - The advertised definition and execution handler
8
+ * @returns A tool bound to the supplied handler
1644
9
  *
1645
10
  * @example
1646
11
  * ```ts
1647
- * import { expandInclude } from '@src/core'
12
+ * import { createTool } from '@orkestrel/tool'
1648
13
  *
1649
- * expandInclude(['contacts', 'contacts.account'], 3)
1650
- * // { contacts: { account: true } }
14
+ * const add = createTool({
15
+ * name: 'add',
16
+ * description: 'Add two numbers',
17
+ * execute: (args) => Number(args.a) + Number(args.b),
18
+ * })
1651
19
  * ```
1652
20
  */
1653
- export declare function expandInclude(paths: readonly string[] | undefined, depth: number): Include;
21
+ export declare function createTool(options: ToolOptions): ToolInterface;
1654
22
 
1655
23
  /**
1656
- * Expand a flat {@link WorkflowSteps} blob into a strict {@link WorkflowDefinition} — each step
1657
- * becomes a one-task phase, IN ORDER.
24
+ * Create an empty tool registry.
1658
25
  *
1659
- * @remarks
1660
- * The expansion of the tool's ADVERTISED surface: the deliberately-reduced flat form. Each
1661
- * {@link import('./types.js').WorkflowStep} maps to a phase holding exactly one task: the step's
1662
- * `name` becomes the task's `run` (the behavior-registry key). Ids/names are auto-filled
1663
- * positionally — it builds an ids-omitted {@link WorkflowDraft} and delegates to
1664
- * {@link completeDraft}, so the two lenient surfaces share ONE synthesis path (step `i` → phase
1665
- * `phase-<i>`, its task `phase-<i>-task-0`). The optional `name` becomes the workflow's `name`.
1666
- * The result is a complete definition the caller validates against the STRICT contract before
1667
- * running.
26
+ * @returns A registry that advertises definitions and executes calls with per-call
27
+ * error isolation
1668
28
  *
1669
- * @param flat - The flat steps blob (`{ name?, steps: [{ name }] }`)
1670
- * @returns A complete {@link WorkflowDefinition} (one one-task phase per step)
1671
- */
1672
- export declare function expandSteps(flat: WorkflowSteps): WorkflowDefinition;
1673
-
1674
- /**
1675
- * Compile a {@link TableSpec} into the `@orkestrel/database` {@link TablesShape} it configures —
1676
- * each {@link ColumnSpec} maps to the matching primitive shaper (`'string'` → `stringShape()`,
1677
- * `'integer'` → `integerShape()`, `'number'` → `numberShape()`, `'boolean'` → `booleanShape()`),
1678
- * wrapped in `optionalShape` when the column declares `optional: true`. Total, pure.
29
+ * @example
30
+ * ```ts
31
+ * import { createTool, createToolManager } from '@orkestrel/tool'
1679
32
  *
1680
- * @param spec - The small-model-facing table layout
1681
- * @returns The compiled `TablesShape` a `@orkestrel/database` `createDatabase` call accepts
1682
- */
1683
- export declare function expandTables(spec: TableSpec): TablesShape;
1684
-
1685
- /** Flat dot-path relation include list, expanded via {@link import('./helpers.js').expandInclude}. */
1686
- export declare const includeShape: OptionalShape<ArrayShape<StringShape>>;
1687
-
1688
- export declare const INFER_TOOL_DESCRIPTION: string;
1689
-
1690
- /**
1691
- * The name {@link import('./factories.js').createInferTool} advertises by default — the key a
1692
- * model calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under.
1693
- */
1694
- export declare const INFER_TOOL_NAME = "infer";
1695
-
1696
- /**
1697
- * The lean {@link import('@orkestrel/agent').ToolInterface.summary} {@link import('./factories.js').createInferTool}
1698
- * advertises in place of {@link INFER_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
1699
- * (`@orkestrel/agent`) advertises `summary ?? description`, so this one-sentence text stands in
1700
- * for the full teaching description; the full text stays retrievable via
1701
- * {@link import('./factories.js').createDescribeTool}.
1702
- */
1703
- export declare const INFER_TOOL_SUMMARY = "Infer a JSON Schema (as advertised tool parameters) from one or more example values. Call describe('infer') for the required fields.";
1704
-
1705
- /**
1706
- * Options for {@link import('./factories.js').createInferTool} — advertised name/description
1707
- * overrides only; `format` / `enum` are RUNTIME call arguments (see
1708
- * {@link import('./shapers.js').inferToolShape}), not construction-time options, since a model
1709
- * chooses them per call.
33
+ * const tools = createToolManager()
34
+ * tools.add(createTool({ name: 'echo', execute: (args) => args.value }))
35
+ * const result = await tools.execute({
36
+ * id: '1',
37
+ * name: 'echo',
38
+ * arguments: { value: 'hello' },
39
+ * })
40
+ * ```
1710
41
  */
1711
- export declare interface InferToolOptions {
1712
- readonly name?: string;
1713
- readonly description?: string;
1714
- }
42
+ export declare function createToolManager(): ToolManagerInterface;
1715
43
 
1716
44
  /**
1717
- * The shape of {@link import('./factories.js').createInferTool}'s call arguments one or more
1718
- * example `samples` to infer a JSON Schema from, plus per-call `format` / `enum` toggles and an
1719
- * optional `candidates` array to check against the inferred schema.
45
+ * Determine whether an unknown value is structurally a {@link ToolCall}.
1720
46
  *
1721
47
  * @remarks
1722
- * `samples` requires at least one element (`min: 1`) an empty array parses to `undefined`,
1723
- * surfaced by the handler as a typed `TOOL` {@link import('./errors.js').AgentToolError}. When
1724
- * `candidates` is present (any array, including empty), the handler compiles a contract from the
1725
- * freshly inferred schema and checks each candidate against it with a STRICT guard (`.is`, no
1726
- * coercion) — the opposite of {@link import('./factories.js').createEndpointTool}'s NORMALIZING
1727
- * `.parse` enforcement.
1728
- */
1729
- export declare const inferToolShape: ObjectShape<{
1730
- samples: ArrayShape<JSONShape>;
1731
- format: OptionalShape<BooleanShape>;
1732
- enum: OptionalShape<BooleanShape>;
1733
- candidates: OptionalShape<ArrayShape<JSONShape>>;
1734
- }, false>;
1735
-
1736
- /**
1737
- * Type guard narrowing an unknown caught value to an {@link AgentToolError}.
48
+ * This total guard accepts a plain record with string `id` and `name` fields and a
49
+ * plain-record `arguments` field. Adversarial values return `false`.
1738
50
  *
1739
- * @param value - The value to test (typically a `catch` binding)
1740
- * @returns `true` when `value` is an {@link AgentToolError}
51
+ * @param value - The value to test
52
+ * @returns `true` when the value has the complete tool-call shape
1741
53
  *
1742
54
  * @example
1743
55
  * ```ts
1744
- * import { isAgentToolError } from '@src/core'
56
+ * import { isToolCall } from '@orkestrel/tool'
1745
57
  *
1746
- * try {
1747
- * // ...
1748
- * } catch (error) {
1749
- * if (isAgentToolError(error)) console.log(error.code)
1750
- * }
58
+ * isToolCall({ id: '1', name: 'search', arguments: { query: 'birds' } }) // true
59
+ * isToolCall({ id: '1', name: 'search', arguments: [] }) // false
1751
60
  * ```
1752
61
  */
1753
- export declare function isAgentToolError(value: unknown): value is AgentToolError;
1754
-
1755
- /** Narrow an unknown value to a {@link import('./types.js').ColumnKind}. */
1756
- export declare function isColumnKind(value: unknown): value is ColumnKind;
1757
-
1758
- /** Narrow an unknown value to a {@link ColumnSpec} — a valid {@link import('./types.js').ColumnKind} shorthand, or `{ type, optional }` with a valid `type`. */
1759
- export declare function isColumnSpec(value: unknown): value is ColumnSpec;
1760
-
1761
- /**
1762
- * Narrow an unknown value to a {@link DatabaseDefinition} — a non-empty `id` + `driver`, a
1763
- * `tables` record whose every value is `{ columns: record of valid ColumnSpec }`, and an optional
1764
- * `keys` record of strings. The boundary guard a {@link import('./types.js').DefinitionStoreInterface}
1765
- * applies to an untrusted persisted blob before trusting it as a definition (never an `as`).
1766
- */
1767
- export declare function isDatabaseDefinition(value: unknown): value is DatabaseDefinition;
1768
-
1769
- /** One key value — a string or number; the array form (multiple keys, positional) resolves FIRST per AGENTS §9.2. */
1770
- export declare const keyShape: UnionShape<readonly [ ArrayShape<UnionShape<readonly [ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1771
-
1772
- /** Map one {@link import('./types.js').ColumnKind} to its primitive `@orkestrel/database` shape — the leaf {@link columnShape} wraps. */
1773
- export declare function kindShape(kind: ColumnKind): ContractShape;
1774
-
1775
- /** Which registered relation manager to address — omitted resolves to the sole registered manager. */
1776
- export declare const managerShape: OptionalShape<StringShape>;
1777
-
1778
- /**
1779
- * The maximum nesting depth a workflow → agent → workflow chain may reach — the bound
1780
- * {@link import('./factories.js').createAgentFunction} and
1781
- * {@link import('./factories.js').createWorkflowTool}'s depth/cycle guards enforce.
1782
- *
1783
- * @remarks
1784
- * OWNED here now (ported from `@orkestrel/workflow`, whose engine no longer uses it — only the
1785
- * tool-authoring guards this package now owns consume it). The limit lives in ONE place: an
1786
- * agent-function-wrapped agent running at this depth can no longer author + run a NESTED
1787
- * workflow through its bound workflow tool (that would be depth `MAX_WORKFLOW_DEPTH + 1`), so
1788
- * the over-deep invocation is REJECTED (a typed `DEPTH` `WorkflowError` throw, `@orkestrel/workflow`).
1789
- */
1790
- export declare const MAX_WORKFLOW_DEPTH = 8;
62
+ export declare function isToolCall(value: unknown): value is ToolCall;
1791
63
 
1792
64
  /**
1793
- * The in-memory {@link DefinitionStoreInterface} a process-lifetime `Map` of
1794
- * {@link DatabaseDefinition}s keyed by database id, the DEFAULT store
1795
- * {@link import('../factories.js').createMemoryDefinitionStore} builds. The EXACT twin of
1796
- * {@link import('./DatabaseDefinitionStore.js').DatabaseDefinitionStore}.
65
+ * An executable tool definition bound to a handler.
1797
66
  *
1798
67
  * @remarks
1799
- * A plain `Map<string, DatabaseDefinition>` (AGENTS §21 the definition is already pure,
1800
- * self-contained CONFIG-only JSON, so no encoding is needed for the memory tier). There is NO
1801
- * idle-TTL and NO eviction: a persisted definition lives until an explicit `delete`. A durable
1802
- * backend (JSON / SQLite / IndexedDB) swaps in through the SAME interface without touching a
1803
- * consumer — its driver-pluggable twin is
1804
- * {@link import('./DatabaseDefinitionStore.js').DatabaseDefinitionStore} (the definition as one
1805
- * opaque JSON column).
1806
- *
1807
- * - **`get` resolves the persisted definition for an id**, or `undefined` if none is stored.
1808
- * - **`set` inserts / replaces under the definition's OWN `id`** (no separate id param).
1809
- * - **`delete` drops a definition by id**; an absent id is a no-op (no throw).
1810
- *
1811
- * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method
1812
- * bijection with {@link DefinitionStoreInterface}).
68
+ * Schema fields and arguments are forwarded by reference. Handler failures are not
69
+ * caught here; {@link ToolManager} owns per-call error isolation.
1813
70
  *
1814
71
  * @example
1815
72
  * ```ts
1816
- * import { createMemoryDefinitionStore } from '@src/core'
1817
- *
1818
- * const store = createMemoryDefinitionStore()
1819
- * await store.set({ id: 'shop', driver: 'memory', tables: {} })
1820
- * const definition = await store.get('shop')
1821
- * await store.delete('shop')
73
+ * import { Tool } from '@orkestrel/tool'
74
+ *
75
+ * const tool = new Tool({
76
+ * name: 'add',
77
+ * description: 'Add two numbers',
78
+ * parameters: {
79
+ * type: 'object',
80
+ * properties: { a: { type: 'number' }, b: { type: 'number' } },
81
+ * },
82
+ * execute: (args) => Number(args.a) + Number(args.b),
83
+ * })
1822
84
  * ```
1823
85
  */
1824
- export declare class MemoryDefinitionStore implements DefinitionStoreInterface {
86
+ export declare class Tool implements ToolInterface {
1825
87
  #private;
1826
- get(id: string): Promise<DatabaseDefinition | undefined>;
1827
- set(definition: DatabaseDefinition): Promise<void>;
1828
- delete(id: string): Promise<void>;
1829
- }
1830
-
1831
- /** One sort term. */
1832
- export declare const orderShape: ObjectShape<{
1833
- column: StringShape;
1834
- direction: LiteralShape<readonly ["ascending", "descending"]>;
1835
- }, false>;
1836
-
1837
- /** A draft phase — a `PhaseDefinition` (`@orkestrel/workflow`) with OPTIONAL `id` / `name` and {@link TaskDraft} tasks. */
1838
- export declare interface PhaseDraft {
1839
- readonly id?: string;
1840
- readonly name?: string;
1841
- readonly description?: string;
1842
- readonly tasks: readonly TaskDraft[];
1843
- /** Max tasks in flight at once (a resource throttle); omitted ⇒ unbounded. */
1844
- readonly concurrency?: number;
1845
- /** The per-phase failure-policy OVERRIDE; omitted ⇒ inherits the workflow `bail`. */
1846
- readonly bail?: boolean;
1847
- }
1848
-
1849
- /**
1850
- * The shape of a PHASE in a draft workflow — identical to a strict phase shape EXCEPT `id` and
1851
- * `name` are OPTIONAL, and its tasks are {@link taskDraftShape}s.
1852
- */
1853
- export declare const phaseDraftShape: ObjectShape<{
1854
- id: OptionalShape<StringShape>;
1855
- name: OptionalShape<StringShape>;
1856
- description: OptionalShape<StringShape>;
1857
- tasks: ArrayShape<ObjectShape<{
1858
- id: OptionalShape<StringShape>;
1859
- name: OptionalShape<StringShape>;
1860
- description: OptionalShape<StringShape>;
1861
- run: OptionalShape<StringShape>;
1862
- retries: OptionalShape<NumberShape>;
1863
- timeout: OptionalShape<NumberShape>;
1864
- }, false>>;
1865
- concurrency: OptionalShape<NumberShape>;
1866
- bail: OptionalShape<LiteralShape<readonly [true, false]>>;
1867
- }, false>;
1868
-
1869
- export declare const PROMPT_TOOL_DESCRIPTION: string;
1870
-
1871
- /**
1872
- * The name {@link import('./factories.js').createPromptTool} advertises by default — the key a
1873
- * model calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under.
1874
- */
1875
- export declare const PROMPT_TOOL_NAME = "ask";
1876
-
1877
- /**
1878
- * The lean {@link import('@orkestrel/agent').ToolInterface.summary} {@link import('./factories.js').createPromptTool}
1879
- * advertises in place of {@link PROMPT_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
1880
- * (`@orkestrel/agent`) advertises `summary ?? description`, so this one-sentence text stands in
1881
- * for the full teaching description; the full text stays retrievable via
1882
- * {@link import('./factories.js').createDescribeTool}.
1883
- */
1884
- export declare const PROMPT_TOOL_SUMMARY = "Ask another terminal a question and BLOCK until it answers; the call resolves with the answered value. Call describe('ask') for the required fields.";
1885
-
1886
- /**
1887
- * Options for {@link import('./factories.js').createPromptTool} — the live
1888
- * {@link TerminalManagerInterface} (`@orkestrel/terminal`) to `ask` through, the terminal name
1889
- * `from`, and the advertised tool overrides.
1890
- *
1891
- * @remarks
1892
- * - `manager` — the terminal manager whose `ask(from, to, form, options)` the tool's handler
1893
- * calls; BLOCKS the calling agent turn until the addressed terminal answers (or the ask
1894
- * rejects — a cycle throws `TerminalError('DEADLOCK')`, re-surfaced as a typed `DEADLOCK`
1895
- * {@link import('./errors.js').AgentToolError}; an expired prompt re-surfaces as `EXPIRE`).
1896
- * - `from` — the terminal identity this tool asks AS; the model supplies the `to` target and the
1897
- * prompt form per call.
1898
- * - `name` / `description` — advertised tool overrides; default to
1899
- * {@link import('./constants.js').PROMPT_TOOL_NAME} / {@link import('./constants.js').PROMPT_TOOL_DESCRIPTION}.
1900
- */
1901
- export declare interface PromptToolOptions {
1902
- readonly manager: TerminalManagerInterface;
1903
- readonly from: string;
1904
- readonly name?: string;
1905
- readonly description?: string;
1906
- }
1907
-
1908
- /**
1909
- * The shape of {@link import('./factories.js').createPromptTool}'s call arguments — `to` (the
1910
- * terminal identity to address), `form` (which of the six {@link import('@orkestrel/terminal').PromptType}
1911
- * forms to ask), `message`, an optional `timeout` override, and every per-form optional field
1912
- * FLATTENED onto one object (mirrors `workspaceToolShape`'s flat-arm style, but a single shared
1913
- * shape rather than a discriminated union — `form` alone does not vary the REQUIRED fields, only
1914
- * which of the optional ones apply, so a flat shape stays faithful without duplicating `to` /
1915
- * `message` / `timeout` across six near-identical arms).
1916
- *
1917
- * @remarks
1918
- * `choices` backs `'select'` / `'checkbox'`; `default` backs `'input'` / `'confirm'` / `'select'`
1919
- * (a string for the first two forms' text default, `'true'`/`'false'` string for confirm — the
1920
- * contract layer cannot vary a field's type by a sibling field's value, so `default` stays a
1921
- * string and the handler coerces per form); `mask` backs `'password'`; `min` / `max` backs
1922
- * `'checkbox'`; `validate` (declarative only) backs the four text-shaped forms
1923
- * (`'input'` / `'password'` / `'confirm'` / `'editor'`).
1924
- */
1925
- export declare const promptToolShape: ObjectShape<{
1926
- to: StringShape;
1927
- form: LiteralShape<readonly ["input", "password", "confirm", "select", "checkbox", "editor"]>;
1928
- message: StringShape;
1929
- default: OptionalShape<StringShape>;
1930
- choices: OptionalShape<ArrayShape<ObjectShape<{
1931
- name: StringShape;
1932
- value: StringShape;
1933
- description: OptionalShape<StringShape>;
1934
- }, boolean | ContractShape>>>;
1935
- mask: OptionalShape<StringShape>;
1936
- min: OptionalShape<NumberShape>;
1937
- max: OptionalShape<NumberShape>;
1938
- validate: OptionalShape<ObjectShape<{
1939
- required: OptionalShape<BooleanShape>;
1940
- minimum: OptionalShape<NumberShape>;
1941
- maximum: OptionalShape<NumberShape>;
1942
- pattern: OptionalShape<StringShape>;
1943
- email: OptionalShape<BooleanShape>;
1944
- url: OptionalShape<BooleanShape>;
1945
- numeric: OptionalShape<BooleanShape>;
1946
- integer: OptionalShape<BooleanShape>;
1947
- alphanumeric: OptionalShape<BooleanShape>;
1948
- }, boolean | ContractShape>>;
1949
- timeout: OptionalShape<NumberShape>;
1950
- }, false>;
1951
-
1952
- /** The default cap on how many `include` path segments deep a `load` / `find` call may traverse — the relation tool's default include-depth ceiling. */
1953
- export declare const RELATION_TOOL_DEPTH = 3;
1954
-
1955
- /**
1956
- * The DESCRIPTION the relation tool advertises — a multi-line guide that teaches a small model
1957
- * the operation list and the flat dot-path `include` syntax.
1958
- *
1959
- * @remarks
1960
- * An include path is a FLAT dot-separated string (`'contacts.account'`), never a nested object —
1961
- * the same small-model ergonomic lever the other tools in this package use for flat args.
1962
- */
1963
- export declare const RELATION_TOOL_DESCRIPTION: string;
1964
-
1965
- /** The default cap on rows a `find` / `links` call returns when the caller omits `limit` — the relation tool's default row ceiling. */
1966
- export declare const RELATION_TOOL_LIMIT = 1000;
1967
-
1968
- /**
1969
- * The name `createRelationTool` advertises by default — the key a model calls and the
1970
- * `ToolManagerInterface` (`@orkestrel/agent`) registers under.
1971
- */
1972
- export declare const RELATION_TOOL_NAME = "relation";
1973
-
1974
- /**
1975
- * The lean {@link import('@orkestrel/agent').ToolInterface.summary} the relation tool advertises
1976
- * in place of {@link RELATION_TOOL_DESCRIPTION}.
1977
- */
1978
- export declare const RELATION_TOOL_SUMMARY = "Traverse and edit relationships between database rows \u2014 one operation per call (load, find, link, unlink, links), chosen by the 'operation' field. Call describe('relation') for the include-path syntax.";
1979
-
1980
- /** One key value — a string or number; the array form (multiple keys, positional) resolves FIRST per AGENTS §9.2. */
1981
- export declare const relationKeyShape: UnionShape<readonly [ ArrayShape<UnionShape<readonly [ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1982
-
1983
- /**
1984
- * Resolve which registered {@link RelationManagerInterface} a relation-tool call addresses — the
1985
- * pure manager-resolution leaf {@link import('./factories.js').createRelationTool} calls on
1986
- * every operation.
1987
- *
1988
- * @remarks
1989
- * An explicit `name` must match a key of `managers` (a miss throws a typed `TOOL`
1990
- * {@link AgentToolError} naming the registered managers). An OMITTED `name` resolves to the sole
1991
- * registered manager when exactly one is registered, else throws the same typed error.
1992
- *
1993
- * @param managers - The tool's registered `RelationManagerInterface` map
1994
- * @param name - The call's optional `manager` field
1995
- * @returns The resolved {@link RelationManagerInterface}
1996
- */
1997
- export declare function relationManagerOf(managers: Readonly<Record<string, RelationManagerInterface>>, name: string | undefined): RelationManagerInterface;
1998
-
1999
- /**
2000
- * Resolve a `model` name against a live {@link RelationManagerInterface} — the pure model-lookup
2001
- * leaf {@link import('./factories.js').createRelationTool} calls on every operation, mirroring
2002
- * {@link relationManagerOf}'s guard shape.
2003
- *
2004
- * @param manager - The resolved {@link RelationManagerInterface}
2005
- * @param name - The call's `model` field
2006
- * @returns The model's {@link ModelInterface}
2007
- */
2008
- export declare function relationModelOf(manager: RelationManagerInterface, name: string): ModelInterface;
2009
-
2010
- /**
2011
- * Map a caught error to the {@link AgentToolErrorCode} the upcoming relation tool should throw
2012
- * with — the pure classification step of that factory's error handling, mirroring
2013
- * {@link terminalToolCode}'s idiom for `@orkestrel/relation`.
2014
- *
2015
- * @param error - The value caught from a `@orkestrel/relation` operation
2016
- * @returns The granular {@link RelationErrorCode}, or `undefined` if `error` is not a `RelationError`
2017
- */
2018
- export declare function relationToolCode(error: unknown): RelationErrorCode | undefined;
2019
-
2020
- /**
2021
- * Options for {@link import('./factories.js').createRelationTool} — SRC-3 (the final unit) of
2022
- * the 3-unit database / relation spine.
2023
- *
2024
- * @remarks
2025
- * - `managers` — the live `RelationManagerInterface` (`@orkestrel/relation`) registry a call's
2026
- * optional `manager` field addresses by name; REQUIRED (unlike the database tool's lazily
2027
- * resolved handles, a relation manager's relations are declared up front and cannot be minted
2028
- * on demand from a tool call). A call that omits `manager` resolves to the SOLE registered
2029
- * manager when exactly one is registered, else throws a typed `TOOL`
2030
- * {@link import('./errors.js').AgentToolError} naming the registered manager keys.
2031
- * - `limit` — the row cap `'find'` / `'links'` enforce when a call's `limit` is omitted or
2032
- * exceeds it. Defaults to {@link import('./constants.js').RELATION_TOOL_LIMIT}.
2033
- * - `depth` — the max dot-path segment count `'load'` / `'find'`'s `include` paths may reach
2034
- * ({@link import('./helpers.js').expandInclude}). Defaults to
2035
- * {@link import('./constants.js').RELATION_TOOL_DEPTH}.
2036
- * - `name` / `description` — advertised tool overrides; default to
2037
- * {@link import('./constants.js').RELATION_TOOL_NAME} / {@link import('./constants.js').RELATION_TOOL_DESCRIPTION}.
2038
- */
2039
- export declare interface RelationToolOptions {
2040
- readonly name?: string;
88
+ readonly name: string;
2041
89
  readonly description?: string;
2042
- readonly managers: Readonly<Record<string, RelationManagerInterface>>;
2043
- readonly limit?: number;
2044
- readonly depth?: number;
90
+ readonly summary?: string;
91
+ readonly parameters?: Readonly<Record<string, unknown>>;
92
+ constructor(options: ToolOptions);
93
+ execute(args: Readonly<Record<string, unknown>>): Promise<unknown> | unknown;
2045
94
  }
2046
95
 
2047
96
  /**
2048
- * The shape of {@link import('./factories.js').createRelationTool}'s call arguments —
2049
- * discriminated by `operation` into the 5 relation operations (`'load'` / `'find'` / `'link'` /
2050
- * `'unlink'` / `'links'`).
2051
- *
2052
- * @remarks
2053
- * `'load'` fetches one or more rows (positional key/array) with `include` attached. `'find'`
2054
- * fetches rows (pagination / sort only) with `include` attached. `'link'` / `'unlink'` write /
2055
- * remove a `through` junction row; `'links'` lists a `through` relation's linked keys.
2056
- */
2057
- export declare const relationToolShape: UnionShape<readonly [ ObjectShape<{
2058
- operation: LiteralShape<readonly ["load"]>;
2059
- manager: OptionalShape<StringShape>;
2060
- model: StringShape;
2061
- key: UnionShape<readonly [ ArrayShape<UnionShape<readonly [ StringShape, NumberShape]>>, StringShape, NumberShape]>;
2062
- include: OptionalShape<ArrayShape<StringShape>>;
2063
- }, false>, ObjectShape<{
2064
- operation: LiteralShape<readonly ["find"]>;
2065
- manager: OptionalShape<StringShape>;
2066
- model: StringShape;
2067
- include: OptionalShape<ArrayShape<StringShape>>;
2068
- limit: OptionalShape<NumberShape>;
2069
- offset: OptionalShape<NumberShape>;
2070
- sort: OptionalShape<StringShape>;
2071
- direction: OptionalShape<LiteralShape<readonly ["ascending", "descending"]>>;
2072
- }, false>, ObjectShape<{
2073
- operation: LiteralShape<readonly ["link"]>;
2074
- manager: OptionalShape<StringShape>;
2075
- model: StringShape;
2076
- key: UnionShape<readonly [ StringShape, NumberShape]>;
2077
- relation: StringShape;
2078
- target: UnionShape<readonly [ StringShape, NumberShape]>;
2079
- }, false>, ObjectShape<{
2080
- operation: LiteralShape<readonly ["unlink"]>;
2081
- manager: OptionalShape<StringShape>;
2082
- model: StringShape;
2083
- key: UnionShape<readonly [ StringShape, NumberShape]>;
2084
- relation: StringShape;
2085
- target: UnionShape<readonly [ StringShape, NumberShape]>;
2086
- }, false>, ObjectShape<{
2087
- operation: LiteralShape<readonly ["links"]>;
2088
- manager: OptionalShape<StringShape>;
2089
- model: StringShape;
2090
- key: UnionShape<readonly [ StringShape, NumberShape]>;
2091
- relation: StringShape;
2092
- }, false>]>;
2093
-
2094
- /** A loose row — a flat object of column name to JSON value; the array form (multiple rows) resolves FIRST per AGENTS §9.2. */
2095
- export declare const rowShape: ObjectShape<Record<never, never>, JSONShape>;
2096
-
2097
- /** One or many loose rows — the array form resolves FIRST per AGENTS §9.2. */
2098
- export declare const rowsShape: UnionShape<readonly [ ArrayShape<ObjectShape<Record<never, never>, JSONShape>>, ObjectShape<Record<never, never>, JSONShape>]>;
2099
-
2100
- /** A single row key (not an array) — used by `'link'` / `'unlink'` / `'links'`, which address exactly one owning row. */
2101
- export declare const singleKeyShape: UnionShape<readonly [ StringShape, NumberShape]>;
2102
-
2103
- /**
2104
- * The shape of ONE flat step — `{ name }` — the building block of {@link workflowStepsShape}.
2105
- *
2106
- * @remarks
2107
- * `name` is the REGISTERED behavior name the step runs (it becomes the task's `run`). The tool
2108
- * expands each step into a one-task phase, in order ({@link import('./helpers.js').expandSteps}).
2109
- */
2110
- export declare const stepShape: ObjectShape<{
2111
- name: StringShape;
2112
- }, false>;
2113
-
2114
- /**
2115
- * Build one {@link TableSchema} from a table NAME and its `@orkestrel/database` `TableExport` —
2116
- * the "deployed" schema shape `DatabaseInterface.migrate` diffs against, derived from a LIVE
2117
- * handle's `export()` rather than a re-declared {@link TableSpec}, so it works for ANY handle
2118
- * (config-tracked or caller-supplied).
2119
- *
2120
- * @param name - The table name
2121
- * @param table - The table's `TableExport` (`{ key, columns }`, `@orkestrel/database`)
2122
- * @returns The equivalent {@link TableSchema} (`indexes` empty — this package declares none)
2123
- */
2124
- export declare function tableSchema(name: string, table: Readonly<{
2125
- key: string;
2126
- columns: Readonly<Record<string, ContractShape>>;
2127
- }>): TableSchema;
2128
-
2129
- /**
2130
- * A database's table layout — one entry per table, each a flat map of column name to
2131
- * {@link ColumnSpec}. The small-model-facing DSL {@link import('./helpers.js').expandTables}
2132
- * compiles into an `@orkestrel/database` `TablesShape`.
2133
- */
2134
- export declare type TableSpec = Readonly<Record<string, Readonly<{
2135
- columns: Readonly<Record<string, ColumnSpec>>;
2136
- }>>>;
2137
-
2138
- /** A {@link import('./types.js').TableSpec} — table name to `{ columns }`, each column a {@link columnSpecShape}. */
2139
- export declare const tableSpecShape: ObjectShape<Record<never, never>, ObjectShape<{
2140
- columns: ObjectShape<Record<never, never>, UnionShape<readonly [ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
2141
- type: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
2142
- optional: OptionalShape<BooleanShape>;
2143
- }, false>]>>;
2144
- }, false>>;
2145
-
2146
- /**
2147
- * A draft task — a `TaskDefinition` (`@orkestrel/workflow`) with OPTIONAL `id` / `name`.
97
+ * A tool call issued by a caller.
2148
98
  *
2149
99
  * @remarks
2150
- * The tool synthesizes a missing `id` positionally and defaults a missing `name` to its `id`
2151
- * ({@link import('./helpers.js').completeDraft}). A PROVIDED `id` / `name` is preserved verbatim
2152
- * (and must be non-empty — the draft contract's `minLength: 1`).
100
+ * `id` correlates the call with its later {@link ToolResult}. `arguments` is the
101
+ * caller-supplied arguments record.
2153
102
  */
2154
- export declare interface TaskDraft {
2155
- readonly id?: string;
2156
- readonly name?: string;
2157
- readonly description?: string;
2158
- /** The behavior reference — a registry key resolved against a workflow's functions registry at construction; omitted ⇒ no handler. */
2159
- readonly run?: string;
2160
- /** Extra attempts after the first on failure (a non-negative integer); overrides the phase Runner default. Execution-only. */
2161
- readonly retries?: number;
2162
- /** The per-attempt deadline in milliseconds (a non-negative integer); overrides the phase Runner default. Execution-only. */
2163
- readonly timeout?: number;
103
+ export declare interface ToolCall {
104
+ /** The identifier that correlates this call with its result. */
105
+ readonly id: string;
106
+ /** The name of the tool to execute. */
107
+ readonly name: string;
108
+ /** The caller-supplied arguments record. */
109
+ readonly arguments: Readonly<Record<string, unknown>>;
2164
110
  }
2165
111
 
2166
112
  /**
2167
- * The shape of a {@link import('./types.js').TaskDraft} — identical to a strict task shape
2168
- * EXCEPT `id` and `name` are OPTIONAL.
2169
- */
2170
- export declare const taskDraftShape: ObjectShape<{
2171
- id: OptionalShape<StringShape>;
2172
- name: OptionalShape<StringShape>;
2173
- description: OptionalShape<StringShape>;
2174
- run: OptionalShape<StringShape>;
2175
- retries: OptionalShape<NumberShape>;
2176
- timeout: OptionalShape<NumberShape>;
2177
- }, false>;
2178
-
2179
- /**
2180
- * Map a caught error to the {@link AgentToolErrorCode} the terminal-tool factory should throw
2181
- * with — the pure classification step of that factory's error handling.
2182
- *
2183
- * @remarks
2184
- * Narrows `error` with {@link isTerminalError} (`@orkestrel/terminal`) first: a non-`TerminalError`
2185
- * value returns `undefined`, telling the caller this mapper does not apply (rethrow / handle
2186
- * otherwise). For a genuine `TerminalError`, `'DEADLOCK'` maps to `'DEADLOCK'`, `'EXPIRE'` maps
2187
- * to `'EXPIRE'`, and every other {@link import('@orkestrel/terminal').TerminalErrorCode}
2188
- * (`'TARGET'`, `'CANCEL'`, `'DRIVER'`) maps to the generic `'TOOL'` code. The mapper only
2189
- * classifies — the factory performs the actual throw.
2190
- *
2191
- * @param error - The value caught from a terminal-manager operation (`ask` / `answer` / …)
2192
- * @returns The mapped {@link AgentToolErrorCode}, or `undefined` if `error` is not a `TerminalError`
2193
- */
2194
- export declare function terminalToolCode(error: unknown): AgentToolErrorCode | undefined;
2195
-
2196
- export declare const WORKFLOW_TOOL_DESCRIPTION: string;
2197
-
2198
- /**
2199
- * A complete FLAT authoring example — the PRIMARY way a small model authors a workflow through
2200
- * {@link import('./factories.js').createWorkflowTool}: `{ name, steps: [{ name }] }`.
2201
- *
2202
- * @remarks
2203
- * OWNED here now (ported from `@orkestrel/workflow`). Each step becomes a one-task phase, in
2204
- * order; a step's `name` is a REGISTERED behavior name (not a label) — the registry key its
2205
- * task's `run` resolves against. The tool expands this
2206
- * ({@link import('./helpers.js').expandSteps}) into a valid `WorkflowDefinition`
2207
- * (`@orkestrel/workflow`). It is embedded VERBATIM in {@link WORKFLOW_TOOL_DESCRIPTION}.
2208
- */
2209
- export declare const WORKFLOW_TOOL_FLAT_EXAMPLE: WorkflowSteps;
2210
-
2211
- /**
2212
- * The name {@link import('./factories.js').createWorkflowTool} advertises by default — the key a
2213
- * model calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under, and the name
2214
- * {@link import('./factories.js').createAgentFunction} binds the depth/cycle-aware workflow tool
2215
- * under onto a wrapped agent's `context.tools`.
2216
- *
2217
- * @remarks
2218
- * OWNED here now (ported from `@orkestrel/workflow`). The propagation seam's well-known key: when
2219
- * `createAgentFunction`'s `runner` option is supplied, it adds a `createWorkflowTool`-built tool
2220
- * under this name to the agent's `context.tools`, so it can author + run a NESTED workflow
2221
- * (bounded by {@link MAX_WORKFLOW_DEPTH}).
2222
- */
2223
- export declare const WORKFLOW_TOOL_NAME = "workflow";
2224
-
2225
- /**
2226
- * A minimal NESTED authoring example — the ADVANCED escape-hatch form a model may use instead of
2227
- * the flat shape: a full `WorkflowDefinition` (`@orkestrel/workflow`).
2228
- *
2229
- * @remarks
2230
- * OWNED here now (ported from `@orkestrel/workflow`). The full four-level form, documented in
2231
- * {@link WORKFLOW_TOOL_DESCRIPTION} as the advanced alternative. It is embedded VERBATIM.
2232
- */
2233
- export declare const WORKFLOW_TOOL_NESTED_EXAMPLE: WorkflowDefinition;
2234
-
2235
- /**
2236
- * The lean {@link import('@orkestrel/agent').ToolInterface.summary} {@link import('./factories.js').createWorkflowTool}
2237
- * advertises in place of {@link WORKFLOW_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
2238
- * (`@orkestrel/agent`) advertises `summary ?? description`, so this one-sentence text stands in
2239
- * for the full teaching description; the full text stays retrievable via
2240
- * {@link import('./factories.js').createDescribeTool}.
2241
- */
2242
- export declare const WORKFLOW_TOOL_SUMMARY = "Author and run a multi-phase workflow in one call \u2014 phases run in sequence, tasks within a phase run concurrently. Call describe('workflow') for the full authoring schema and examples.";
2243
-
2244
- /**
2245
- * A draft workflow — a `WorkflowDefinition` (`@orkestrel/workflow`) with OPTIONAL `id` / `name`
2246
- * at all three levels (workflow / phase / task).
113
+ * A tool definition advertised to a caller.
2247
114
  *
2248
115
  * @remarks
2249
- * The lenient authoring form {@link import('./factories.js').createWorkflowDraftContract}
2250
- * validates and {@link import('./helpers.js').completeDraft} completes into a strict
2251
- * `WorkflowDefinition`. `run` stays optional (a plain name string); the `bail` policy carries
2252
- * over.
116
+ * `parameters` is an open JSON Schema record describing the arguments the tool accepts.
2253
117
  */
2254
- export declare interface WorkflowDraft {
2255
- readonly id?: string;
2256
- readonly name?: string;
118
+ export declare interface ToolDefinition {
119
+ /** The name a caller uses to select the tool. */
120
+ readonly name: string;
121
+ /** A description of the tool's behavior. */
2257
122
  readonly description?: string;
2258
- readonly phases: readonly PhaseDraft[];
2259
- /** Failure policy: `false` (default) continues gracefully, `true` halts on the first failure. */
2260
- readonly bail?: boolean;
123
+ /** The JSON Schema for the tool's arguments. */
124
+ readonly parameters?: Readonly<Record<string, unknown>>;
2261
125
  }
2262
126
 
2263
127
  /**
2264
- * The shape of a DRAFT workflow — identical to a strict workflow shape EXCEPT `id` and `name`
2265
- * are OPTIONAL at all three levels (workflow / phase / task), so a small model can omit the six
2266
- * identity strings and let the tool synthesize them positionally.
2267
- *
2268
- * @remarks
2269
- * The lenient counterpart {@link import('./factories.js').createWorkflowDraftContract} compiles.
2270
- * `run` stays required on the strict form; a provided `id` / `name` still has `minLength: 1` (so
2271
- * an explicitly-empty `id: ''` is REJECTED, not auto-filled). After
2272
- * {@link import('./helpers.js').completeDraft} fills the missing ids/names, the result is
2273
- * validated against the STRICT `createWorkflowContract` (`@orkestrel/workflow`) gate before
2274
- * running.
2275
- */
2276
- export declare const workflowDraftShape: ObjectShape<{
2277
- id: OptionalShape<StringShape>;
2278
- name: OptionalShape<StringShape>;
2279
- description: OptionalShape<StringShape>;
2280
- phases: ArrayShape<ObjectShape<{
2281
- id: OptionalShape<StringShape>;
2282
- name: OptionalShape<StringShape>;
2283
- description: OptionalShape<StringShape>;
2284
- tasks: ArrayShape<ObjectShape<{
2285
- id: OptionalShape<StringShape>;
2286
- name: OptionalShape<StringShape>;
2287
- description: OptionalShape<StringShape>;
2288
- run: OptionalShape<StringShape>;
2289
- retries: OptionalShape<NumberShape>;
2290
- timeout: OptionalShape<NumberShape>;
2291
- }, false>>;
2292
- concurrency: OptionalShape<NumberShape>;
2293
- bail: OptionalShape<LiteralShape<readonly [true, false]>>;
2294
- }, false>>;
2295
- bail: OptionalShape<LiteralShape<readonly [true, false]>>;
2296
- }, false>;
2297
-
2298
- /**
2299
- * One flat step — `{ name }` — the building block of a {@link WorkflowSteps} blob.
128
+ * The failed outcome of executing a {@link ToolCall}.
2300
129
  *
2301
130
  * @remarks
2302
- * `name` is the REGISTERED behavior name the step runs (it becomes the task's `run`, NOT a
2303
- * human label) resolved against a workflow-level functions registry at construction.
131
+ * `error` is the failure message: an unknown tool name, an `Error`'s message, or
132
+ * a String-converted throw. The registry carries no further structure. An
133
+ * in-process caller needing a typed error calls `tools.tool(name)`, then
134
+ * `tool.execute(args)` in its own `try`/`catch`.
2304
135
  */
2305
- export declare interface WorkflowStep {
2306
- /** The registered behavior name this step runs (becomes the task's `run`). */
136
+ export declare interface ToolFailure extends Failure<string> {
137
+ /** The identifier of the corresponding call. */
138
+ readonly id: string;
139
+ /** The name of the called tool. */
2307
140
  readonly name: string;
2308
141
  }
2309
142
 
2310
143
  /**
2311
- * The FLAT authoring blob {@link import('./factories.js').createWorkflowTool} advertises
2312
- * `{ name?, steps }` — the simplest surface a small model can fill.
144
+ * An executable tool: its advertised definition plus its local handler.
2313
145
  *
2314
146
  * @remarks
2315
- * Each {@link WorkflowStep} becomes a one-task phase, in order
2316
- * ({@link import('./helpers.js').expandSteps}); `name` is the optional workflow name (defaulted
2317
- * when omitted).
147
+ * `summary`, when present, is advertised in place of the full `description` by a
148
+ * {@link ToolManagerInterface}. The full description remains available on the tool.
2318
149
  */
2319
- export declare interface WorkflowSteps {
2320
- readonly name?: string;
2321
- readonly steps: readonly WorkflowStep[];
150
+ export declare interface ToolInterface extends ToolDefinition {
151
+ /** A concise description to advertise in place of the full description. */
152
+ readonly summary?: string;
153
+ /**
154
+ * Execute the tool.
155
+ *
156
+ * @param args - The caller-supplied arguments record
157
+ * @returns The tool's synchronous or asynchronous result
158
+ */
159
+ execute(args: Readonly<Record<string, unknown>>): Promise<unknown> | unknown;
2322
160
  }
2323
161
 
2324
162
  /**
2325
- * The FLAT authoring shape {@link import('./factories.js').createWorkflowTool} advertises as its
2326
- * `parameters` — the simplest surface a small model can fill: `{ name?, steps: [{ name }] }`.
2327
- *
2328
- * @remarks
2329
- * A deliberately-reduced surface: a flat ordered list of steps, each a `{ name }`. The tool
2330
- * EXPANDS it ({@link import('./helpers.js').expandSteps}) into a full
2331
- * {@link import('./types.js').WorkflowDefinition} — one one-task phase per step, in order —
2332
- * then validates against the STRICT `createWorkflowContract` (`@orkestrel/workflow`) gate. The
2333
- * full nested form is STILL accepted by the tool (it branches on the args' shape) and is
2334
- * documented as the advanced escape-hatch in the tool's description — but THIS is what
2335
- * `parameters` advertises.
2336
- */
2337
- export declare const workflowStepsShape: ObjectShape<{
2338
- name: OptionalShape<StringShape>;
2339
- steps: ArrayShape<ObjectShape<{
2340
- name: StringShape;
2341
- }, false>>;
2342
- }, false>;
2343
-
2344
- /**
2345
- * The ancestry identifier of a workflow in a run chain — `workflow:<id>`.
163
+ * An insertion-ordered tool registry with per-call error isolation.
2346
164
  *
2347
165
  * @remarks
2348
- * Namespacing keeps a workflow id and an {@link agentTag} agent name in ONE set without
2349
- * collision, so re-entering a workflow OR an agent already in the chain is a single `includes`
2350
- * check.
2351
- *
2352
- * @param id - The workflow definition's `id`
2353
- * @returns The namespaced ancestry tag (`workflow:<id>`)
2354
- */
2355
- export declare function workflowTag(id: string): string;
2356
-
2357
- /**
2358
- * Options for {@link import('./factories.js').createWorkflowTool} — the depth + ancestry a
2359
- * nested workflow run is bound at, plus the optional durable {@link WorkflowStoreInterface}
2360
- * (`@orkestrel/workflow`) this package layers on top of the ported handler logic.
166
+ * A repeated name overwrites the registered tool without changing its insertion
167
+ * position. Definitions advertise `summary` in place of `description` when present.
168
+ * Unknown names and handler throws resolve to error results; batch execution preserves
169
+ * input order and never fails as a whole because of an individual call.
2361
170
  *
2362
- * @remarks
2363
- * This is the PROPAGATION carrier across the agent/tool boundary. A `Tool`'s handler receives
2364
- * ONLY the model-supplied `args` (no ambient context, no signal see `@orkestrel/agent`'s
2365
- * `ToolOptions`), so the run's position in the workflow→agent→workflow chain CANNOT be threaded
2366
- * through a tool call at runtime. Instead {@link import('./factories.js').createAgentFunction}
2367
- * CLOSES `depth` / `ancestry` over the tool at BIND time. Both are OPTIONAL: a workflow tool
2368
- * built for a TOP-LEVEL caller omits them — its nested run starts the chain at depth `1` with
2369
- * the bare `workflow:<id>` ancestry.
171
+ * @example
172
+ * ```ts
173
+ * import { Tool, ToolManager } from '@orkestrel/tool'
2370
174
  *
2371
- * `store` is this package's ADDITION: when supplied, the tool's handler persists the run's final
2372
- * snapshot (`store.set(result.workflow.snapshot())`) once the run settles, so a workflow
2373
- * authored + run through the tool is retrievable / restorable afterwards. Omitted ⇒ no
2374
- * persistence.
175
+ * const tools = new ToolManager()
176
+ * tools.add(new Tool({ name: 'add', execute: (args) => Number(args.x) + Number(args.y) }))
177
+ * const result = await tools.execute({
178
+ * id: '1',
179
+ * name: 'add',
180
+ * arguments: { x: 1, y: 2 },
181
+ * })
182
+ * ```
2375
183
  */
2376
- export declare interface WorkflowToolOptions {
2377
- /** The depth the INVOKING agent runs at; the nested workflow runs at `depth + 1`. Default `0`. */
2378
- readonly depth?: number;
2379
- /** The ancestry of the invoking run; the nested run extends it with its own `workflow:<id>`. Default empty. */
2380
- readonly ancestry?: readonly string[];
2381
- readonly store?: WorkflowStoreInterface;
184
+ export declare class ToolManager implements ToolManagerInterface {
185
+ #private;
186
+ get count(): number;
187
+ add(tool: ToolInterface): void;
188
+ add(tools: readonly ToolInterface[]): void;
189
+ tool(name: string): ToolInterface | undefined;
190
+ tools(): readonly ToolInterface[];
191
+ definitions(): readonly ToolDefinition[];
192
+ execute(call: ToolCall): Promise<ToolResult>;
193
+ execute(calls: readonly ToolCall[]): Promise<readonly ToolResult[]>;
194
+ remove(name: string): boolean;
195
+ remove(names: readonly string[]): boolean;
196
+ clear(): void;
2382
197
  }
2383
198
 
2384
199
  /**
2385
- * Build the plain success summary {@link import('./factories.js').createWorkflowTool} returns on
2386
- * a completed run — the universal tool-handler contract (AGENTS §14): return a plain value on
2387
- * success, appearing identically over BOTH the agent loop and MCP.
200
+ * A registry of executable tools with per-call error isolation.
2388
201
  *
2389
202
  * @remarks
2390
- * The summary is LEAN: the workflow's terminal `status` and the COUNT of settled task results —
2391
- * enough for a caller / model to react without serializing the whole live tree. (It carries no
2392
- * synthetic `id` / `name`: a tool handler has no call id; the `ToolManagerInterface`
2393
- * (`@orkestrel/agent`) supplies the canonical envelope's identity.)
2394
- *
2395
- * @param result - The terminal `WorkflowResult` (`@orkestrel/workflow`) the run produced
2396
- * @returns The plain success summary — `{ status, count }`
203
+ * Tools are keyed by name in insertion order. Adding an existing name overwrites its
204
+ * value without changing its position. Every call resolves to a {@link ToolResult};
205
+ * missing tools and thrown handlers become error results. Batch execution preserves
206
+ * input order and isolates each call.
2397
207
  */
2398
- export declare function workflowToolSummary(result: WorkflowResult): Readonly<{
2399
- status: WorkflowStatus;
2400
- count: number;
2401
- }>;
2402
-
2403
- export declare const WORKSPACE_TOOL_DESCRIPTION: string;
208
+ export declare interface ToolManagerInterface {
209
+ /** The number of registered tools. */
210
+ readonly count: number;
211
+ /**
212
+ * Register one tool.
213
+ *
214
+ * @param tool - The tool to register
215
+ * @returns Nothing
216
+ */
217
+ add(tool: ToolInterface): void;
218
+ /**
219
+ * Register a batch of tools.
220
+ *
221
+ * @param tools - The tools to register
222
+ * @returns Nothing
223
+ */
224
+ add(tools: readonly ToolInterface[]): void;
225
+ /**
226
+ * Find one registered tool by name.
227
+ *
228
+ * @param name - The registered tool name
229
+ * @returns The tool when found, otherwise `undefined`
230
+ */
231
+ tool(name: string): ToolInterface | undefined;
232
+ /**
233
+ * List the registered tools in insertion order.
234
+ *
235
+ * @returns A new readonly array of registered tools
236
+ */
237
+ tools(): readonly ToolInterface[];
238
+ /**
239
+ * List the definitions advertised to a caller.
240
+ *
241
+ * The projected `description` is the tool's `summary` when one was authored,
242
+ * advertised in place of the full description. The full text stays on the tool
243
+ * for direct lookup.
244
+ *
245
+ * @returns A new readonly array of tool definitions
246
+ */
247
+ definitions(): readonly ToolDefinition[];
248
+ /**
249
+ * Execute one call with error isolation.
250
+ *
251
+ * @param call - The tool call to execute
252
+ * @returns The correlated result
253
+ */
254
+ execute(call: ToolCall): Promise<ToolResult>;
255
+ /**
256
+ * Execute a batch of calls with per-call error isolation.
257
+ *
258
+ * @param calls - The tool calls to execute
259
+ * @returns The correlated results in input order
260
+ */
261
+ execute(calls: readonly ToolCall[]): Promise<readonly ToolResult[]>;
262
+ /**
263
+ * Remove one registered tool.
264
+ *
265
+ * @param name - The tool name to remove
266
+ * @returns Whether the tool was present
267
+ */
268
+ remove(name: string): boolean;
269
+ /**
270
+ * Remove a batch of registered tools.
271
+ *
272
+ * @param names - The tool names to remove
273
+ * @returns Whether any named tool was present
274
+ */
275
+ remove(names: readonly string[]): boolean;
276
+ /**
277
+ * Remove every registered tool.
278
+ *
279
+ * @returns Nothing
280
+ */
281
+ clear(): void;
282
+ }
2404
283
 
2405
284
  /**
2406
- * A valid `WorkspaceOperation` (`@orkestrel/agent`) object — the canonical example embedded
2407
- * VERBATIM in {@link WORKSPACE_TOOL_DESCRIPTION}.
285
+ * Options for creating an executable tool.
2408
286
  *
2409
287
  * @remarks
2410
- * OWNED here now (ported from `@orkestrel/agent`). A `'write'` op (the most common authoring
2411
- * action): create or overwrite `notes.txt` with `hello`. Frozen so it cannot be mutated in
2412
- * place.
288
+ * `name` identifies the tool, `description` and `parameters` define what is advertised
289
+ * to a caller, `summary` optionally replaces the advertised description, and `execute`
290
+ * handles the caller-supplied arguments record.
2413
291
  */
2414
- export declare const WORKSPACE_TOOL_EXAMPLE: WorkspaceOperation;
292
+ export declare interface ToolOptions {
293
+ /** The name a caller uses to select the tool. */
294
+ readonly name: string;
295
+ /** The full description of the tool's behavior. */
296
+ readonly description?: string;
297
+ /** A concise description to advertise in place of the full description. */
298
+ readonly summary?: string;
299
+ /** The JSON Schema for the tool's arguments. */
300
+ readonly parameters?: Readonly<Record<string, unknown>>;
301
+ /** The handler that executes the tool. */
302
+ readonly execute: (args: Readonly<Record<string, unknown>>) => Promise<unknown> | unknown;
303
+ }
2415
304
 
2416
305
  /**
2417
- * The name {@link import('./factories.js').createWorkspaceTool} advertises by default — the key a
2418
- * model calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under.
306
+ * The outcome of executing a {@link ToolCall}.
2419
307
  *
2420
308
  * @remarks
2421
- * OWNED here now (ported from `@orkestrel/agent`).
2422
- */
2423
- export declare const WORKSPACE_TOOL_NAME = "workspace";
2424
-
2425
- /**
2426
- * The lean {@link import('@orkestrel/agent').ToolInterface.summary} {@link import('./factories.js').createWorkspaceTool}
2427
- * advertises in place of {@link WORKSPACE_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
2428
- * (`@orkestrel/agent`) advertises `summary ?? description`, so this one-sentence text stands in
2429
- * for the full teaching description; the full text stays retrievable via
2430
- * {@link import('./factories.js').createDescribeTool}.
309
+ * Always a result and never a throw. Narrow on `success`.
2431
310
  */
2432
- export declare const WORKSPACE_TOOL_SUMMARY = "Read and edit files in a workspace \u2014 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.";
311
+ export declare type ToolResult = ToolSuccess | ToolFailure;
2433
312
 
2434
313
  /**
2435
- * One operation an agent invokes through {@link import('./factories.js').createWorkspaceTool} — a
2436
- * FLAT, descriptive tagged union over the 13 workspace edit / read / navigation actions,
2437
- * discriminated by the `operation` literal (AGENTS §4.8: a discriminant is named for its axis —
2438
- * the action being performed — NEVER `kind`).
314
+ * The successful outcome of executing a {@link ToolCall}.
2439
315
  *
2440
316
  * @remarks
2441
- * This is the SOURCE OF TRUTH the tool contract is typed to
2442
- * ({@link import('./shapers.js').workspaceToolShape} compiles to a structurally-identical guard /
2443
- * parser / JSON Schema). Every field is FLAT (no nested objects) — the small-model ergonomic
2444
- * lever: a range edit is the four flat integers of the `'splice'` arm (`fromLine` /
2445
- * `fromColumn` / `toLine` / `toColumn`), reassembled into a 1-based `Range` (`@orkestrel/agent`)
2446
- * by `rangeOf`, never a nested `{ start, end }`. Each EDIT / READ arm maps onto exactly one
2447
- * `WorkspaceInterface` call against the manager's ACTIVE workspace; the two REGISTRY arms
2448
- * (`switch` / `workspaces`) drive the {@link WorkspaceManagerInterface} pointer instead —
2449
- * `workspaces` LISTS the workspaces the model can move between, and `switch` re-points which one
2450
- * the edit / read arms target.
317
+ * `value` is whatever the handler returned including `undefined`, `null`, `0`,
318
+ * `''`, or `false`. A present value never implies a meaningful one.
2451
319
  */
2452
- export declare type WorkspaceOperation =
2453
- /** Read a whole text file's text by `path` from the ACTIVE workspace (a binary / absent path — or no active workspace — yields no content). */
2454
- {
2455
- readonly operation: 'read';
2456
- readonly path: string;
2457
- }
2458
- /** List every file in the ACTIVE workspace (path / state / size / lines / kind summaries); `[]` when no workspace is active. */
2459
- | {
2460
- readonly operation: 'list';
2461
- }
2462
- /** Whether a file exists at `path` in the ACTIVE workspace (`false` when no workspace is active). */
2463
- | {
2464
- readonly operation: 'has';
2465
- readonly path: string;
2466
- }
2467
- /**
2468
- * Scan every text file for `query`, returning each hit (path + 1-based line / column + the line).
2469
- *
2470
- * @remarks
2471
- * `regex` treats `query` as a regular-expression source (default `false` — a literal substring);
2472
- * `exact` matches case-sensitively (default `true`); `limit` caps the total hits returned.
2473
- */
2474
- | {
2475
- readonly operation: 'search';
2476
- readonly query: string;
2477
- readonly regex?: boolean;
2478
- readonly exact?: boolean;
2479
- readonly limit?: number;
2480
- }
2481
- /**
2482
- * Replace `query` with `replacement` across every text file, returning the tally.
2483
- *
2484
- * @remarks
2485
- * Same matching axes as `search`: `regex` (default `false`), `exact` (default `true`), `limit`
2486
- * (cap the total replacements).
2487
- */
2488
- | {
2489
- readonly operation: 'replace';
2490
- readonly query: string;
2491
- readonly replacement: string;
2492
- readonly regex?: boolean;
2493
- readonly exact?: boolean;
2494
- readonly limit?: number;
2495
- }
2496
- /** Write (create or overwrite) the whole file at `path` with `content`. */
2497
- | {
2498
- readonly operation: 'write';
2499
- readonly path: string;
2500
- readonly content: string;
2501
- }
2502
- /**
2503
- * Splice `content` into an existing text file, replacing the 1-based range
2504
- * `(fromLine, fromColumn)` (INCLUSIVE) → `(toLine, toColumn)` (EXCLUSIVE).
2505
- *
2506
- * @remarks
2507
- * The FLAT range edit — the four positive-integer caret components reassemble into a `Range`
2508
- * (`@orkestrel/agent`) via `rangeOf`. An empty span (`from === to`) inserts; a span past the
2509
- * end is clamped. An inverted / sub-1 range throws `RANGE`; a binary target throws
2510
- * `MODALITY`.
2511
- */
2512
- | {
2513
- readonly operation: 'splice';
2514
- readonly path: string;
2515
- readonly content: string;
2516
- readonly fromLine: number;
2517
- readonly fromColumn: number;
2518
- readonly toLine: number;
2519
- readonly toColumn: number;
2520
- }
2521
- /** Prepend `content` to the start of the file at `path` (creating it when absent). */
2522
- | {
2523
- readonly operation: 'prepend';
2524
- readonly path: string;
2525
- readonly content: string;
2526
- }
2527
- /** Append `content` to the end of the file at `path` (creating it when absent). */
2528
- | {
2529
- readonly operation: 'append';
2530
- readonly path: string;
2531
- readonly content: string;
2532
- }
2533
- /** Re-key the file `from` → `to` (overwriting an occupied target). */
2534
- | {
2535
- readonly operation: 'move';
2536
- readonly from: string;
2537
- readonly to: string;
2538
- }
2539
- /** Remove the file at `path` from the workspace. */
2540
- | {
2541
- readonly operation: 'remove';
2542
- readonly path: string;
2543
- }
2544
- /** List the workspaces the model can move between — each `{ id, files, active }` — so it can choose an `id` to `switch` to. */
2545
- | {
2546
- readonly operation: 'workspaces';
2547
- }
2548
- /** Re-point the manager's ACTIVE workspace to the one with `id` (an unknown `id` is a lenient no-op). The edit / read arms target the active workspace from then on. */
2549
- | {
2550
- readonly operation: 'switch';
320
+ export declare interface ToolSuccess extends Success<unknown> {
321
+ /** The identifier of the corresponding call. */
2551
322
  readonly id: string;
2552
- };
2553
-
2554
- /**
2555
- * Options for {@link import('./factories.js').createWorkspaceTool} — EITHER a caller-built
2556
- * {@link WorkspaceManagerInterface} to drive directly, OR a {@link WorkspaceStoreInterface} the
2557
- * tool constructs a fresh manager over; neither given constructs a manager over
2558
- * `@orkestrel/agent`'s in-memory store.
2559
- *
2560
- * @remarks
2561
- * - `manager` — drive THIS manager directly (its `active` workspace is what every edit / read
2562
- * operation targets). Takes priority over `store` when both are supplied.
2563
- * - `store` — construct a manager over this durable {@link WorkspaceStoreInterface} (via
2564
- * `@orkestrel/agent`'s `createWorkspaceManager`) — used only when `manager` is omitted.
2565
- * The store only backs the manager's own `open` / `save` operations: the tool's edits are
2566
- * NOT auto-persisted — durability requires an explicit caller `save` on the manager
2567
- * (unlike the workflow tool's `store`, which persists each executed snapshot on settle).
2568
- * - `name` / `description` — advertised tool overrides; default to
2569
- * {@link import('./constants.js').WORKSPACE_TOOL_NAME} / {@link import('./constants.js').WORKSPACE_TOOL_DESCRIPTION}.
2570
- */
2571
- export declare interface WorkspaceToolOptions {
2572
- readonly name?: string;
2573
- readonly description?: string;
2574
- readonly manager?: WorkspaceManagerInterface;
2575
- readonly store?: WorkspaceStoreInterface;
323
+ /** The name of the called tool. */
324
+ readonly name: string;
2576
325
  }
2577
326
 
2578
- /**
2579
- * The shape of a {@link import('./types.js').WorkspaceOperation} — a descriptive tagged union
2580
- * over the 13 workspace edit / read / navigation operations, discriminated by the `operation`
2581
- * literal (never a bare `kind`; AGENTS §4.4). Each variant leads with its `operation`
2582
- * discriminant then its FLAT fields, every field via `stringShape` / `optionalShape` /
2583
- * `integerShape({ min: 1 })` / `booleanShape`, each carrying a strong field-level `description`.
2584
- *
2585
- * @remarks
2586
- * The union compiles to an `anyOf` JSON Schema + a `unionOf` guard + a first-match parser
2587
- * automatically ({@link import('./factories.js').createWorkspaceTool} types the result to the
2588
- * hand-written {@link import('./types.js').WorkspaceOperation}). `limit` and the four `'splice'`
2589
- * caret components are POSITIVE integers (`integerShape({ min: 1 })`); `regex` / `exact` are
2590
- * `optionalShape(booleanShape(...))`. The two REGISTRY arms — `workspaces` (list the workspaces
2591
- * the model can move between) and `switch` (re-point the active one by `id`) — let a model
2592
- * DISCOVER then CHOOSE which workspace the edit / read arms target.
2593
- */
2594
- export declare const workspaceToolShape: UnionShape<readonly [ ObjectShape<{
2595
- operation: LiteralShape<readonly ["read"]>;
2596
- path: StringShape;
2597
- }, false>, ObjectShape<{
2598
- operation: LiteralShape<readonly ["list"]>;
2599
- }, false>, ObjectShape<{
2600
- operation: LiteralShape<readonly ["has"]>;
2601
- path: StringShape;
2602
- }, false>, ObjectShape<{
2603
- operation: LiteralShape<readonly ["search"]>;
2604
- query: StringShape;
2605
- regex: OptionalShape<BooleanShape>;
2606
- exact: OptionalShape<BooleanShape>;
2607
- limit: OptionalShape<NumberShape>;
2608
- }, false>, ObjectShape<{
2609
- operation: LiteralShape<readonly ["replace"]>;
2610
- query: StringShape;
2611
- replacement: StringShape;
2612
- regex: OptionalShape<BooleanShape>;
2613
- exact: OptionalShape<BooleanShape>;
2614
- limit: OptionalShape<NumberShape>;
2615
- }, false>, ObjectShape<{
2616
- operation: LiteralShape<readonly ["write"]>;
2617
- path: StringShape;
2618
- content: StringShape;
2619
- }, false>, ObjectShape<{
2620
- operation: LiteralShape<readonly ["splice"]>;
2621
- path: StringShape;
2622
- content: StringShape;
2623
- fromLine: NumberShape;
2624
- fromColumn: NumberShape;
2625
- toLine: NumberShape;
2626
- toColumn: NumberShape;
2627
- }, false>, ObjectShape<{
2628
- operation: LiteralShape<readonly ["prepend"]>;
2629
- path: StringShape;
2630
- content: StringShape;
2631
- }, false>, ObjectShape<{
2632
- operation: LiteralShape<readonly ["append"]>;
2633
- path: StringShape;
2634
- content: StringShape;
2635
- }, false>, ObjectShape<{
2636
- operation: LiteralShape<readonly ["move"]>;
2637
- from: StringShape;
2638
- to: StringShape;
2639
- }, false>, ObjectShape<{
2640
- operation: LiteralShape<readonly ["remove"]>;
2641
- path: StringShape;
2642
- }, false>, ObjectShape<{
2643
- operation: LiteralShape<readonly ["workspaces"]>;
2644
- }, false>, ObjectShape<{
2645
- operation: LiteralShape<readonly ["switch"]>;
2646
- id: StringShape;
2647
- }, false>]>;
2648
-
2649
327
  export { }