@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
package/dist/src/core/index.cjs
CHANGED
|
@@ -591,7 +591,7 @@ var INFER_TOOL_DESCRIPTION = [
|
|
|
591
591
|
* @remarks
|
|
592
592
|
* Carries a machine-readable `code` (see {@link import('./types.js').ToolboxErrorCode}) and
|
|
593
593
|
* an optional `context` bag for structured diagnostics. They are readable through an in-process
|
|
594
|
-
* catch, including around a direct `tool.execute(args)` call. The `ToolManagerInterface`
|
|
594
|
+
* catch, including around a direct `tool.execute(args, context)` call. The `ToolManagerInterface`
|
|
595
595
|
* (`@orkestrel/tool`) instead flattens every throw to the canonical tool result's top-level
|
|
596
596
|
* `error` message string under AGENTS' “narrow untrusted input with guards” rule.
|
|
597
597
|
*
|
|
@@ -633,7 +633,7 @@ var ToolboxError = class extends Error {
|
|
|
633
633
|
* ```
|
|
634
634
|
*/
|
|
635
635
|
function isToolboxError(value) {
|
|
636
|
-
return value
|
|
636
|
+
return (0, _orkestrel_contract.isInstance)(value, ToolboxError);
|
|
637
637
|
}
|
|
638
638
|
//#endregion
|
|
639
639
|
//#region src/core/validators.ts
|
|
@@ -645,7 +645,7 @@ function isToolboxError(value) {
|
|
|
645
645
|
*/
|
|
646
646
|
function isWorkflowLineage(value) {
|
|
647
647
|
const inspected = (0, _orkestrel_contract.attempt)(() => {
|
|
648
|
-
if (!
|
|
648
|
+
if (!(0, _orkestrel_contract.isArray)(value)) return false;
|
|
649
649
|
const seen = /* @__PURE__ */ new Set();
|
|
650
650
|
for (const [index, tag] of value.entries()) {
|
|
651
651
|
if (!(0, _orkestrel_contract.isString)(tag)) return false;
|
|
@@ -665,7 +665,7 @@ function isWorkflowLineage(value) {
|
|
|
665
665
|
*/
|
|
666
666
|
function isAgentFunction(value) {
|
|
667
667
|
const inspected = (0, _orkestrel_contract.attempt)(() => {
|
|
668
|
-
if (
|
|
668
|
+
if (!(0, _orkestrel_contract.isFunction)(value) || !Object.isFrozen(value)) return false;
|
|
669
669
|
const category = Reflect.getOwnPropertyDescriptor(value, "category");
|
|
670
670
|
const lineage = Reflect.getOwnPropertyDescriptor(value, "lineage");
|
|
671
671
|
return category?.value === "agent" && lineage !== void 0 && "value" in lineage && Object.isFrozen(lineage.value) && isWorkflowLineage(lineage.value);
|
|
@@ -681,7 +681,7 @@ function isAgentFunction(value) {
|
|
|
681
681
|
function isColumnSpec(value) {
|
|
682
682
|
if (isColumnPrimitive(value)) return true;
|
|
683
683
|
if (!(0, _orkestrel_contract.isRecord)(value)) return false;
|
|
684
|
-
return isColumnPrimitive(value.primitive) && (value.optional === void 0 ||
|
|
684
|
+
return isColumnPrimitive(value.primitive) && (value.optional === void 0 || (0, _orkestrel_contract.isBoolean)(value.optional));
|
|
685
685
|
}
|
|
686
686
|
/**
|
|
687
687
|
* Narrows an unknown value to a {@link ColumnPrimitive}.
|
|
@@ -689,9 +689,7 @@ function isColumnSpec(value) {
|
|
|
689
689
|
* @param value - The value to inspect
|
|
690
690
|
* @returns True if `value` is `'string'`, `'integer'`, `'number'`, or `'boolean'`; false otherwise
|
|
691
691
|
*/
|
|
692
|
-
|
|
693
|
-
return value === "string" || value === "integer" || value === "number" || value === "boolean";
|
|
694
|
-
}
|
|
692
|
+
var isColumnPrimitive = (0, _orkestrel_contract.literalOf)("string", "integer", "number", "boolean");
|
|
695
693
|
/**
|
|
696
694
|
* Narrows an unknown value to a {@link DatabaseDefinition} — a non-empty `id` and `driver`, a
|
|
697
695
|
* `tables` record whose every value is `{ columns: record of valid ColumnSpec }`, plus optional
|
|
@@ -718,9 +716,9 @@ function isDatabaseDefinition(value) {
|
|
|
718
716
|
if (value.indexes !== void 0) {
|
|
719
717
|
if (!(0, _orkestrel_contract.isRecord)(value.indexes)) return false;
|
|
720
718
|
for (const groups of Object.values(value.indexes)) {
|
|
721
|
-
if (!
|
|
719
|
+
if (!(0, _orkestrel_contract.isArray)(groups)) return false;
|
|
722
720
|
for (const group of groups) {
|
|
723
|
-
if (!
|
|
721
|
+
if (!(0, _orkestrel_contract.isArray)(group) || group.length === 0) return false;
|
|
724
722
|
for (const column of group) if (!(0, _orkestrel_contract.isNonEmptyString)(column)) return false;
|
|
725
723
|
}
|
|
726
724
|
}
|
|
@@ -1576,7 +1574,7 @@ function expandInclude(paths, depth) {
|
|
|
1576
1574
|
});
|
|
1577
1575
|
ancestors.push(branch);
|
|
1578
1576
|
const existing = branch[segment];
|
|
1579
|
-
branch =
|
|
1577
|
+
branch = (0, _orkestrel_contract.isObject)(existing) ? existing : {};
|
|
1580
1578
|
}
|
|
1581
1579
|
const leaf = segments[last];
|
|
1582
1580
|
if (leaf === void 0) throw new ToolboxError("TOOL", `malformed include path '${path}'`, {
|
|
@@ -2059,7 +2057,9 @@ var DatabaseResolver = class {
|
|
|
2059
2057
|
* (`{ publish: createToolFunction(tools, 'publish') }`); the pure workflow runner has no
|
|
2060
2058
|
* knowledge of tools itself. The returned function executes `name` against `tools` with the
|
|
2061
2059
|
* task's `controller.input` as the call arguments. The adapter resolves the live tool, calls its
|
|
2062
|
-
* `execute` method directly, and deep-gates the returned unknown through `parseJSONValue`.
|
|
2060
|
+
* `execute` method directly, and deep-gates the returned unknown through `parseJSONValue`. The
|
|
2061
|
+
* execution context it passes carries the task's own `controller.signal`, so a handler that
|
|
2062
|
+
* reads `context.signal` observes the caller's cancellation.
|
|
2063
2063
|
* Genuine execution throws retain identity. An unregistered name or non-JSON return throws this
|
|
2064
2064
|
* package's typed `TOOL` `ToolboxError`.
|
|
2065
2065
|
*
|
|
@@ -2084,7 +2084,7 @@ function createToolFunction(tools, name) {
|
|
|
2084
2084
|
return async (controller) => {
|
|
2085
2085
|
const tool = tools.tool(name);
|
|
2086
2086
|
if (tool === void 0) throw new ToolboxError("TOOL", `tool '${name}' is not registered`, { tool: name });
|
|
2087
|
-
const result = (0, _orkestrel_contract.parseJSONValue)(await tool.execute(controller.input));
|
|
2087
|
+
const result = (0, _orkestrel_contract.parseJSONValue)(await tool.execute(controller.input, { signal: controller.signal }));
|
|
2088
2088
|
if (result === void 0) throw new ToolboxError("TOOL", `tool '${name}' returned a non-JSON value`, { tool: name });
|
|
2089
2089
|
return result;
|
|
2090
2090
|
};
|
|
@@ -2209,7 +2209,7 @@ function createWorkflowFunctions(runner, options) {
|
|
|
2209
2209
|
const composed = {};
|
|
2210
2210
|
Object.setPrototypeOf(composed, null);
|
|
2211
2211
|
for (const [name, fn] of Object.entries(functions)) {
|
|
2212
|
-
if (
|
|
2212
|
+
if (!(0, _orkestrel_contract.isFunction)(fn)) throw new ToolboxError("TOOL", `workflow function '${name}' is not callable`, { function: name });
|
|
2213
2213
|
if (isAgentFunction(fn)) throw new ToolboxError("TOOL", `agent function '${name}' must be supplied through agents`, { function: name });
|
|
2214
2214
|
composed[name] = fn;
|
|
2215
2215
|
}
|
|
@@ -2338,7 +2338,7 @@ function createWorkflowTool(definition, runner, options) {
|
|
|
2338
2338
|
const owned = cloned.value;
|
|
2339
2339
|
let target;
|
|
2340
2340
|
if (Object.keys(owned).length === 0) target = definition;
|
|
2341
|
-
else if (
|
|
2341
|
+
else if ((0, _orkestrel_contract.isArray)(owned.steps)) {
|
|
2342
2342
|
const flat = steps.parse(owned);
|
|
2343
2343
|
target = flat === void 0 ? void 0 : expandSteps(flat);
|
|
2344
2344
|
} else {
|
|
@@ -2886,15 +2886,18 @@ function createDatabaseDefinitionStore(driver = (0, _orkestrel_database.createMe
|
|
|
2886
2886
|
* import { createDatabaseTool } from '@src/core'
|
|
2887
2887
|
*
|
|
2888
2888
|
* const tool = createDatabaseTool()
|
|
2889
|
-
* await tool.execute(
|
|
2890
|
-
*
|
|
2891
|
-
*
|
|
2892
|
-
*
|
|
2893
|
-
* }
|
|
2889
|
+
* await tool.execute(
|
|
2890
|
+
* {
|
|
2891
|
+
* operation: 'create',
|
|
2892
|
+
* id: 'shop',
|
|
2893
|
+
* tables: { products: { columns: { name: 'string', price: 'number' } } },
|
|
2894
|
+
* },
|
|
2895
|
+
* { signal: new AbortController().signal },
|
|
2896
|
+
* )
|
|
2894
2897
|
* ```
|
|
2895
2898
|
*/
|
|
2896
2899
|
function createDatabaseTool(options = {}) {
|
|
2897
|
-
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 });
|
|
2900
|
+
if (options.timeout !== void 0 && (options.timeout < 0 || !(0, _orkestrel_contract.isNumber)(options.timeout) || !Number.isSafeInteger(options.timeout))) throw new ToolboxError("TOOL", "database timeout must be a nonnegative safe integer", { timeout: options.timeout });
|
|
2898
2901
|
const contract = (0, _orkestrel_contract.createContract)(databaseToolShape);
|
|
2899
2902
|
const parameters = (0, _orkestrel_contract.schemaToParameters)(contract.schema);
|
|
2900
2903
|
const handles = new Map(Object.entries(options.databases ?? {}));
|
|
@@ -2964,8 +2967,8 @@ function createDatabaseTool(options = {}) {
|
|
|
2964
2967
|
}
|
|
2965
2968
|
case "get": {
|
|
2966
2969
|
const table = (await resolver.resolve(call.id)).table(call.table);
|
|
2967
|
-
const many =
|
|
2968
|
-
const keys =
|
|
2970
|
+
const many = (0, _orkestrel_contract.isArray)(call.key);
|
|
2971
|
+
const keys = (0, _orkestrel_contract.isArray)(call.key) ? call.key : [call.key];
|
|
2969
2972
|
const rows = await table.get(keys);
|
|
2970
2973
|
return many ? { rows } : { row: rows[0] };
|
|
2971
2974
|
}
|
|
@@ -2986,30 +2989,30 @@ function createDatabaseTool(options = {}) {
|
|
|
2986
2989
|
case "aggregate": return { value: await (await resolver.resolve(call.id)).table(call.table).aggregate(call.function, call.column, normalizeQuery(call.query), read) };
|
|
2987
2990
|
case "add": {
|
|
2988
2991
|
const table = (await resolver.resolve(call.id)).table(call.table);
|
|
2989
|
-
const many =
|
|
2990
|
-
const rows =
|
|
2992
|
+
const many = (0, _orkestrel_contract.isArray)(call.row);
|
|
2993
|
+
const rows = (0, _orkestrel_contract.isArray)(call.row) ? call.row : [call.row];
|
|
2991
2994
|
const keys = await table.add(rows, read);
|
|
2992
2995
|
return many ? { keys } : { key: keys[0] };
|
|
2993
2996
|
}
|
|
2994
2997
|
case "set": {
|
|
2995
2998
|
const table = (await resolver.resolve(call.id)).table(call.table);
|
|
2996
|
-
const many =
|
|
2997
|
-
const rows =
|
|
2999
|
+
const many = (0, _orkestrel_contract.isArray)(call.row);
|
|
3000
|
+
const rows = (0, _orkestrel_contract.isArray)(call.row) ? call.row : [call.row];
|
|
2998
3001
|
const keys = await table.set(rows, read);
|
|
2999
3002
|
return many ? { keys } : { key: keys[0] };
|
|
3000
3003
|
}
|
|
3001
3004
|
case "update": {
|
|
3002
3005
|
const table = (await resolver.resolve(call.id)).table(call.table);
|
|
3003
3006
|
const changes = call.changes;
|
|
3004
|
-
const many =
|
|
3005
|
-
const keys =
|
|
3007
|
+
const many = (0, _orkestrel_contract.isArray)(call.key);
|
|
3008
|
+
const keys = (0, _orkestrel_contract.isArray)(call.key) ? call.key : [call.key];
|
|
3006
3009
|
const updated = await table.update(keys, changes, read);
|
|
3007
3010
|
return many ? { updated } : { updated: updated[0] };
|
|
3008
3011
|
}
|
|
3009
3012
|
case "remove": {
|
|
3010
3013
|
const table = (await resolver.resolve(call.id)).table(call.table);
|
|
3011
|
-
const many =
|
|
3012
|
-
const keys =
|
|
3014
|
+
const many = (0, _orkestrel_contract.isArray)(call.key);
|
|
3015
|
+
const keys = (0, _orkestrel_contract.isArray)(call.key) ? call.key : [call.key];
|
|
3013
3016
|
const removed = await table.remove(keys, read);
|
|
3014
3017
|
return many ? { removed } : { removed: removed[0] };
|
|
3015
3018
|
}
|
|
@@ -3031,7 +3034,7 @@ function createDatabaseTool(options = {}) {
|
|
|
3031
3034
|
if (isToolboxError(error)) throw error;
|
|
3032
3035
|
const code = inferDatabaseCode(error);
|
|
3033
3036
|
if (code === void 0) throw error;
|
|
3034
|
-
throw new ToolboxError("DATABASE", error
|
|
3037
|
+
throw new ToolboxError("DATABASE", (0, _orkestrel_contract.isError)(error) ? error.message : String(error), {
|
|
3035
3038
|
code,
|
|
3036
3039
|
operation: call.operation,
|
|
3037
3040
|
id: call.id,
|
|
@@ -3086,7 +3089,10 @@ function createDatabaseTool(options = {}) {
|
|
|
3086
3089
|
* import { createRelationTool } from '@src/core'
|
|
3087
3090
|
*
|
|
3088
3091
|
* const tool = createRelationTool({ managers: { shop: manager } })
|
|
3089
|
-
* await tool.execute(
|
|
3092
|
+
* await tool.execute(
|
|
3093
|
+
* { operation: 'load', model: 'accounts', key: 'acc1', include: ['contacts'] },
|
|
3094
|
+
* { signal: new AbortController().signal },
|
|
3095
|
+
* )
|
|
3090
3096
|
* ```
|
|
3091
3097
|
*/
|
|
3092
3098
|
function createRelationTool(options) {
|
|
@@ -3107,7 +3113,7 @@ function createRelationTool(options) {
|
|
|
3107
3113
|
switch (call.operation) {
|
|
3108
3114
|
case "load": {
|
|
3109
3115
|
const include = expandInclude(call.include, depth);
|
|
3110
|
-
if (
|
|
3116
|
+
if ((0, _orkestrel_contract.isString)(call.key) || (0, _orkestrel_contract.isNumber)(call.key)) return { row: await model.load(call.key, include) };
|
|
3111
3117
|
return { rows: await model.load(call.key, include) };
|
|
3112
3118
|
}
|
|
3113
3119
|
case "find": {
|
|
@@ -3150,7 +3156,7 @@ function createRelationTool(options) {
|
|
|
3150
3156
|
} catch (error) {
|
|
3151
3157
|
if (isToolboxError(error)) throw error;
|
|
3152
3158
|
const relation = inferRelationCode(error);
|
|
3153
|
-
if (relation !== void 0) throw new ToolboxError("RELATION", error
|
|
3159
|
+
if (relation !== void 0) throw new ToolboxError("RELATION", (0, _orkestrel_contract.isError)(error) ? error.message : String(error), {
|
|
3154
3160
|
code: relation,
|
|
3155
3161
|
operation: call.operation,
|
|
3156
3162
|
model: call.model,
|
|
@@ -3158,7 +3164,7 @@ function createRelationTool(options) {
|
|
|
3158
3164
|
});
|
|
3159
3165
|
const database = inferDatabaseCode(error);
|
|
3160
3166
|
if (database === void 0) throw error;
|
|
3161
|
-
throw new ToolboxError("DATABASE", error
|
|
3167
|
+
throw new ToolboxError("DATABASE", (0, _orkestrel_contract.isError)(error) ? error.message : String(error), {
|
|
3162
3168
|
code: database,
|
|
3163
3169
|
operation: call.operation
|
|
3164
3170
|
});
|
|
@@ -3305,8 +3311,10 @@ function createInferTool(options) {
|
|
|
3305
3311
|
* never asserted, and a key outside the closed inferred schema is silently dropped rather than
|
|
3306
3312
|
* rejected (see {@link import('./types.js').EndpointToolOptions.validate}). With
|
|
3307
3313
|
* `validate: false`, the tool's `execute` passes through the model-supplied `args` to
|
|
3308
|
-
* `definition.execute` without re-validation — the raw-passthrough opt-out.
|
|
3309
|
-
*
|
|
3314
|
+
* `definition.execute` without re-validation — the raw-passthrough opt-out. The execution context
|
|
3315
|
+
* the tool's `execute` receives reaches `definition.execute` unchanged whichever way `args` are
|
|
3316
|
+
* handled, so a handler that reads `context.signal` observes the caller's cancellation. Either way,
|
|
3317
|
+
* the definition's return flows back as the tool call's plain result; a throw propagates uncaught,
|
|
3310
3318
|
* isolated by the `ToolManagerInterface` (`@orkestrel/tool`) into the canonical error envelope
|
|
3311
3319
|
* — never caught or re-wrapped here.
|
|
3312
3320
|
*
|
|
@@ -3359,8 +3367,8 @@ function createEndpointTool(definition, options) {
|
|
|
3359
3367
|
name: definition.name,
|
|
3360
3368
|
description: definition.description,
|
|
3361
3369
|
...parameters === void 0 ? {} : { parameters },
|
|
3362
|
-
execute(args) {
|
|
3363
|
-
return definition.execute(args);
|
|
3370
|
+
execute(args, context) {
|
|
3371
|
+
return definition.execute(args, context);
|
|
3364
3372
|
}
|
|
3365
3373
|
});
|
|
3366
3374
|
const contract = (0, _orkestrel_contract.createContract)((0, _orkestrel_contract.schemaToShape)(objectSchema));
|
|
@@ -3368,13 +3376,13 @@ function createEndpointTool(definition, options) {
|
|
|
3368
3376
|
name: definition.name,
|
|
3369
3377
|
description: definition.description,
|
|
3370
3378
|
...parameters === void 0 ? {} : { parameters },
|
|
3371
|
-
execute(args) {
|
|
3379
|
+
execute(args, context) {
|
|
3372
3380
|
const parsed = contract.parse(args);
|
|
3373
3381
|
if (parsed === void 0 || !(0, _orkestrel_contract.isRecord)(parsed)) throw new ToolboxError("TOOL", "malformed endpoint call arguments", {
|
|
3374
3382
|
name: definition.name,
|
|
3375
3383
|
faults: contract.explain(args)
|
|
3376
3384
|
});
|
|
3377
|
-
return definition.execute(parsed);
|
|
3385
|
+
return definition.execute(parsed, context);
|
|
3378
3386
|
}
|
|
3379
3387
|
});
|
|
3380
3388
|
}
|