@orkestrel/tool 0.0.3 → 0.0.5

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.
@@ -296,12 +296,12 @@ export declare interface AnswerToolOptions {
296
296
  * union directly, so `value` is typed as the full `string | boolean | readonly string[]` union
297
297
  * here (no lossy string-only fallback needed).
298
298
  */
299
- export declare const answerToolShape: UnionShape<[ ObjectShape<{
299
+ export declare const answerToolShape: UnionShape<readonly [ ObjectShape<{
300
300
  operation: LiteralShape<readonly ["pending"]>;
301
301
  }, false>, ObjectShape<{
302
302
  operation: LiteralShape<readonly ["answer"]>;
303
303
  id: StringShape;
304
- value: UnionShape<[ StringShape, BooleanShape, ArrayShape<StringShape>]>;
304
+ value: UnionShape<readonly [ StringShape, BooleanShape, ArrayShape<StringShape>]>;
305
305
  }, false>]>;
306
306
 
307
307
  /**
@@ -379,7 +379,7 @@ export declare type ColumnSpec = ColumnKind | Readonly<{
379
379
  }>;
380
380
 
381
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<{
382
+ export declare const columnSpecShape: UnionShape<readonly [ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
383
383
  type: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
384
384
  optional: OptionalShape<BooleanShape>;
385
385
  }, false>]>;
@@ -673,6 +673,153 @@ export declare function createDatabaseTool(options?: DatabaseToolOptions): ToolI
673
673
  */
674
674
  export declare function createDescribeTool(tools: ToolManagerInterface): ToolInterface;
675
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
+
676
823
  /**
677
824
  * Create the in-memory {@link DefinitionStoreInterface} — a process-lifetime `Map` of database
678
825
  * definitions, the DEFAULT store the upcoming database / relation tools will persist their
@@ -1111,6 +1258,66 @@ export declare class DatabaseDefinitionStore implements DefinitionStoreInterface
1111
1258
  delete(id: string): Promise<void>;
1112
1259
  }
1113
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
+
1114
1321
  /**
1115
1322
  * Map a caught error to the {@link AgentToolErrorCode} the upcoming database tool should throw
1116
1323
  * with — the pure classification step of that factory's error handling, mirroring
@@ -1177,11 +1384,11 @@ export declare interface DatabaseToolOptions {
1177
1384
  * `'aggregate'` carry an optional `criteria` (the SERIALIZED form — `values` is ALWAYS an array,
1178
1385
  * even for a single-value operator, so a caller never chains method calls or guesses arity).
1179
1386
  */
1180
- export declare const databaseToolShape: UnionShape<[ ObjectShape<{
1387
+ export declare const databaseToolShape: UnionShape<readonly [ ObjectShape<{
1181
1388
  operation: LiteralShape<readonly ["create"]>;
1182
1389
  id: StringShape;
1183
1390
  tables: ObjectShape<Record<never, never>, ObjectShape<{
1184
- columns: ObjectShape<Record<never, never>, UnionShape<[ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
1391
+ columns: ObjectShape<Record<never, never>, UnionShape<readonly [ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
1185
1392
  type: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
1186
1393
  optional: OptionalShape<BooleanShape>;
1187
1394
  }, false>]>>;
@@ -1195,7 +1402,7 @@ export declare const databaseToolShape: UnionShape<[ ObjectShape<{
1195
1402
  operation: LiteralShape<readonly ["get"]>;
1196
1403
  id: StringShape;
1197
1404
  table: StringShape;
1198
- key: UnionShape<[ ArrayShape<UnionShape<[ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1405
+ key: UnionShape<readonly [ ArrayShape<UnionShape<readonly [ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1199
1406
  }, false>, ObjectShape<{
1200
1407
  operation: LiteralShape<readonly ["records"]>;
1201
1408
  id: StringShape;
@@ -1256,28 +1463,28 @@ export declare const databaseToolShape: UnionShape<[ ObjectShape<{
1256
1463
  operation: LiteralShape<readonly ["add"]>;
1257
1464
  id: StringShape;
1258
1465
  table: StringShape;
1259
- row: UnionShape<[ ArrayShape<ObjectShape<Record<never, never>, JSONShape>>, ObjectShape<Record<never, never>, JSONShape>]>;
1466
+ row: UnionShape<readonly [ ArrayShape<ObjectShape<Record<never, never>, JSONShape>>, ObjectShape<Record<never, never>, JSONShape>]>;
1260
1467
  }, false>, ObjectShape<{
1261
1468
  operation: LiteralShape<readonly ["set"]>;
1262
1469
  id: StringShape;
1263
1470
  table: StringShape;
1264
- row: UnionShape<[ ArrayShape<ObjectShape<Record<never, never>, JSONShape>>, ObjectShape<Record<never, never>, JSONShape>]>;
1471
+ row: UnionShape<readonly [ ArrayShape<ObjectShape<Record<never, never>, JSONShape>>, ObjectShape<Record<never, never>, JSONShape>]>;
1265
1472
  }, false>, ObjectShape<{
1266
1473
  operation: LiteralShape<readonly ["update"]>;
1267
1474
  id: StringShape;
1268
1475
  table: StringShape;
1269
- key: UnionShape<[ ArrayShape<UnionShape<[ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1476
+ key: UnionShape<readonly [ ArrayShape<UnionShape<readonly [ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1270
1477
  changes: ObjectShape<Record<never, never>, JSONShape>;
1271
1478
  }, false>, ObjectShape<{
1272
1479
  operation: LiteralShape<readonly ["remove"]>;
1273
1480
  id: StringShape;
1274
1481
  table: StringShape;
1275
- key: UnionShape<[ ArrayShape<UnionShape<[ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1482
+ key: UnionShape<readonly [ ArrayShape<UnionShape<readonly [ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1276
1483
  }, false>, ObjectShape<{
1277
1484
  operation: LiteralShape<readonly ["migrate"]>;
1278
1485
  id: StringShape;
1279
1486
  tables: ObjectShape<Record<never, never>, ObjectShape<{
1280
- columns: ObjectShape<Record<never, never>, UnionShape<[ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
1487
+ columns: ObjectShape<Record<never, never>, UnionShape<readonly [ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
1281
1488
  type: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
1282
1489
  optional: OptionalShape<BooleanShape>;
1283
1490
  }, false>]>>;
@@ -1349,6 +1556,76 @@ export declare const describeToolShape: ObjectShape<{
1349
1556
  name: StringShape;
1350
1557
  }, false>;
1351
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
+
1352
1629
  /**
1353
1630
  * Expand the relation tool's FLAT dot-path `include` list into a live `@orkestrel/relation`
1354
1631
  * {@link Include} tree — the pure leaf {@link import('./factories.js').createRelationTool} calls
@@ -1408,6 +1685,54 @@ export declare function expandTables(spec: TableSpec): TablesShape;
1408
1685
  /** Flat dot-path relation include list, expanded via {@link import('./helpers.js').expandInclude}. */
1409
1686
  export declare const includeShape: OptionalShape<ArrayShape<StringShape>>;
1410
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.
1710
+ */
1711
+ export declare interface InferToolOptions {
1712
+ readonly name?: string;
1713
+ readonly description?: string;
1714
+ }
1715
+
1716
+ /**
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.
1720
+ *
1721
+ * @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
+
1411
1736
  /**
1412
1737
  * Type guard narrowing an unknown caught value to an {@link AgentToolError}.
1413
1738
  *
@@ -1442,7 +1767,7 @@ export declare function isColumnSpec(value: unknown): value is ColumnSpec;
1442
1767
  export declare function isDatabaseDefinition(value: unknown): value is DatabaseDefinition;
1443
1768
 
1444
1769
  /** 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]>;
1770
+ export declare const keyShape: UnionShape<readonly [ ArrayShape<UnionShape<readonly [ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1446
1771
 
1447
1772
  /** Map one {@link import('./types.js').ColumnKind} to its primitive `@orkestrel/database` shape — the leaf {@link columnShape} wraps. */
1448
1773
  export declare function kindShape(kind: ColumnKind): ContractShape;
@@ -1653,7 +1978,7 @@ export declare const RELATION_TOOL_NAME = "relation";
1653
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.";
1654
1979
 
1655
1980
  /** 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]>;
1981
+ export declare const relationKeyShape: UnionShape<readonly [ ArrayShape<UnionShape<readonly [ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1657
1982
 
1658
1983
  /**
1659
1984
  * Resolve which registered {@link RelationManagerInterface} a relation-tool call addresses — the
@@ -1729,11 +2054,11 @@ export declare interface RelationToolOptions {
1729
2054
  * fetches rows (pagination / sort only) with `include` attached. `'link'` / `'unlink'` write /
1730
2055
  * remove a `through` junction row; `'links'` lists a `through` relation's linked keys.
1731
2056
  */
1732
- export declare const relationToolShape: UnionShape<[ ObjectShape<{
2057
+ export declare const relationToolShape: UnionShape<readonly [ ObjectShape<{
1733
2058
  operation: LiteralShape<readonly ["load"]>;
1734
2059
  manager: OptionalShape<StringShape>;
1735
2060
  model: StringShape;
1736
- key: UnionShape<[ ArrayShape<UnionShape<[ StringShape, NumberShape]>>, StringShape, NumberShape]>;
2061
+ key: UnionShape<readonly [ ArrayShape<UnionShape<readonly [ StringShape, NumberShape]>>, StringShape, NumberShape]>;
1737
2062
  include: OptionalShape<ArrayShape<StringShape>>;
1738
2063
  }, false>, ObjectShape<{
1739
2064
  operation: LiteralShape<readonly ["find"]>;
@@ -1748,21 +2073,21 @@ export declare const relationToolShape: UnionShape<[ ObjectShape<{
1748
2073
  operation: LiteralShape<readonly ["link"]>;
1749
2074
  manager: OptionalShape<StringShape>;
1750
2075
  model: StringShape;
1751
- key: UnionShape<[ StringShape, NumberShape]>;
2076
+ key: UnionShape<readonly [ StringShape, NumberShape]>;
1752
2077
  relation: StringShape;
1753
- target: UnionShape<[ StringShape, NumberShape]>;
2078
+ target: UnionShape<readonly [ StringShape, NumberShape]>;
1754
2079
  }, false>, ObjectShape<{
1755
2080
  operation: LiteralShape<readonly ["unlink"]>;
1756
2081
  manager: OptionalShape<StringShape>;
1757
2082
  model: StringShape;
1758
- key: UnionShape<[ StringShape, NumberShape]>;
2083
+ key: UnionShape<readonly [ StringShape, NumberShape]>;
1759
2084
  relation: StringShape;
1760
- target: UnionShape<[ StringShape, NumberShape]>;
2085
+ target: UnionShape<readonly [ StringShape, NumberShape]>;
1761
2086
  }, false>, ObjectShape<{
1762
2087
  operation: LiteralShape<readonly ["links"]>;
1763
2088
  manager: OptionalShape<StringShape>;
1764
2089
  model: StringShape;
1765
- key: UnionShape<[ StringShape, NumberShape]>;
2090
+ key: UnionShape<readonly [ StringShape, NumberShape]>;
1766
2091
  relation: StringShape;
1767
2092
  }, false>]>;
1768
2093
 
@@ -1770,10 +2095,10 @@ export declare const relationToolShape: UnionShape<[ ObjectShape<{
1770
2095
  export declare const rowShape: ObjectShape<Record<never, never>, JSONShape>;
1771
2096
 
1772
2097
  /** 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>]>;
2098
+ export declare const rowsShape: UnionShape<readonly [ ArrayShape<ObjectShape<Record<never, never>, JSONShape>>, ObjectShape<Record<never, never>, JSONShape>]>;
1774
2099
 
1775
2100
  /** 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]>;
2101
+ export declare const singleKeyShape: UnionShape<readonly [ StringShape, NumberShape]>;
1777
2102
 
1778
2103
  /**
1779
2104
  * The shape of ONE flat step — `{ name }` — the building block of {@link workflowStepsShape}.
@@ -1812,7 +2137,7 @@ export declare type TableSpec = Readonly<Record<string, Readonly<{
1812
2137
 
1813
2138
  /** A {@link import('./types.js').TableSpec} — table name to `{ columns }`, each column a {@link columnSpecShape}. */
1814
2139
  export declare const tableSpecShape: ObjectShape<Record<never, never>, ObjectShape<{
1815
- columns: ObjectShape<Record<never, never>, UnionShape<[ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
2140
+ columns: ObjectShape<Record<never, never>, UnionShape<readonly [ LiteralShape<readonly ["string", "integer", "number", "boolean"]>, ObjectShape<{
1816
2141
  type: LiteralShape<readonly ["string", "integer", "number", "boolean"]>;
1817
2142
  optional: OptionalShape<BooleanShape>;
1818
2143
  }, false>]>>;
@@ -2266,7 +2591,7 @@ export declare interface WorkspaceToolOptions {
2266
2591
  * the model can move between) and `switch` (re-point the active one by `id`) — let a model
2267
2592
  * DISCOVER then CHOOSE which workspace the edit / read arms target.
2268
2593
  */
2269
- export declare const workspaceToolShape: UnionShape<[ ObjectShape<{
2594
+ export declare const workspaceToolShape: UnionShape<readonly [ ObjectShape<{
2270
2595
  operation: LiteralShape<readonly ["read"]>;
2271
2596
  path: StringShape;
2272
2597
  }, false>, ObjectShape<{