@orkestrel/toolbox 0.0.13 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/core/index.cjs +50 -42
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +35 -16
- package/dist/src/core/index.d.ts +35 -16
- package/dist/src/core/index.js +51 -43
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +4 -8
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.js +5 -9
- package/dist/src/server/index.js.map +1 -1
- package/package.json +17 -17
|
@@ -10,6 +10,7 @@ import type { ConversationStoreInterface } from '@orkestrel/agent';
|
|
|
10
10
|
import type { DatabaseErrorCode } from '@orkestrel/database';
|
|
11
11
|
import type { DatabaseInterface } from '@orkestrel/database';
|
|
12
12
|
import type { DriverInterface } from '@orkestrel/database';
|
|
13
|
+
import type { Guard } from '@orkestrel/contract';
|
|
13
14
|
import type { Include } from '@orkestrel/relation';
|
|
14
15
|
import type { IndexMap } from '@orkestrel/database';
|
|
15
16
|
import { JSONShape } from '@orkestrel/contract';
|
|
@@ -29,6 +30,7 @@ import { StringShape } from '@orkestrel/contract';
|
|
|
29
30
|
import type { TableInterface } from '@orkestrel/database';
|
|
30
31
|
import type { TableMap } from '@orkestrel/database';
|
|
31
32
|
import type { TerminalManagerInterface } from '@orkestrel/terminal';
|
|
33
|
+
import type { ToolContext } from '@orkestrel/tool';
|
|
32
34
|
import type { ToolInterface } from '@orkestrel/tool';
|
|
33
35
|
import type { ToolManagerInterface } from '@orkestrel/tool';
|
|
34
36
|
import { UnionShape } from '@orkestrel/contract';
|
|
@@ -571,11 +573,14 @@ export declare function createDatabaseDefinitionStore(driver?: DriverInterface):
|
|
|
571
573
|
* import { createDatabaseTool } from '@src/core'
|
|
572
574
|
*
|
|
573
575
|
* const tool = createDatabaseTool()
|
|
574
|
-
* await tool.execute(
|
|
575
|
-
*
|
|
576
|
-
*
|
|
577
|
-
*
|
|
578
|
-
* }
|
|
576
|
+
* await tool.execute(
|
|
577
|
+
* {
|
|
578
|
+
* operation: 'create',
|
|
579
|
+
* id: 'shop',
|
|
580
|
+
* tables: { products: { columns: { name: 'string', price: 'number' } } },
|
|
581
|
+
* },
|
|
582
|
+
* { signal: new AbortController().signal },
|
|
583
|
+
* )
|
|
579
584
|
* ```
|
|
580
585
|
*/
|
|
581
586
|
export declare function createDatabaseTool(options?: DatabaseToolOptions): ToolInterface;
|
|
@@ -638,8 +643,10 @@ export declare function createDescribeTool(tools: ToolManagerInterface): ToolInt
|
|
|
638
643
|
* never asserted, and a key outside the closed inferred schema is silently dropped rather than
|
|
639
644
|
* rejected (see {@link import('./types.js').EndpointToolOptions.validate}). With
|
|
640
645
|
* `validate: false`, the tool's `execute` passes through the model-supplied `args` to
|
|
641
|
-
* `definition.execute` without re-validation — the raw-passthrough opt-out.
|
|
642
|
-
*
|
|
646
|
+
* `definition.execute` without re-validation — the raw-passthrough opt-out. The execution context
|
|
647
|
+
* the tool's `execute` receives reaches `definition.execute` unchanged whichever way `args` are
|
|
648
|
+
* handled, so a handler that reads `context.signal` observes the caller's cancellation. Either way,
|
|
649
|
+
* the definition's return flows back as the tool call's plain result; a throw propagates uncaught,
|
|
643
650
|
* isolated by the `ToolManagerInterface` (`@orkestrel/tool`) into the canonical error envelope
|
|
644
651
|
* — never caught or re-wrapped here.
|
|
645
652
|
*
|
|
@@ -862,7 +869,10 @@ export declare function createPromptTool(options: PromptToolOptions): ToolInterf
|
|
|
862
869
|
* import { createRelationTool } from '@src/core'
|
|
863
870
|
*
|
|
864
871
|
* const tool = createRelationTool({ managers: { shop: manager } })
|
|
865
|
-
* await tool.execute(
|
|
872
|
+
* await tool.execute(
|
|
873
|
+
* { operation: 'load', model: 'accounts', key: 'acc1', include: ['contacts'] },
|
|
874
|
+
* { signal: new AbortController().signal },
|
|
875
|
+
* )
|
|
866
876
|
* ```
|
|
867
877
|
*/
|
|
868
878
|
export declare function createRelationTool(options: RelationToolOptions): ToolInterface;
|
|
@@ -876,7 +886,9 @@ export declare function createRelationTool(options: RelationToolOptions): ToolIn
|
|
|
876
886
|
* (`{ publish: createToolFunction(tools, 'publish') }`); the pure workflow runner has no
|
|
877
887
|
* knowledge of tools itself. The returned function executes `name` against `tools` with the
|
|
878
888
|
* task's `controller.input` as the call arguments. The adapter resolves the live tool, calls its
|
|
879
|
-
* `execute` method directly, and deep-gates the returned unknown through `parseJSONValue`.
|
|
889
|
+
* `execute` method directly, and deep-gates the returned unknown through `parseJSONValue`. The
|
|
890
|
+
* execution context it passes carries the task's own `controller.signal`, so a handler that
|
|
891
|
+
* reads `context.signal` observes the caller's cancellation.
|
|
880
892
|
* Genuine execution throws retain identity. An unregistered name or non-JSON return throws this
|
|
881
893
|
* package's typed `TOOL` `ToolboxError`.
|
|
882
894
|
*
|
|
@@ -1561,12 +1573,19 @@ export declare interface EndpointDefinition {
|
|
|
1561
1573
|
|
|
1562
1574
|
/**
|
|
1563
1575
|
* Represents the handler {@link EndpointDefinition.execute} implements — it mirrors
|
|
1564
|
-
* `@orkestrel/tool`'s `ToolOptions.execute` signature exactly
|
|
1565
|
-
*
|
|
1566
|
-
*
|
|
1567
|
-
*
|
|
1576
|
+
* `@orkestrel/tool`'s `ToolOptions.execute` signature exactly, so
|
|
1577
|
+
* {@link import('./factories.js').createEndpointTool} forwards the execution context it receives
|
|
1578
|
+
* to the handler unchanged and a handler that reads `context.signal` observes the caller's
|
|
1579
|
+
* cancellation.
|
|
1580
|
+
*
|
|
1581
|
+
* @remarks
|
|
1582
|
+
* The mirrored signature is the same `Readonly<Record<string, unknown>>` argument, the same
|
|
1583
|
+
* `ToolContext` second parameter, and the same `Promise<unknown> | unknown` return. A handler that
|
|
1584
|
+
* declares `args` alone still satisfies the type, the way a function declaring fewer parameters
|
|
1585
|
+
* than its contract does, so an endpoint definition written against the argument alone keeps
|
|
1586
|
+
* typechecking and reads no signal.
|
|
1568
1587
|
*/
|
|
1569
|
-
export declare type EndpointHandler = (args: Readonly<Record<string, unknown
|
|
1588
|
+
export declare type EndpointHandler = (args: Readonly<Record<string, unknown>>, context: ToolContext) => Promise<unknown> | unknown;
|
|
1570
1589
|
|
|
1571
1590
|
/**
|
|
1572
1591
|
* Represents the construction-time tuning for {@link import('./factories.js').createEndpointTool} —
|
|
@@ -1782,7 +1801,7 @@ export declare function isAgentFunction(value: unknown): value is AgentFunction;
|
|
|
1782
1801
|
* @param value - The value to inspect
|
|
1783
1802
|
* @returns True if `value` is `'string'`, `'integer'`, `'number'`, or `'boolean'`; false otherwise
|
|
1784
1803
|
*/
|
|
1785
|
-
export declare
|
|
1804
|
+
export declare const isColumnPrimitive: Guard<ColumnPrimitive>;
|
|
1786
1805
|
|
|
1787
1806
|
/**
|
|
1788
1807
|
* Narrows an unknown value to a {@link ColumnSpec}.
|
|
@@ -2349,7 +2368,7 @@ timeout: OptionalShape<NumberShape>;
|
|
|
2349
2368
|
* @remarks
|
|
2350
2369
|
* Carries a machine-readable `code` (see {@link import('./types.js').ToolboxErrorCode}) and
|
|
2351
2370
|
* an optional `context` bag for structured diagnostics. They are readable through an in-process
|
|
2352
|
-
* catch, including around a direct `tool.execute(args)` call. The `ToolManagerInterface`
|
|
2371
|
+
* catch, including around a direct `tool.execute(args, context)` call. The `ToolManagerInterface`
|
|
2353
2372
|
* (`@orkestrel/tool`) instead flattens every throw to the canonical tool result's top-level
|
|
2354
2373
|
* `error` message string under AGENTS' “narrow untrusted input with guards” rule.
|
|
2355
2374
|
*
|
package/dist/src/core/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type { ConversationStoreInterface } from '@orkestrel/agent';
|
|
|
10
10
|
import type { DatabaseErrorCode } from '@orkestrel/database';
|
|
11
11
|
import type { DatabaseInterface } from '@orkestrel/database';
|
|
12
12
|
import type { DriverInterface } from '@orkestrel/database';
|
|
13
|
+
import type { Guard } from '@orkestrel/contract';
|
|
13
14
|
import type { Include } from '@orkestrel/relation';
|
|
14
15
|
import type { IndexMap } from '@orkestrel/database';
|
|
15
16
|
import { JSONShape } from '@orkestrel/contract';
|
|
@@ -29,6 +30,7 @@ import { StringShape } from '@orkestrel/contract';
|
|
|
29
30
|
import type { TableInterface } from '@orkestrel/database';
|
|
30
31
|
import type { TableMap } from '@orkestrel/database';
|
|
31
32
|
import type { TerminalManagerInterface } from '@orkestrel/terminal';
|
|
33
|
+
import type { ToolContext } from '@orkestrel/tool';
|
|
32
34
|
import type { ToolInterface } from '@orkestrel/tool';
|
|
33
35
|
import type { ToolManagerInterface } from '@orkestrel/tool';
|
|
34
36
|
import { UnionShape } from '@orkestrel/contract';
|
|
@@ -571,11 +573,14 @@ export declare function createDatabaseDefinitionStore(driver?: DriverInterface):
|
|
|
571
573
|
* import { createDatabaseTool } from '@src/core'
|
|
572
574
|
*
|
|
573
575
|
* const tool = createDatabaseTool()
|
|
574
|
-
* await tool.execute(
|
|
575
|
-
*
|
|
576
|
-
*
|
|
577
|
-
*
|
|
578
|
-
* }
|
|
576
|
+
* await tool.execute(
|
|
577
|
+
* {
|
|
578
|
+
* operation: 'create',
|
|
579
|
+
* id: 'shop',
|
|
580
|
+
* tables: { products: { columns: { name: 'string', price: 'number' } } },
|
|
581
|
+
* },
|
|
582
|
+
* { signal: new AbortController().signal },
|
|
583
|
+
* )
|
|
579
584
|
* ```
|
|
580
585
|
*/
|
|
581
586
|
export declare function createDatabaseTool(options?: DatabaseToolOptions): ToolInterface;
|
|
@@ -638,8 +643,10 @@ export declare function createDescribeTool(tools: ToolManagerInterface): ToolInt
|
|
|
638
643
|
* never asserted, and a key outside the closed inferred schema is silently dropped rather than
|
|
639
644
|
* rejected (see {@link import('./types.js').EndpointToolOptions.validate}). With
|
|
640
645
|
* `validate: false`, the tool's `execute` passes through the model-supplied `args` to
|
|
641
|
-
* `definition.execute` without re-validation — the raw-passthrough opt-out.
|
|
642
|
-
*
|
|
646
|
+
* `definition.execute` without re-validation — the raw-passthrough opt-out. The execution context
|
|
647
|
+
* the tool's `execute` receives reaches `definition.execute` unchanged whichever way `args` are
|
|
648
|
+
* handled, so a handler that reads `context.signal` observes the caller's cancellation. Either way,
|
|
649
|
+
* the definition's return flows back as the tool call's plain result; a throw propagates uncaught,
|
|
643
650
|
* isolated by the `ToolManagerInterface` (`@orkestrel/tool`) into the canonical error envelope
|
|
644
651
|
* — never caught or re-wrapped here.
|
|
645
652
|
*
|
|
@@ -862,7 +869,10 @@ export declare function createPromptTool(options: PromptToolOptions): ToolInterf
|
|
|
862
869
|
* import { createRelationTool } from '@src/core'
|
|
863
870
|
*
|
|
864
871
|
* const tool = createRelationTool({ managers: { shop: manager } })
|
|
865
|
-
* await tool.execute(
|
|
872
|
+
* await tool.execute(
|
|
873
|
+
* { operation: 'load', model: 'accounts', key: 'acc1', include: ['contacts'] },
|
|
874
|
+
* { signal: new AbortController().signal },
|
|
875
|
+
* )
|
|
866
876
|
* ```
|
|
867
877
|
*/
|
|
868
878
|
export declare function createRelationTool(options: RelationToolOptions): ToolInterface;
|
|
@@ -876,7 +886,9 @@ export declare function createRelationTool(options: RelationToolOptions): ToolIn
|
|
|
876
886
|
* (`{ publish: createToolFunction(tools, 'publish') }`); the pure workflow runner has no
|
|
877
887
|
* knowledge of tools itself. The returned function executes `name` against `tools` with the
|
|
878
888
|
* task's `controller.input` as the call arguments. The adapter resolves the live tool, calls its
|
|
879
|
-
* `execute` method directly, and deep-gates the returned unknown through `parseJSONValue`.
|
|
889
|
+
* `execute` method directly, and deep-gates the returned unknown through `parseJSONValue`. The
|
|
890
|
+
* execution context it passes carries the task's own `controller.signal`, so a handler that
|
|
891
|
+
* reads `context.signal` observes the caller's cancellation.
|
|
880
892
|
* Genuine execution throws retain identity. An unregistered name or non-JSON return throws this
|
|
881
893
|
* package's typed `TOOL` `ToolboxError`.
|
|
882
894
|
*
|
|
@@ -1561,12 +1573,19 @@ export declare interface EndpointDefinition {
|
|
|
1561
1573
|
|
|
1562
1574
|
/**
|
|
1563
1575
|
* Represents the handler {@link EndpointDefinition.execute} implements — it mirrors
|
|
1564
|
-
* `@orkestrel/tool`'s `ToolOptions.execute` signature exactly
|
|
1565
|
-
*
|
|
1566
|
-
*
|
|
1567
|
-
*
|
|
1576
|
+
* `@orkestrel/tool`'s `ToolOptions.execute` signature exactly, so
|
|
1577
|
+
* {@link import('./factories.js').createEndpointTool} forwards the execution context it receives
|
|
1578
|
+
* to the handler unchanged and a handler that reads `context.signal` observes the caller's
|
|
1579
|
+
* cancellation.
|
|
1580
|
+
*
|
|
1581
|
+
* @remarks
|
|
1582
|
+
* The mirrored signature is the same `Readonly<Record<string, unknown>>` argument, the same
|
|
1583
|
+
* `ToolContext` second parameter, and the same `Promise<unknown> | unknown` return. A handler that
|
|
1584
|
+
* declares `args` alone still satisfies the type, the way a function declaring fewer parameters
|
|
1585
|
+
* than its contract does, so an endpoint definition written against the argument alone keeps
|
|
1586
|
+
* typechecking and reads no signal.
|
|
1568
1587
|
*/
|
|
1569
|
-
export declare type EndpointHandler = (args: Readonly<Record<string, unknown
|
|
1588
|
+
export declare type EndpointHandler = (args: Readonly<Record<string, unknown>>, context: ToolContext) => Promise<unknown> | unknown;
|
|
1570
1589
|
|
|
1571
1590
|
/**
|
|
1572
1591
|
* Represents the construction-time tuning for {@link import('./factories.js').createEndpointTool} —
|
|
@@ -1782,7 +1801,7 @@ export declare function isAgentFunction(value: unknown): value is AgentFunction;
|
|
|
1782
1801
|
* @param value - The value to inspect
|
|
1783
1802
|
* @returns True if `value` is `'string'`, `'integer'`, `'number'`, or `'boolean'`; false otherwise
|
|
1784
1803
|
*/
|
|
1785
|
-
export declare
|
|
1804
|
+
export declare const isColumnPrimitive: Guard<ColumnPrimitive>;
|
|
1786
1805
|
|
|
1787
1806
|
/**
|
|
1788
1807
|
* Narrows an unknown value to a {@link ColumnSpec}.
|
|
@@ -2349,7 +2368,7 @@ timeout: OptionalShape<NumberShape>;
|
|
|
2349
2368
|
* @remarks
|
|
2350
2369
|
* Carries a machine-readable `code` (see {@link import('./types.js').ToolboxErrorCode}) and
|
|
2351
2370
|
* an optional `context` bag for structured diagnostics. They are readable through an in-process
|
|
2352
|
-
* catch, including around a direct `tool.execute(args)` call. The `ToolManagerInterface`
|
|
2371
|
+
* catch, including around a direct `tool.execute(args, context)` call. The `ToolManagerInterface`
|
|
2353
2372
|
* (`@orkestrel/tool`) instead flattens every throw to the canonical tool result's top-level
|
|
2354
2373
|
* `error` message string under AGENTS' “narrow untrusted input with guards” rule.
|
|
2355
2374
|
*
|
package/dist/src/core/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { arrayShape, attempt, booleanShape, cloneJSONRecord, createContract, integerShape, isFiniteNumber, isNonEmptyString, isRecord, isString, jsonShape, literalShape, numberShape, objectShape, optionalShape, parseJSONValue, rawShape, recordShape, samplesToSchema, schemaToObject, schemaToParameters, schemaToShape, stringShape, unionShape } from "@orkestrel/contract";
|
|
1
|
+
import { arrayShape, attempt, booleanShape, cloneJSONRecord, createContract, integerShape, isArray, isBoolean, isError, isFiniteNumber, isFunction, isInstance, isNonEmptyString, isNumber, isObject, isRecord, isString, jsonShape, literalOf, literalShape, numberShape, objectShape, optionalShape, parseJSONValue, rawShape, recordShape, samplesToSchema, schemaToObject, schemaToParameters, schemaToShape, stringShape, unionShape } from "@orkestrel/contract";
|
|
2
2
|
import { MAX_TIMER_MS, createWorkflowContract } from "@orkestrel/workflow";
|
|
3
3
|
import { isTerminalError } from "@orkestrel/terminal";
|
|
4
4
|
import { createDatabase, createMemoryDriver, isDatabaseError } from "@orkestrel/database";
|
|
@@ -590,7 +590,7 @@ var INFER_TOOL_DESCRIPTION = [
|
|
|
590
590
|
* @remarks
|
|
591
591
|
* Carries a machine-readable `code` (see {@link import('./types.js').ToolboxErrorCode}) and
|
|
592
592
|
* an optional `context` bag for structured diagnostics. They are readable through an in-process
|
|
593
|
-
* catch, including around a direct `tool.execute(args)` call. The `ToolManagerInterface`
|
|
593
|
+
* catch, including around a direct `tool.execute(args, context)` call. The `ToolManagerInterface`
|
|
594
594
|
* (`@orkestrel/tool`) instead flattens every throw to the canonical tool result's top-level
|
|
595
595
|
* `error` message string under AGENTS' “narrow untrusted input with guards” rule.
|
|
596
596
|
*
|
|
@@ -632,7 +632,7 @@ var ToolboxError = class extends Error {
|
|
|
632
632
|
* ```
|
|
633
633
|
*/
|
|
634
634
|
function isToolboxError(value) {
|
|
635
|
-
return value
|
|
635
|
+
return isInstance(value, ToolboxError);
|
|
636
636
|
}
|
|
637
637
|
//#endregion
|
|
638
638
|
//#region src/core/validators.ts
|
|
@@ -644,7 +644,7 @@ function isToolboxError(value) {
|
|
|
644
644
|
*/
|
|
645
645
|
function isWorkflowLineage(value) {
|
|
646
646
|
const inspected = attempt(() => {
|
|
647
|
-
if (!
|
|
647
|
+
if (!isArray(value)) return false;
|
|
648
648
|
const seen = /* @__PURE__ */ new Set();
|
|
649
649
|
for (const [index, tag] of value.entries()) {
|
|
650
650
|
if (!isString(tag)) return false;
|
|
@@ -664,7 +664,7 @@ function isWorkflowLineage(value) {
|
|
|
664
664
|
*/
|
|
665
665
|
function isAgentFunction(value) {
|
|
666
666
|
const inspected = attempt(() => {
|
|
667
|
-
if (
|
|
667
|
+
if (!isFunction(value) || !Object.isFrozen(value)) return false;
|
|
668
668
|
const category = Reflect.getOwnPropertyDescriptor(value, "category");
|
|
669
669
|
const lineage = Reflect.getOwnPropertyDescriptor(value, "lineage");
|
|
670
670
|
return category?.value === "agent" && lineage !== void 0 && "value" in lineage && Object.isFrozen(lineage.value) && isWorkflowLineage(lineage.value);
|
|
@@ -680,7 +680,7 @@ function isAgentFunction(value) {
|
|
|
680
680
|
function isColumnSpec(value) {
|
|
681
681
|
if (isColumnPrimitive(value)) return true;
|
|
682
682
|
if (!isRecord(value)) return false;
|
|
683
|
-
return isColumnPrimitive(value.primitive) && (value.optional === void 0 ||
|
|
683
|
+
return isColumnPrimitive(value.primitive) && (value.optional === void 0 || isBoolean(value.optional));
|
|
684
684
|
}
|
|
685
685
|
/**
|
|
686
686
|
* Narrows an unknown value to a {@link ColumnPrimitive}.
|
|
@@ -688,9 +688,7 @@ function isColumnSpec(value) {
|
|
|
688
688
|
* @param value - The value to inspect
|
|
689
689
|
* @returns True if `value` is `'string'`, `'integer'`, `'number'`, or `'boolean'`; false otherwise
|
|
690
690
|
*/
|
|
691
|
-
|
|
692
|
-
return value === "string" || value === "integer" || value === "number" || value === "boolean";
|
|
693
|
-
}
|
|
691
|
+
var isColumnPrimitive = literalOf("string", "integer", "number", "boolean");
|
|
694
692
|
/**
|
|
695
693
|
* Narrows an unknown value to a {@link DatabaseDefinition} — a non-empty `id` and `driver`, a
|
|
696
694
|
* `tables` record whose every value is `{ columns: record of valid ColumnSpec }`, plus optional
|
|
@@ -717,9 +715,9 @@ function isDatabaseDefinition(value) {
|
|
|
717
715
|
if (value.indexes !== void 0) {
|
|
718
716
|
if (!isRecord(value.indexes)) return false;
|
|
719
717
|
for (const groups of Object.values(value.indexes)) {
|
|
720
|
-
if (!
|
|
718
|
+
if (!isArray(groups)) return false;
|
|
721
719
|
for (const group of groups) {
|
|
722
|
-
if (!
|
|
720
|
+
if (!isArray(group) || group.length === 0) return false;
|
|
723
721
|
for (const column of group) if (!isNonEmptyString(column)) return false;
|
|
724
722
|
}
|
|
725
723
|
}
|
|
@@ -1575,7 +1573,7 @@ function expandInclude(paths, depth) {
|
|
|
1575
1573
|
});
|
|
1576
1574
|
ancestors.push(branch);
|
|
1577
1575
|
const existing = branch[segment];
|
|
1578
|
-
branch =
|
|
1576
|
+
branch = isObject(existing) ? existing : {};
|
|
1579
1577
|
}
|
|
1580
1578
|
const leaf = segments[last];
|
|
1581
1579
|
if (leaf === void 0) throw new ToolboxError("TOOL", `malformed include path '${path}'`, {
|
|
@@ -2058,7 +2056,9 @@ var DatabaseResolver = class {
|
|
|
2058
2056
|
* (`{ publish: createToolFunction(tools, 'publish') }`); the pure workflow runner has no
|
|
2059
2057
|
* knowledge of tools itself. The returned function executes `name` against `tools` with the
|
|
2060
2058
|
* task's `controller.input` as the call arguments. The adapter resolves the live tool, calls its
|
|
2061
|
-
* `execute` method directly, and deep-gates the returned unknown through `parseJSONValue`.
|
|
2059
|
+
* `execute` method directly, and deep-gates the returned unknown through `parseJSONValue`. The
|
|
2060
|
+
* execution context it passes carries the task's own `controller.signal`, so a handler that
|
|
2061
|
+
* reads `context.signal` observes the caller's cancellation.
|
|
2062
2062
|
* Genuine execution throws retain identity. An unregistered name or non-JSON return throws this
|
|
2063
2063
|
* package's typed `TOOL` `ToolboxError`.
|
|
2064
2064
|
*
|
|
@@ -2083,7 +2083,7 @@ function createToolFunction(tools, name) {
|
|
|
2083
2083
|
return async (controller) => {
|
|
2084
2084
|
const tool = tools.tool(name);
|
|
2085
2085
|
if (tool === void 0) throw new ToolboxError("TOOL", `tool '${name}' is not registered`, { tool: name });
|
|
2086
|
-
const result = parseJSONValue(await tool.execute(controller.input));
|
|
2086
|
+
const result = parseJSONValue(await tool.execute(controller.input, { signal: controller.signal }));
|
|
2087
2087
|
if (result === void 0) throw new ToolboxError("TOOL", `tool '${name}' returned a non-JSON value`, { tool: name });
|
|
2088
2088
|
return result;
|
|
2089
2089
|
};
|
|
@@ -2208,7 +2208,7 @@ function createWorkflowFunctions(runner, options) {
|
|
|
2208
2208
|
const composed = {};
|
|
2209
2209
|
Object.setPrototypeOf(composed, null);
|
|
2210
2210
|
for (const [name, fn] of Object.entries(functions)) {
|
|
2211
|
-
if (
|
|
2211
|
+
if (!isFunction(fn)) throw new ToolboxError("TOOL", `workflow function '${name}' is not callable`, { function: name });
|
|
2212
2212
|
if (isAgentFunction(fn)) throw new ToolboxError("TOOL", `agent function '${name}' must be supplied through agents`, { function: name });
|
|
2213
2213
|
composed[name] = fn;
|
|
2214
2214
|
}
|
|
@@ -2337,7 +2337,7 @@ function createWorkflowTool(definition, runner, options) {
|
|
|
2337
2337
|
const owned = cloned.value;
|
|
2338
2338
|
let target;
|
|
2339
2339
|
if (Object.keys(owned).length === 0) target = definition;
|
|
2340
|
-
else if (
|
|
2340
|
+
else if (isArray(owned.steps)) {
|
|
2341
2341
|
const flat = steps.parse(owned);
|
|
2342
2342
|
target = flat === void 0 ? void 0 : expandSteps(flat);
|
|
2343
2343
|
} else {
|
|
@@ -2885,15 +2885,18 @@ function createDatabaseDefinitionStore(driver = createMemoryDriver()) {
|
|
|
2885
2885
|
* import { createDatabaseTool } from '@src/core'
|
|
2886
2886
|
*
|
|
2887
2887
|
* const tool = createDatabaseTool()
|
|
2888
|
-
* await tool.execute(
|
|
2889
|
-
*
|
|
2890
|
-
*
|
|
2891
|
-
*
|
|
2892
|
-
* }
|
|
2888
|
+
* await tool.execute(
|
|
2889
|
+
* {
|
|
2890
|
+
* operation: 'create',
|
|
2891
|
+
* id: 'shop',
|
|
2892
|
+
* tables: { products: { columns: { name: 'string', price: 'number' } } },
|
|
2893
|
+
* },
|
|
2894
|
+
* { signal: new AbortController().signal },
|
|
2895
|
+
* )
|
|
2893
2896
|
* ```
|
|
2894
2897
|
*/
|
|
2895
2898
|
function createDatabaseTool(options = {}) {
|
|
2896
|
-
if (options.timeout !== void 0 && (options.timeout < 0 || !Number.isSafeInteger(options.timeout))) throw new ToolboxError("TOOL", "database timeout must be a nonnegative safe integer", { timeout: options.timeout });
|
|
2899
|
+
if (options.timeout !== void 0 && (options.timeout < 0 || !isNumber(options.timeout) || !Number.isSafeInteger(options.timeout))) throw new ToolboxError("TOOL", "database timeout must be a nonnegative safe integer", { timeout: options.timeout });
|
|
2897
2900
|
const contract = createContract(databaseToolShape);
|
|
2898
2901
|
const parameters = schemaToParameters(contract.schema);
|
|
2899
2902
|
const handles = new Map(Object.entries(options.databases ?? {}));
|
|
@@ -2963,8 +2966,8 @@ function createDatabaseTool(options = {}) {
|
|
|
2963
2966
|
}
|
|
2964
2967
|
case "get": {
|
|
2965
2968
|
const table = (await resolver.resolve(call.id)).table(call.table);
|
|
2966
|
-
const many =
|
|
2967
|
-
const keys =
|
|
2969
|
+
const many = isArray(call.key);
|
|
2970
|
+
const keys = isArray(call.key) ? call.key : [call.key];
|
|
2968
2971
|
const rows = await table.get(keys);
|
|
2969
2972
|
return many ? { rows } : { row: rows[0] };
|
|
2970
2973
|
}
|
|
@@ -2985,30 +2988,30 @@ function createDatabaseTool(options = {}) {
|
|
|
2985
2988
|
case "aggregate": return { value: await (await resolver.resolve(call.id)).table(call.table).aggregate(call.function, call.column, normalizeQuery(call.query), read) };
|
|
2986
2989
|
case "add": {
|
|
2987
2990
|
const table = (await resolver.resolve(call.id)).table(call.table);
|
|
2988
|
-
const many =
|
|
2989
|
-
const rows =
|
|
2991
|
+
const many = isArray(call.row);
|
|
2992
|
+
const rows = isArray(call.row) ? call.row : [call.row];
|
|
2990
2993
|
const keys = await table.add(rows, read);
|
|
2991
2994
|
return many ? { keys } : { key: keys[0] };
|
|
2992
2995
|
}
|
|
2993
2996
|
case "set": {
|
|
2994
2997
|
const table = (await resolver.resolve(call.id)).table(call.table);
|
|
2995
|
-
const many =
|
|
2996
|
-
const rows =
|
|
2998
|
+
const many = isArray(call.row);
|
|
2999
|
+
const rows = isArray(call.row) ? call.row : [call.row];
|
|
2997
3000
|
const keys = await table.set(rows, read);
|
|
2998
3001
|
return many ? { keys } : { key: keys[0] };
|
|
2999
3002
|
}
|
|
3000
3003
|
case "update": {
|
|
3001
3004
|
const table = (await resolver.resolve(call.id)).table(call.table);
|
|
3002
3005
|
const changes = call.changes;
|
|
3003
|
-
const many =
|
|
3004
|
-
const keys =
|
|
3006
|
+
const many = isArray(call.key);
|
|
3007
|
+
const keys = isArray(call.key) ? call.key : [call.key];
|
|
3005
3008
|
const updated = await table.update(keys, changes, read);
|
|
3006
3009
|
return many ? { updated } : { updated: updated[0] };
|
|
3007
3010
|
}
|
|
3008
3011
|
case "remove": {
|
|
3009
3012
|
const table = (await resolver.resolve(call.id)).table(call.table);
|
|
3010
|
-
const many =
|
|
3011
|
-
const keys =
|
|
3013
|
+
const many = isArray(call.key);
|
|
3014
|
+
const keys = isArray(call.key) ? call.key : [call.key];
|
|
3012
3015
|
const removed = await table.remove(keys, read);
|
|
3013
3016
|
return many ? { removed } : { removed: removed[0] };
|
|
3014
3017
|
}
|
|
@@ -3030,7 +3033,7 @@ function createDatabaseTool(options = {}) {
|
|
|
3030
3033
|
if (isToolboxError(error)) throw error;
|
|
3031
3034
|
const code = inferDatabaseCode(error);
|
|
3032
3035
|
if (code === void 0) throw error;
|
|
3033
|
-
throw new ToolboxError("DATABASE", error
|
|
3036
|
+
throw new ToolboxError("DATABASE", isError(error) ? error.message : String(error), {
|
|
3034
3037
|
code,
|
|
3035
3038
|
operation: call.operation,
|
|
3036
3039
|
id: call.id,
|
|
@@ -3085,7 +3088,10 @@ function createDatabaseTool(options = {}) {
|
|
|
3085
3088
|
* import { createRelationTool } from '@src/core'
|
|
3086
3089
|
*
|
|
3087
3090
|
* const tool = createRelationTool({ managers: { shop: manager } })
|
|
3088
|
-
* await tool.execute(
|
|
3091
|
+
* await tool.execute(
|
|
3092
|
+
* { operation: 'load', model: 'accounts', key: 'acc1', include: ['contacts'] },
|
|
3093
|
+
* { signal: new AbortController().signal },
|
|
3094
|
+
* )
|
|
3089
3095
|
* ```
|
|
3090
3096
|
*/
|
|
3091
3097
|
function createRelationTool(options) {
|
|
@@ -3106,7 +3112,7 @@ function createRelationTool(options) {
|
|
|
3106
3112
|
switch (call.operation) {
|
|
3107
3113
|
case "load": {
|
|
3108
3114
|
const include = expandInclude(call.include, depth);
|
|
3109
|
-
if (
|
|
3115
|
+
if (isString(call.key) || isNumber(call.key)) return { row: await model.load(call.key, include) };
|
|
3110
3116
|
return { rows: await model.load(call.key, include) };
|
|
3111
3117
|
}
|
|
3112
3118
|
case "find": {
|
|
@@ -3149,7 +3155,7 @@ function createRelationTool(options) {
|
|
|
3149
3155
|
} catch (error) {
|
|
3150
3156
|
if (isToolboxError(error)) throw error;
|
|
3151
3157
|
const relation = inferRelationCode(error);
|
|
3152
|
-
if (relation !== void 0) throw new ToolboxError("RELATION", error
|
|
3158
|
+
if (relation !== void 0) throw new ToolboxError("RELATION", isError(error) ? error.message : String(error), {
|
|
3153
3159
|
code: relation,
|
|
3154
3160
|
operation: call.operation,
|
|
3155
3161
|
model: call.model,
|
|
@@ -3157,7 +3163,7 @@ function createRelationTool(options) {
|
|
|
3157
3163
|
});
|
|
3158
3164
|
const database = inferDatabaseCode(error);
|
|
3159
3165
|
if (database === void 0) throw error;
|
|
3160
|
-
throw new ToolboxError("DATABASE", error
|
|
3166
|
+
throw new ToolboxError("DATABASE", isError(error) ? error.message : String(error), {
|
|
3161
3167
|
code: database,
|
|
3162
3168
|
operation: call.operation
|
|
3163
3169
|
});
|
|
@@ -3304,8 +3310,10 @@ function createInferTool(options) {
|
|
|
3304
3310
|
* never asserted, and a key outside the closed inferred schema is silently dropped rather than
|
|
3305
3311
|
* rejected (see {@link import('./types.js').EndpointToolOptions.validate}). With
|
|
3306
3312
|
* `validate: false`, the tool's `execute` passes through the model-supplied `args` to
|
|
3307
|
-
* `definition.execute` without re-validation — the raw-passthrough opt-out.
|
|
3308
|
-
*
|
|
3313
|
+
* `definition.execute` without re-validation — the raw-passthrough opt-out. The execution context
|
|
3314
|
+
* the tool's `execute` receives reaches `definition.execute` unchanged whichever way `args` are
|
|
3315
|
+
* handled, so a handler that reads `context.signal` observes the caller's cancellation. Either way,
|
|
3316
|
+
* the definition's return flows back as the tool call's plain result; a throw propagates uncaught,
|
|
3309
3317
|
* isolated by the `ToolManagerInterface` (`@orkestrel/tool`) into the canonical error envelope
|
|
3310
3318
|
* — never caught or re-wrapped here.
|
|
3311
3319
|
*
|
|
@@ -3358,8 +3366,8 @@ function createEndpointTool(definition, options) {
|
|
|
3358
3366
|
name: definition.name,
|
|
3359
3367
|
description: definition.description,
|
|
3360
3368
|
...parameters === void 0 ? {} : { parameters },
|
|
3361
|
-
execute(args) {
|
|
3362
|
-
return definition.execute(args);
|
|
3369
|
+
execute(args, context) {
|
|
3370
|
+
return definition.execute(args, context);
|
|
3363
3371
|
}
|
|
3364
3372
|
});
|
|
3365
3373
|
const contract = createContract(schemaToShape(objectSchema));
|
|
@@ -3367,13 +3375,13 @@ function createEndpointTool(definition, options) {
|
|
|
3367
3375
|
name: definition.name,
|
|
3368
3376
|
description: definition.description,
|
|
3369
3377
|
...parameters === void 0 ? {} : { parameters },
|
|
3370
|
-
execute(args) {
|
|
3378
|
+
execute(args, context) {
|
|
3371
3379
|
const parsed = contract.parse(args);
|
|
3372
3380
|
if (parsed === void 0 || !isRecord(parsed)) throw new ToolboxError("TOOL", "malformed endpoint call arguments", {
|
|
3373
3381
|
name: definition.name,
|
|
3374
3382
|
faults: contract.explain(args)
|
|
3375
3383
|
});
|
|
3376
|
-
return definition.execute(parsed);
|
|
3384
|
+
return definition.execute(parsed, context);
|
|
3377
3385
|
}
|
|
3378
3386
|
});
|
|
3379
3387
|
}
|