@orkestrel/tool 0.0.1 → 0.0.3

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.
@@ -2,13 +2,33 @@ import { AgentInterface } from '@orkestrel/agent';
2
2
  import { AgentRegistryInterface } from '@orkestrel/agent';
3
3
  import { ArrayShape } from '@orkestrel/contract';
4
4
  import { BooleanShape } from '@orkestrel/contract';
5
+ import { ColumnSchema } from '@orkestrel/database';
6
+ import { Condition } from '@orkestrel/database';
7
+ import { Connector } from '@orkestrel/database';
5
8
  import { ContractInterface } from '@orkestrel/contract';
9
+ import { ContractShape } from '@orkestrel/contract';
6
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';
7
19
  import { LiteralShape } from '@orkestrel/contract';
20
+ import { ModelInterface } from '@orkestrel/relation';
8
21
  import { NumberShape } from '@orkestrel/contract';
9
22
  import { ObjectShape } from '@orkestrel/contract';
10
23
  import { OptionalShape } from '@orkestrel/contract';
24
+ import { PromptType } from '@orkestrel/terminal';
25
+ import { RelationErrorCode } from '@orkestrel/relation';
26
+ import { RelationManagerInterface } from '@orkestrel/relation';
11
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';
12
32
  import { ToolInterface } from '@orkestrel/agent';
13
33
  import { ToolManagerInterface } from '@orkestrel/agent';
14
34
  import { UnionShape } from '@orkestrel/contract';
@@ -112,8 +132,14 @@ export declare interface AgentToolArguments {
112
132
  /**
113
133
  * Thrown by {@link import('./factories.js').createAgentTool}'s and
114
134
  * {@link import('./factories.js').createDescribeTool}'s handlers on every failure path — a
115
- * malformed / unresolvable call or an unknown tool name (`TOOL`), or a delegation that would
116
- * exceed the configured depth bound or re-enter an ancestor (`DEPTH`).
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`.
117
143
  *
118
144
  * @remarks
119
145
  * Carries a machine-readable `code` (see {@link import('./types.js').AgentToolErrorCode}) and
@@ -148,8 +174,19 @@ export declare class AgentToolError extends Error {
148
174
  * `TOOL` — malformed / unresolvable call args (a missing `task`, no resolvable `provider`).
149
175
  * `DEPTH` — the delegation would exceed {@link import('./constants.js').AGENT_TOOL_DEPTH}, or
150
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`.
151
188
  */
152
- export declare type AgentToolErrorCode = 'TOOL' | 'DEPTH';
189
+ export declare type AgentToolErrorCode = 'TOOL' | 'DEPTH' | 'DEADLOCK' | 'EXPIRE' | 'ANSWER' | 'DATABASE' | 'RELATION';
153
190
 
154
191
  /**
155
192
  * Options for {@link import('./factories.js').createAgentTool} — the sub-agent delegation
@@ -207,8 +244,146 @@ export declare const agentToolShape: ObjectShape<{
207
244
  provider: OptionalShape<StringShape>;
208
245
  tools: OptionalShape<ArrayShape<StringShape>>;
209
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<[ ObjectShape<{
300
+ operation: LiteralShape<readonly ["pending"]>;
301
+ }, false>, ObjectShape<{
302
+ operation: LiteralShape<readonly ["answer"]>;
303
+ id: StringShape;
304
+ value: UnionShape<[ 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;
210
336
  }>;
211
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<[ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
383
+ type: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
384
+ optional: OptionalShape<BooleanShape>;
385
+ }, false>]>;
386
+
212
387
  /**
213
388
  * Complete a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesize any
214
389
  * MISSING `id` deterministically + positionally, and default any MISSING `name` to its
@@ -251,6 +426,14 @@ export declare function completePhaseDraft(phase: PhaseDraft, index: number): Wo
251
426
  */
252
427
  export declare function completeTaskDraft(task: TaskDraft, phaseId: string, index: number): WorkflowDefinition['phases'][number]['tasks'][number];
253
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
+
254
437
  /**
255
438
  * Wrap a live `AgentInterface` (`@orkestrel/agent`) as a {@link WorkflowFunction}
256
439
  * (`@orkestrel/workflow`) — the OPT-IN adapter that runs the agent to a settled result, folding
@@ -334,6 +517,126 @@ export declare function createAgentFunction(agent: AgentInterface, options?: Age
334
517
  */
335
518
  export declare function createAgentTool(registry: AgentRegistryInterface, options?: AgentToolOptions): ToolInterface;
336
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
+
337
640
  /**
338
641
  * Build an LLM-callable tool that returns the FULL `description` of another registered tool by
339
642
  * name — the counterpart to the lean `summary` the other tools in this package advertise
@@ -370,6 +673,107 @@ export declare function createAgentTool(registry: AgentRegistryInterface, option
370
673
  */
371
674
  export declare function createDescribeTool(tools: ToolManagerInterface): ToolInterface;
372
675
 
676
+ /**
677
+ * Create the in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of database
678
+ * definitions, the DEFAULT store the upcoming database / relation tools will persist their
679
+ * `DatabaseDefinition` configs through.
680
+ *
681
+ * @returns A {@link DefinitionStoreInterface}
682
+ *
683
+ * @example
684
+ * ```ts
685
+ * import { createMemoryDefinitionStore } from '@src/core'
686
+ *
687
+ * const store = createMemoryDefinitionStore()
688
+ * ```
689
+ */
690
+ export declare function createMemoryDefinitionStore(): DefinitionStoreInterface;
691
+
692
+ /**
693
+ * Build an LLM-callable prompt tool — the ASK side of the terminal seam. Asks
694
+ * {@link import('./types.js').PromptToolOptions.to} a question and BLOCKS until it answers,
695
+ * returning the resolved answer value.
696
+ *
697
+ * @remarks
698
+ * The universal tool-handler contract (AGENTS §14): validates the call args against
699
+ * {@link import('./shapers.js').promptToolShape}, dispatches to the matching
700
+ * `TerminalManagerInterface.ask` overload (`@orkestrel/terminal`) for the call's `form`, and
701
+ * RETURNS the resolved answer on success. `from` is FIXED at construction
702
+ * ({@link import('./types.js').PromptToolOptions.from}) — never read from the model-supplied
703
+ * args — so a model cannot spoof which terminal is asking. A prompt CYCLE rejects with
704
+ * `TerminalError('DEADLOCK')`, re-surfaced as a typed `DEADLOCK`
705
+ * {@link import('./errors.js').AgentToolError}; an expired prompt re-surfaces as `EXPIRE`; an
706
+ * unknown `to` (or any other `TerminalError`) re-surfaces as `TOOL`, naming the unknown terminal
707
+ * plus the known ones (`manager.terminals()`).
708
+ *
709
+ * @param options - The live manager, the fixed `from` identity, and advertised overrides (see
710
+ * {@link import('./types.js').PromptToolOptions})
711
+ * @returns A `ToolInterface` (named {@link import('./constants.js').PROMPT_TOOL_NAME} by default)
712
+ *
713
+ * @example
714
+ * ```ts
715
+ * import { createPromptTool } from '@src/core'
716
+ * import { createTerminalManager, createToolManager } from '@orkestrel/terminal'
717
+ *
718
+ * const manager = createTerminalManager()
719
+ * manager.add('agent')
720
+ * manager.add('reviewer')
721
+ * const tool = createPromptTool({ manager, from: 'agent' })
722
+ * const tools = createToolManager()
723
+ * tools.add(tool) // the agent can now ask 'reviewer' and block for the answer
724
+ * ```
725
+ */
726
+ export declare function createPromptTool(options: PromptToolOptions): ToolInterface;
727
+
728
+ /**
729
+ * Build an LLM-callable relation tool — traverse and edit `@orkestrel/relation` relationships
730
+ * through one `operation`-discriminated call (AGENTS §14, matching {@link createDatabaseTool}'s
731
+ * single-tool-many-operations shape).
732
+ *
733
+ * @remarks
734
+ * The universal tool-handler contract (AGENTS §14): validates the call args against
735
+ * {@link import('./shapers.js').relationToolShape}, resolves the addressed
736
+ * {@link import('@orkestrel/relation').RelationManagerInterface} — an explicit `manager` field
737
+ * must match a key of {@link import('./types.js').RelationToolOptions.managers}, an OMITTED one
738
+ * resolves to the SOLE registered manager, either miss throwing a typed `TOOL`
739
+ * {@link import('./errors.js').AgentToolError}
740
+ * ({@link import('./helpers.js').relationManagerOf}) — then resolves `model` against it
741
+ * ({@link import('./helpers.js').relationModelOf}, same typed-`TOOL`-on-miss shape), and
742
+ * dispatches to the matched operation, RETURNING a plain result on success.
743
+ *
744
+ * `'load'` / `'find'` expand the call's FLAT dot-path `include` list into a live
745
+ * `@orkestrel/relation` `Include` tree via {@link import('./helpers.js').expandInclude}, capped
746
+ * at {@link import('./types.js').RelationToolOptions.depth} (default
747
+ * {@link import('./constants.js').RELATION_TOOL_DEPTH}) — a path exceeding the cap, or carrying an
748
+ * empty segment, throws a typed `TOOL` error. `'load'` dispatches on whether `key` is an array
749
+ * (positional many-key form, AGENTS §9.2) or a single key. `'find'` and `'links'` clamp their
750
+ * result to {@link import('./types.js').RelationToolOptions.limit} (default
751
+ * {@link import('./constants.js').RELATION_TOOL_LIMIT}) — `'find'` probes one row past the
752
+ * effective limit (mirroring {@link import('./helpers.js').clampCriteria}'s idiom) to report
753
+ * `truncated`; `'links'` (which has no upstream pagination) fetches the FULL linked-key list and
754
+ * slices/truncates it the same way. `'link'` / `'unlink'` write / remove one `through` junction
755
+ * row.
756
+ *
757
+ * A typed `@orkestrel/relation` failure (`RelationError`) re-surfaces as a typed `RELATION`
758
+ * `AgentToolError` carrying the original {@link import('@orkestrel/relation').RelationErrorCode}
759
+ * in `context.code`; a typed `@orkestrel/database` failure underneath it (`DatabaseError`)
760
+ * re-surfaces as a typed `DATABASE` `AgentToolError`, mirroring {@link createDatabaseTool}'s error
761
+ * mapping; an `AgentToolError` thrown by this tool's own guards (malformed args, an unknown
762
+ * manager/model) passes through unwrapped.
763
+ *
764
+ * @param options - The tool's configuration (see {@link import('./types.js').RelationToolOptions})
765
+ * @returns A `ToolInterface` (named {@link import('./constants.js').RELATION_TOOL_NAME} by default)
766
+ *
767
+ * @example
768
+ * ```ts
769
+ * import { createRelationTool } from '@src/core'
770
+ *
771
+ * const tool = createRelationTool({ managers: { shop: manager } })
772
+ * await tool.execute({ operation: 'load', model: 'accounts', key: 'acc1', include: ['contacts'] })
773
+ * ```
774
+ */
775
+ export declare function createRelationTool(options: RelationToolOptions): ToolInterface;
776
+
373
777
  /**
374
778
  * Wrap a registered tool as a {@link WorkflowFunction} (`@orkestrel/workflow`) — the OPT-IN
375
779
  * adapter that lets a `function`-form task run a `@orkestrel/agent` tool BY NAME.
@@ -545,6 +949,355 @@ export declare function createWorkflowTool(definition: WorkflowDefinition, runne
545
949
  */
546
950
  export declare function createWorkspaceTool(options?: WorkspaceToolOptions): ToolInterface;
547
951
 
952
+ /**
953
+ * Normalize the database tool's parsed SERIALIZED criteria into a live `@orkestrel/database`
954
+ * {@link Criteria} — default each condition's OMITTED `connector` to `'and'`.
955
+ *
956
+ * @remarks
957
+ * The wire form ({@link import('./shapers.js').databaseToolShape}) lets a caller drop `connector`
958
+ * on the last condition (it has nothing to join FORWARD to); the compiled `Condition` a live
959
+ * `@orkestrel/database` table call accepts always carries one, so this fills the gap. `order` /
960
+ * `limit` / `offset` pass through unchanged. Pure and total.
961
+ *
962
+ * @param criteria - The parsed criteria (or `undefined`)
963
+ * @returns The equivalent live `Criteria`, or `undefined` when `criteria` is `undefined`
964
+ */
965
+ export declare function criteriaOf(criteria: Readonly<{
966
+ conditions?: readonly Readonly<{
967
+ column: string;
968
+ operator: Condition['operator'];
969
+ values: readonly unknown[];
970
+ connector?: Connector;
971
+ }>[];
972
+ order?: readonly Readonly<{
973
+ column: string;
974
+ direction: Direction;
975
+ }>[];
976
+ limit?: number;
977
+ offset?: number;
978
+ }> | undefined): Criteria | undefined;
979
+
980
+ /** The SERIALIZED criteria form — conditions, order, and pagination. */
981
+ export declare const criteriaShape: ObjectShape<{
982
+ conditions: OptionalShape<ArrayShape<ObjectShape<{
983
+ column: StringShape;
984
+ operator: LiteralShape<readonly ["equals", "not", "above", "below", "from", "to", "between", "like", "glob", "starts", "ends", "any", "none", "absent", "present"]>;
985
+ values: ArrayShape<JSONShape>;
986
+ connector: OptionalShape<LiteralShape<readonly ["and", "or"]>>;
987
+ }, false>>>;
988
+ order: OptionalShape<ArrayShape<ObjectShape<{
989
+ column: StringShape;
990
+ direction: LiteralShape<readonly ["ascending", "descending"]>;
991
+ }, false>>>;
992
+ limit: OptionalShape<NumberShape>;
993
+ offset: OptionalShape<NumberShape>;
994
+ }, false>;
995
+
996
+ /**
997
+ * The DESCRIPTION the upcoming database tool will advertise — a multi-line guide that teaches a
998
+ * small model the operation list, the SERIALIZED criteria form, and the {@link import('./types.js').TableSpec}
999
+ * column DSL.
1000
+ *
1001
+ * @remarks
1002
+ * The criteria form is deliberately SERIALIZED (never fluent) — every condition is a flat object
1003
+ * `{ column, operator, values, connector? }` where `values` is ALWAYS an array, even for a
1004
+ * single-value operator (`{ column: 'age', operator: 'from', values: [18] }`), so a small model
1005
+ * never has to chain method calls or guess whether a value is scalar or a list.
1006
+ */
1007
+ export declare const DATABASE_TOOL_DESCRIPTION: string;
1008
+
1009
+ /** 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. */
1010
+ export declare const DATABASE_TOOL_LIMIT = 1000;
1011
+
1012
+ /** The database tool's mutating operations — disabled by `DatabaseToolOptions.readonly`. */
1013
+ export declare const DATABASE_TOOL_MUTATIONS: Set<string>;
1014
+
1015
+ /**
1016
+ * The name the upcoming `createDatabaseTool` factory will advertise by default — the key a model
1017
+ * calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under.
1018
+ *
1019
+ * @remarks
1020
+ * SRC-1 of a 3-unit spine: this unit lands the persistence + schema foundation
1021
+ * ({@link import('./types.js').DatabaseDefinition}, {@link import('./types.js').DefinitionStoreInterface},
1022
+ * {@link import('./helpers.js').expandTables}); `createDatabaseTool` itself is built in a later unit.
1023
+ */
1024
+ export declare const DATABASE_TOOL_NAME = "database";
1025
+
1026
+ /**
1027
+ * The lean {@link import('@orkestrel/agent').ToolInterface.summary} the upcoming database tool
1028
+ * will advertise in place of {@link DATABASE_TOOL_DESCRIPTION}.
1029
+ */
1030
+ 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.";
1031
+
1032
+ /**
1033
+ * One database's CONFIG-ONLY definition — `id` + `driver` + {@link TableSpec} (+ optional `keys`),
1034
+ * the pure-JSON blueprint the upcoming database / relation tools build a live database from.
1035
+ *
1036
+ * @remarks
1037
+ * A `DatabaseDefinition` is NEVER a live handle — it is the durable, serializable config a
1038
+ * {@link DefinitionStoreInterface} persists and a tool factory turns into a real
1039
+ * `@orkestrel/database` `DatabaseInterface` (via `createDatabase` + {@link import('./helpers.js').expandTables})
1040
+ * on demand. `keys`, when present, maps a table name to its primary-key column (omitted ⇒ the
1041
+ * driver's default primary key).
1042
+ */
1043
+ export declare interface DatabaseDefinition {
1044
+ readonly id: string;
1045
+ readonly driver: string;
1046
+ readonly tables: TableSpec;
1047
+ readonly keys?: Readonly<Record<string, string>>;
1048
+ }
1049
+
1050
+ /** One opaque persisted row — the shape a `TableInterface<DatabaseDefinitionRow>`-backed store reads/writes; `definition` is narrowed with {@link import('./helpers.js').isDatabaseDefinition} on read. */
1051
+ export declare interface DatabaseDefinitionRow {
1052
+ readonly id: string;
1053
+ readonly definition: unknown;
1054
+ }
1055
+
1056
+ /**
1057
+ * A {@link DefinitionStoreInterface} backed by one table of the `@orkestrel/database` layer — a
1058
+ * database's durable CONFIG state IS a row, so persistence reduces to keyed point-access
1059
+ * (`get` / `set` / `delete`) over a {@link TableInterface}, the driver-pluggable twin of the
1060
+ * plain-`Map` {@link import('./MemoryDefinitionStore.js').MemoryDefinitionStore}.
1061
+ *
1062
+ * @remarks
1063
+ * The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,
1064
+ * JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a JSON / SQLite /
1065
+ * IndexedDB backend swaps in WITHOUT touching a consumer — the same seam as
1066
+ * {@link import('./MemoryDefinitionStore.js').MemoryDefinitionStore}. The driver defaults to
1067
+ * memory ({@link import('../factories.js').createDatabaseDefinitionStore} passes
1068
+ * `createMemoryDriver()`), so it ALSO works in memory out of the box; you opt into the durable
1069
+ * plumbing by passing a JSON / SQLite / IndexedDB driver.
1070
+ *
1071
+ * The {@link DatabaseDefinition} is stored as ONE OPAQUE JSON COLUMN — the table is a row of
1072
+ * `{ id; definition }` ({@link DatabaseDefinitionRow}). The definition is already a COMPLETE,
1073
+ * self-contained, pure-JSON CONFIG payload (never a live handle), so storing it whole is lossless
1074
+ * AND keeps the row type flat (`definition` reads back as `unknown`).
1075
+ *
1076
+ * - **`set(definition)` upserts under the definition's OWN `id`** (no separate id param) — it
1077
+ * writes the row `{ id: definition.id, definition }`.
1078
+ * - **`get(id)` resolves the stored definition for an id**, narrowing the opaque JSON column back
1079
+ * to a {@link DatabaseDefinition} ({@link import('../helpers.js').isDatabaseDefinition} — the
1080
+ * AGENTS §14 boundary narrow for an untrusted storage read), or `undefined` if none is stored
1081
+ * or the stored blob is malformed.
1082
+ * - **`delete(id)` drops a definition by id**; an absent id is a no-op (no throw).
1083
+ *
1084
+ * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method
1085
+ * bijection with {@link DefinitionStoreInterface}).
1086
+ *
1087
+ * @example
1088
+ * ```ts
1089
+ * import { createDatabaseDefinitionStore, createMemoryDriver } from '@src/core'
1090
+ *
1091
+ * const store = createDatabaseDefinitionStore(createMemoryDriver()) // a durable driver swaps in here
1092
+ * await store.set({ id: 'shop', driver: 'memory', tables: {} }) // persist the config (one JSON column)
1093
+ * const definition = await store.get('shop')
1094
+ * await store.delete('shop')
1095
+ * ```
1096
+ */
1097
+ export declare class DatabaseDefinitionStore implements DefinitionStoreInterface {
1098
+ #private;
1099
+ /**
1100
+ * Wrap a table as a definition store.
1101
+ *
1102
+ * @param table - The {@link TableInterface} holding the definitions — its row is the
1103
+ * {@link DatabaseDefinitionRow} `{ id; definition }` shape (the definition one opaque JSON column)
1104
+ */
1105
+ constructor(table: TableInterface<DatabaseDefinitionRow>);
1106
+ /** Resolve the persisted definition for `id`, narrowing the opaque JSON column back to a `DatabaseDefinition`. */
1107
+ get(id: string): Promise<DatabaseDefinition | undefined>;
1108
+ /** Insert or replace under the definition's OWN `id` (no separate id param) — the row is `{ id, definition }`. */
1109
+ set(definition: DatabaseDefinition): Promise<void>;
1110
+ /** Drop a definition by id; an absent id is a no-op (no throw). */
1111
+ delete(id: string): Promise<void>;
1112
+ }
1113
+
1114
+ /**
1115
+ * Map a caught error to the {@link AgentToolErrorCode} the upcoming database tool should throw
1116
+ * with — the pure classification step of that factory's error handling, mirroring
1117
+ * {@link terminalToolCode}'s idiom for `@orkestrel/database`.
1118
+ *
1119
+ * @param error - The value caught from a `@orkestrel/database` table operation
1120
+ * @returns The granular {@link DatabaseErrorCode}, or `undefined` if `error` is not a `DatabaseError`
1121
+ */
1122
+ export declare function databaseToolCode(error: unknown): DatabaseErrorCode | undefined;
1123
+
1124
+ /**
1125
+ * Options for {@link import('./factories.js').createDatabaseTool} — SRC-2 of the 3-unit database
1126
+ * / relation spine, built over the SRC-1 foundation ({@link DatabaseDefinition},
1127
+ * {@link DefinitionStoreInterface}, {@link import('./helpers.js').expandTables}).
1128
+ *
1129
+ * @remarks
1130
+ * - `databases` — live `DatabaseInterface` handles to seed the tool's cache with (e.g. a
1131
+ * caller-constructed database it should manage alongside store-backed ones); keyed by the id a
1132
+ * call's `id` field addresses.
1133
+ * - `store` — the {@link DefinitionStoreInterface} the `'create'` / `'migrate'` operations persist
1134
+ * their {@link DatabaseDefinition} CONFIG through, and `'destroy'` deletes from; also the source
1135
+ * `'get'`/every other operation resolves an id from when it isn't already cached. Omitted means
1136
+ * no persistence — a database created without a store lives only for the tool's lifetime.
1137
+ * - `drivers` — registry of driver-name to `() => DriverInterface` factories a `'create'` call's
1138
+ * `driver` field (or a persisted definition's `driver`) resolves against. Defaults to
1139
+ * `{ memory: () => createMemoryDriver() }` (`@orkestrel/database`).
1140
+ * - `key` — the `KeyFunction` (`@orkestrel/database`) every minted database is constructed with,
1141
+ * used when a written row lacks its primary key. Defaults to `generateUUID`.
1142
+ * - `limit` — the row cap `'records'` / `'remove'` — via {@link import('./helpers.js').clampCriteria}
1143
+ * — enforce when a call's `criteria.limit` is omitted or exceeds it. Defaults to
1144
+ * {@link import('./constants.js').DATABASE_TOOL_LIMIT}.
1145
+ * - `timeout` — milliseconds; when set, every `@orkestrel/database` call this tool makes is given
1146
+ * a fresh `AbortSignal.timeout(timeout)` per tool call.
1147
+ * - `readonly` — when `true`, every mutating operation (`'create'` / `'add'` / `'set'` /
1148
+ * `'update'` / `'remove'` / `'migrate'` / `'destroy'`) throws a typed `TOOL`
1149
+ * {@link import('./errors.js').AgentToolError} before doing anything.
1150
+ * - `name` / `description` — advertised tool overrides; default to
1151
+ * {@link import('./constants.js').DATABASE_TOOL_NAME} / {@link import('./constants.js').DATABASE_TOOL_DESCRIPTION}.
1152
+ */
1153
+ export declare interface DatabaseToolOptions {
1154
+ readonly name?: string;
1155
+ readonly description?: string;
1156
+ readonly databases?: Readonly<Record<string, DatabaseInterface>>;
1157
+ readonly store?: DefinitionStoreInterface;
1158
+ readonly drivers?: Readonly<Record<string, () => DriverInterface>>;
1159
+ readonly key?: KeyFunction;
1160
+ readonly limit?: number;
1161
+ readonly timeout?: number;
1162
+ readonly readonly?: boolean;
1163
+ }
1164
+
1165
+ /**
1166
+ * The shape of {@link import('./factories.js').createDatabaseTool}'s call arguments —
1167
+ * discriminated by `operation` into the 12 database operations (`'create'` / `'tables'` /
1168
+ * `'get'` / `'records'` / `'count'` / `'aggregate'` / `'add'` / `'set'` / `'update'` /
1169
+ * `'remove'` / `'migrate'` / `'destroy'`).
1170
+ *
1171
+ * @remarks
1172
+ * Every arm carries `id` (the database id). `'create'` / `'migrate'` carry `tables` (the
1173
+ * {@link import('./types.js').TableSpec} column DSL, compiled via
1174
+ * {@link import('./helpers.js').expandTables}); `'get'` / `'update'` / `'remove'` carry `key`
1175
+ * (one key or an array of keys, positional); `'add'` / `'set'` carry `row` (one row or an array of
1176
+ * rows); `'update'` also carries `changes` (a loose partial row); `'records'` / `'count'` /
1177
+ * `'aggregate'` carry an optional `criteria` (the SERIALIZED form — `values` is ALWAYS an array,
1178
+ * even for a single-value operator, so a caller never chains method calls or guesses arity).
1179
+ */
1180
+ export declare const databaseToolShape: UnionShape<[ ObjectShape<{
1181
+ operation: LiteralShape<readonly ["create"]>;
1182
+ id: StringShape;
1183
+ tables: ObjectShape<Record<never, never>, ObjectShape<{
1184
+ columns: ObjectShape<Record<never, never>, UnionShape<[ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
1185
+ type: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
1186
+ optional: OptionalShape<BooleanShape>;
1187
+ }, false>]>>;
1188
+ }, false>>;
1189
+ driver: OptionalShape<StringShape>;
1190
+ keys: OptionalShape<ObjectShape<Record<never, never>, StringShape>>;
1191
+ }, false>, ObjectShape<{
1192
+ operation: LiteralShape<readonly ["tables"]>;
1193
+ id: StringShape;
1194
+ }, false>, ObjectShape<{
1195
+ operation: LiteralShape<readonly ["get"]>;
1196
+ id: StringShape;
1197
+ table: StringShape;
1198
+ key: UnionShape<[ ArrayShape<UnionShape<[ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1199
+ }, false>, ObjectShape<{
1200
+ operation: LiteralShape<readonly ["records"]>;
1201
+ id: StringShape;
1202
+ table: StringShape;
1203
+ criteria: OptionalShape<ObjectShape<{
1204
+ conditions: OptionalShape<ArrayShape<ObjectShape<{
1205
+ column: StringShape;
1206
+ operator: LiteralShape<readonly ["equals", "not", "above", "below", "from", "to", "between", "like", "glob", "starts", "ends", "any", "none", "absent", "present"]>;
1207
+ values: ArrayShape<JSONShape>;
1208
+ connector: OptionalShape<LiteralShape<readonly ["and", "or"]>>;
1209
+ }, false>>>;
1210
+ order: OptionalShape<ArrayShape<ObjectShape<{
1211
+ column: StringShape;
1212
+ direction: LiteralShape<readonly ["ascending", "descending"]>;
1213
+ }, false>>>;
1214
+ limit: OptionalShape<NumberShape>;
1215
+ offset: OptionalShape<NumberShape>;
1216
+ }, false>>;
1217
+ }, false>, ObjectShape<{
1218
+ operation: LiteralShape<readonly ["count"]>;
1219
+ id: StringShape;
1220
+ table: StringShape;
1221
+ criteria: OptionalShape<ObjectShape<{
1222
+ conditions: OptionalShape<ArrayShape<ObjectShape<{
1223
+ column: StringShape;
1224
+ operator: LiteralShape<readonly ["equals", "not", "above", "below", "from", "to", "between", "like", "glob", "starts", "ends", "any", "none", "absent", "present"]>;
1225
+ values: ArrayShape<JSONShape>;
1226
+ connector: OptionalShape<LiteralShape<readonly ["and", "or"]>>;
1227
+ }, false>>>;
1228
+ order: OptionalShape<ArrayShape<ObjectShape<{
1229
+ column: StringShape;
1230
+ direction: LiteralShape<readonly ["ascending", "descending"]>;
1231
+ }, false>>>;
1232
+ limit: OptionalShape<NumberShape>;
1233
+ offset: OptionalShape<NumberShape>;
1234
+ }, false>>;
1235
+ }, false>, ObjectShape<{
1236
+ operation: LiteralShape<readonly ["aggregate"]>;
1237
+ id: StringShape;
1238
+ table: StringShape;
1239
+ function: LiteralShape<readonly ["count", "sum", "average", "minimum", "maximum"]>;
1240
+ column: StringShape;
1241
+ criteria: OptionalShape<ObjectShape<{
1242
+ conditions: OptionalShape<ArrayShape<ObjectShape<{
1243
+ column: StringShape;
1244
+ operator: LiteralShape<readonly ["equals", "not", "above", "below", "from", "to", "between", "like", "glob", "starts", "ends", "any", "none", "absent", "present"]>;
1245
+ values: ArrayShape<JSONShape>;
1246
+ connector: OptionalShape<LiteralShape<readonly ["and", "or"]>>;
1247
+ }, false>>>;
1248
+ order: OptionalShape<ArrayShape<ObjectShape<{
1249
+ column: StringShape;
1250
+ direction: LiteralShape<readonly ["ascending", "descending"]>;
1251
+ }, false>>>;
1252
+ limit: OptionalShape<NumberShape>;
1253
+ offset: OptionalShape<NumberShape>;
1254
+ }, false>>;
1255
+ }, false>, ObjectShape<{
1256
+ operation: LiteralShape<readonly ["add"]>;
1257
+ id: StringShape;
1258
+ table: StringShape;
1259
+ row: UnionShape<[ ArrayShape<ObjectShape<Record<never, never>, JSONShape>>, ObjectShape<Record<never, never>, JSONShape>]>;
1260
+ }, false>, ObjectShape<{
1261
+ operation: LiteralShape<readonly ["set"]>;
1262
+ id: StringShape;
1263
+ table: StringShape;
1264
+ row: UnionShape<[ ArrayShape<ObjectShape<Record<never, never>, JSONShape>>, ObjectShape<Record<never, never>, JSONShape>]>;
1265
+ }, false>, ObjectShape<{
1266
+ operation: LiteralShape<readonly ["update"]>;
1267
+ id: StringShape;
1268
+ table: StringShape;
1269
+ key: UnionShape<[ ArrayShape<UnionShape<[ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1270
+ changes: ObjectShape<Record<never, never>, JSONShape>;
1271
+ }, false>, ObjectShape<{
1272
+ operation: LiteralShape<readonly ["remove"]>;
1273
+ id: StringShape;
1274
+ table: StringShape;
1275
+ key: UnionShape<[ ArrayShape<UnionShape<[ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1276
+ }, false>, ObjectShape<{
1277
+ operation: LiteralShape<readonly ["migrate"]>;
1278
+ id: StringShape;
1279
+ tables: ObjectShape<Record<never, never>, ObjectShape<{
1280
+ columns: ObjectShape<Record<never, never>, UnionShape<[ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
1281
+ type: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
1282
+ optional: OptionalShape<BooleanShape>;
1283
+ }, false>]>>;
1284
+ }, false>>;
1285
+ }, false>, ObjectShape<{
1286
+ operation: LiteralShape<readonly ["destroy"]>;
1287
+ id: StringShape;
1288
+ }, false>]>;
1289
+
1290
+ /**
1291
+ * The point-access persistence seam (AGENTS §5 — Stores) for {@link DatabaseDefinition} configs —
1292
+ * the twin of `@orkestrel/terminal`'s `TerminalStoreInterface`, storing a database's CONFIG-ONLY
1293
+ * blueprint (never a live handle). Every primitive is async; `delete` of an absent id is a no-op.
1294
+ */
1295
+ export declare interface DefinitionStoreInterface {
1296
+ get(id: string): Promise<DatabaseDefinition | undefined>;
1297
+ set(definition: DatabaseDefinition): Promise<void>;
1298
+ delete(id: string): Promise<void>;
1299
+ }
1300
+
548
1301
  /**
549
1302
  * The DESCRIPTION {@link import('./factories.js').createDescribeTool} advertises.
550
1303
  *
@@ -594,7 +1347,33 @@ export declare interface DescribeToolArguments {
594
1347
  */
595
1348
  export declare const describeToolShape: ObjectShape<{
596
1349
  name: StringShape;
597
- }>;
1350
+ }, false>;
1351
+
1352
+ /**
1353
+ * Expand the relation tool's FLAT dot-path `include` list into a live `@orkestrel/relation`
1354
+ * {@link Include} tree — the pure leaf {@link import('./factories.js').createRelationTool} calls
1355
+ * before a `'load'` / `'find'` call.
1356
+ *
1357
+ * @remarks
1358
+ * Each path splits on `'.'` into a chain of relation names, deep-merged into one nested
1359
+ * `Include` object with a leaf `true`. A longer path SUBSUMES a shorter sibling's bare `true` —
1360
+ * `'contacts'` followed by `'contacts.account'` yields `{ contacts: { account: true } }`, never
1361
+ * overwriting the deeper chain. An EMPTY segment (`''`, from a leading/trailing/doubled `.`) or a
1362
+ * path whose segment count exceeds `depth` throws a typed `TOOL` {@link AgentToolError}.
1363
+ *
1364
+ * @param paths - The flat dot-path `include` list (or `undefined` — yields `{}`)
1365
+ * @param depth - The max segment count a single path may reach
1366
+ * @returns The equivalent nested {@link Include}
1367
+ *
1368
+ * @example
1369
+ * ```ts
1370
+ * import { expandInclude } from '@src/core'
1371
+ *
1372
+ * expandInclude(['contacts', 'contacts.account'], 3)
1373
+ * // { contacts: { account: true } }
1374
+ * ```
1375
+ */
1376
+ export declare function expandInclude(paths: readonly string[] | undefined, depth: number): Include;
598
1377
 
599
1378
  /**
600
1379
  * Expand a flat {@link WorkflowSteps} blob into a strict {@link WorkflowDefinition} — each step
@@ -615,6 +1394,20 @@ export declare const describeToolShape: ObjectShape<{
615
1394
  */
616
1395
  export declare function expandSteps(flat: WorkflowSteps): WorkflowDefinition;
617
1396
 
1397
+ /**
1398
+ * Compile a {@link TableSpec} into the `@orkestrel/database` {@link TablesShape} it configures —
1399
+ * each {@link ColumnSpec} maps to the matching primitive shaper (`'string'` → `stringShape()`,
1400
+ * `'integer'` → `integerShape()`, `'number'` → `numberShape()`, `'boolean'` → `booleanShape()`),
1401
+ * wrapped in `optionalShape` when the column declares `optional: true`. Total, pure.
1402
+ *
1403
+ * @param spec - The small-model-facing table layout
1404
+ * @returns The compiled `TablesShape` a `@orkestrel/database` `createDatabase` call accepts
1405
+ */
1406
+ export declare function expandTables(spec: TableSpec): TablesShape;
1407
+
1408
+ /** Flat dot-path relation include list, expanded via {@link import('./helpers.js').expandInclude}. */
1409
+ export declare const includeShape: OptionalShape<ArrayShape<StringShape>>;
1410
+
618
1411
  /**
619
1412
  * Type guard narrowing an unknown caught value to an {@link AgentToolError}.
620
1413
  *
@@ -634,6 +1427,29 @@ export declare function expandSteps(flat: WorkflowSteps): WorkflowDefinition;
634
1427
  */
635
1428
  export declare function isAgentToolError(value: unknown): value is AgentToolError;
636
1429
 
1430
+ /** Narrow an unknown value to a {@link import('./types.js').ColumnKind}. */
1431
+ export declare function isColumnKind(value: unknown): value is ColumnKind;
1432
+
1433
+ /** Narrow an unknown value to a {@link ColumnSpec} — a valid {@link import('./types.js').ColumnKind} shorthand, or `{ type, optional }` with a valid `type`. */
1434
+ export declare function isColumnSpec(value: unknown): value is ColumnSpec;
1435
+
1436
+ /**
1437
+ * Narrow an unknown value to a {@link DatabaseDefinition} — a non-empty `id` + `driver`, a
1438
+ * `tables` record whose every value is `{ columns: record of valid ColumnSpec }`, and an optional
1439
+ * `keys` record of strings. The boundary guard a {@link import('./types.js').DefinitionStoreInterface}
1440
+ * applies to an untrusted persisted blob before trusting it as a definition (never an `as`).
1441
+ */
1442
+ export declare function isDatabaseDefinition(value: unknown): value is DatabaseDefinition;
1443
+
1444
+ /** One key value — a string or number; the array form (multiple keys, positional) resolves FIRST per AGENTS §9.2. */
1445
+ export declare const keyShape: UnionShape<[ ArrayShape<UnionShape<[ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1446
+
1447
+ /** Map one {@link import('./types.js').ColumnKind} to its primitive `@orkestrel/database` shape — the leaf {@link columnShape} wraps. */
1448
+ export declare function kindShape(kind: ColumnKind): ContractShape;
1449
+
1450
+ /** Which registered relation manager to address — omitted resolves to the sole registered manager. */
1451
+ export declare const managerShape: OptionalShape<StringShape>;
1452
+
637
1453
  /**
638
1454
  * The maximum nesting depth a workflow → agent → workflow chain may reach — the bound
639
1455
  * {@link import('./factories.js').createAgentFunction} and
@@ -648,6 +1464,51 @@ export declare function isAgentToolError(value: unknown): value is AgentToolErro
648
1464
  */
649
1465
  export declare const MAX_WORKFLOW_DEPTH = 8;
650
1466
 
1467
+ /**
1468
+ * The in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of
1469
+ * {@link DatabaseDefinition}s keyed by database id, the DEFAULT store
1470
+ * {@link import('../factories.js').createMemoryDefinitionStore} builds. The EXACT twin of
1471
+ * {@link import('./DatabaseDefinitionStore.js').DatabaseDefinitionStore}.
1472
+ *
1473
+ * @remarks
1474
+ * A plain `Map<string, DatabaseDefinition>` (AGENTS §21 — the definition is already pure,
1475
+ * self-contained CONFIG-only JSON, so no encoding is needed for the memory tier). There is NO
1476
+ * idle-TTL and NO eviction: a persisted definition lives until an explicit `delete`. A durable
1477
+ * backend (JSON / SQLite / IndexedDB) swaps in through the SAME interface without touching a
1478
+ * consumer — its driver-pluggable twin is
1479
+ * {@link import('./DatabaseDefinitionStore.js').DatabaseDefinitionStore} (the definition as one
1480
+ * opaque JSON column).
1481
+ *
1482
+ * - **`get` resolves the persisted definition for an id**, or `undefined` if none is stored.
1483
+ * - **`set` inserts / replaces under the definition's OWN `id`** (no separate id param).
1484
+ * - **`delete` drops a definition by id**; an absent id is a no-op (no throw).
1485
+ *
1486
+ * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method
1487
+ * bijection with {@link DefinitionStoreInterface}).
1488
+ *
1489
+ * @example
1490
+ * ```ts
1491
+ * import { createMemoryDefinitionStore } from '@src/core'
1492
+ *
1493
+ * const store = createMemoryDefinitionStore()
1494
+ * await store.set({ id: 'shop', driver: 'memory', tables: {} })
1495
+ * const definition = await store.get('shop')
1496
+ * await store.delete('shop')
1497
+ * ```
1498
+ */
1499
+ export declare class MemoryDefinitionStore implements DefinitionStoreInterface {
1500
+ #private;
1501
+ get(id: string): Promise<DatabaseDefinition | undefined>;
1502
+ set(definition: DatabaseDefinition): Promise<void>;
1503
+ delete(id: string): Promise<void>;
1504
+ }
1505
+
1506
+ /** One sort term. */
1507
+ export declare const orderShape: ObjectShape<{
1508
+ column: StringShape;
1509
+ direction: LiteralShape<readonly ["ascending", "descending"]>;
1510
+ }, false>;
1511
+
651
1512
  /** A draft phase — a `PhaseDefinition` (`@orkestrel/workflow`) with OPTIONAL `id` / `name` and {@link TaskDraft} tasks. */
652
1513
  export declare interface PhaseDraft {
653
1514
  readonly id?: string;
@@ -675,10 +1536,244 @@ export declare const phaseDraftShape: ObjectShape<{
675
1536
  run: OptionalShape<StringShape>;
676
1537
  retries: OptionalShape<NumberShape>;
677
1538
  timeout: OptionalShape<NumberShape>;
678
- }>>;
1539
+ }, false>>;
679
1540
  concurrency: OptionalShape<NumberShape>;
680
1541
  bail: OptionalShape<LiteralShape<readonly [true, false]>>;
681
- }>;
1542
+ }, false>;
1543
+
1544
+ export declare const PROMPT_TOOL_DESCRIPTION: string;
1545
+
1546
+ /**
1547
+ * The name {@link import('./factories.js').createPromptTool} advertises by default — the key a
1548
+ * model calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under.
1549
+ */
1550
+ export declare const PROMPT_TOOL_NAME = "ask";
1551
+
1552
+ /**
1553
+ * The lean {@link import('@orkestrel/agent').ToolInterface.summary} {@link import('./factories.js').createPromptTool}
1554
+ * advertises in place of {@link PROMPT_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
1555
+ * (`@orkestrel/agent`) advertises `summary ?? description`, so this one-sentence text stands in
1556
+ * for the full teaching description; the full text stays retrievable via
1557
+ * {@link import('./factories.js').createDescribeTool}.
1558
+ */
1559
+ 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.";
1560
+
1561
+ /**
1562
+ * Options for {@link import('./factories.js').createPromptTool} — the live
1563
+ * {@link TerminalManagerInterface} (`@orkestrel/terminal`) to `ask` through, the terminal name
1564
+ * `from`, and the advertised tool overrides.
1565
+ *
1566
+ * @remarks
1567
+ * - `manager` — the terminal manager whose `ask(from, to, form, options)` the tool's handler
1568
+ * calls; BLOCKS the calling agent turn until the addressed terminal answers (or the ask
1569
+ * rejects — a cycle throws `TerminalError('DEADLOCK')`, re-surfaced as a typed `DEADLOCK`
1570
+ * {@link import('./errors.js').AgentToolError}; an expired prompt re-surfaces as `EXPIRE`).
1571
+ * - `from` — the terminal identity this tool asks AS; the model supplies the `to` target and the
1572
+ * prompt form per call.
1573
+ * - `name` / `description` — advertised tool overrides; default to
1574
+ * {@link import('./constants.js').PROMPT_TOOL_NAME} / {@link import('./constants.js').PROMPT_TOOL_DESCRIPTION}.
1575
+ */
1576
+ export declare interface PromptToolOptions {
1577
+ readonly manager: TerminalManagerInterface;
1578
+ readonly from: string;
1579
+ readonly name?: string;
1580
+ readonly description?: string;
1581
+ }
1582
+
1583
+ /**
1584
+ * The shape of {@link import('./factories.js').createPromptTool}'s call arguments — `to` (the
1585
+ * terminal identity to address), `form` (which of the six {@link import('@orkestrel/terminal').PromptType}
1586
+ * forms to ask), `message`, an optional `timeout` override, and every per-form optional field
1587
+ * FLATTENED onto one object (mirrors `workspaceToolShape`'s flat-arm style, but a single shared
1588
+ * shape rather than a discriminated union — `form` alone does not vary the REQUIRED fields, only
1589
+ * which of the optional ones apply, so a flat shape stays faithful without duplicating `to` /
1590
+ * `message` / `timeout` across six near-identical arms).
1591
+ *
1592
+ * @remarks
1593
+ * `choices` backs `'select'` / `'checkbox'`; `default` backs `'input'` / `'confirm'` / `'select'`
1594
+ * (a string for the first two forms' text default, `'true'`/`'false'` string for confirm — the
1595
+ * contract layer cannot vary a field's type by a sibling field's value, so `default` stays a
1596
+ * string and the handler coerces per form); `mask` backs `'password'`; `min` / `max` backs
1597
+ * `'checkbox'`; `validate` (declarative only) backs the four text-shaped forms
1598
+ * (`'input'` / `'password'` / `'confirm'` / `'editor'`).
1599
+ */
1600
+ export declare const promptToolShape: ObjectShape<{
1601
+ to: StringShape;
1602
+ form: LiteralShape<readonly ["input", "password", "confirm", "select", "checkbox", "editor"]>;
1603
+ message: StringShape;
1604
+ default: OptionalShape<StringShape>;
1605
+ choices: OptionalShape<ArrayShape<ObjectShape<{
1606
+ name: StringShape;
1607
+ value: StringShape;
1608
+ description: OptionalShape<StringShape>;
1609
+ }, boolean | ContractShape>>>;
1610
+ mask: OptionalShape<StringShape>;
1611
+ min: OptionalShape<NumberShape>;
1612
+ max: OptionalShape<NumberShape>;
1613
+ validate: OptionalShape<ObjectShape<{
1614
+ required: OptionalShape<BooleanShape>;
1615
+ minimum: OptionalShape<NumberShape>;
1616
+ maximum: OptionalShape<NumberShape>;
1617
+ pattern: OptionalShape<StringShape>;
1618
+ email: OptionalShape<BooleanShape>;
1619
+ url: OptionalShape<BooleanShape>;
1620
+ numeric: OptionalShape<BooleanShape>;
1621
+ integer: OptionalShape<BooleanShape>;
1622
+ alphanumeric: OptionalShape<BooleanShape>;
1623
+ }, boolean | ContractShape>>;
1624
+ timeout: OptionalShape<NumberShape>;
1625
+ }, false>;
1626
+
1627
+ /** The default cap on how many `include` path segments deep a `load` / `find` call may traverse — the relation tool's default include-depth ceiling. */
1628
+ export declare const RELATION_TOOL_DEPTH = 3;
1629
+
1630
+ /**
1631
+ * The DESCRIPTION the relation tool advertises — a multi-line guide that teaches a small model
1632
+ * the operation list and the flat dot-path `include` syntax.
1633
+ *
1634
+ * @remarks
1635
+ * An include path is a FLAT dot-separated string (`'contacts.account'`), never a nested object —
1636
+ * the same small-model ergonomic lever the other tools in this package use for flat args.
1637
+ */
1638
+ export declare const RELATION_TOOL_DESCRIPTION: string;
1639
+
1640
+ /** The default cap on rows a `find` / `links` call returns when the caller omits `limit` — the relation tool's default row ceiling. */
1641
+ export declare const RELATION_TOOL_LIMIT = 1000;
1642
+
1643
+ /**
1644
+ * The name `createRelationTool` advertises by default — the key a model calls and the
1645
+ * `ToolManagerInterface` (`@orkestrel/agent`) registers under.
1646
+ */
1647
+ export declare const RELATION_TOOL_NAME = "relation";
1648
+
1649
+ /**
1650
+ * The lean {@link import('@orkestrel/agent').ToolInterface.summary} the relation tool advertises
1651
+ * in place of {@link RELATION_TOOL_DESCRIPTION}.
1652
+ */
1653
+ 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.";
1654
+
1655
+ /** One key value — a string or number; the array form (multiple keys, positional) resolves FIRST per AGENTS §9.2. */
1656
+ export declare const relationKeyShape: UnionShape<[ ArrayShape<UnionShape<[ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1657
+
1658
+ /**
1659
+ * Resolve which registered {@link RelationManagerInterface} a relation-tool call addresses — the
1660
+ * pure manager-resolution leaf {@link import('./factories.js').createRelationTool} calls on
1661
+ * every operation.
1662
+ *
1663
+ * @remarks
1664
+ * An explicit `name` must match a key of `managers` (a miss throws a typed `TOOL`
1665
+ * {@link AgentToolError} naming the registered managers). An OMITTED `name` resolves to the sole
1666
+ * registered manager when exactly one is registered, else throws the same typed error.
1667
+ *
1668
+ * @param managers - The tool's registered `RelationManagerInterface` map
1669
+ * @param name - The call's optional `manager` field
1670
+ * @returns The resolved {@link RelationManagerInterface}
1671
+ */
1672
+ export declare function relationManagerOf(managers: Readonly<Record<string, RelationManagerInterface>>, name: string | undefined): RelationManagerInterface;
1673
+
1674
+ /**
1675
+ * Resolve a `model` name against a live {@link RelationManagerInterface} — the pure model-lookup
1676
+ * leaf {@link import('./factories.js').createRelationTool} calls on every operation, mirroring
1677
+ * {@link relationManagerOf}'s guard shape.
1678
+ *
1679
+ * @param manager - The resolved {@link RelationManagerInterface}
1680
+ * @param name - The call's `model` field
1681
+ * @returns The model's {@link ModelInterface}
1682
+ */
1683
+ export declare function relationModelOf(manager: RelationManagerInterface, name: string): ModelInterface;
1684
+
1685
+ /**
1686
+ * Map a caught error to the {@link AgentToolErrorCode} the upcoming relation tool should throw
1687
+ * with — the pure classification step of that factory's error handling, mirroring
1688
+ * {@link terminalToolCode}'s idiom for `@orkestrel/relation`.
1689
+ *
1690
+ * @param error - The value caught from a `@orkestrel/relation` operation
1691
+ * @returns The granular {@link RelationErrorCode}, or `undefined` if `error` is not a `RelationError`
1692
+ */
1693
+ export declare function relationToolCode(error: unknown): RelationErrorCode | undefined;
1694
+
1695
+ /**
1696
+ * Options for {@link import('./factories.js').createRelationTool} — SRC-3 (the final unit) of
1697
+ * the 3-unit database / relation spine.
1698
+ *
1699
+ * @remarks
1700
+ * - `managers` — the live `RelationManagerInterface` (`@orkestrel/relation`) registry a call's
1701
+ * optional `manager` field addresses by name; REQUIRED (unlike the database tool's lazily
1702
+ * resolved handles, a relation manager's relations are declared up front and cannot be minted
1703
+ * on demand from a tool call). A call that omits `manager` resolves to the SOLE registered
1704
+ * manager when exactly one is registered, else throws a typed `TOOL`
1705
+ * {@link import('./errors.js').AgentToolError} naming the registered manager keys.
1706
+ * - `limit` — the row cap `'find'` / `'links'` enforce when a call's `limit` is omitted or
1707
+ * exceeds it. Defaults to {@link import('./constants.js').RELATION_TOOL_LIMIT}.
1708
+ * - `depth` — the max dot-path segment count `'load'` / `'find'`'s `include` paths may reach
1709
+ * ({@link import('./helpers.js').expandInclude}). Defaults to
1710
+ * {@link import('./constants.js').RELATION_TOOL_DEPTH}.
1711
+ * - `name` / `description` — advertised tool overrides; default to
1712
+ * {@link import('./constants.js').RELATION_TOOL_NAME} / {@link import('./constants.js').RELATION_TOOL_DESCRIPTION}.
1713
+ */
1714
+ export declare interface RelationToolOptions {
1715
+ readonly name?: string;
1716
+ readonly description?: string;
1717
+ readonly managers: Readonly<Record<string, RelationManagerInterface>>;
1718
+ readonly limit?: number;
1719
+ readonly depth?: number;
1720
+ }
1721
+
1722
+ /**
1723
+ * The shape of {@link import('./factories.js').createRelationTool}'s call arguments —
1724
+ * discriminated by `operation` into the 5 relation operations (`'load'` / `'find'` / `'link'` /
1725
+ * `'unlink'` / `'links'`).
1726
+ *
1727
+ * @remarks
1728
+ * `'load'` fetches one or more rows (positional key/array) with `include` attached. `'find'`
1729
+ * fetches rows (pagination / sort only) with `include` attached. `'link'` / `'unlink'` write /
1730
+ * remove a `through` junction row; `'links'` lists a `through` relation's linked keys.
1731
+ */
1732
+ export declare const relationToolShape: UnionShape<[ ObjectShape<{
1733
+ operation: LiteralShape<readonly ["load"]>;
1734
+ manager: OptionalShape<StringShape>;
1735
+ model: StringShape;
1736
+ key: UnionShape<[ ArrayShape<UnionShape<[ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1737
+ include: OptionalShape<ArrayShape<StringShape>>;
1738
+ }, false>, ObjectShape<{
1739
+ operation: LiteralShape<readonly ["find"]>;
1740
+ manager: OptionalShape<StringShape>;
1741
+ model: StringShape;
1742
+ include: OptionalShape<ArrayShape<StringShape>>;
1743
+ limit: OptionalShape<NumberShape>;
1744
+ offset: OptionalShape<NumberShape>;
1745
+ sort: OptionalShape<StringShape>;
1746
+ direction: OptionalShape<LiteralShape<readonly ["ascending", "descending"]>>;
1747
+ }, false>, ObjectShape<{
1748
+ operation: LiteralShape<readonly ["link"]>;
1749
+ manager: OptionalShape<StringShape>;
1750
+ model: StringShape;
1751
+ key: UnionShape<[ StringShape, NumberShape]>;
1752
+ relation: StringShape;
1753
+ target: UnionShape<[ StringShape, NumberShape]>;
1754
+ }, false>, ObjectShape<{
1755
+ operation: LiteralShape<readonly ["unlink"]>;
1756
+ manager: OptionalShape<StringShape>;
1757
+ model: StringShape;
1758
+ key: UnionShape<[ StringShape, NumberShape]>;
1759
+ relation: StringShape;
1760
+ target: UnionShape<[ StringShape, NumberShape]>;
1761
+ }, false>, ObjectShape<{
1762
+ operation: LiteralShape<readonly ["links"]>;
1763
+ manager: OptionalShape<StringShape>;
1764
+ model: StringShape;
1765
+ key: UnionShape<[ StringShape, NumberShape]>;
1766
+ relation: StringShape;
1767
+ }, false>]>;
1768
+
1769
+ /** A loose row — a flat object of column name to JSON value; the array form (multiple rows) resolves FIRST per AGENTS §9.2. */
1770
+ export declare const rowShape: ObjectShape<Record<never, never>, JSONShape>;
1771
+
1772
+ /** One or many loose rows — the array form resolves FIRST per AGENTS §9.2. */
1773
+ export declare const rowsShape: UnionShape<[ ArrayShape<ObjectShape<Record<never, never>, JSONShape>>, ObjectShape<Record<never, never>, JSONShape>]>;
1774
+
1775
+ /** A single row key (not an array) — used by `'link'` / `'unlink'` / `'links'`, which address exactly one owning row. */
1776
+ export declare const singleKeyShape: UnionShape<[ StringShape, NumberShape]>;
682
1777
 
683
1778
  /**
684
1779
  * The shape of ONE flat step — `{ name }` — the building block of {@link workflowStepsShape}.
@@ -689,7 +1784,39 @@ export declare const phaseDraftShape: ObjectShape<{
689
1784
  */
690
1785
  export declare const stepShape: ObjectShape<{
691
1786
  name: StringShape;
692
- }>;
1787
+ }, false>;
1788
+
1789
+ /**
1790
+ * Build one {@link TableSchema} from a table NAME and its `@orkestrel/database` `TableExport` —
1791
+ * the "deployed" schema shape `DatabaseInterface.migrate` diffs against, derived from a LIVE
1792
+ * handle's `export()` rather than a re-declared {@link TableSpec}, so it works for ANY handle
1793
+ * (config-tracked or caller-supplied).
1794
+ *
1795
+ * @param name - The table name
1796
+ * @param table - The table's `TableExport` (`{ key, columns }`, `@orkestrel/database`)
1797
+ * @returns The equivalent {@link TableSchema} (`indexes` empty — this package declares none)
1798
+ */
1799
+ export declare function tableSchema(name: string, table: Readonly<{
1800
+ key: string;
1801
+ columns: Readonly<Record<string, ContractShape>>;
1802
+ }>): TableSchema;
1803
+
1804
+ /**
1805
+ * A database's table layout — one entry per table, each a flat map of column name to
1806
+ * {@link ColumnSpec}. The small-model-facing DSL {@link import('./helpers.js').expandTables}
1807
+ * compiles into an `@orkestrel/database` `TablesShape`.
1808
+ */
1809
+ export declare type TableSpec = Readonly<Record<string, Readonly<{
1810
+ columns: Readonly<Record<string, ColumnSpec>>;
1811
+ }>>>;
1812
+
1813
+ /** A {@link import('./types.js').TableSpec} — table name to `{ columns }`, each column a {@link columnSpecShape}. */
1814
+ export declare const tableSpecShape: ObjectShape<Record<never, never>, ObjectShape<{
1815
+ columns: ObjectShape<Record<never, never>, UnionShape<[ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
1816
+ type: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
1817
+ optional: OptionalShape<BooleanShape>;
1818
+ }, false>]>>;
1819
+ }, false>>;
693
1820
 
694
1821
  /**
695
1822
  * A draft task — a `TaskDefinition` (`@orkestrel/workflow`) with OPTIONAL `id` / `name`.
@@ -722,7 +1849,24 @@ export declare const taskDraftShape: ObjectShape<{
722
1849
  run: OptionalShape<StringShape>;
723
1850
  retries: OptionalShape<NumberShape>;
724
1851
  timeout: OptionalShape<NumberShape>;
725
- }>;
1852
+ }, false>;
1853
+
1854
+ /**
1855
+ * Map a caught error to the {@link AgentToolErrorCode} the terminal-tool factory should throw
1856
+ * with — the pure classification step of that factory's error handling.
1857
+ *
1858
+ * @remarks
1859
+ * Narrows `error` with {@link isTerminalError} (`@orkestrel/terminal`) first: a non-`TerminalError`
1860
+ * value returns `undefined`, telling the caller this mapper does not apply (rethrow / handle
1861
+ * otherwise). For a genuine `TerminalError`, `'DEADLOCK'` maps to `'DEADLOCK'`, `'EXPIRE'` maps
1862
+ * to `'EXPIRE'`, and every other {@link import('@orkestrel/terminal').TerminalErrorCode}
1863
+ * (`'TARGET'`, `'CANCEL'`, `'DRIVER'`) maps to the generic `'TOOL'` code. The mapper only
1864
+ * classifies — the factory performs the actual throw.
1865
+ *
1866
+ * @param error - The value caught from a terminal-manager operation (`ask` / `answer` / …)
1867
+ * @returns The mapped {@link AgentToolErrorCode}, or `undefined` if `error` is not a `TerminalError`
1868
+ */
1869
+ export declare function terminalToolCode(error: unknown): AgentToolErrorCode | undefined;
726
1870
 
727
1871
  export declare const WORKFLOW_TOOL_DESCRIPTION: string;
728
1872
 
@@ -819,12 +1963,12 @@ export declare const workflowDraftShape: ObjectShape<{
819
1963
  run: OptionalShape<StringShape>;
820
1964
  retries: OptionalShape<NumberShape>;
821
1965
  timeout: OptionalShape<NumberShape>;
822
- }>>;
1966
+ }, false>>;
823
1967
  concurrency: OptionalShape<NumberShape>;
824
1968
  bail: OptionalShape<LiteralShape<readonly [true, false]>>;
825
- }>>;
1969
+ }, false>>;
826
1970
  bail: OptionalShape<LiteralShape<readonly [true, false]>>;
827
- }>;
1971
+ }, false>;
828
1972
 
829
1973
  /**
830
1974
  * One flat step — `{ name }` — the building block of a {@link WorkflowSteps} blob.
@@ -869,8 +2013,8 @@ export declare const workflowStepsShape: ObjectShape<{
869
2013
  name: OptionalShape<StringShape>;
870
2014
  steps: ArrayShape<ObjectShape<{
871
2015
  name: StringShape;
872
- }>>;
873
- }>;
2016
+ }, false>>;
2017
+ }, false>;
874
2018
 
875
2019
  /**
876
2020
  * The ancestry identifier of a workflow in a run chain — `workflow:<id>`.
@@ -1125,29 +2269,29 @@ export declare interface WorkspaceToolOptions {
1125
2269
  export declare const workspaceToolShape: UnionShape<[ ObjectShape<{
1126
2270
  operation: LiteralShape<readonly ["read"]>;
1127
2271
  path: StringShape;
1128
- }>, ObjectShape<{
2272
+ }, false>, ObjectShape<{
1129
2273
  operation: LiteralShape<readonly ["list"]>;
1130
- }>, ObjectShape<{
2274
+ }, false>, ObjectShape<{
1131
2275
  operation: LiteralShape<readonly ["has"]>;
1132
2276
  path: StringShape;
1133
- }>, ObjectShape<{
2277
+ }, false>, ObjectShape<{
1134
2278
  operation: LiteralShape<readonly ["search"]>;
1135
2279
  query: StringShape;
1136
2280
  regex: OptionalShape<BooleanShape>;
1137
2281
  exact: OptionalShape<BooleanShape>;
1138
2282
  limit: OptionalShape<NumberShape>;
1139
- }>, ObjectShape<{
2283
+ }, false>, ObjectShape<{
1140
2284
  operation: LiteralShape<readonly ["replace"]>;
1141
2285
  query: StringShape;
1142
2286
  replacement: StringShape;
1143
2287
  regex: OptionalShape<BooleanShape>;
1144
2288
  exact: OptionalShape<BooleanShape>;
1145
2289
  limit: OptionalShape<NumberShape>;
1146
- }>, ObjectShape<{
2290
+ }, false>, ObjectShape<{
1147
2291
  operation: LiteralShape<readonly ["write"]>;
1148
2292
  path: StringShape;
1149
2293
  content: StringShape;
1150
- }>, ObjectShape<{
2294
+ }, false>, ObjectShape<{
1151
2295
  operation: LiteralShape<readonly ["splice"]>;
1152
2296
  path: StringShape;
1153
2297
  content: StringShape;
@@ -1155,26 +2299,26 @@ export declare const workspaceToolShape: UnionShape<[ ObjectShape<{
1155
2299
  fromColumn: NumberShape;
1156
2300
  toLine: NumberShape;
1157
2301
  toColumn: NumberShape;
1158
- }>, ObjectShape<{
2302
+ }, false>, ObjectShape<{
1159
2303
  operation: LiteralShape<readonly ["prepend"]>;
1160
2304
  path: StringShape;
1161
2305
  content: StringShape;
1162
- }>, ObjectShape<{
2306
+ }, false>, ObjectShape<{
1163
2307
  operation: LiteralShape<readonly ["append"]>;
1164
2308
  path: StringShape;
1165
2309
  content: StringShape;
1166
- }>, ObjectShape<{
2310
+ }, false>, ObjectShape<{
1167
2311
  operation: LiteralShape<readonly ["move"]>;
1168
2312
  from: StringShape;
1169
2313
  to: StringShape;
1170
- }>, ObjectShape<{
2314
+ }, false>, ObjectShape<{
1171
2315
  operation: LiteralShape<readonly ["remove"]>;
1172
2316
  path: StringShape;
1173
- }>, ObjectShape<{
2317
+ }, false>, ObjectShape<{
1174
2318
  operation: LiteralShape<readonly ["workspaces"]>;
1175
- }>, ObjectShape<{
2319
+ }, false>, ObjectShape<{
1176
2320
  operation: LiteralShape<readonly ["switch"]>;
1177
2321
  id: StringShape;
1178
- }>]>;
2322
+ }, false>]>;
1179
2323
 
1180
2324
  export { }