@jangts/agent-core 0.3.6 → 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 +20 -0
- package/README.md +5 -5
- 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 +4 -2
- package/development/docs/api/README.md +2 -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/reference.en.md +508 -410
- package/development/docs/api/reference.md +508 -410
- package/development/docs/api/support.en.md +55 -9
- package/development/docs/api/support.md +53 -7
- package/development/docs/api/types.en.md +35 -1
- package/development/docs/api/types.md +43 -0
- 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 +4 -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/model.js +56 -12
- package/dist/cjs/capabilities/tool-conditions.js +65 -0
- package/dist/cjs/capabilities/tool-runtime.js +10 -3
- package/dist/cjs/context/audit.js +5 -8
- package/dist/cjs/context/index.js +3 -4
- package/dist/cjs/index.js +21 -17
- package/dist/cjs/kits/answering/tasks.js +5 -5
- 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/presentation/formats.js +110 -0
- package/dist/cjs/kits/presentation/index.js +10 -5
- package/dist/cjs/kits/reflection.js +2 -2
- package/dist/cjs/kits/text-blocks.js +101 -0
- package/dist/cjs/kits/tools.js +246 -158
- 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 +14 -0
- 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/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/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/esm/capabilities/index.d.ts +5 -10
- package/dist/esm/capabilities/index.js +5 -9
- 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 +10 -3
- package/dist/esm/capabilities/tools.d.ts +3 -3
- 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/index.d.ts +19 -13
- package/dist/esm/index.js +18 -15
- package/dist/esm/kits/answering/tasks.d.ts +6 -6
- package/dist/esm/kits/answering/tasks.js +5 -5
- 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/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/reflection.js +3 -3
- 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 +246 -158
- 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.js +14 -0
- 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 +1 -1
- package/dist/esm/structs/capabilities/model.d.ts +42 -11
- package/dist/esm/structs/capabilities/tools.d.ts +9 -4
- package/dist/esm/structs/common.d.ts +1 -1
- package/dist/esm/structs/index.d.ts +7 -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/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 +7 -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/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/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/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/cjs/structs/kits/{intents → domains}/catalog.js +0 -0
- /package/dist/cjs/structs/kits/{intents → domains}/registry.js +0 -0
- /package/dist/cjs/structs/kits/{intents → domains}/scopes.js +0 -0
- /package/dist/esm/structs/kits/{intents → domains}/catalog.js +0 -0
- /package/dist/esm/structs/kits/{intents → domains}/registry.js +0 -0
- /package/dist/esm/structs/kits/{intents → domains}/scopes.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);
|
|
@@ -117,17 +162,31 @@ class ToolLifecycleRegistry {
|
|
|
117
162
|
* hooks must return `void` synchronously, while the remaining handlers are checked for
|
|
118
163
|
* accidental thenables only.
|
|
119
164
|
*
|
|
120
|
-
* @param input - Tool definition with identity, audience, effect and its
|
|
165
|
+
* @param input - Tool definition with identity, audience, effect and its hooks.
|
|
121
166
|
* @returns This registry, for chaining.
|
|
122
167
|
* @throws A configured registration error for a sealed registry, invalid identity,
|
|
123
|
-
* description, audience, effect,
|
|
124
|
-
* 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.
|
|
125
171
|
*/
|
|
126
172
|
register(input) {
|
|
127
|
-
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;
|
|
128
174
|
const parseInput = inputParser?.bind(input), parseOutput = outputParser?.bind(input);
|
|
129
|
-
const available = availability
|
|
130
|
-
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);
|
|
131
190
|
const tool = {
|
|
132
191
|
...(0, registration_js_1.registrationData)(input, [
|
|
133
192
|
'id',
|
|
@@ -135,148 +194,148 @@ class ToolLifecycleRegistry {
|
|
|
135
194
|
'description',
|
|
136
195
|
'audience',
|
|
137
196
|
'effect',
|
|
138
|
-
'
|
|
139
|
-
'
|
|
140
|
-
'
|
|
197
|
+
'goalIds',
|
|
198
|
+
'delegate',
|
|
199
|
+
'lifecycle',
|
|
141
200
|
'parseInput',
|
|
142
201
|
'parseOutput',
|
|
143
202
|
'execute',
|
|
144
203
|
'debugSteps',
|
|
145
|
-
'
|
|
204
|
+
'active',
|
|
146
205
|
]),
|
|
206
|
+
...modelTool,
|
|
147
207
|
id,
|
|
148
208
|
kind,
|
|
149
209
|
description,
|
|
150
210
|
audience,
|
|
151
211
|
effect,
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
212
|
+
delegate,
|
|
213
|
+
lifecycle,
|
|
214
|
+
goalIds: frozenGoalIds,
|
|
155
215
|
parseInput,
|
|
156
216
|
parseOutput,
|
|
157
217
|
debugSteps: debugSteps?.bind(input),
|
|
158
218
|
execute: execute?.bind(input),
|
|
159
|
-
|
|
160
|
-
? (context) => (0, synchronous_js_1.booleanResult)(available(context), 'Tool availability must be synchronous', 'Tool availability must return boolean')
|
|
161
|
-
: undefined,
|
|
219
|
+
active: available,
|
|
162
220
|
};
|
|
163
|
-
const bindMethods = (value, keys, data = {}) => Object.freeze({
|
|
164
|
-
...(0, registration_js_1.registrationData)(value, [...keys, ...Reflect.ownKeys(data)]),
|
|
165
|
-
...data,
|
|
166
|
-
...Object.fromEntries(keys.map((key) => {
|
|
167
|
-
const handler = value[key];
|
|
168
|
-
return [
|
|
169
|
-
key,
|
|
170
|
-
typeof handler === 'function'
|
|
171
|
-
? (...args) => (['authorize', 'inspect', 'finalize'].includes(String(key))
|
|
172
|
-
? synchronous_js_1.assertion
|
|
173
|
-
: synchronous_js_1.synchronous)(handler.apply(value, args), `Tool lifecycle ${String(key)} must finish synchronously with the declared result`)
|
|
174
|
-
: handler,
|
|
175
|
-
];
|
|
176
|
-
})),
|
|
177
|
-
});
|
|
178
221
|
const registered = Object.freeze({
|
|
179
222
|
...tool,
|
|
180
|
-
...(
|
|
181
|
-
? {
|
|
182
|
-
invocation: bindMethods(invocation, ['call', 'inspect', 'authorize', 'resume', 'complete'], { step: invocation.step, protocol: invocation.protocol }),
|
|
183
|
-
}
|
|
184
|
-
: {}),
|
|
185
|
-
...(contribution
|
|
186
|
-
? {
|
|
187
|
-
contribution: bindMethods(contribution, [
|
|
188
|
-
'composition',
|
|
189
|
-
'inspect',
|
|
190
|
-
'recoveryContext',
|
|
191
|
-
'projectContext',
|
|
192
|
-
'visibleText',
|
|
193
|
-
'reviewDraft',
|
|
194
|
-
'finalize',
|
|
195
|
-
'missingInteractionAllowed',
|
|
196
|
-
'rules',
|
|
197
|
-
'modelFields',
|
|
198
|
-
'supportsIntent',
|
|
199
|
-
]),
|
|
200
|
-
}
|
|
201
|
-
: {}),
|
|
223
|
+
...(lifecycle ? { lifecycle: bindLifecycle(lifecycle) } : {}),
|
|
202
224
|
});
|
|
203
|
-
return this.install(input, registered);
|
|
225
|
+
return this.install(input, registered, true);
|
|
204
226
|
}
|
|
205
|
-
|
|
206
|
-
|
|
227
|
+
/** Validate one declaration in the fixed order documented by `register`. */
|
|
228
|
+
assertRegistration(input, handlers) {
|
|
207
229
|
const policy = this.options.registration;
|
|
208
230
|
const identityPredicate = policy.isValidId;
|
|
209
231
|
const isValidId = () => (0, synchronous_js_1.booleanResult)(identityPredicate(input), 'Tool identity predicates must be synchronous', 'Tool identity predicates must return boolean');
|
|
210
232
|
const invalid = policy.invalidTool ?? 'Invalid registered tool';
|
|
211
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;
|
|
212
242
|
(0, rules_js_1.breakWhile)([
|
|
243
|
+
{ occur: () => this.sealed, error: 'Tool registry is sealed', tags: ['sealed'] },
|
|
213
244
|
{
|
|
214
|
-
occur: [() => !policy.kinds.includes(
|
|
245
|
+
occur: [() => !policy.kinds.includes(input.kind), () => !isValidId()],
|
|
215
246
|
error: invalid,
|
|
216
247
|
tags: ['identity'],
|
|
217
248
|
},
|
|
218
|
-
{
|
|
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
|
+
},
|
|
219
261
|
{
|
|
220
262
|
occur: [
|
|
221
|
-
() => !policy.audiences.includes(
|
|
222
|
-
() => !policy.effects.includes(
|
|
263
|
+
() => !policy.audiences.includes(input.audience),
|
|
264
|
+
() => !policy.effects.includes(input.effect),
|
|
223
265
|
],
|
|
224
266
|
error: invalid,
|
|
225
267
|
tags: ['execution-contract'],
|
|
226
268
|
},
|
|
227
269
|
{
|
|
228
270
|
occur: [
|
|
229
|
-
() =>
|
|
230
|
-
() =>
|
|
231
|
-
() =>
|
|
232
|
-
|
|
233
|
-
() =>
|
|
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,
|
|
234
276
|
],
|
|
235
277
|
error: invalid,
|
|
236
|
-
tags: ['
|
|
278
|
+
tags: ['goals'],
|
|
237
279
|
},
|
|
238
280
|
{
|
|
239
|
-
occur: () => ![
|
|
281
|
+
occur: () => ![parseInput, parseOutput, execute].every((handler) => typeof handler === 'function'),
|
|
240
282
|
error: invalid,
|
|
241
283
|
tags: ['handlers'],
|
|
242
284
|
},
|
|
243
285
|
{
|
|
244
|
-
occur: () => this.tools.has(
|
|
245
|
-
error: () => new Error(`Duplicate registered tool: ${
|
|
286
|
+
occur: () => this.tools.has(input.id),
|
|
287
|
+
error: () => new Error(`Duplicate registered tool: ${input.id}`),
|
|
246
288
|
tags: ['duplicate-name'],
|
|
247
289
|
},
|
|
248
290
|
{
|
|
249
|
-
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,
|
|
250
297
|
error: invalidInvocation,
|
|
251
|
-
tags: ['
|
|
298
|
+
tags: ['lifecycle', 'identity'],
|
|
252
299
|
},
|
|
253
300
|
{
|
|
254
|
-
occur:
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
301
|
+
occur: () => ownsInvocation && typeof lifecycle.call !== 'function',
|
|
302
|
+
error: invalidInvocation,
|
|
303
|
+
tags: ['lifecycle', 'contract'],
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
occur: () => ownsInvocation && typeof lifecycle.protocol?.keys !== 'function',
|
|
258
307
|
error: invalidInvocation,
|
|
259
|
-
tags: ['
|
|
308
|
+
tags: ['lifecycle', 'contract'],
|
|
260
309
|
},
|
|
261
310
|
{
|
|
262
|
-
occur: () =>
|
|
311
|
+
occur: () => ownsInvocation &&
|
|
263
312
|
policy.protocolVersion !== undefined &&
|
|
264
|
-
|
|
265
|
-
|
|
313
|
+
lifecycle.protocol?.version !== undefined &&
|
|
314
|
+
lifecycle.protocol.version !== policy.protocolVersion,
|
|
266
315
|
error: invalidInvocation,
|
|
267
|
-
tags: ['
|
|
316
|
+
tags: ['lifecycle', 'version'],
|
|
268
317
|
},
|
|
269
318
|
{
|
|
270
|
-
occur: () =>
|
|
319
|
+
occur: () => !!lifecycle?.id && this.invocations.has(lifecycle.id),
|
|
271
320
|
error: invalidInvocation,
|
|
272
|
-
tags: ['
|
|
321
|
+
tags: ['lifecycle', 'duplicate-id'],
|
|
273
322
|
},
|
|
274
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
|
+
});
|
|
275
332
|
this.tools.register(tool);
|
|
276
333
|
this.registered.set(tool.id, tool);
|
|
277
334
|
this.sources.set(tool.id, input);
|
|
278
|
-
if (tool.
|
|
279
|
-
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);
|
|
280
339
|
return this;
|
|
281
340
|
}
|
|
282
341
|
/** Register every tool in iteration order. */
|
|
@@ -328,6 +387,10 @@ class ToolLifecycleRegistry {
|
|
|
328
387
|
values() {
|
|
329
388
|
return this.registered.values();
|
|
330
389
|
}
|
|
390
|
+
/** Whether a delegate id is claimed by a registered tool. */
|
|
391
|
+
hasDelegate(id) {
|
|
392
|
+
return this.delegateIndex.has(id);
|
|
393
|
+
}
|
|
331
394
|
/**
|
|
332
395
|
* Install the single normalization handler.
|
|
333
396
|
*
|
|
@@ -363,134 +426,142 @@ class ToolLifecycleRegistry {
|
|
|
363
426
|
return (0, synchronous_js_1.synchronous)(this.finalizer.call(receiver, receiver, decision, context), 'Tool finalization must be synchronous');
|
|
364
427
|
}
|
|
365
428
|
/**
|
|
366
|
-
*
|
|
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.
|
|
367
433
|
*
|
|
368
434
|
* Diagnostics are swapped to the invocation's own sink for the duration of the call and
|
|
369
435
|
* restored afterwards, so nested tool calls report under the innermost scope.
|
|
370
436
|
*
|
|
371
|
-
* @param
|
|
437
|
+
* @param next - Decision next carrying the claimed delegate id in `type`.
|
|
372
438
|
* @param context - Execution context forwarded to Core's invocation executor.
|
|
373
|
-
* @throws A configured error when the
|
|
439
|
+
* @throws A configured error when the delegate is unknown or the tool is unavailable.
|
|
374
440
|
*/
|
|
375
|
-
call(
|
|
376
|
-
const tool = this.invocations.get(
|
|
441
|
+
call(next, context) {
|
|
442
|
+
const tool = this.delegateIndex.get(next.type) ?? this.invocations.get(next.type);
|
|
377
443
|
(0, rules_js_1.breakWhile)([
|
|
378
444
|
{
|
|
379
|
-
occur: () => !tool?.
|
|
380
|
-
error: () => this.options.
|
|
381
|
-
new Error(`Tool
|
|
445
|
+
occur: () => !tool?.lifecycle,
|
|
446
|
+
error: () => this.options.unavailableInvocation?.(next.type) ??
|
|
447
|
+
new Error(`Tool invocation is not registered: ${next.type}`),
|
|
382
448
|
},
|
|
383
449
|
{
|
|
384
|
-
occur: () => tool.
|
|
450
|
+
occur: () => !(0, tool_conditions_js_1.toolActive)(tool.active, context),
|
|
385
451
|
error: () => this.options.forbidden?.() ?? new Error('Tool is not available'),
|
|
386
452
|
},
|
|
387
453
|
]);
|
|
388
454
|
(0, invocation_js_2.executeInvocation)({
|
|
389
455
|
id: tool.id,
|
|
390
|
-
call: (
|
|
456
|
+
call: (input, executionContext, execution) => {
|
|
391
457
|
const previous = this.activeDiagnostics;
|
|
392
458
|
this.activeDiagnostics = execution.diagnostics;
|
|
393
459
|
try {
|
|
394
|
-
tool.
|
|
460
|
+
tool.lifecycle.call(input, executionContext, execution);
|
|
395
461
|
}
|
|
396
462
|
finally {
|
|
397
463
|
this.activeDiagnostics = previous;
|
|
398
464
|
}
|
|
399
465
|
},
|
|
400
|
-
},
|
|
466
|
+
}, next, context, this.invocationPorts);
|
|
401
467
|
}
|
|
402
|
-
/** Output protocols plus one protocol per registered invocation
|
|
468
|
+
/** Output protocols plus one protocol per registered invocation. */
|
|
403
469
|
protocols() {
|
|
404
|
-
return new protocol_registry_js_1.ProtocolRegistry([
|
|
405
|
-
...this.options.outputs(),
|
|
406
|
-
...[...this.invocations].map(([step, tool]) => [step, tool.invocation.protocol]),
|
|
407
|
-
]);
|
|
470
|
+
return new protocol_registry_js_1.ProtocolRegistry([...this.options.outputs(), ...this.invocationProtocols()]);
|
|
408
471
|
}
|
|
409
472
|
/**
|
|
410
|
-
* Protocols exposed to the model: output protocols plus
|
|
473
|
+
* Protocols exposed to the model: output protocols plus invocations whose audience is `model` and
|
|
411
474
|
* which are currently available in `context`.
|
|
412
475
|
*/
|
|
413
476
|
modelProtocols(context) {
|
|
414
477
|
return new protocol_registry_js_1.ProtocolRegistry([
|
|
415
478
|
...(this.options.modelOutputs?.(context) ?? this.options.outputs()),
|
|
416
|
-
...
|
|
417
|
-
.filter(([, tool]) => tool.audience === 'model' && (!tool.available || tool.available(context)))
|
|
418
|
-
.map(([step, tool]) => [step, tool.invocation.protocol]),
|
|
479
|
+
...this.invocationProtocols((tool) => tool.audience === 'model' && (0, tool_conditions_js_1.toolActive)(tool.active, context)),
|
|
419
480
|
]);
|
|
420
481
|
}
|
|
421
|
-
/** Whether the protocol registered for this
|
|
422
|
-
isTerminal(
|
|
423
|
-
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]);
|
|
424
491
|
}
|
|
425
|
-
/**
|
|
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
|
+
*/
|
|
426
498
|
assertDecision(decision, context) {
|
|
427
499
|
for (const tool of this.registered.values())
|
|
428
|
-
tool.
|
|
429
|
-
this.selected(decision)?.invocation?.inspect?.(decision, context);
|
|
500
|
+
tool.lifecycle?.inspect?.(decision, context);
|
|
430
501
|
}
|
|
431
502
|
/** Run the selected invocation's authorization hook, if any. */
|
|
432
503
|
authorize(decision, context) {
|
|
433
|
-
this.selected(decision)?.
|
|
504
|
+
this.selected(decision)?.lifecycle?.authorize?.(decision, context);
|
|
434
505
|
}
|
|
435
506
|
/** Whether the selected invocation should resume rather than start fresh; defaults to false. */
|
|
436
507
|
resume(decision, context) {
|
|
437
|
-
const
|
|
438
|
-
return
|
|
439
|
-
? (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')
|
|
440
511
|
: false;
|
|
441
512
|
}
|
|
442
513
|
/** Let the selected invocation rewrite the decision on completion, if it declares a hook. */
|
|
443
514
|
complete(decision, context) {
|
|
444
|
-
return this.selected(decision)?.
|
|
515
|
+
return this.selected(decision)?.lifecycle?.complete?.(decision, context);
|
|
445
516
|
}
|
|
446
|
-
/** Fold every
|
|
517
|
+
/** Fold every tool's context projection over the value, in registration order. */
|
|
447
518
|
projectContext(value) {
|
|
448
|
-
return [...this.registered.values()].reduce((current, tool) => tool.
|
|
519
|
+
return [...this.registered.values()].reduce((current, tool) => tool.lifecycle?.projectContext?.(current) ?? current, value);
|
|
449
520
|
}
|
|
450
|
-
/** Fold every
|
|
521
|
+
/** Fold every tool's visible-text transform over the text. */
|
|
451
522
|
visibleText(text, context) {
|
|
452
|
-
return [...this.registered.values()].reduce((value, tool) => tool.
|
|
523
|
+
return [...this.registered.values()].reduce((value, tool) => tool.lifecycle?.visibleText?.(value, context) ?? value, text);
|
|
453
524
|
}
|
|
454
|
-
/** Fold every
|
|
525
|
+
/** Fold every tool's review transform over the draft. */
|
|
455
526
|
reviewDraft(draft, context) {
|
|
456
|
-
return [...this.registered.values()].reduce((value, tool) => tool.
|
|
527
|
+
return [...this.registered.values()].reduce((value, tool) => tool.lifecycle?.reviewDraft?.(value, context) ?? value, draft);
|
|
457
528
|
}
|
|
458
529
|
/** Collected recovery context values; `undefined` results are omitted. */
|
|
459
530
|
recoveryContext(context) {
|
|
460
531
|
return [...this.registered.values()].flatMap((tool) => {
|
|
461
|
-
const value = tool.
|
|
532
|
+
const value = tool.lifecycle?.recoveryContext?.(context);
|
|
462
533
|
return value === undefined ? [] : [value];
|
|
463
534
|
});
|
|
464
535
|
}
|
|
465
536
|
/**
|
|
466
537
|
* The single output template that owns this delivery.
|
|
467
538
|
*
|
|
468
|
-
* @throws An error when more than one
|
|
469
|
-
*
|
|
539
|
+
* @throws An error when more than one tool claims composition, because delivery would
|
|
540
|
+
* otherwise depend on registration order.
|
|
470
541
|
*/
|
|
471
542
|
composition(context) {
|
|
472
543
|
const values = [...this.registered.values()].flatMap((tool) => {
|
|
473
|
-
const value = tool.
|
|
544
|
+
const value = tool.lifecycle?.composition?.(context);
|
|
474
545
|
return value ? [value] : [];
|
|
475
546
|
});
|
|
476
547
|
(0, rules_js_1.breakWhile)(values.length > 1, 'More than one output template owns this delivery');
|
|
477
548
|
return values[0];
|
|
478
549
|
}
|
|
479
|
-
/** Run every
|
|
550
|
+
/** Run every tool's finalize hook for the given phase. */
|
|
480
551
|
finalize(decision, context, phase) {
|
|
481
552
|
for (const tool of this.registered.values())
|
|
482
|
-
tool.
|
|
553
|
+
tool.lifecycle?.finalize?.(decision, context, phase);
|
|
483
554
|
}
|
|
484
|
-
/** Whether any
|
|
555
|
+
/** Whether any tool permits the interaction to be missing. */
|
|
485
556
|
missingInteractionAllowed(decision, context) {
|
|
486
|
-
return [...this.registered.values()].some((tool) => tool.
|
|
487
|
-
? (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')
|
|
488
559
|
: false);
|
|
489
560
|
}
|
|
490
561
|
/** Task rules ordered by their declared `order`, joined into one prompt block. */
|
|
491
562
|
taskRules(context) {
|
|
492
563
|
return [...this.registered.values()]
|
|
493
|
-
.flatMap((tool) => tool.
|
|
564
|
+
.flatMap((tool) => tool.lifecycle?.rules?.(context) ?? [])
|
|
494
565
|
.sort((left, right) => left.order - right.order)
|
|
495
566
|
.map((rule) => rule.text)
|
|
496
567
|
.filter(Boolean)
|
|
@@ -499,7 +570,7 @@ class ToolLifecycleRegistry {
|
|
|
499
570
|
/** Model-context fragments for one placement, ordered by each field's `order`. */
|
|
500
571
|
contextFields(context, placement) {
|
|
501
572
|
return [...this.registered.values()]
|
|
502
|
-
.flatMap((tool) => (tool.
|
|
573
|
+
.flatMap((tool) => (tool.lifecycle?.modelFields?.(context, placement) ?? [])
|
|
503
574
|
.filter((field) => field.placement === placement)
|
|
504
575
|
.map((field) => ({ tool, field })))
|
|
505
576
|
.sort((left, right) => left.field.order - right.field.order)
|
|
@@ -507,11 +578,25 @@ class ToolLifecycleRegistry {
|
|
|
507
578
|
}
|
|
508
579
|
/** Merged model-context values for one placement; later fragments win per key. */
|
|
509
580
|
modelFields(context, placement) {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
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);
|
|
515
600
|
}
|
|
516
601
|
/**
|
|
517
602
|
* Describe registered tools, optionally limited by audience and availability.
|
|
@@ -521,19 +606,22 @@ class ToolLifecycleRegistry {
|
|
|
521
606
|
*
|
|
522
607
|
* @param audience - Audience to keep; omit to include every audience.
|
|
523
608
|
* @param context - Context for availability checks.
|
|
524
|
-
* @returns Plain metadata; `
|
|
609
|
+
* @returns Plain metadata; `goalIds: 'all'` is expanded to the current goal ids.
|
|
525
610
|
*/
|
|
526
611
|
describe(audience, context) {
|
|
527
612
|
return [...this.registered.values()]
|
|
528
613
|
.filter((tool) => (!audience || tool.audience === audience) &&
|
|
529
|
-
(
|
|
530
|
-
|
|
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 }) => ({
|
|
531
619
|
id,
|
|
532
620
|
kind,
|
|
533
621
|
description,
|
|
534
622
|
audience,
|
|
535
623
|
effect,
|
|
536
|
-
|
|
624
|
+
goalIds: goalIds === 'all' ? [...this.options.goalIds()] : [...goalIds],
|
|
537
625
|
}));
|
|
538
626
|
}
|
|
539
627
|
/**
|
|
@@ -556,9 +644,9 @@ class ToolLifecycleRegistry {
|
|
|
556
644
|
this.tools.seal();
|
|
557
645
|
return this;
|
|
558
646
|
}
|
|
559
|
-
/** Tool that owns the invocation
|
|
647
|
+
/** Tool that owns the invocation id named by the decision, if any. */
|
|
560
648
|
selected(decision) {
|
|
561
|
-
return this.invocations.get(this.options.
|
|
649
|
+
return this.invocations.get(this.options.invocationId(decision));
|
|
562
650
|
}
|
|
563
651
|
}
|
|
564
652
|
exports.ToolLifecycleRegistry = ToolLifecycleRegistry;
|