@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.
Files changed (288) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +33 -31
  3. package/development/docs/README.en.md +2 -2
  4. package/development/docs/acceptance.en.md +2 -2
  5. package/development/docs/agent-development.en.md +1 -1
  6. package/development/docs/api/README.en.md +6 -2
  7. package/development/docs/api/README.md +4 -0
  8. package/development/docs/api/configuration-in-workflow.en.md +403 -0
  9. package/development/docs/api/configuration-in-workflow.md +403 -0
  10. package/development/docs/api/core.en.md +7 -7
  11. package/development/docs/api/core.md +6 -6
  12. package/development/docs/api/decorators.en.md +20 -0
  13. package/development/docs/api/decorators.md +20 -0
  14. package/development/docs/api/examples.en.md +1 -1
  15. package/development/docs/api/examples.md +1 -1
  16. package/development/docs/api/kits.en.md +22 -4
  17. package/development/docs/api/kits.md +22 -4
  18. package/development/docs/api/knowledge-answering.en.md +4 -1
  19. package/development/docs/api/knowledge-answering.md +4 -1
  20. package/development/docs/api/mock.en.md +2 -0
  21. package/development/docs/api/mock.md +2 -0
  22. package/development/docs/api/observability.en.md +37 -11
  23. package/development/docs/api/observability.md +64 -11
  24. package/development/docs/api/reference.en.md +876 -657
  25. package/development/docs/api/reference.md +662 -508
  26. package/development/docs/api/support.en.md +55 -9
  27. package/development/docs/api/support.md +53 -7
  28. package/development/docs/api/types.en.md +36 -1
  29. package/development/docs/api/types.md +44 -0
  30. package/development/docs/api/workflow-views.en.md +64 -0
  31. package/development/docs/api/workflow-views.md +78 -0
  32. package/development/docs/api/workflow.en.md +6 -2
  33. package/development/docs/api/workflow.md +6 -2
  34. package/development/docs/basic-usage.en.md +1 -1
  35. package/development/docs/basic-usage.md +1 -1
  36. package/development/docs/create-app.en.md +1 -1
  37. package/development/docs/examples/registration/associated.mjs +8 -0
  38. package/development/docs/examples/registration/independent.mjs +20 -0
  39. package/development/docs/examples/registration/protocol.mjs +48 -0
  40. package/development/docs/examples/registration/run.mjs +47 -0
  41. package/development/docs/examples/registration/tools.mjs +75 -0
  42. package/development/docs/examples/registration/workflow.mjs +109 -0
  43. package/development/docs/flows/knowledge-maintenance.en.md +1 -1
  44. package/development/docs/materials.en.md +1 -1
  45. package/development/docs/mechanisms.en.md +2 -2
  46. package/development/docs/mechanisms.md +1 -1
  47. package/development/docs/operations.en.md +1 -1
  48. package/development/docs/records.en.md +1 -1
  49. package/development/docs/registration.en.md +4 -4
  50. package/development/docs/registration.md +2 -2
  51. package/development/skills/agent-core-app/SKILL.md +16 -4
  52. package/development/skills/agent-core-app/templates/node-ts/README.md.tpl +1 -1
  53. package/development/skills/agent-core-app/templates/node-ts/src/catalog.ts.tpl +2 -2
  54. package/development/skills/agent-core-app/templates/node-ts/test/app.test.mjs.tpl +1 -1
  55. package/dist/cjs/capabilities/index.js +5 -12
  56. package/dist/cjs/capabilities/invocation.js +21 -1
  57. package/dist/cjs/capabilities/model.js +56 -12
  58. package/dist/cjs/capabilities/tool-conditions.js +65 -0
  59. package/dist/cjs/capabilities/tool-runtime.js +18 -4
  60. package/dist/cjs/capabilities/tools.js +12 -17
  61. package/dist/cjs/context/audit.js +5 -8
  62. package/dist/cjs/context/index.js +3 -4
  63. package/dist/cjs/diagnostics/index.js +51 -3
  64. package/dist/cjs/diagnostics/native-sub-flow.js +106 -0
  65. package/dist/cjs/diagnostics/sub-flow.js +278 -32
  66. package/dist/cjs/execution/engine.js +3 -2
  67. package/dist/cjs/execution/events.js +5 -5
  68. package/dist/cjs/execution/reporting.js +18 -28
  69. package/dist/cjs/execution/workflow-chain.js +211 -0
  70. package/dist/cjs/execution/workflow-graph.js +72 -0
  71. package/dist/cjs/execution/workflow.js +34 -6
  72. package/dist/cjs/index.js +21 -17
  73. package/dist/cjs/kits/aggregation.js +17 -14
  74. package/dist/cjs/kits/answering/checks.js +2 -1
  75. package/dist/cjs/kits/answering/flow.js +24 -21
  76. package/dist/cjs/kits/answering/tasks.js +30 -25
  77. package/dist/cjs/kits/delivery.js +36 -24
  78. package/dist/cjs/kits/domains/catalog.js +113 -0
  79. package/dist/cjs/kits/domains/index.js +20 -0
  80. package/dist/cjs/kits/{intents → domains}/registry.js +77 -31
  81. package/dist/cjs/kits/{intents → domains}/scopes.js +21 -21
  82. package/dist/cjs/kits/index.js +14 -13
  83. package/dist/cjs/kits/knowledge/catalog.js +33 -30
  84. package/dist/cjs/kits/policies.js +3 -2
  85. package/dist/cjs/kits/presentation/formats.js +110 -0
  86. package/dist/cjs/kits/presentation/index.js +10 -5
  87. package/dist/cjs/kits/presentation/outputs.js +2 -1
  88. package/dist/cjs/kits/reflection.js +2 -2
  89. package/dist/cjs/kits/retrieval.js +7 -1
  90. package/dist/cjs/kits/text-blocks.js +101 -0
  91. package/dist/cjs/kits/tools.js +247 -158
  92. package/dist/cjs/model/decision-retry.js +2 -1
  93. package/dist/cjs/model/index.js +2 -6
  94. package/dist/cjs/model/interactions/calls.js +61 -0
  95. package/dist/cjs/model/interactions/json-object.js +11 -11
  96. package/dist/cjs/model/interactions/native-functions.js +17 -23
  97. package/dist/cjs/model/message-diagnostics.js +13 -3
  98. package/dist/cjs/model/options.js +2 -0
  99. package/dist/cjs/model/preparation.js +39 -6
  100. package/dist/cjs/model/runner.js +34 -5
  101. package/dist/cjs/model/selection-transport.js +4 -4
  102. package/dist/cjs/model/token-budget.js +3 -0
  103. package/dist/cjs/model/transports.js +3 -2
  104. package/dist/cjs/structs/index.js +7 -6
  105. package/dist/cjs/structs/kits/domains/scopes.js +2 -0
  106. package/dist/cjs/structs/kits/presentation/formats.js +2 -0
  107. package/dist/cjs/structs/kits/text-blocks.js +11 -0
  108. package/dist/cjs/structs/model/session.js +11 -0
  109. package/dist/cjs/structs/support/associations.js +2 -0
  110. package/dist/cjs/support/associations.js +79 -0
  111. package/dist/cjs/support/context/nodes.js +48 -45
  112. package/dist/cjs/support/context/processing.js +6 -3
  113. package/dist/cjs/support/context/snapshot.js +11 -1
  114. package/dist/cjs/support/decorators/index.js +45 -3
  115. package/dist/cjs/support/index.js +1 -0
  116. package/dist/cjs/support/model/capabilities.js +35 -5
  117. package/dist/cjs/support/model/chat-completions.js +11 -2
  118. package/dist/cjs/support/model/completion/calls.js +10 -56
  119. package/dist/cjs/support/model/preview-rules.js +11 -11
  120. package/dist/cjs/support/model/reply-preview.js +3 -3
  121. package/dist/cjs/support/model/session.js +152 -0
  122. package/dist/cjs/support/model/stage-transport.js +8 -8
  123. package/dist/cjs/support/model/transports.js +5 -2
  124. package/dist/cjs/support/tools.js +42 -17
  125. package/dist/cjs/utils/invocation.js +1 -0
  126. package/dist/esm/capabilities/index.d.ts +5 -10
  127. package/dist/esm/capabilities/index.js +5 -9
  128. package/dist/esm/capabilities/invocation.js +21 -1
  129. package/dist/esm/capabilities/model.d.ts +17 -13
  130. package/dist/esm/capabilities/model.js +54 -10
  131. package/dist/esm/capabilities/tool-conditions.d.ts +9 -0
  132. package/dist/esm/capabilities/tool-conditions.js +59 -0
  133. package/dist/esm/capabilities/tool-runtime.js +18 -4
  134. package/dist/esm/capabilities/tools.d.ts +3 -3
  135. package/dist/esm/capabilities/tools.js +12 -17
  136. package/dist/esm/context/audit.js +5 -8
  137. package/dist/esm/context/index.d.ts +3 -4
  138. package/dist/esm/context/index.js +3 -4
  139. package/dist/esm/diagnostics/index.d.ts +1 -0
  140. package/dist/esm/diagnostics/index.js +48 -2
  141. package/dist/esm/diagnostics/native-sub-flow.d.ts +94 -0
  142. package/dist/esm/diagnostics/native-sub-flow.js +101 -0
  143. package/dist/esm/diagnostics/sub-flow.d.ts +56 -4
  144. package/dist/esm/diagnostics/sub-flow.js +271 -32
  145. package/dist/esm/execution/engine.d.ts +1 -0
  146. package/dist/esm/execution/engine.js +3 -2
  147. package/dist/esm/execution/events.js +5 -5
  148. package/dist/esm/execution/reporting.d.ts +6 -12
  149. package/dist/esm/execution/reporting.js +19 -29
  150. package/dist/esm/execution/workflow-chain.d.ts +3 -0
  151. package/dist/esm/execution/workflow-chain.js +208 -0
  152. package/dist/esm/execution/workflow-graph.d.ts +7 -0
  153. package/dist/esm/execution/workflow-graph.js +68 -0
  154. package/dist/esm/execution/workflow.d.ts +6 -0
  155. package/dist/esm/execution/workflow.js +34 -6
  156. package/dist/esm/index.d.ts +19 -13
  157. package/dist/esm/index.js +18 -15
  158. package/dist/esm/kits/aggregation.d.ts +1 -1
  159. package/dist/esm/kits/aggregation.js +17 -14
  160. package/dist/esm/kits/answering/checks.js +2 -1
  161. package/dist/esm/kits/answering/flow.js +24 -21
  162. package/dist/esm/kits/answering/tasks.d.ts +6 -6
  163. package/dist/esm/kits/answering/tasks.js +30 -25
  164. package/dist/esm/kits/delivery.d.ts +0 -9
  165. package/dist/esm/kits/delivery.js +36 -24
  166. package/dist/esm/kits/domains/catalog.d.ts +42 -0
  167. package/dist/esm/kits/domains/catalog.js +110 -0
  168. package/dist/esm/kits/domains/index.d.ts +4 -0
  169. package/dist/esm/kits/domains/index.js +4 -0
  170. package/dist/esm/kits/domains/registry.d.ts +100 -0
  171. package/dist/esm/kits/{intents → domains}/registry.js +77 -31
  172. package/dist/esm/kits/{intents → domains}/scopes.d.ts +18 -18
  173. package/dist/esm/kits/{intents → domains}/scopes.js +21 -21
  174. package/dist/esm/kits/index.d.ts +6 -5
  175. package/dist/esm/kits/index.js +6 -5
  176. package/dist/esm/kits/knowledge/catalog.js +33 -30
  177. package/dist/esm/kits/policies.d.ts +1 -1
  178. package/dist/esm/kits/policies.js +3 -2
  179. package/dist/esm/kits/presentation/formats.d.ts +42 -0
  180. package/dist/esm/kits/presentation/formats.js +105 -0
  181. package/dist/esm/kits/presentation/index.d.ts +14 -5
  182. package/dist/esm/kits/presentation/index.js +10 -5
  183. package/dist/esm/kits/presentation/outputs.js +2 -1
  184. package/dist/esm/kits/reflection.js +3 -3
  185. package/dist/esm/kits/retrieval.js +7 -1
  186. package/dist/esm/kits/text-blocks.d.ts +24 -0
  187. package/dist/esm/kits/text-blocks.js +97 -0
  188. package/dist/esm/kits/tools.d.ts +69 -52
  189. package/dist/esm/kits/tools.js +247 -158
  190. package/dist/esm/model/decision-retry.d.ts +2 -0
  191. package/dist/esm/model/decision-retry.js +2 -1
  192. package/dist/esm/model/index.d.ts +2 -6
  193. package/dist/esm/model/index.js +2 -6
  194. package/dist/esm/model/interactions/calls.d.ts +40 -0
  195. package/dist/esm/model/interactions/calls.js +58 -0
  196. package/dist/esm/model/interactions/json-object.js +11 -11
  197. package/dist/esm/model/interactions/native-functions.js +17 -23
  198. package/dist/esm/model/message-diagnostics.d.ts +6 -5
  199. package/dist/esm/model/message-diagnostics.js +13 -3
  200. package/dist/esm/model/options.js +2 -0
  201. package/dist/esm/model/preparation.js +39 -6
  202. package/dist/esm/model/runner.d.ts +2 -0
  203. package/dist/esm/model/runner.js +34 -5
  204. package/dist/esm/model/selection-transport.js +4 -4
  205. package/dist/esm/model/token-budget.js +3 -0
  206. package/dist/esm/model/transports.d.ts +2 -1
  207. package/dist/esm/model/transports.js +3 -2
  208. package/dist/esm/structs/capabilities/invocation.d.ts +3 -1
  209. package/dist/esm/structs/capabilities/model.d.ts +42 -11
  210. package/dist/esm/structs/capabilities/tools.d.ts +16 -7
  211. package/dist/esm/structs/common.d.ts +3 -1
  212. package/dist/esm/structs/debug.d.ts +36 -20
  213. package/dist/esm/structs/execution/workflow-views.d.ts +123 -0
  214. package/dist/esm/structs/execution/workflow.d.ts +4 -3
  215. package/dist/esm/structs/index.d.ts +8 -6
  216. package/dist/esm/structs/index.js +7 -6
  217. package/dist/esm/structs/kits/answering/tasks.d.ts +2 -2
  218. package/dist/esm/structs/kits/{intents → domains}/catalog.d.ts +20 -20
  219. package/dist/esm/structs/kits/{intents → domains}/registry.d.ts +24 -21
  220. package/dist/esm/structs/kits/{intents → domains}/scopes.d.ts +9 -9
  221. package/dist/esm/structs/kits/domains/scopes.js +1 -0
  222. package/dist/esm/structs/kits/presentation/formats.d.ts +42 -0
  223. package/dist/esm/structs/kits/presentation/formats.js +1 -0
  224. package/dist/esm/structs/kits/text-blocks.d.ts +25 -0
  225. package/dist/esm/structs/kits/text-blocks.js +10 -0
  226. package/dist/esm/structs/kits/tools.d.ts +82 -83
  227. package/dist/esm/structs/model/interactions.d.ts +18 -11
  228. package/dist/esm/structs/model/messages.d.ts +34 -2
  229. package/dist/esm/structs/model/runtime.d.ts +9 -0
  230. package/dist/esm/structs/model/session.d.ts +29 -0
  231. package/dist/esm/structs/model/session.js +10 -0
  232. package/dist/esm/structs/support/associations.d.ts +22 -0
  233. package/dist/esm/structs/support/associations.js +1 -0
  234. package/dist/esm/structs/support/model/interactions.d.ts +2 -2
  235. package/dist/esm/structs/support/model/messages.d.ts +6 -13
  236. package/dist/esm/structs/support/tools.d.ts +23 -23
  237. package/dist/esm/support/associations.d.ts +26 -0
  238. package/dist/esm/support/associations.js +76 -0
  239. package/dist/esm/support/context/nodes.js +48 -45
  240. package/dist/esm/support/context/processing.js +6 -3
  241. package/dist/esm/support/context/snapshot.js +11 -1
  242. package/dist/esm/support/decorators/index.d.ts +13 -2
  243. package/dist/esm/support/decorators/index.js +40 -3
  244. package/dist/esm/support/decorators/pool.d.ts +6 -5
  245. package/dist/esm/support/decorators/types.d.ts +3 -1
  246. package/dist/esm/support/index.d.ts +1 -0
  247. package/dist/esm/support/index.js +1 -0
  248. package/dist/esm/support/model/capabilities.d.ts +8 -3
  249. package/dist/esm/support/model/capabilities.js +35 -5
  250. package/dist/esm/support/model/chat-completions.js +11 -2
  251. package/dist/esm/support/model/completion/calls.d.ts +6 -34
  252. package/dist/esm/support/model/completion/calls.js +8 -55
  253. package/dist/esm/support/model/index.d.ts +1 -1
  254. package/dist/esm/support/model/preview-rules.d.ts +13 -8
  255. package/dist/esm/support/model/preview-rules.js +11 -11
  256. package/dist/esm/support/model/reply-preview.d.ts +2 -2
  257. package/dist/esm/support/model/reply-preview.js +3 -3
  258. package/dist/esm/support/model/session.d.ts +61 -0
  259. package/dist/esm/support/model/session.js +148 -0
  260. package/dist/esm/support/model/stage-transport.d.ts +1 -1
  261. package/dist/esm/support/model/stage-transport.js +9 -9
  262. package/dist/esm/support/model/transports.d.ts +2 -0
  263. package/dist/esm/support/model/transports.js +2 -1
  264. package/dist/esm/support/tools.d.ts +11 -3
  265. package/dist/esm/support/tools.js +43 -18
  266. package/dist/esm/utils/catalog.d.ts +1 -1
  267. package/dist/esm/utils/invocation.d.ts +1 -0
  268. package/dist/esm/utils/invocation.js +1 -0
  269. package/package.json +20 -6
  270. package/dist/cjs/execution/index.js +0 -30
  271. package/dist/cjs/kits/intents/catalog.js +0 -82
  272. package/dist/cjs/kits/intents/index.js +0 -35
  273. package/dist/cjs/utils/debug.js +0 -30
  274. package/dist/esm/execution/index.d.ts +0 -11
  275. package/dist/esm/execution/index.js +0 -11
  276. package/dist/esm/kits/intents/catalog.d.ts +0 -39
  277. package/dist/esm/kits/intents/catalog.js +0 -79
  278. package/dist/esm/kits/intents/index.d.ts +0 -22
  279. package/dist/esm/kits/intents/index.js +0 -18
  280. package/dist/esm/kits/intents/registry.d.ts +0 -88
  281. package/dist/esm/utils/debug.d.ts +0 -27
  282. package/dist/esm/utils/debug.js +0 -27
  283. /package/dist/cjs/structs/{kits/intents/catalog.js → execution/workflow-views.js} +0 -0
  284. /package/dist/cjs/structs/kits/{intents/registry.js → domains/catalog.js} +0 -0
  285. /package/dist/cjs/structs/kits/{intents/scopes.js → domains/registry.js} +0 -0
  286. /package/dist/esm/structs/{kits/intents/catalog.js → execution/workflow-views.js} +0 -0
  287. /package/dist/esm/structs/kits/{intents/registry.js → domains/catalog.js} +0 -0
  288. /package/dist/esm/structs/kits/{intents/scopes.js → domains/registry.js} +0 -0
@@ -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 domain tools with declared invocation and contribution.
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, per-step protocols, output ownership, context fields, task rules
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, step, outputs, modelOutputs, unavailableStep, forbidden, contextFragment, intentIds, diagnostics, signal, journal, checkpoint, receipt, receiptError, } = options;
24
- if (typeof intentIds !== 'function')
25
- throw new TypeError('An intentIds provider is required');
26
- const { kinds, isValidId, audiences, effects, intentExists, protocolVersion, tags, invalidTool, invalidInvocation, } = registration;
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
- intentExists: intentExists.bind(registration),
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
- step: step.bind(options),
73
+ invocationId: invocationId.bind(options),
49
74
  outputs: outputs.bind(options),
50
75
  modelOutputs: modelOutputs?.bind(options),
51
- unavailableStep: unavailableStep?.bind(options),
76
+ unavailableInvocation: unavailableInvocation?.bind(options),
52
77
  forbidden: forbidden?.bind(options),
53
78
  contextFragment: contextFragment.bind(options),
54
- intentIds: intentIds.bind(options),
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 are declared by the App.
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 contribution hook is optional and is applied in
68
- * registration order, which is why `registerAll` preserves iteration order.
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 `intentIds` provider is supplied.
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 handlers.
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, intent ids, missing handlers, duplicate tool id,
123
- * incomplete invocation contract, protocol version mismatch or duplicate invocation step.
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, intentIds, invocation, contribution, parseInput: inputParser, parseOutput: outputParser, available: availability, execute, debugSteps, } = input;
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?.bind(input);
129
- const frozenIntents = Array.isArray(intentIds) ? Object.freeze([...intentIds]) : intentIds;
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
- 'intentIds',
138
- 'invocation',
139
- 'contribution',
197
+ 'goalIds',
198
+ 'delegate',
199
+ 'lifecycle',
140
200
  'parseInput',
141
201
  'parseOutput',
142
202
  'execute',
143
203
  'debugSteps',
144
- 'available',
204
+ 'active',
145
205
  ]),
206
+ ...modelTool,
146
207
  id,
147
208
  kind,
148
209
  description,
149
210
  audience,
150
211
  effect,
151
- invocation,
152
- contribution,
153
- intentIds: frozenIntents,
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
- available: available
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
- ...(invocation
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
- install(input, tool) {
205
- (0, rules_js_1.breakWhile)(this.sealed, 'Tool registry is sealed');
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(tool.kind), () => !isValidId()],
245
+ occur: [() => !policy.kinds.includes(input.kind), () => !isValidId()],
214
246
  error: invalid,
215
247
  tags: ['identity'],
216
248
  },
217
- { occur: () => !tool.description.trim(), error: invalid, tags: ['description'] },
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(tool.audience),
221
- () => !policy.effects.includes(tool.effect),
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
- () => tool.intentIds !== 'all' && !Array.isArray(tool.intentIds),
229
- () => tool.intentIds !== 'all' && !tool.intentIds.length,
230
- () => tool.intentIds !== 'all' &&
231
- tool.intentIds.some((goal) => !(0, synchronous_js_1.booleanResult)(policy.intentExists(goal), 'Intent lookup must return boolean synchronously')),
232
- () => tool.intentIds !== 'all' && new Set(tool.intentIds).size !== tool.intentIds.length,
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: ['intents'],
278
+ tags: ['goals'],
236
279
  },
237
280
  {
238
- occur: () => ![tool.parseInput, tool.parseOutput, tool.execute].every((handler) => typeof handler === 'function'),
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(tool.id),
244
- error: () => new Error(`Duplicate registered tool: ${tool.id}`),
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: () => tool.invocation && !tool.invocation.step,
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: ['invocation', 'step'],
298
+ tags: ['lifecycle', 'identity'],
251
299
  },
252
300
  {
253
- occur: [
254
- () => tool.invocation && typeof tool.invocation.call !== 'function',
255
- () => tool.invocation && typeof tool.invocation.protocol?.keys !== 'function',
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: ['invocation', 'contract'],
308
+ tags: ['lifecycle', 'contract'],
259
309
  },
260
310
  {
261
- occur: () => tool.invocation &&
311
+ occur: () => ownsInvocation &&
262
312
  policy.protocolVersion !== undefined &&
263
- tool.invocation.protocol.version !== undefined &&
264
- tool.invocation.protocol.version !== policy.protocolVersion,
313
+ lifecycle.protocol?.version !== undefined &&
314
+ lifecycle.protocol.version !== policy.protocolVersion,
265
315
  error: invalidInvocation,
266
- tags: ['invocation', 'version'],
316
+ tags: ['lifecycle', 'version'],
267
317
  },
268
318
  {
269
- occur: () => tool.invocation && this.invocations.has(tool.invocation.step),
319
+ occur: () => !!lifecycle?.id && this.invocations.has(lifecycle.id),
270
320
  error: invalidInvocation,
271
- tags: ['invocation', 'duplicate-step'],
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.invocation)
278
- this.invocations.set(tool.invocation.step, 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
- * Execute the invocation registered for a step type.
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 step - Step carrying the registered `type`.
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 step is unknown or the tool is unavailable.
439
+ * @throws A configured error when the delegate is unknown or the tool is unavailable.
373
440
  */
374
- call(step, context) {
375
- const tool = this.invocations.get(step.type);
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?.invocation,
379
- error: () => this.options.unavailableStep?.(step.type) ??
380
- new Error(`Tool step is not registered: ${step.type}`),
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.available && !tool.available(context),
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: (value, input, execution) => {
456
+ call: (input, executionContext, execution) => {
390
457
  const previous = this.activeDiagnostics;
391
458
  this.activeDiagnostics = execution.diagnostics;
392
459
  try {
393
- tool.invocation.call(value, input, execution);
460
+ tool.lifecycle.call(input, executionContext, execution);
394
461
  }
395
462
  finally {
396
463
  this.activeDiagnostics = previous;
397
464
  }
398
465
  },
399
- }, step, context, this.invocationPorts);
466
+ }, next, context, this.invocationPorts);
400
467
  }
401
- /** Output protocols plus one protocol per registered invocation step. */
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 steps whose audience is `model` and
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
- ...[...this.invocations]
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 step is declared terminal. */
421
- isTerminal(step) {
422
- return this.protocols().get(step.type)?.terminal === true;
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
- /** Run contribution inspection for every tool, then the selected invocation's own check. */
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.contribution?.inspect?.(decision, context);
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)?.invocation?.authorize?.(decision, context);
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 invocation = this.selected(decision)?.invocation;
437
- return invocation?.resume
438
- ? (0, synchronous_js_1.booleanResult)(invocation.resume(decision, context), 'Tool resume must return boolean synchronously')
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)?.invocation?.complete?.(decision, context);
515
+ return this.selected(decision)?.lifecycle?.complete?.(decision, context);
444
516
  }
445
- /** Fold every contribution's context projection over the value, in registration order. */
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.contribution?.projectContext?.(current) ?? current, value);
519
+ return [...this.registered.values()].reduce((current, tool) => tool.lifecycle?.projectContext?.(current) ?? current, value);
448
520
  }
449
- /** Fold every contribution's visible-text transform over the text. */
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.contribution?.visibleText?.(value, context) ?? value, text);
523
+ return [...this.registered.values()].reduce((value, tool) => tool.lifecycle?.visibleText?.(value, context) ?? value, text);
452
524
  }
453
- /** Fold every contribution's review transform over the draft. */
525
+ /** Fold every tool's review transform over the draft. */
454
526
  reviewDraft(draft, context) {
455
- return [...this.registered.values()].reduce((value, tool) => tool.contribution?.reviewDraft?.(value, context) ?? value, draft);
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.contribution?.recoveryContext?.(context);
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 contribution claims composition, because delivery
468
- * would otherwise depend on registration order.
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.contribution?.composition?.(context);
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 contribution's finalize hook for the given phase. */
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.contribution?.finalize?.(decision, context, phase);
553
+ tool.lifecycle?.finalize?.(decision, context, phase);
482
554
  }
483
- /** Whether any contribution permits the interaction to be missing. */
555
+ /** Whether any tool permits the interaction to be missing. */
484
556
  missingInteractionAllowed(decision, context) {
485
- return [...this.registered.values()].some((tool) => tool.contribution?.missingInteractionAllowed
486
- ? (0, synchronous_js_1.booleanResult)(tool.contribution.missingInteractionAllowed(decision, context), 'Missing interaction predicates must return boolean synchronously')
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.contribution?.rules?.(context) ?? [])
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.contribution?.modelFields?.(context, placement) ?? [])
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
- return Object.assign({}, ...this.contextFields(context, placement).map((fragment) => fragment.value));
510
- }
511
- /** A contribution may veto an intent by returning `false`; silence means support. */
512
- supportsIntent(intentId, context) {
513
- return [...this.registered.values()].every((tool) => tool.contribution?.supportsIntent?.(intentId, context) !== false);
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; `intentIds: 'all'` is expanded to the current intent ids.
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
- (!tool.available || (!!context && tool.available(context))))
529
- .map(({ id, kind, description, audience, effect, intentIds }) => ({
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
- intentIds: intentIds === 'all' ? [...this.options.intentIds()] : [...intentIds],
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 step named by the decision, if any. */
647
+ /** Tool that owns the invocation id named by the decision, if any. */
559
648
  selected(decision) {
560
- return this.invocations.get(this.options.step(decision));
649
+ return this.invocations.get(this.options.invocationId(decision));
561
650
  }
562
651
  }
563
652
  exports.ToolLifecycleRegistry = ToolLifecycleRegistry;