@jangts/agent-core 0.3.5 → 0.5.0
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/CHANGELOG.md +41 -0
- package/README.md +33 -31
- package/development/docs/README.en.md +2 -2
- package/development/docs/acceptance.en.md +2 -2
- package/development/docs/agent-development.en.md +1 -1
- package/development/docs/api/README.en.md +6 -2
- package/development/docs/api/README.md +4 -0
- package/development/docs/api/configuration-in-workflow.en.md +403 -0
- package/development/docs/api/configuration-in-workflow.md +403 -0
- package/development/docs/api/core.en.md +7 -7
- package/development/docs/api/core.md +6 -6
- package/development/docs/api/decorators.en.md +20 -0
- package/development/docs/api/decorators.md +20 -0
- package/development/docs/api/examples.en.md +1 -1
- package/development/docs/api/examples.md +1 -1
- package/development/docs/api/kits.en.md +22 -4
- package/development/docs/api/kits.md +22 -4
- package/development/docs/api/knowledge-answering.en.md +4 -1
- package/development/docs/api/knowledge-answering.md +4 -1
- package/development/docs/api/mock.en.md +2 -0
- package/development/docs/api/mock.md +2 -0
- package/development/docs/api/observability.en.md +37 -11
- package/development/docs/api/observability.md +64 -11
- package/development/docs/api/reference.en.md +876 -657
- package/development/docs/api/reference.md +662 -508
- package/development/docs/api/support.en.md +55 -9
- package/development/docs/api/support.md +53 -7
- package/development/docs/api/types.en.md +36 -1
- package/development/docs/api/types.md +44 -0
- package/development/docs/api/workflow-views.en.md +64 -0
- package/development/docs/api/workflow-views.md +78 -0
- package/development/docs/api/workflow.en.md +6 -2
- package/development/docs/api/workflow.md +6 -2
- package/development/docs/basic-usage.en.md +1 -1
- package/development/docs/basic-usage.md +1 -1
- package/development/docs/create-app.en.md +1 -1
- package/development/docs/examples/registration/associated.mjs +8 -0
- package/development/docs/examples/registration/independent.mjs +20 -0
- package/development/docs/examples/registration/protocol.mjs +48 -0
- package/development/docs/examples/registration/run.mjs +47 -0
- package/development/docs/examples/registration/tools.mjs +75 -0
- package/development/docs/examples/registration/workflow.mjs +109 -0
- package/development/docs/flows/knowledge-maintenance.en.md +1 -1
- package/development/docs/materials.en.md +1 -1
- package/development/docs/mechanisms.en.md +2 -2
- package/development/docs/mechanisms.md +1 -1
- package/development/docs/operations.en.md +1 -1
- package/development/docs/records.en.md +1 -1
- package/development/docs/registration.en.md +4 -4
- package/development/docs/registration.md +2 -2
- package/development/skills/agent-core-app/SKILL.md +16 -4
- package/development/skills/agent-core-app/templates/node-ts/README.md.tpl +1 -1
- package/development/skills/agent-core-app/templates/node-ts/src/catalog.ts.tpl +2 -2
- package/development/skills/agent-core-app/templates/node-ts/test/app.test.mjs.tpl +1 -1
- package/dist/cjs/capabilities/index.js +5 -12
- package/dist/cjs/capabilities/invocation.js +21 -1
- package/dist/cjs/capabilities/model.js +56 -12
- package/dist/cjs/capabilities/tool-conditions.js +65 -0
- package/dist/cjs/capabilities/tool-runtime.js +18 -4
- package/dist/cjs/capabilities/tools.js +12 -17
- package/dist/cjs/context/audit.js +5 -8
- package/dist/cjs/context/index.js +3 -4
- package/dist/cjs/diagnostics/index.js +51 -3
- package/dist/cjs/diagnostics/native-sub-flow.js +106 -0
- package/dist/cjs/diagnostics/sub-flow.js +278 -32
- package/dist/cjs/execution/engine.js +3 -2
- package/dist/cjs/execution/events.js +5 -5
- package/dist/cjs/execution/reporting.js +18 -28
- package/dist/cjs/execution/workflow-chain.js +211 -0
- package/dist/cjs/execution/workflow-graph.js +72 -0
- package/dist/cjs/execution/workflow.js +34 -6
- package/dist/cjs/index.js +21 -17
- package/dist/cjs/kits/aggregation.js +17 -14
- package/dist/cjs/kits/answering/checks.js +2 -1
- package/dist/cjs/kits/answering/flow.js +24 -21
- package/dist/cjs/kits/answering/tasks.js +30 -25
- package/dist/cjs/kits/delivery.js +36 -24
- package/dist/cjs/kits/domains/catalog.js +113 -0
- package/dist/cjs/kits/domains/index.js +20 -0
- package/dist/cjs/kits/{intents → domains}/registry.js +77 -31
- package/dist/cjs/kits/{intents → domains}/scopes.js +21 -21
- package/dist/cjs/kits/index.js +14 -13
- package/dist/cjs/kits/knowledge/catalog.js +33 -30
- package/dist/cjs/kits/policies.js +3 -2
- package/dist/cjs/kits/presentation/formats.js +110 -0
- package/dist/cjs/kits/presentation/index.js +10 -5
- package/dist/cjs/kits/presentation/outputs.js +2 -1
- package/dist/cjs/kits/reflection.js +2 -2
- package/dist/cjs/kits/retrieval.js +7 -1
- package/dist/cjs/kits/text-blocks.js +101 -0
- package/dist/cjs/kits/tools.js +247 -158
- package/dist/cjs/model/decision-retry.js +2 -1
- package/dist/cjs/model/index.js +2 -6
- package/dist/cjs/model/interactions/calls.js +61 -0
- package/dist/cjs/model/interactions/json-object.js +11 -11
- package/dist/cjs/model/interactions/native-functions.js +17 -23
- package/dist/cjs/model/message-diagnostics.js +13 -3
- package/dist/cjs/model/options.js +2 -0
- package/dist/cjs/model/preparation.js +39 -6
- package/dist/cjs/model/runner.js +34 -5
- package/dist/cjs/model/selection-transport.js +4 -4
- package/dist/cjs/model/token-budget.js +3 -0
- package/dist/cjs/model/transports.js +3 -2
- package/dist/cjs/structs/index.js +7 -6
- package/dist/cjs/structs/kits/domains/scopes.js +2 -0
- package/dist/cjs/structs/kits/presentation/formats.js +2 -0
- package/dist/cjs/structs/kits/text-blocks.js +11 -0
- package/dist/cjs/structs/model/session.js +11 -0
- package/dist/cjs/structs/support/associations.js +2 -0
- package/dist/cjs/support/associations.js +79 -0
- package/dist/cjs/support/context/nodes.js +48 -45
- package/dist/cjs/support/context/processing.js +6 -3
- package/dist/cjs/support/context/snapshot.js +11 -1
- package/dist/cjs/support/decorators/index.js +45 -3
- package/dist/cjs/support/index.js +1 -0
- package/dist/cjs/support/model/capabilities.js +35 -5
- package/dist/cjs/support/model/chat-completions.js +11 -2
- package/dist/cjs/support/model/completion/calls.js +10 -56
- package/dist/cjs/support/model/preview-rules.js +11 -11
- package/dist/cjs/support/model/reply-preview.js +3 -3
- package/dist/cjs/support/model/session.js +152 -0
- package/dist/cjs/support/model/stage-transport.js +8 -8
- package/dist/cjs/support/model/transports.js +5 -2
- package/dist/cjs/support/tools.js +42 -17
- package/dist/cjs/utils/invocation.js +1 -0
- package/dist/esm/capabilities/index.d.ts +5 -10
- package/dist/esm/capabilities/index.js +5 -9
- package/dist/esm/capabilities/invocation.js +21 -1
- package/dist/esm/capabilities/model.d.ts +17 -13
- package/dist/esm/capabilities/model.js +54 -10
- package/dist/esm/capabilities/tool-conditions.d.ts +9 -0
- package/dist/esm/capabilities/tool-conditions.js +59 -0
- package/dist/esm/capabilities/tool-runtime.js +18 -4
- package/dist/esm/capabilities/tools.d.ts +3 -3
- package/dist/esm/capabilities/tools.js +12 -17
- package/dist/esm/context/audit.js +5 -8
- package/dist/esm/context/index.d.ts +3 -4
- package/dist/esm/context/index.js +3 -4
- package/dist/esm/diagnostics/index.d.ts +1 -0
- package/dist/esm/diagnostics/index.js +48 -2
- package/dist/esm/diagnostics/native-sub-flow.d.ts +94 -0
- package/dist/esm/diagnostics/native-sub-flow.js +101 -0
- package/dist/esm/diagnostics/sub-flow.d.ts +56 -4
- package/dist/esm/diagnostics/sub-flow.js +271 -32
- package/dist/esm/execution/engine.d.ts +1 -0
- package/dist/esm/execution/engine.js +3 -2
- package/dist/esm/execution/events.js +5 -5
- package/dist/esm/execution/reporting.d.ts +6 -12
- package/dist/esm/execution/reporting.js +19 -29
- package/dist/esm/execution/workflow-chain.d.ts +3 -0
- package/dist/esm/execution/workflow-chain.js +208 -0
- package/dist/esm/execution/workflow-graph.d.ts +7 -0
- package/dist/esm/execution/workflow-graph.js +68 -0
- package/dist/esm/execution/workflow.d.ts +6 -0
- package/dist/esm/execution/workflow.js +34 -6
- package/dist/esm/index.d.ts +19 -13
- package/dist/esm/index.js +18 -15
- package/dist/esm/kits/aggregation.d.ts +1 -1
- package/dist/esm/kits/aggregation.js +17 -14
- package/dist/esm/kits/answering/checks.js +2 -1
- package/dist/esm/kits/answering/flow.js +24 -21
- package/dist/esm/kits/answering/tasks.d.ts +6 -6
- package/dist/esm/kits/answering/tasks.js +30 -25
- package/dist/esm/kits/delivery.d.ts +0 -9
- package/dist/esm/kits/delivery.js +36 -24
- package/dist/esm/kits/domains/catalog.d.ts +42 -0
- package/dist/esm/kits/domains/catalog.js +110 -0
- package/dist/esm/kits/domains/index.d.ts +4 -0
- package/dist/esm/kits/domains/index.js +4 -0
- package/dist/esm/kits/domains/registry.d.ts +100 -0
- package/dist/esm/kits/{intents → domains}/registry.js +77 -31
- package/dist/esm/kits/{intents → domains}/scopes.d.ts +18 -18
- package/dist/esm/kits/{intents → domains}/scopes.js +21 -21
- package/dist/esm/kits/index.d.ts +6 -5
- package/dist/esm/kits/index.js +6 -5
- package/dist/esm/kits/knowledge/catalog.js +33 -30
- package/dist/esm/kits/policies.d.ts +1 -1
- package/dist/esm/kits/policies.js +3 -2
- package/dist/esm/kits/presentation/formats.d.ts +42 -0
- package/dist/esm/kits/presentation/formats.js +105 -0
- package/dist/esm/kits/presentation/index.d.ts +14 -5
- package/dist/esm/kits/presentation/index.js +10 -5
- package/dist/esm/kits/presentation/outputs.js +2 -1
- package/dist/esm/kits/reflection.js +3 -3
- package/dist/esm/kits/retrieval.js +7 -1
- package/dist/esm/kits/text-blocks.d.ts +24 -0
- package/dist/esm/kits/text-blocks.js +97 -0
- package/dist/esm/kits/tools.d.ts +69 -52
- package/dist/esm/kits/tools.js +247 -158
- package/dist/esm/model/decision-retry.d.ts +2 -0
- package/dist/esm/model/decision-retry.js +2 -1
- package/dist/esm/model/index.d.ts +2 -6
- package/dist/esm/model/index.js +2 -6
- package/dist/esm/model/interactions/calls.d.ts +40 -0
- package/dist/esm/model/interactions/calls.js +58 -0
- package/dist/esm/model/interactions/json-object.js +11 -11
- package/dist/esm/model/interactions/native-functions.js +17 -23
- package/dist/esm/model/message-diagnostics.d.ts +6 -5
- package/dist/esm/model/message-diagnostics.js +13 -3
- package/dist/esm/model/options.js +2 -0
- package/dist/esm/model/preparation.js +39 -6
- package/dist/esm/model/runner.d.ts +2 -0
- package/dist/esm/model/runner.js +34 -5
- package/dist/esm/model/selection-transport.js +4 -4
- package/dist/esm/model/token-budget.js +3 -0
- package/dist/esm/model/transports.d.ts +2 -1
- package/dist/esm/model/transports.js +3 -2
- package/dist/esm/structs/capabilities/invocation.d.ts +3 -1
- package/dist/esm/structs/capabilities/model.d.ts +42 -11
- package/dist/esm/structs/capabilities/tools.d.ts +16 -7
- package/dist/esm/structs/common.d.ts +3 -1
- package/dist/esm/structs/debug.d.ts +36 -20
- package/dist/esm/structs/execution/workflow-views.d.ts +123 -0
- package/dist/esm/structs/execution/workflow.d.ts +4 -3
- package/dist/esm/structs/index.d.ts +8 -6
- package/dist/esm/structs/index.js +7 -6
- package/dist/esm/structs/kits/answering/tasks.d.ts +2 -2
- package/dist/esm/structs/kits/{intents → domains}/catalog.d.ts +20 -20
- package/dist/esm/structs/kits/{intents → domains}/registry.d.ts +24 -21
- package/dist/esm/structs/kits/{intents → domains}/scopes.d.ts +9 -9
- package/dist/esm/structs/kits/domains/scopes.js +1 -0
- package/dist/esm/structs/kits/presentation/formats.d.ts +42 -0
- package/dist/esm/structs/kits/presentation/formats.js +1 -0
- package/dist/esm/structs/kits/text-blocks.d.ts +25 -0
- package/dist/esm/structs/kits/text-blocks.js +10 -0
- package/dist/esm/structs/kits/tools.d.ts +82 -83
- package/dist/esm/structs/model/interactions.d.ts +18 -11
- package/dist/esm/structs/model/messages.d.ts +34 -2
- package/dist/esm/structs/model/runtime.d.ts +9 -0
- package/dist/esm/structs/model/session.d.ts +29 -0
- package/dist/esm/structs/model/session.js +10 -0
- package/dist/esm/structs/support/associations.d.ts +22 -0
- package/dist/esm/structs/support/associations.js +1 -0
- package/dist/esm/structs/support/model/interactions.d.ts +2 -2
- package/dist/esm/structs/support/model/messages.d.ts +6 -13
- package/dist/esm/structs/support/tools.d.ts +23 -23
- package/dist/esm/support/associations.d.ts +26 -0
- package/dist/esm/support/associations.js +76 -0
- package/dist/esm/support/context/nodes.js +48 -45
- package/dist/esm/support/context/processing.js +6 -3
- package/dist/esm/support/context/snapshot.js +11 -1
- package/dist/esm/support/decorators/index.d.ts +13 -2
- package/dist/esm/support/decorators/index.js +40 -3
- package/dist/esm/support/decorators/pool.d.ts +6 -5
- package/dist/esm/support/decorators/types.d.ts +3 -1
- package/dist/esm/support/index.d.ts +1 -0
- package/dist/esm/support/index.js +1 -0
- package/dist/esm/support/model/capabilities.d.ts +8 -3
- package/dist/esm/support/model/capabilities.js +35 -5
- package/dist/esm/support/model/chat-completions.js +11 -2
- package/dist/esm/support/model/completion/calls.d.ts +6 -34
- package/dist/esm/support/model/completion/calls.js +8 -55
- package/dist/esm/support/model/index.d.ts +1 -1
- package/dist/esm/support/model/preview-rules.d.ts +13 -8
- package/dist/esm/support/model/preview-rules.js +11 -11
- package/dist/esm/support/model/reply-preview.d.ts +2 -2
- package/dist/esm/support/model/reply-preview.js +3 -3
- package/dist/esm/support/model/session.d.ts +61 -0
- package/dist/esm/support/model/session.js +148 -0
- package/dist/esm/support/model/stage-transport.d.ts +1 -1
- package/dist/esm/support/model/stage-transport.js +9 -9
- package/dist/esm/support/model/transports.d.ts +2 -0
- package/dist/esm/support/model/transports.js +2 -1
- package/dist/esm/support/tools.d.ts +11 -3
- package/dist/esm/support/tools.js +43 -18
- package/dist/esm/utils/catalog.d.ts +1 -1
- package/dist/esm/utils/invocation.d.ts +1 -0
- package/dist/esm/utils/invocation.js +1 -0
- package/package.json +20 -6
- package/dist/cjs/execution/index.js +0 -30
- package/dist/cjs/kits/intents/catalog.js +0 -82
- package/dist/cjs/kits/intents/index.js +0 -35
- package/dist/cjs/utils/debug.js +0 -30
- package/dist/esm/execution/index.d.ts +0 -11
- package/dist/esm/execution/index.js +0 -11
- package/dist/esm/kits/intents/catalog.d.ts +0 -39
- package/dist/esm/kits/intents/catalog.js +0 -79
- package/dist/esm/kits/intents/index.d.ts +0 -22
- package/dist/esm/kits/intents/index.js +0 -18
- package/dist/esm/kits/intents/registry.d.ts +0 -88
- package/dist/esm/utils/debug.d.ts +0 -27
- package/dist/esm/utils/debug.js +0 -27
- /package/dist/cjs/structs/{kits/intents/catalog.js → execution/workflow-views.js} +0 -0
- /package/dist/cjs/structs/kits/{intents/registry.js → domains/catalog.js} +0 -0
- /package/dist/cjs/structs/kits/{intents/scopes.js → domains/registry.js} +0 -0
- /package/dist/esm/structs/{kits/intents/catalog.js → execution/workflow-views.js} +0 -0
- /package/dist/esm/structs/kits/{intents/registry.js → domains/catalog.js} +0 -0
- /package/dist/esm/structs/kits/{intents/scopes.js → domains/registry.js} +0 -0
package/dist/cjs/kits/tools.js
CHANGED
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Tools = exports.ToolLifecycleRegistry = void 0;
|
|
4
4
|
/**
|
|
5
|
-
* Tools Kit: a lifecycle registry for
|
|
5
|
+
* Tools Kit: a lifecycle registry for App-declared tools.
|
|
6
6
|
*
|
|
7
7
|
* Place in the package: an optional App-side library for tools that need more than a plain
|
|
8
|
-
* definition — availability,
|
|
8
|
+
* definition — availability, one lifecycle hook set, output ownership, context fields, task rules
|
|
9
9
|
* and delivery hooks. Actual invocation is delegated to Core (`ToolRegistry` and
|
|
10
10
|
* `executeInvocation`); domain predicates, phase names and vocabulary stay App configuration.
|
|
11
11
|
*
|
|
12
|
+
* A tool claims an invocation through `lifecycle.id` and, when a node dispatches by name, a
|
|
13
|
+
* delegate id through `delegate`. Both indexes live here, so dispatch is one lookup.
|
|
14
|
+
*
|
|
12
15
|
* Exports: `ToolLifecycleRegistry` (also exported as `Tools`) and the tool lifecycle types.
|
|
13
16
|
*/
|
|
14
17
|
const synchronous_js_1 = require("../utils/synchronous.js");
|
|
@@ -18,12 +21,34 @@ const tools_js_1 = require("../capabilities/tools.js");
|
|
|
18
21
|
const invocation_js_2 = require("../capabilities/invocation.js");
|
|
19
22
|
const protocol_registry_js_1 = require("../utils/protocol-registry.js");
|
|
20
23
|
const registration_js_1 = require("../utils/registration.js");
|
|
24
|
+
const model_js_1 = require("../capabilities/model.js");
|
|
25
|
+
const tool_conditions_js_1 = require("../capabilities/tool-conditions.js");
|
|
26
|
+
/** Hooks that must finish with `undefined`; every other hook only rejects thenables. */
|
|
27
|
+
const assertionHooks = ['authorize', 'inspect', 'finalize'];
|
|
28
|
+
/** Every hook a lifecycle block may declare, in binding order. */
|
|
29
|
+
const lifecycleHooks = [
|
|
30
|
+
'call',
|
|
31
|
+
'authorize',
|
|
32
|
+
'resume',
|
|
33
|
+
'complete',
|
|
34
|
+
'inspect',
|
|
35
|
+
'finalize',
|
|
36
|
+
'rules',
|
|
37
|
+
'modelFields',
|
|
38
|
+
'visibleText',
|
|
39
|
+
'reviewDraft',
|
|
40
|
+
'composition',
|
|
41
|
+
'recoveryContext',
|
|
42
|
+
'projectContext',
|
|
43
|
+
'missingInteractionAllowed',
|
|
44
|
+
'supportsGoal',
|
|
45
|
+
];
|
|
21
46
|
/** Pin contract methods and configuration without cloning the App services they use. */
|
|
22
47
|
function snapshotLifecycleOptions(options) {
|
|
23
|
-
const { receiver, execution, errors, registration,
|
|
24
|
-
if (typeof
|
|
25
|
-
throw new TypeError('An
|
|
26
|
-
const { kinds, isValidId, audiences, effects,
|
|
48
|
+
const { receiver, execution, errors, registration, invocationId, outputs, modelOutputs, unavailableInvocation, forbidden, contextFragment, goalIds, diagnostics, signal, journal, checkpoint, receipt, receiptError, } = options;
|
|
49
|
+
if (typeof goalIds !== 'function')
|
|
50
|
+
throw new TypeError('An goalIds provider is required');
|
|
51
|
+
const { kinds, isValidId, audiences, effects, goalExists, protocolVersion, tags, invalidTool, invalidInvocation, } = registration;
|
|
27
52
|
return Object.freeze({
|
|
28
53
|
receiver: receiver?.bind(options),
|
|
29
54
|
execution: execution && Object.freeze({ signal: execution.signal, diagnostics: execution.diagnostics }),
|
|
@@ -37,7 +62,7 @@ function snapshotLifecycleOptions(options) {
|
|
|
37
62
|
audiences: Object.freeze([...audiences]),
|
|
38
63
|
effects: Object.freeze([...effects]),
|
|
39
64
|
isValidId: isValidId.bind(registration),
|
|
40
|
-
|
|
65
|
+
goalExists: goalExists.bind(registration),
|
|
41
66
|
protocolVersion,
|
|
42
67
|
tags: tags && Object.freeze([...tags]),
|
|
43
68
|
invalidTool: typeof invalidTool === 'function' ? invalidTool.bind(registration) : invalidTool,
|
|
@@ -45,13 +70,13 @@ function snapshotLifecycleOptions(options) {
|
|
|
45
70
|
? invalidInvocation.bind(registration)
|
|
46
71
|
: invalidInvocation,
|
|
47
72
|
}),
|
|
48
|
-
|
|
73
|
+
invocationId: invocationId.bind(options),
|
|
49
74
|
outputs: outputs.bind(options),
|
|
50
75
|
modelOutputs: modelOutputs?.bind(options),
|
|
51
|
-
|
|
76
|
+
unavailableInvocation: unavailableInvocation?.bind(options),
|
|
52
77
|
forbidden: forbidden?.bind(options),
|
|
53
78
|
contextFragment: contextFragment.bind(options),
|
|
54
|
-
|
|
79
|
+
goalIds: goalIds.bind(options),
|
|
55
80
|
diagnostics: diagnostics?.bind(options),
|
|
56
81
|
signal: signal?.bind(options),
|
|
57
82
|
journal: journal?.bind(options),
|
|
@@ -60,18 +85,38 @@ function snapshotLifecycleOptions(options) {
|
|
|
60
85
|
receiptError: receiptError?.bind(options),
|
|
61
86
|
});
|
|
62
87
|
}
|
|
88
|
+
/** Bind every declared hook to its owner and freeze the result. */
|
|
89
|
+
function bindLifecycle(value) {
|
|
90
|
+
return Object.freeze({
|
|
91
|
+
...(0, registration_js_1.registrationData)(value, [...lifecycleHooks, 'id', 'protocol']),
|
|
92
|
+
id: value.id,
|
|
93
|
+
protocol: value.protocol,
|
|
94
|
+
...Object.fromEntries(lifecycleHooks.map((key) => {
|
|
95
|
+
const handler = value[key];
|
|
96
|
+
return [
|
|
97
|
+
key,
|
|
98
|
+
typeof handler === 'function'
|
|
99
|
+
? (...args) => (assertionHooks.includes(key) ? synchronous_js_1.assertion : synchronous_js_1.synchronous)(handler.apply(value, args), `Tool lifecycle ${key} must finish synchronously with the declared result`)
|
|
100
|
+
: handler,
|
|
101
|
+
];
|
|
102
|
+
})),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
63
105
|
/**
|
|
64
|
-
* Registry of tools whose lifecycle, protocols and contributions
|
|
106
|
+
* Registry of tools whose lifecycle, protocols and context contributions the App declares.
|
|
65
107
|
*
|
|
66
108
|
* Registration is only possible before `seal()`; afterwards the catalog is read-only, so a run
|
|
67
|
-
* cannot change which tools exist. Every
|
|
68
|
-
*
|
|
109
|
+
* cannot change which tools exist. Every hook is optional and is applied in registration order,
|
|
110
|
+
* which is why `registerAll` preserves iteration order.
|
|
69
111
|
*/
|
|
70
112
|
class ToolLifecycleRegistry {
|
|
71
113
|
tools;
|
|
72
114
|
registered = new Map();
|
|
73
115
|
sources = new Map();
|
|
116
|
+
/** Tools that own an invocation id; dispatch by decision next reads this index. */
|
|
74
117
|
invocations = new Map();
|
|
118
|
+
/** Tools that answer a delegate id; dispatch by node reads this index. */
|
|
119
|
+
delegateIndex = new Map();
|
|
75
120
|
normalizer;
|
|
76
121
|
finalizer;
|
|
77
122
|
sealed = false;
|
|
@@ -82,7 +127,7 @@ class ToolLifecycleRegistry {
|
|
|
82
127
|
/**
|
|
83
128
|
* @param options - Receiver, execution context, error wording, registration policy, protocol
|
|
84
129
|
* providers and optional journal/receipt ports; contract methods are bound to their owner.
|
|
85
|
-
* @throws TypeError When no `
|
|
130
|
+
* @throws TypeError When no `goalIds` provider is supplied.
|
|
86
131
|
*/
|
|
87
132
|
constructor(options) {
|
|
88
133
|
this.options = snapshotLifecycleOptions(options);
|
|
@@ -92,6 +137,7 @@ class ToolLifecycleRegistry {
|
|
|
92
137
|
});
|
|
93
138
|
this.diagnostics = this.options.execution?.diagnostics;
|
|
94
139
|
this.invocationPorts = Object.freeze({
|
|
140
|
+
logger: this.options.logger,
|
|
95
141
|
diagnostics: this.options.diagnostics ?? (() => this.diagnostics),
|
|
96
142
|
signal: this.options.signal,
|
|
97
143
|
journal: this.options.journal,
|
|
@@ -116,17 +162,31 @@ class ToolLifecycleRegistry {
|
|
|
116
162
|
* hooks must return `void` synchronously, while the remaining handlers are checked for
|
|
117
163
|
* accidental thenables only.
|
|
118
164
|
*
|
|
119
|
-
* @param input - Tool definition with identity, audience, effect and its
|
|
165
|
+
* @param input - Tool definition with identity, audience, effect and its hooks.
|
|
120
166
|
* @returns This registry, for chaining.
|
|
121
167
|
* @throws A configured registration error for a sealed registry, invalid identity,
|
|
122
|
-
* description, audience, effect,
|
|
123
|
-
* incomplete
|
|
168
|
+
* description, audience, effect, goal ids, missing handlers, duplicate tool id,
|
|
169
|
+
* duplicate delegate id, incomplete lifecycle contract, protocol version mismatch or
|
|
170
|
+
* duplicate invocation id.
|
|
124
171
|
*/
|
|
125
172
|
register(input) {
|
|
126
|
-
const { id, kind, description, audience, effect,
|
|
173
|
+
const { id, kind, description, audience, effect, goalIds, delegate, lifecycle, parseInput: inputParser, parseOutput: outputParser, active: availability, execute, debugSteps, } = input;
|
|
127
174
|
const parseInput = inputParser?.bind(input), parseOutput = outputParser?.bind(input);
|
|
128
|
-
const available = availability
|
|
129
|
-
const
|
|
175
|
+
const available = typeof availability === 'function' ? availability.bind(input) : availability;
|
|
176
|
+
const frozenGoalIds = Array.isArray(goalIds) ? Object.freeze([...goalIds]) : goalIds;
|
|
177
|
+
// Validate the declaration before projecting it into a model tool: a sealed or invalid
|
|
178
|
+
// registration must report its configured error instead of a schema-projection failure.
|
|
179
|
+
this.assertRegistration(input, { parseInput, parseOutput, execute });
|
|
180
|
+
const modelTool = new model_js_1.ModelToolRegistry([
|
|
181
|
+
{
|
|
182
|
+
id,
|
|
183
|
+
description,
|
|
184
|
+
inputSchema: input.inputSchema ?? { jsonSchema: { type: 'object' }, parse: parseInput },
|
|
185
|
+
resolve: input.resolve?.bind(input) ?? ((value) => ({ toolId: id, input: value })),
|
|
186
|
+
active: typeof input.active === 'function' ? input.active.bind(input) : input.active,
|
|
187
|
+
asIntent: typeof input.asIntent === 'function' ? input.asIntent.bind(input) : input.asIntent,
|
|
188
|
+
},
|
|
189
|
+
]).require(id);
|
|
130
190
|
const tool = {
|
|
131
191
|
...(0, registration_js_1.registrationData)(input, [
|
|
132
192
|
'id',
|
|
@@ -134,148 +194,148 @@ class ToolLifecycleRegistry {
|
|
|
134
194
|
'description',
|
|
135
195
|
'audience',
|
|
136
196
|
'effect',
|
|
137
|
-
'
|
|
138
|
-
'
|
|
139
|
-
'
|
|
197
|
+
'goalIds',
|
|
198
|
+
'delegate',
|
|
199
|
+
'lifecycle',
|
|
140
200
|
'parseInput',
|
|
141
201
|
'parseOutput',
|
|
142
202
|
'execute',
|
|
143
203
|
'debugSteps',
|
|
144
|
-
'
|
|
204
|
+
'active',
|
|
145
205
|
]),
|
|
206
|
+
...modelTool,
|
|
146
207
|
id,
|
|
147
208
|
kind,
|
|
148
209
|
description,
|
|
149
210
|
audience,
|
|
150
211
|
effect,
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
212
|
+
delegate,
|
|
213
|
+
lifecycle,
|
|
214
|
+
goalIds: frozenGoalIds,
|
|
154
215
|
parseInput,
|
|
155
216
|
parseOutput,
|
|
156
217
|
debugSteps: debugSteps?.bind(input),
|
|
157
218
|
execute: execute?.bind(input),
|
|
158
|
-
|
|
159
|
-
? (context) => (0, synchronous_js_1.booleanResult)(available(context), 'Tool availability must be synchronous', 'Tool availability must return boolean')
|
|
160
|
-
: undefined,
|
|
219
|
+
active: available,
|
|
161
220
|
};
|
|
162
|
-
const bindMethods = (value, keys, data = {}) => Object.freeze({
|
|
163
|
-
...(0, registration_js_1.registrationData)(value, [...keys, ...Reflect.ownKeys(data)]),
|
|
164
|
-
...data,
|
|
165
|
-
...Object.fromEntries(keys.map((key) => {
|
|
166
|
-
const handler = value[key];
|
|
167
|
-
return [
|
|
168
|
-
key,
|
|
169
|
-
typeof handler === 'function'
|
|
170
|
-
? (...args) => (['authorize', 'inspect', 'finalize'].includes(String(key))
|
|
171
|
-
? synchronous_js_1.assertion
|
|
172
|
-
: synchronous_js_1.synchronous)(handler.apply(value, args), `Tool lifecycle ${String(key)} must finish synchronously with the declared result`)
|
|
173
|
-
: handler,
|
|
174
|
-
];
|
|
175
|
-
})),
|
|
176
|
-
});
|
|
177
221
|
const registered = Object.freeze({
|
|
178
222
|
...tool,
|
|
179
|
-
...(
|
|
180
|
-
? {
|
|
181
|
-
invocation: bindMethods(invocation, ['call', 'inspect', 'authorize', 'resume', 'complete'], { step: invocation.step, protocol: invocation.protocol }),
|
|
182
|
-
}
|
|
183
|
-
: {}),
|
|
184
|
-
...(contribution
|
|
185
|
-
? {
|
|
186
|
-
contribution: bindMethods(contribution, [
|
|
187
|
-
'composition',
|
|
188
|
-
'inspect',
|
|
189
|
-
'recoveryContext',
|
|
190
|
-
'projectContext',
|
|
191
|
-
'visibleText',
|
|
192
|
-
'reviewDraft',
|
|
193
|
-
'finalize',
|
|
194
|
-
'missingInteractionAllowed',
|
|
195
|
-
'rules',
|
|
196
|
-
'modelFields',
|
|
197
|
-
'supportsIntent',
|
|
198
|
-
]),
|
|
199
|
-
}
|
|
200
|
-
: {}),
|
|
223
|
+
...(lifecycle ? { lifecycle: bindLifecycle(lifecycle) } : {}),
|
|
201
224
|
});
|
|
202
|
-
return this.install(input, registered);
|
|
225
|
+
return this.install(input, registered, true);
|
|
203
226
|
}
|
|
204
|
-
|
|
205
|
-
|
|
227
|
+
/** Validate one declaration in the fixed order documented by `register`. */
|
|
228
|
+
assertRegistration(input, handlers) {
|
|
206
229
|
const policy = this.options.registration;
|
|
207
230
|
const identityPredicate = policy.isValidId;
|
|
208
231
|
const isValidId = () => (0, synchronous_js_1.booleanResult)(identityPredicate(input), 'Tool identity predicates must be synchronous', 'Tool identity predicates must return boolean');
|
|
209
232
|
const invalid = policy.invalidTool ?? 'Invalid registered tool';
|
|
210
233
|
const invalidInvocation = policy.invalidInvocation ?? 'Invalid or duplicate tool invocation';
|
|
234
|
+
const { lifecycle } = input;
|
|
235
|
+
// A lifecycle block may declare hooks only. Declaring any invocation part makes all three
|
|
236
|
+
// required, so a partial declaration fails instead of silently never running.
|
|
237
|
+
const ownsInvocation = !!lifecycle &&
|
|
238
|
+
(lifecycle.id !== undefined ||
|
|
239
|
+
lifecycle.protocol !== undefined ||
|
|
240
|
+
lifecycle.call !== undefined);
|
|
241
|
+
const { parseInput, parseOutput, execute } = handlers;
|
|
211
242
|
(0, rules_js_1.breakWhile)([
|
|
243
|
+
{ occur: () => this.sealed, error: 'Tool registry is sealed', tags: ['sealed'] },
|
|
212
244
|
{
|
|
213
|
-
occur: [() => !policy.kinds.includes(
|
|
245
|
+
occur: [() => !policy.kinds.includes(input.kind), () => !isValidId()],
|
|
214
246
|
error: invalid,
|
|
215
247
|
tags: ['identity'],
|
|
216
248
|
},
|
|
217
|
-
{
|
|
249
|
+
{
|
|
250
|
+
occur: () => typeof input.description !== 'string' || !input.description.trim(),
|
|
251
|
+
error: invalid,
|
|
252
|
+
tags: ['description'],
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
occur: () => input.active !== undefined &&
|
|
256
|
+
typeof input.active !== 'boolean' &&
|
|
257
|
+
typeof input.active !== 'function',
|
|
258
|
+
error: invalid,
|
|
259
|
+
tags: ['active'],
|
|
260
|
+
},
|
|
218
261
|
{
|
|
219
262
|
occur: [
|
|
220
|
-
() => !policy.audiences.includes(
|
|
221
|
-
() => !policy.effects.includes(
|
|
263
|
+
() => !policy.audiences.includes(input.audience),
|
|
264
|
+
() => !policy.effects.includes(input.effect),
|
|
222
265
|
],
|
|
223
266
|
error: invalid,
|
|
224
267
|
tags: ['execution-contract'],
|
|
225
268
|
},
|
|
226
269
|
{
|
|
227
270
|
occur: [
|
|
228
|
-
() =>
|
|
229
|
-
() =>
|
|
230
|
-
() =>
|
|
231
|
-
|
|
232
|
-
() =>
|
|
271
|
+
() => input.goalIds !== 'all' && !Array.isArray(input.goalIds),
|
|
272
|
+
() => input.goalIds !== 'all' && !input.goalIds.length,
|
|
273
|
+
() => input.goalIds !== 'all' &&
|
|
274
|
+
input.goalIds.some((goal) => !(0, synchronous_js_1.booleanResult)(policy.goalExists(goal), 'Goal lookup must return boolean synchronously')),
|
|
275
|
+
() => input.goalIds !== 'all' && new Set(input.goalIds).size !== input.goalIds.length,
|
|
233
276
|
],
|
|
234
277
|
error: invalid,
|
|
235
|
-
tags: ['
|
|
278
|
+
tags: ['goals'],
|
|
236
279
|
},
|
|
237
280
|
{
|
|
238
|
-
occur: () => ![
|
|
281
|
+
occur: () => ![parseInput, parseOutput, execute].every((handler) => typeof handler === 'function'),
|
|
239
282
|
error: invalid,
|
|
240
283
|
tags: ['handlers'],
|
|
241
284
|
},
|
|
242
285
|
{
|
|
243
|
-
occur: () => this.tools.has(
|
|
244
|
-
error: () => new Error(`Duplicate registered tool: ${
|
|
286
|
+
occur: () => this.tools.has(input.id),
|
|
287
|
+
error: () => new Error(`Duplicate registered tool: ${input.id}`),
|
|
245
288
|
tags: ['duplicate-name'],
|
|
246
289
|
},
|
|
247
290
|
{
|
|
248
|
-
occur: () =>
|
|
291
|
+
occur: () => !!input.delegate && this.delegateIndex.has(input.delegate),
|
|
292
|
+
error: () => new Error(`Duplicate registered delegate: ${input.delegate}`),
|
|
293
|
+
tags: ['delegate', 'duplicate-id'],
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
occur: () => ownsInvocation && !lifecycle.id,
|
|
249
297
|
error: invalidInvocation,
|
|
250
|
-
tags: ['
|
|
298
|
+
tags: ['lifecycle', 'identity'],
|
|
251
299
|
},
|
|
252
300
|
{
|
|
253
|
-
occur:
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
301
|
+
occur: () => ownsInvocation && typeof lifecycle.call !== 'function',
|
|
302
|
+
error: invalidInvocation,
|
|
303
|
+
tags: ['lifecycle', 'contract'],
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
occur: () => ownsInvocation && typeof lifecycle.protocol?.keys !== 'function',
|
|
257
307
|
error: invalidInvocation,
|
|
258
|
-
tags: ['
|
|
308
|
+
tags: ['lifecycle', 'contract'],
|
|
259
309
|
},
|
|
260
310
|
{
|
|
261
|
-
occur: () =>
|
|
311
|
+
occur: () => ownsInvocation &&
|
|
262
312
|
policy.protocolVersion !== undefined &&
|
|
263
|
-
|
|
264
|
-
|
|
313
|
+
lifecycle.protocol?.version !== undefined &&
|
|
314
|
+
lifecycle.protocol.version !== policy.protocolVersion,
|
|
265
315
|
error: invalidInvocation,
|
|
266
|
-
tags: ['
|
|
316
|
+
tags: ['lifecycle', 'version'],
|
|
267
317
|
},
|
|
268
318
|
{
|
|
269
|
-
occur: () =>
|
|
319
|
+
occur: () => !!lifecycle?.id && this.invocations.has(lifecycle.id),
|
|
270
320
|
error: invalidInvocation,
|
|
271
|
-
tags: ['
|
|
321
|
+
tags: ['lifecycle', 'duplicate-id'],
|
|
272
322
|
},
|
|
273
323
|
], policy.tags);
|
|
324
|
+
}
|
|
325
|
+
install(input, tool, validated = false) {
|
|
326
|
+
if (!validated)
|
|
327
|
+
this.assertRegistration(input, {
|
|
328
|
+
parseInput: tool.parseInput,
|
|
329
|
+
parseOutput: tool.parseOutput,
|
|
330
|
+
execute: tool.execute,
|
|
331
|
+
});
|
|
274
332
|
this.tools.register(tool);
|
|
275
333
|
this.registered.set(tool.id, tool);
|
|
276
334
|
this.sources.set(tool.id, input);
|
|
277
|
-
if (tool.
|
|
278
|
-
this.invocations.set(tool.
|
|
335
|
+
if (tool.lifecycle?.id)
|
|
336
|
+
this.invocations.set(tool.lifecycle.id, tool);
|
|
337
|
+
if (tool.delegate)
|
|
338
|
+
this.delegateIndex.set(tool.delegate, tool);
|
|
279
339
|
return this;
|
|
280
340
|
}
|
|
281
341
|
/** Register every tool in iteration order. */
|
|
@@ -327,6 +387,10 @@ class ToolLifecycleRegistry {
|
|
|
327
387
|
values() {
|
|
328
388
|
return this.registered.values();
|
|
329
389
|
}
|
|
390
|
+
/** Whether a delegate id is claimed by a registered tool. */
|
|
391
|
+
hasDelegate(id) {
|
|
392
|
+
return this.delegateIndex.has(id);
|
|
393
|
+
}
|
|
330
394
|
/**
|
|
331
395
|
* Install the single normalization handler.
|
|
332
396
|
*
|
|
@@ -362,134 +426,142 @@ class ToolLifecycleRegistry {
|
|
|
362
426
|
return (0, synchronous_js_1.synchronous)(this.finalizer.call(receiver, receiver, decision, context), 'Tool finalization must be synchronous');
|
|
363
427
|
}
|
|
364
428
|
/**
|
|
365
|
-
*
|
|
429
|
+
* Run the invocation that answers one decision next.
|
|
430
|
+
*
|
|
431
|
+
* Delegation is the App's choice; this method only executes the tool that claimed the id, so a
|
|
432
|
+
* purely programmatic node, a model choice and a mixed pipeline all dispatch the same way.
|
|
366
433
|
*
|
|
367
434
|
* Diagnostics are swapped to the invocation's own sink for the duration of the call and
|
|
368
435
|
* restored afterwards, so nested tool calls report under the innermost scope.
|
|
369
436
|
*
|
|
370
|
-
* @param
|
|
437
|
+
* @param next - Decision next carrying the claimed delegate id in `type`.
|
|
371
438
|
* @param context - Execution context forwarded to Core's invocation executor.
|
|
372
|
-
* @throws A configured error when the
|
|
439
|
+
* @throws A configured error when the delegate is unknown or the tool is unavailable.
|
|
373
440
|
*/
|
|
374
|
-
call(
|
|
375
|
-
const tool = this.invocations.get(
|
|
441
|
+
call(next, context) {
|
|
442
|
+
const tool = this.delegateIndex.get(next.type) ?? this.invocations.get(next.type);
|
|
376
443
|
(0, rules_js_1.breakWhile)([
|
|
377
444
|
{
|
|
378
|
-
occur: () => !tool?.
|
|
379
|
-
error: () => this.options.
|
|
380
|
-
new Error(`Tool
|
|
445
|
+
occur: () => !tool?.lifecycle,
|
|
446
|
+
error: () => this.options.unavailableInvocation?.(next.type) ??
|
|
447
|
+
new Error(`Tool invocation is not registered: ${next.type}`),
|
|
381
448
|
},
|
|
382
449
|
{
|
|
383
|
-
occur: () => tool.
|
|
450
|
+
occur: () => !(0, tool_conditions_js_1.toolActive)(tool.active, context),
|
|
384
451
|
error: () => this.options.forbidden?.() ?? new Error('Tool is not available'),
|
|
385
452
|
},
|
|
386
453
|
]);
|
|
387
454
|
(0, invocation_js_2.executeInvocation)({
|
|
388
455
|
id: tool.id,
|
|
389
|
-
call: (
|
|
456
|
+
call: (input, executionContext, execution) => {
|
|
390
457
|
const previous = this.activeDiagnostics;
|
|
391
458
|
this.activeDiagnostics = execution.diagnostics;
|
|
392
459
|
try {
|
|
393
|
-
tool.
|
|
460
|
+
tool.lifecycle.call(input, executionContext, execution);
|
|
394
461
|
}
|
|
395
462
|
finally {
|
|
396
463
|
this.activeDiagnostics = previous;
|
|
397
464
|
}
|
|
398
465
|
},
|
|
399
|
-
},
|
|
466
|
+
}, next, context, this.invocationPorts);
|
|
400
467
|
}
|
|
401
|
-
/** Output protocols plus one protocol per registered invocation
|
|
468
|
+
/** Output protocols plus one protocol per registered invocation. */
|
|
402
469
|
protocols() {
|
|
403
|
-
return new protocol_registry_js_1.ProtocolRegistry([
|
|
404
|
-
...this.options.outputs(),
|
|
405
|
-
...[...this.invocations].map(([step, tool]) => [step, tool.invocation.protocol]),
|
|
406
|
-
]);
|
|
470
|
+
return new protocol_registry_js_1.ProtocolRegistry([...this.options.outputs(), ...this.invocationProtocols()]);
|
|
407
471
|
}
|
|
408
472
|
/**
|
|
409
|
-
* Protocols exposed to the model: output protocols plus
|
|
473
|
+
* Protocols exposed to the model: output protocols plus invocations whose audience is `model` and
|
|
410
474
|
* which are currently available in `context`.
|
|
411
475
|
*/
|
|
412
476
|
modelProtocols(context) {
|
|
413
477
|
return new protocol_registry_js_1.ProtocolRegistry([
|
|
414
478
|
...(this.options.modelOutputs?.(context) ?? this.options.outputs()),
|
|
415
|
-
...
|
|
416
|
-
.filter(([, tool]) => tool.audience === 'model' && (!tool.available || tool.available(context)))
|
|
417
|
-
.map(([step, tool]) => [step, tool.invocation.protocol]),
|
|
479
|
+
...this.invocationProtocols((tool) => tool.audience === 'model' && (0, tool_conditions_js_1.toolActive)(tool.active, context)),
|
|
418
480
|
]);
|
|
419
481
|
}
|
|
420
|
-
/** Whether the protocol registered for this
|
|
421
|
-
isTerminal(
|
|
422
|
-
return this.protocols().get(
|
|
482
|
+
/** Whether the protocol registered for this invocation is declared terminal. */
|
|
483
|
+
isTerminal(next) {
|
|
484
|
+
return this.protocols().get(next.type)?.terminal === true;
|
|
485
|
+
}
|
|
486
|
+
/** `[invocationId, protocol]` pairs, optionally filtered by the owning tool. */
|
|
487
|
+
invocationProtocols(keep) {
|
|
488
|
+
return [...this.invocations]
|
|
489
|
+
.filter(([, tool]) => !keep || keep(tool))
|
|
490
|
+
.map(([id, tool]) => [id, tool.lifecycle.protocol]);
|
|
423
491
|
}
|
|
424
|
-
/**
|
|
492
|
+
/**
|
|
493
|
+
* Run `inspect` for every registered tool in registration order.
|
|
494
|
+
*
|
|
495
|
+
* `inspect` belongs to the all-tools group, so the selected tool participates exactly once
|
|
496
|
+
* through the same loop rather than through a second selected-only pass.
|
|
497
|
+
*/
|
|
425
498
|
assertDecision(decision, context) {
|
|
426
499
|
for (const tool of this.registered.values())
|
|
427
|
-
tool.
|
|
428
|
-
this.selected(decision)?.invocation?.inspect?.(decision, context);
|
|
500
|
+
tool.lifecycle?.inspect?.(decision, context);
|
|
429
501
|
}
|
|
430
502
|
/** Run the selected invocation's authorization hook, if any. */
|
|
431
503
|
authorize(decision, context) {
|
|
432
|
-
this.selected(decision)?.
|
|
504
|
+
this.selected(decision)?.lifecycle?.authorize?.(decision, context);
|
|
433
505
|
}
|
|
434
506
|
/** Whether the selected invocation should resume rather than start fresh; defaults to false. */
|
|
435
507
|
resume(decision, context) {
|
|
436
|
-
const
|
|
437
|
-
return
|
|
438
|
-
? (0, synchronous_js_1.booleanResult)(
|
|
508
|
+
const lifecycle = this.selected(decision)?.lifecycle;
|
|
509
|
+
return lifecycle?.resume
|
|
510
|
+
? (0, synchronous_js_1.booleanResult)(lifecycle.resume(decision, context), 'Tool resume must return boolean synchronously')
|
|
439
511
|
: false;
|
|
440
512
|
}
|
|
441
513
|
/** Let the selected invocation rewrite the decision on completion, if it declares a hook. */
|
|
442
514
|
complete(decision, context) {
|
|
443
|
-
return this.selected(decision)?.
|
|
515
|
+
return this.selected(decision)?.lifecycle?.complete?.(decision, context);
|
|
444
516
|
}
|
|
445
|
-
/** Fold every
|
|
517
|
+
/** Fold every tool's context projection over the value, in registration order. */
|
|
446
518
|
projectContext(value) {
|
|
447
|
-
return [...this.registered.values()].reduce((current, tool) => tool.
|
|
519
|
+
return [...this.registered.values()].reduce((current, tool) => tool.lifecycle?.projectContext?.(current) ?? current, value);
|
|
448
520
|
}
|
|
449
|
-
/** Fold every
|
|
521
|
+
/** Fold every tool's visible-text transform over the text. */
|
|
450
522
|
visibleText(text, context) {
|
|
451
|
-
return [...this.registered.values()].reduce((value, tool) => tool.
|
|
523
|
+
return [...this.registered.values()].reduce((value, tool) => tool.lifecycle?.visibleText?.(value, context) ?? value, text);
|
|
452
524
|
}
|
|
453
|
-
/** Fold every
|
|
525
|
+
/** Fold every tool's review transform over the draft. */
|
|
454
526
|
reviewDraft(draft, context) {
|
|
455
|
-
return [...this.registered.values()].reduce((value, tool) => tool.
|
|
527
|
+
return [...this.registered.values()].reduce((value, tool) => tool.lifecycle?.reviewDraft?.(value, context) ?? value, draft);
|
|
456
528
|
}
|
|
457
529
|
/** Collected recovery context values; `undefined` results are omitted. */
|
|
458
530
|
recoveryContext(context) {
|
|
459
531
|
return [...this.registered.values()].flatMap((tool) => {
|
|
460
|
-
const value = tool.
|
|
532
|
+
const value = tool.lifecycle?.recoveryContext?.(context);
|
|
461
533
|
return value === undefined ? [] : [value];
|
|
462
534
|
});
|
|
463
535
|
}
|
|
464
536
|
/**
|
|
465
537
|
* The single output template that owns this delivery.
|
|
466
538
|
*
|
|
467
|
-
* @throws An error when more than one
|
|
468
|
-
*
|
|
539
|
+
* @throws An error when more than one tool claims composition, because delivery would
|
|
540
|
+
* otherwise depend on registration order.
|
|
469
541
|
*/
|
|
470
542
|
composition(context) {
|
|
471
543
|
const values = [...this.registered.values()].flatMap((tool) => {
|
|
472
|
-
const value = tool.
|
|
544
|
+
const value = tool.lifecycle?.composition?.(context);
|
|
473
545
|
return value ? [value] : [];
|
|
474
546
|
});
|
|
475
547
|
(0, rules_js_1.breakWhile)(values.length > 1, 'More than one output template owns this delivery');
|
|
476
548
|
return values[0];
|
|
477
549
|
}
|
|
478
|
-
/** Run every
|
|
550
|
+
/** Run every tool's finalize hook for the given phase. */
|
|
479
551
|
finalize(decision, context, phase) {
|
|
480
552
|
for (const tool of this.registered.values())
|
|
481
|
-
tool.
|
|
553
|
+
tool.lifecycle?.finalize?.(decision, context, phase);
|
|
482
554
|
}
|
|
483
|
-
/** Whether any
|
|
555
|
+
/** Whether any tool permits the interaction to be missing. */
|
|
484
556
|
missingInteractionAllowed(decision, context) {
|
|
485
|
-
return [...this.registered.values()].some((tool) => tool.
|
|
486
|
-
? (0, synchronous_js_1.booleanResult)(tool.
|
|
557
|
+
return [...this.registered.values()].some((tool) => tool.lifecycle?.missingInteractionAllowed
|
|
558
|
+
? (0, synchronous_js_1.booleanResult)(tool.lifecycle.missingInteractionAllowed(decision, context), 'Missing interaction predicates must return boolean synchronously')
|
|
487
559
|
: false);
|
|
488
560
|
}
|
|
489
561
|
/** Task rules ordered by their declared `order`, joined into one prompt block. */
|
|
490
562
|
taskRules(context) {
|
|
491
563
|
return [...this.registered.values()]
|
|
492
|
-
.flatMap((tool) => tool.
|
|
564
|
+
.flatMap((tool) => tool.lifecycle?.rules?.(context) ?? [])
|
|
493
565
|
.sort((left, right) => left.order - right.order)
|
|
494
566
|
.map((rule) => rule.text)
|
|
495
567
|
.filter(Boolean)
|
|
@@ -498,7 +570,7 @@ class ToolLifecycleRegistry {
|
|
|
498
570
|
/** Model-context fragments for one placement, ordered by each field's `order`. */
|
|
499
571
|
contextFields(context, placement) {
|
|
500
572
|
return [...this.registered.values()]
|
|
501
|
-
.flatMap((tool) => (tool.
|
|
573
|
+
.flatMap((tool) => (tool.lifecycle?.modelFields?.(context, placement) ?? [])
|
|
502
574
|
.filter((field) => field.placement === placement)
|
|
503
575
|
.map((field) => ({ tool, field })))
|
|
504
576
|
.sort((left, right) => left.field.order - right.field.order)
|
|
@@ -506,11 +578,25 @@ class ToolLifecycleRegistry {
|
|
|
506
578
|
}
|
|
507
579
|
/** Merged model-context values for one placement; later fragments win per key. */
|
|
508
580
|
modelFields(context, placement) {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
581
|
+
const fields = {};
|
|
582
|
+
for (const { value } of this.contextFields(context, placement)) {
|
|
583
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
584
|
+
continue;
|
|
585
|
+
for (const [key, entry] of Object.entries(value))
|
|
586
|
+
// Own data properties keep keys such as `__proto__` from rewriting the merged result's
|
|
587
|
+
// prototype, matching how context assembly writes structured fields.
|
|
588
|
+
Object.defineProperty(fields, key, {
|
|
589
|
+
value: entry,
|
|
590
|
+
enumerable: true,
|
|
591
|
+
configurable: true,
|
|
592
|
+
writable: true,
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
return fields;
|
|
596
|
+
}
|
|
597
|
+
/** A tool may veto a goal by returning `false`; silence means support. */
|
|
598
|
+
supportsGoal(intentId, context) {
|
|
599
|
+
return [...this.registered.values()].every((tool) => tool.lifecycle?.supportsGoal?.(intentId, context) !== false);
|
|
514
600
|
}
|
|
515
601
|
/**
|
|
516
602
|
* Describe registered tools, optionally limited by audience and availability.
|
|
@@ -520,19 +606,22 @@ class ToolLifecycleRegistry {
|
|
|
520
606
|
*
|
|
521
607
|
* @param audience - Audience to keep; omit to include every audience.
|
|
522
608
|
* @param context - Context for availability checks.
|
|
523
|
-
* @returns Plain metadata; `
|
|
609
|
+
* @returns Plain metadata; `goalIds: 'all'` is expanded to the current goal ids.
|
|
524
610
|
*/
|
|
525
611
|
describe(audience, context) {
|
|
526
612
|
return [...this.registered.values()]
|
|
527
613
|
.filter((tool) => (!audience || tool.audience === audience) &&
|
|
528
|
-
(
|
|
529
|
-
|
|
614
|
+
(tool.active === undefined ||
|
|
615
|
+
(typeof tool.active === 'boolean'
|
|
616
|
+
? (0, tool_conditions_js_1.toolActive)(tool.active, context)
|
|
617
|
+
: !!context && (0, tool_conditions_js_1.toolActive)(tool.active, context))))
|
|
618
|
+
.map(({ id, kind, description, audience, effect, goalIds }) => ({
|
|
530
619
|
id,
|
|
531
620
|
kind,
|
|
532
621
|
description,
|
|
533
622
|
audience,
|
|
534
623
|
effect,
|
|
535
|
-
|
|
624
|
+
goalIds: goalIds === 'all' ? [...this.options.goalIds()] : [...goalIds],
|
|
536
625
|
}));
|
|
537
626
|
}
|
|
538
627
|
/**
|
|
@@ -555,9 +644,9 @@ class ToolLifecycleRegistry {
|
|
|
555
644
|
this.tools.seal();
|
|
556
645
|
return this;
|
|
557
646
|
}
|
|
558
|
-
/** Tool that owns the invocation
|
|
647
|
+
/** Tool that owns the invocation id named by the decision, if any. */
|
|
559
648
|
selected(decision) {
|
|
560
|
-
return this.invocations.get(this.options.
|
|
649
|
+
return this.invocations.get(this.options.invocationId(decision));
|
|
561
650
|
}
|
|
562
651
|
}
|
|
563
652
|
exports.ToolLifecycleRegistry = ToolLifecycleRegistry;
|