@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.
Files changed (214) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +5 -5
  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 +4 -2
  7. package/development/docs/api/README.md +2 -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/reference.en.md +508 -410
  23. package/development/docs/api/reference.md +508 -410
  24. package/development/docs/api/support.en.md +55 -9
  25. package/development/docs/api/support.md +53 -7
  26. package/development/docs/api/types.en.md +35 -1
  27. package/development/docs/api/types.md +43 -0
  28. package/development/docs/basic-usage.en.md +1 -1
  29. package/development/docs/basic-usage.md +1 -1
  30. package/development/docs/create-app.en.md +1 -1
  31. package/development/docs/examples/registration/associated.mjs +8 -0
  32. package/development/docs/examples/registration/independent.mjs +20 -0
  33. package/development/docs/examples/registration/protocol.mjs +48 -0
  34. package/development/docs/examples/registration/run.mjs +47 -0
  35. package/development/docs/examples/registration/tools.mjs +75 -0
  36. package/development/docs/examples/registration/workflow.mjs +109 -0
  37. package/development/docs/flows/knowledge-maintenance.en.md +1 -1
  38. package/development/docs/materials.en.md +1 -1
  39. package/development/docs/mechanisms.en.md +2 -2
  40. package/development/docs/mechanisms.md +1 -1
  41. package/development/docs/operations.en.md +1 -1
  42. package/development/docs/records.en.md +1 -1
  43. package/development/docs/registration.en.md +4 -4
  44. package/development/docs/registration.md +2 -2
  45. package/development/skills/agent-core-app/SKILL.md +4 -4
  46. package/development/skills/agent-core-app/templates/node-ts/README.md.tpl +1 -1
  47. package/development/skills/agent-core-app/templates/node-ts/src/catalog.ts.tpl +2 -2
  48. package/development/skills/agent-core-app/templates/node-ts/test/app.test.mjs.tpl +1 -1
  49. package/dist/cjs/capabilities/index.js +5 -12
  50. package/dist/cjs/capabilities/model.js +56 -12
  51. package/dist/cjs/capabilities/tool-conditions.js +65 -0
  52. package/dist/cjs/capabilities/tool-runtime.js +10 -3
  53. package/dist/cjs/context/audit.js +5 -8
  54. package/dist/cjs/context/index.js +3 -4
  55. package/dist/cjs/index.js +21 -17
  56. package/dist/cjs/kits/answering/tasks.js +5 -5
  57. package/dist/cjs/kits/domains/catalog.js +113 -0
  58. package/dist/cjs/kits/domains/index.js +20 -0
  59. package/dist/cjs/kits/{intents → domains}/registry.js +77 -31
  60. package/dist/cjs/kits/{intents → domains}/scopes.js +21 -21
  61. package/dist/cjs/kits/index.js +14 -13
  62. package/dist/cjs/kits/presentation/formats.js +110 -0
  63. package/dist/cjs/kits/presentation/index.js +10 -5
  64. package/dist/cjs/kits/reflection.js +2 -2
  65. package/dist/cjs/kits/text-blocks.js +101 -0
  66. package/dist/cjs/kits/tools.js +246 -158
  67. package/dist/cjs/model/index.js +2 -6
  68. package/dist/cjs/model/interactions/calls.js +61 -0
  69. package/dist/cjs/model/interactions/json-object.js +11 -11
  70. package/dist/cjs/model/interactions/native-functions.js +17 -23
  71. package/dist/cjs/model/message-diagnostics.js +13 -3
  72. package/dist/cjs/model/options.js +2 -0
  73. package/dist/cjs/model/preparation.js +39 -6
  74. package/dist/cjs/model/runner.js +14 -0
  75. package/dist/cjs/model/selection-transport.js +4 -4
  76. package/dist/cjs/model/token-budget.js +3 -0
  77. package/dist/cjs/model/transports.js +3 -2
  78. package/dist/cjs/structs/index.js +7 -6
  79. package/dist/cjs/structs/kits/presentation/formats.js +2 -0
  80. package/dist/cjs/structs/kits/text-blocks.js +11 -0
  81. package/dist/cjs/structs/model/session.js +11 -0
  82. package/dist/cjs/structs/support/associations.js +2 -0
  83. package/dist/cjs/support/associations.js +79 -0
  84. package/dist/cjs/support/context/snapshot.js +11 -1
  85. package/dist/cjs/support/decorators/index.js +45 -3
  86. package/dist/cjs/support/index.js +1 -0
  87. package/dist/cjs/support/model/capabilities.js +35 -5
  88. package/dist/cjs/support/model/chat-completions.js +11 -2
  89. package/dist/cjs/support/model/completion/calls.js +10 -56
  90. package/dist/cjs/support/model/preview-rules.js +11 -11
  91. package/dist/cjs/support/model/reply-preview.js +3 -3
  92. package/dist/cjs/support/model/session.js +152 -0
  93. package/dist/cjs/support/model/stage-transport.js +8 -8
  94. package/dist/cjs/support/model/transports.js +5 -2
  95. package/dist/cjs/support/tools.js +42 -17
  96. package/dist/esm/capabilities/index.d.ts +5 -10
  97. package/dist/esm/capabilities/index.js +5 -9
  98. package/dist/esm/capabilities/model.d.ts +17 -13
  99. package/dist/esm/capabilities/model.js +54 -10
  100. package/dist/esm/capabilities/tool-conditions.d.ts +9 -0
  101. package/dist/esm/capabilities/tool-conditions.js +59 -0
  102. package/dist/esm/capabilities/tool-runtime.js +10 -3
  103. package/dist/esm/capabilities/tools.d.ts +3 -3
  104. package/dist/esm/context/audit.js +5 -8
  105. package/dist/esm/context/index.d.ts +3 -4
  106. package/dist/esm/context/index.js +3 -4
  107. package/dist/esm/index.d.ts +19 -13
  108. package/dist/esm/index.js +18 -15
  109. package/dist/esm/kits/answering/tasks.d.ts +6 -6
  110. package/dist/esm/kits/answering/tasks.js +5 -5
  111. package/dist/esm/kits/domains/catalog.d.ts +42 -0
  112. package/dist/esm/kits/domains/catalog.js +110 -0
  113. package/dist/esm/kits/domains/index.d.ts +4 -0
  114. package/dist/esm/kits/domains/index.js +4 -0
  115. package/dist/esm/kits/domains/registry.d.ts +100 -0
  116. package/dist/esm/kits/{intents → domains}/registry.js +77 -31
  117. package/dist/esm/kits/{intents → domains}/scopes.d.ts +18 -18
  118. package/dist/esm/kits/{intents → domains}/scopes.js +21 -21
  119. package/dist/esm/kits/index.d.ts +6 -5
  120. package/dist/esm/kits/index.js +6 -5
  121. package/dist/esm/kits/presentation/formats.d.ts +42 -0
  122. package/dist/esm/kits/presentation/formats.js +105 -0
  123. package/dist/esm/kits/presentation/index.d.ts +14 -5
  124. package/dist/esm/kits/presentation/index.js +10 -5
  125. package/dist/esm/kits/reflection.js +3 -3
  126. package/dist/esm/kits/text-blocks.d.ts +24 -0
  127. package/dist/esm/kits/text-blocks.js +97 -0
  128. package/dist/esm/kits/tools.d.ts +69 -52
  129. package/dist/esm/kits/tools.js +246 -158
  130. package/dist/esm/model/index.d.ts +2 -6
  131. package/dist/esm/model/index.js +2 -6
  132. package/dist/esm/model/interactions/calls.d.ts +40 -0
  133. package/dist/esm/model/interactions/calls.js +58 -0
  134. package/dist/esm/model/interactions/json-object.js +11 -11
  135. package/dist/esm/model/interactions/native-functions.js +17 -23
  136. package/dist/esm/model/message-diagnostics.d.ts +6 -5
  137. package/dist/esm/model/message-diagnostics.js +13 -3
  138. package/dist/esm/model/options.js +2 -0
  139. package/dist/esm/model/preparation.js +39 -6
  140. package/dist/esm/model/runner.js +14 -0
  141. package/dist/esm/model/selection-transport.js +4 -4
  142. package/dist/esm/model/token-budget.js +3 -0
  143. package/dist/esm/model/transports.d.ts +2 -1
  144. package/dist/esm/model/transports.js +3 -2
  145. package/dist/esm/structs/capabilities/invocation.d.ts +1 -1
  146. package/dist/esm/structs/capabilities/model.d.ts +42 -11
  147. package/dist/esm/structs/capabilities/tools.d.ts +9 -4
  148. package/dist/esm/structs/common.d.ts +1 -1
  149. package/dist/esm/structs/index.d.ts +7 -6
  150. package/dist/esm/structs/index.js +7 -6
  151. package/dist/esm/structs/kits/answering/tasks.d.ts +2 -2
  152. package/dist/esm/structs/kits/{intents → domains}/catalog.d.ts +20 -20
  153. package/dist/esm/structs/kits/{intents → domains}/registry.d.ts +24 -21
  154. package/dist/esm/structs/kits/{intents → domains}/scopes.d.ts +9 -9
  155. package/dist/esm/structs/kits/presentation/formats.d.ts +42 -0
  156. package/dist/esm/structs/kits/presentation/formats.js +1 -0
  157. package/dist/esm/structs/kits/text-blocks.d.ts +25 -0
  158. package/dist/esm/structs/kits/text-blocks.js +10 -0
  159. package/dist/esm/structs/kits/tools.d.ts +82 -83
  160. package/dist/esm/structs/model/interactions.d.ts +18 -11
  161. package/dist/esm/structs/model/messages.d.ts +34 -2
  162. package/dist/esm/structs/model/runtime.d.ts +7 -0
  163. package/dist/esm/structs/model/session.d.ts +29 -0
  164. package/dist/esm/structs/model/session.js +10 -0
  165. package/dist/esm/structs/support/associations.d.ts +22 -0
  166. package/dist/esm/structs/support/associations.js +1 -0
  167. package/dist/esm/structs/support/model/interactions.d.ts +2 -2
  168. package/dist/esm/structs/support/model/messages.d.ts +6 -13
  169. package/dist/esm/structs/support/tools.d.ts +23 -23
  170. package/dist/esm/support/associations.d.ts +26 -0
  171. package/dist/esm/support/associations.js +76 -0
  172. package/dist/esm/support/context/snapshot.js +11 -1
  173. package/dist/esm/support/decorators/index.d.ts +13 -2
  174. package/dist/esm/support/decorators/index.js +40 -3
  175. package/dist/esm/support/decorators/pool.d.ts +6 -5
  176. package/dist/esm/support/decorators/types.d.ts +3 -1
  177. package/dist/esm/support/index.d.ts +1 -0
  178. package/dist/esm/support/index.js +1 -0
  179. package/dist/esm/support/model/capabilities.d.ts +8 -3
  180. package/dist/esm/support/model/capabilities.js +35 -5
  181. package/dist/esm/support/model/chat-completions.js +11 -2
  182. package/dist/esm/support/model/completion/calls.d.ts +6 -34
  183. package/dist/esm/support/model/completion/calls.js +8 -55
  184. package/dist/esm/support/model/index.d.ts +1 -1
  185. package/dist/esm/support/model/preview-rules.d.ts +13 -8
  186. package/dist/esm/support/model/preview-rules.js +11 -11
  187. package/dist/esm/support/model/reply-preview.d.ts +2 -2
  188. package/dist/esm/support/model/reply-preview.js +3 -3
  189. package/dist/esm/support/model/session.d.ts +61 -0
  190. package/dist/esm/support/model/session.js +148 -0
  191. package/dist/esm/support/model/stage-transport.d.ts +1 -1
  192. package/dist/esm/support/model/stage-transport.js +9 -9
  193. package/dist/esm/support/model/transports.d.ts +2 -0
  194. package/dist/esm/support/model/transports.js +2 -1
  195. package/dist/esm/support/tools.d.ts +11 -3
  196. package/dist/esm/support/tools.js +43 -18
  197. package/dist/esm/utils/catalog.d.ts +1 -1
  198. package/package.json +20 -6
  199. package/dist/cjs/execution/index.js +0 -30
  200. package/dist/cjs/kits/intents/catalog.js +0 -82
  201. package/dist/cjs/kits/intents/index.js +0 -35
  202. package/dist/esm/execution/index.d.ts +0 -11
  203. package/dist/esm/execution/index.js +0 -11
  204. package/dist/esm/kits/intents/catalog.d.ts +0 -39
  205. package/dist/esm/kits/intents/catalog.js +0 -79
  206. package/dist/esm/kits/intents/index.d.ts +0 -22
  207. package/dist/esm/kits/intents/index.js +0 -18
  208. package/dist/esm/kits/intents/registry.d.ts +0 -88
  209. /package/dist/cjs/structs/kits/{intents → domains}/catalog.js +0 -0
  210. /package/dist/cjs/structs/kits/{intents → domains}/registry.js +0 -0
  211. /package/dist/cjs/structs/kits/{intents → domains}/scopes.js +0 -0
  212. /package/dist/esm/structs/kits/{intents → domains}/catalog.js +0 -0
  213. /package/dist/esm/structs/kits/{intents → domains}/registry.js +0 -0
  214. /package/dist/esm/structs/kits/{intents → domains}/scopes.js +0 -0
@@ -80,29 +80,29 @@ function previewSnapshot(preview) {
80
80
  * Capabilities without preview metadata are skipped even when their stage opts in. Default paths
81
81
  * are `text` and `bubbles[*]`, each kept only when the capability schema declares it.
82
82
  *
83
- * @param options Stage declarations and the capabilities they may reference.
83
+ * @param options Stage declarations and the tools they may reference.
84
84
  * @returns Frozen rules in stage order, each with deep-frozen paths and eligibility.
85
85
  * @throws {Error} When a capability or stage ID repeats, a stage references an unknown capability,
86
86
  * a preview mode is unknown, or a preview path or eligibility field is absent from the schema.
87
87
  */
88
88
  export function createReplyPreviewRules(options) {
89
- const capabilities = new Map();
90
- for (const capability of options.capabilities) {
89
+ const tools = new Map();
90
+ for (const capability of options.tools) {
91
91
  const id = capability.id;
92
- breakWhile(!id || capabilities.has(id), 'Duplicate preview capability declaration');
92
+ breakWhile(!id || tools.has(id), 'Duplicate preview capability declaration');
93
93
  const preview = previewSnapshot(capability.preview);
94
94
  // Validate and emit the same canonical snapshot, never reread App getters.
95
95
  const jsonSchema = preview ? structuredClone(capability.jsonSchema) : {};
96
- capabilities.set(id, { id, preview, jsonSchema });
96
+ tools.set(id, { id, preview, jsonSchema });
97
97
  }
98
98
  const stages = new Set(), rules = [];
99
99
  for (const stage of options.stages) {
100
- const { id: stageId, preview, capabilityIds } = stage;
100
+ const { id: stageId, preview, toolIds } = stage;
101
101
  breakWhile(!stageId || stages.has(stageId), 'Duplicate preview stage declaration');
102
102
  stages.add(stageId);
103
- const ids = capabilityIds === undefined ? [] : stringList(capabilityIds, 'capability IDs');
104
- breakWhile(new Set(ids).size !== ids.length || ids.some((id) => !capabilities.has(id)), 'Preview stage references an unknown capability');
105
- breakWhile(preview !== undefined && !['text', 'capabilities'].includes(preview), 'Unknown preview stage mode');
103
+ const ids = toolIds === undefined ? [] : stringList(toolIds, 'capability IDs');
104
+ breakWhile(new Set(ids).size !== ids.length || ids.some((id) => !tools.has(id)), 'Preview stage references an unknown capability');
105
+ breakWhile(preview !== undefined && !['text', 'tools'].includes(preview), 'Unknown preview stage mode');
106
106
  if (!preview)
107
107
  continue;
108
108
  if (preview === 'text') {
@@ -111,7 +111,7 @@ export function createReplyPreviewRules(options) {
111
111
  continue;
112
112
  }
113
113
  for (const id of ids) {
114
- const capability = capabilities.get(id);
114
+ const capability = tools.get(id);
115
115
  if (!capability.preview)
116
116
  continue;
117
117
  const source = capability.preview === true ? {} : capability.preview;
@@ -127,7 +127,7 @@ export function createReplyPreviewRules(options) {
127
127
  Object.freeze({ path: Object.freeze(when.path), values: Object.freeze(when.values) });
128
128
  rules.push(Object.freeze({
129
129
  stageId,
130
- capabilityId: wireName(id),
130
+ toolId: wireName(id),
131
131
  paths: emittedPaths,
132
132
  ...(emittedWhen ? { when: emittedWhen } : {}),
133
133
  }));
@@ -2,11 +2,11 @@ import type { ModelOutputEvent } from '../../structs/model/runtime.js';
2
2
  /**
3
3
  * One projection rule: which stage/capability it matches and which prose fields may be shown.
4
4
  *
5
- * A rule without `capabilityId` may only match a registered plain-text stage.
5
+ * A rule without `toolId` may only match a registered plain-text stage.
6
6
  */
7
7
  export interface ReplyPreviewRule {
8
8
  /** Native function wire name. Omit only for a registered plain-text stage. */
9
- capabilityId?: string;
9
+ toolId?: string;
10
10
  /** Restrict the rule to one stage; omitted matches any stage producing this capability. */
11
11
  stageId?: string;
12
12
  /** JSON paths to project, where `*` matches any array index; defaults to text/bubble paths. */
@@ -196,7 +196,7 @@ export function createReplyPreview(options) {
196
196
  if (!Number.isSafeInteger(maxChars) || maxChars < 1)
197
197
  throw new TypeError('Invalid reply preview budget');
198
198
  const rules = options.rules.map((rule) => Object.freeze({
199
- capabilityId: rule.capabilityId,
199
+ toolId: rule.toolId,
200
200
  stageId: rule.stageId,
201
201
  paths: rule.paths === undefined ? undefined : structuredClone(rule.paths),
202
202
  when: rule.when === undefined ? undefined : structuredClone(rule.when),
@@ -258,7 +258,7 @@ export function createReplyPreview(options) {
258
258
  return;
259
259
  }
260
260
  if (typeof part === 'string') {
261
- const rule = rules.find((rule) => !rule.capabilityId && rule.stageId === event.payload.stageId);
261
+ const rule = rules.find((rule) => !rule.toolId && rule.stageId === event.payload.stageId);
262
262
  if (!rule) {
263
263
  if (part.trim()) {
264
264
  disabled = true;
@@ -276,7 +276,7 @@ export function createReplyPreview(options) {
276
276
  return;
277
277
  }
278
278
  name += part.name ?? '';
279
- const rule = rules.find((rule) => rule.capabilityId === name && (!rule.stageId || rule.stageId === event.payload.stageId));
279
+ const rule = rules.find((rule) => rule.toolId === name && (!rule.stageId || rule.stageId === event.payload.stageId));
280
280
  if (!rule) {
281
281
  if (selected) {
282
282
  disabled = true;
@@ -0,0 +1,61 @@
1
+ import type { ModelToolSource, RegisteredModelTool } from '../../structs/capabilities/model.js';
2
+ import type { ModelResponseCollector } from '../../structs/model/interactions.js';
3
+ import type { ModelOptions } from '../../structs/model/messages.js';
4
+ import type { ModelTransportDefinition } from '../../structs/model/runtime.js';
5
+ import type { ModelSessionCall, ModelSessionResult } from '../../structs/model/session.js';
6
+ /** One completed call with host-facing resolution; unknown tools and bad JSON stay non-fatal. */
7
+ export interface ResolvedSessionCall extends ModelSessionCall {
8
+ /** Registered tool id, absent when the name is unknown to this stage. */
9
+ readonly toolId?: string;
10
+ /** Parsed arguments, absent when parsing failed or the tool is unknown. */
11
+ readonly input?: Record<string, unknown>;
12
+ /** Non-fatal problem the workflow should turn into a tool error message. */
13
+ readonly problem?: 'unknown-tool' | 'invalid-arguments';
14
+ }
15
+ /** Complete result of one session response after host-facing resolution. */
16
+ export interface ResolvedSessionResult extends Omit<ModelSessionResult, 'calls'> {
17
+ readonly calls: readonly ResolvedSessionCall[];
18
+ }
19
+ /** Prepared session transport handed to the runner. */
20
+ export interface PreparedSessionTransport {
21
+ readonly options: Pick<ModelOptions, 'functions' | 'json' | 'temperature' | 'toolChoice' | 'parallelToolCalls'>;
22
+ readonly schemaChars: number;
23
+ readonly instruction: string;
24
+ createResponse(): ModelResponseCollector<ResolvedSessionResult>;
25
+ }
26
+ /** Options a session transport may pass through to provider options. */
27
+ export interface SessionFunctionOptions {
28
+ readonly temperature?: number;
29
+ readonly toolChoice?: 'auto' | 'required' | 'none';
30
+ readonly parallelToolCalls?: boolean | 'omit';
31
+ }
32
+ /** Registration for one session transport. */
33
+ export interface SessionModelTransportRegistration {
34
+ /** Transport id used by call requests and diagnostics. */
35
+ readonly id: string;
36
+ /** Tools advertised to the model for this stage. */
37
+ readonly tools: ModelToolSource;
38
+ /** Sampling and tool-selection settings. */
39
+ readonly options?: SessionFunctionOptions;
40
+ }
41
+ /**
42
+ * Build the session policy for one stage.
43
+ *
44
+ * @param tools - Registered tools available in this stage; must be non-empty.
45
+ * @param options - Sampling and tool-selection settings.
46
+ * @returns A prepared transport whose collector returns text and every completed call.
47
+ * @throws TypeError When the tool list is empty or two ids collide on the wire name.
48
+ */
49
+ export declare function prepareSessionFunctions(tools: readonly RegisteredModelTool[], options?: SessionFunctionOptions): PreparedSessionTransport;
50
+ /**
51
+ * Create a session transport.
52
+ *
53
+ * @param registration - Transport id, tool source and optional settings.
54
+ * @returns A frozen transport definition whose result contains text and every completed call.
55
+ * @throws TypeError When the id is blank.
56
+ */
57
+ export declare function createSessionModelTransport<const Id extends string>(registration: SessionModelTransportRegistration & {
58
+ readonly id: Id;
59
+ }): ModelTransportDefinition<ResolvedSessionResult> & {
60
+ readonly id: Id;
61
+ };
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Session transport policy: one response may contain prose and several tool calls.
3
+ *
4
+ * Core owns the raw `ModelSessionResult`; this Support module adds the host-facing
5
+ * resolution fields (`toolId`, parsed `input`, non-fatal `problem`) and the transport
6
+ * that advertises the stage's tools. Keeping the resolution policy here prevents Core
7
+ * from depending on tool catalogs or business error categories.
8
+ *
9
+ * Exports: `ResolvedSessionCall`, `ResolvedSessionResult`, `PreparedSessionTransport`,
10
+ * `SessionFunctionOptions`, `SessionModelTransportRegistration`, `prepareSessionFunctions`
11
+ * and `createSessionModelTransport`.
12
+ */
13
+ import { wireName } from '../../model/interactions/arguments.js';
14
+ import { createToolCallCollector } from '../../model/interactions/calls.js';
15
+ import { snapshotModelOptions } from '../../model/options.js';
16
+ import { modelProtocolError } from '../../utils/model-protocol.js';
17
+ /**
18
+ * Parse one call's raw arguments without failing the whole response.
19
+ *
20
+ * @param raw - Raw JSON text; an empty string means an empty argument object.
21
+ * @returns The parsed object, or undefined when the text is not a JSON object.
22
+ */
23
+ function parseArguments(raw) {
24
+ try {
25
+ const value = JSON.parse(raw === '' ? '{}' : raw);
26
+ return value && typeof value === 'object' && !Array.isArray(value)
27
+ ? value
28
+ : undefined;
29
+ }
30
+ catch {
31
+ return undefined;
32
+ }
33
+ }
34
+ /**
35
+ * Build the session policy for one stage.
36
+ *
37
+ * @param tools - Registered tools available in this stage; must be non-empty.
38
+ * @param options - Sampling and tool-selection settings.
39
+ * @returns A prepared transport whose collector returns text and every completed call.
40
+ * @throws TypeError When the tool list is empty or two ids collide on the wire name.
41
+ */
42
+ export function prepareSessionFunctions(tools, options = {}) {
43
+ if (!tools.length)
44
+ throw new TypeError('Session transport requires registered tools');
45
+ const names = new Map(tools.map((tool) => [wireName(tool.id), tool.id]));
46
+ if (names.size !== tools.length)
47
+ throw new TypeError('Model wire name collision');
48
+ const functions = tools.map((tool) => ({
49
+ name: wireName(tool.id),
50
+ description: tool.description,
51
+ parameters: tool.inputSchema.jsonSchema,
52
+ strict: false,
53
+ }));
54
+ const instruction = 'You may answer directly or call one or more registered tools. Prose and calls may appear together. A call is a proposal, not proof of execution.';
55
+ return {
56
+ options: {
57
+ json: false,
58
+ functions,
59
+ toolChoice: options.toolChoice ?? 'auto',
60
+ ...(options.parallelToolCalls === undefined
61
+ ? {}
62
+ : { parallelToolCalls: options.parallelToolCalls }),
63
+ ...(options.temperature === undefined ? {} : { temperature: options.temperature }),
64
+ },
65
+ schemaChars: JSON.stringify(functions).length + instruction.length,
66
+ instruction,
67
+ createResponse() {
68
+ const collector = createToolCallCollector();
69
+ let text = '';
70
+ return {
71
+ get outputChars() {
72
+ return (text.length +
73
+ collector.calls.reduce((sum, call) => sum + call.id.length + call.name.length + call.arguments.length, 0));
74
+ },
75
+ get calls() {
76
+ try {
77
+ return collector.complete().map((call) => ({
78
+ id: call.id,
79
+ name: call.name,
80
+ argumentChars: call.arguments.length,
81
+ toolId: names.get(call.name),
82
+ }));
83
+ }
84
+ catch {
85
+ return undefined;
86
+ }
87
+ },
88
+ push(part) {
89
+ if (typeof part === 'string') {
90
+ text += part;
91
+ return;
92
+ }
93
+ collector.push(part);
94
+ },
95
+ finish() {
96
+ const completed = collector.complete();
97
+ if (text.trim() === '' && completed.length === 0)
98
+ modelProtocolError('Model response is empty', 'MODEL_INCOMPLETE');
99
+ const calls = completed.map((call) => {
100
+ const toolId = names.get(call.name);
101
+ const input = parseArguments(call.arguments);
102
+ return {
103
+ index: call.index,
104
+ id: call.id,
105
+ name: call.name,
106
+ arguments: call.arguments,
107
+ argumentChars: call.arguments.length,
108
+ ...(toolId === undefined ? {} : { toolId }),
109
+ ...(input === undefined ? {} : { input }),
110
+ ...(toolId === undefined
111
+ ? { problem: 'unknown-tool' }
112
+ : input === undefined
113
+ ? { problem: 'invalid-arguments' }
114
+ : {}),
115
+ };
116
+ });
117
+ return { text, calls };
118
+ },
119
+ };
120
+ },
121
+ };
122
+ }
123
+ /**
124
+ * Create a session transport.
125
+ *
126
+ * @param registration - Transport id, tool source and optional settings.
127
+ * @returns A frozen transport definition whose result contains text and every completed call.
128
+ * @throws TypeError When the id is blank.
129
+ */
130
+ export function createSessionModelTransport(registration) {
131
+ const id = registration.id;
132
+ if (typeof id !== 'string' || !id.trim())
133
+ throw new TypeError('Session transport requires an ID');
134
+ const source = registration.tools;
135
+ const options = snapshotModelOptions(registration.options ?? {});
136
+ return Object.freeze({
137
+ id,
138
+ prepare() {
139
+ return prepareSessionFunctions([...source.values()], {
140
+ ...(options.temperature === undefined ? {} : { temperature: options.temperature }),
141
+ ...(options.toolChoice === undefined ? {} : { toolChoice: options.toolChoice }),
142
+ ...(options.parallelToolCalls === undefined
143
+ ? {}
144
+ : { parallelToolCalls: options.parallelToolCalls }),
145
+ });
146
+ },
147
+ });
148
+ }
@@ -4,7 +4,7 @@ import type { ModelStageTransportRegistration } from '../../structs/support/mode
4
4
  *
5
5
  * @param registration Transport declaration: unique ID, stage-to-capability references, interaction
6
6
  * adapter, options and a static or per-stage capability source.
7
- * @returns A Core model transport with `capabilities(stage)`.
7
+ * @returns A Core model transport with `tools(stage)`.
8
8
  * @throws {Error} When a stage ID repeats, has no capability IDs, the declaration has no stages, a
9
9
  * stage or capability is not registered, or a dynamic capability source is asynchronous.
10
10
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Stage-scoped model transport: expose only the capabilities declared for each stage.
2
+ * Stage-scoped model transport: expose only the tools declared for each stage.
3
3
  *
4
4
  * Static capability sources are projected once at construction; dynamic sources are re-projected
5
5
  * at the model boundary. Either way, an undeclared stage or capability is rejected rather than
@@ -8,7 +8,7 @@
8
8
  * Main export: `createStageModelTransport`.
9
9
  */
10
10
  import { synchronous } from '../../utils/synchronous.js';
11
- import { ModelCapabilityRegistry } from '../../capabilities/model.js';
11
+ import { ModelToolRegistry } from '../../capabilities/model.js';
12
12
  import { breakWhile } from '../../utils/rules.js';
13
13
  import { createModelTransport } from './transports.js';
14
14
  /**
@@ -16,14 +16,14 @@ import { createModelTransport } from './transports.js';
16
16
  *
17
17
  * @param registration Transport declaration: unique ID, stage-to-capability references, interaction
18
18
  * adapter, options and a static or per-stage capability source.
19
- * @returns A Core model transport with `capabilities(stage)`.
19
+ * @returns A Core model transport with `tools(stage)`.
20
20
  * @throws {Error} When a stage ID repeats, has no capability IDs, the declaration has no stages, a
21
21
  * stage or capability is not registered, or a dynamic capability source is asynchronous.
22
22
  */
23
23
  export function createStageModelTransport(registration) {
24
24
  const stages = new Map();
25
25
  for (const stage of registration.stages) {
26
- const ids = stage.capabilityIds;
26
+ const ids = stage.toolIds;
27
27
  breakWhile(!stage.id?.trim() ||
28
28
  stages.has(stage.id) ||
29
29
  !Array.isArray(ids) ||
@@ -32,15 +32,15 @@ export function createStageModelTransport(registration) {
32
32
  stages.set(stage.id, Object.freeze([...ids]));
33
33
  }
34
34
  breakWhile(!stages.size, 'Model transport requires declared stages');
35
- const { id, adapter, options, requireStrictArguments, capabilities: source } = registration;
36
- const project = (stage, capabilities) => {
35
+ const { id, adapter, options, requireStrictArguments, tools: source } = registration;
36
+ const project = (stage, tools) => {
37
37
  const ids = stages.get(stage);
38
38
  breakWhile(!ids, `Unregistered model stage: ${id} -> ${stage}`);
39
- const catalog = new ModelCapabilityRegistry(capabilities.values());
39
+ const catalog = new ModelToolRegistry(tools.values());
40
40
  for (const id of ids)
41
41
  breakWhile(!catalog.has(id), `Unregistered model capability: ${stage} -> ${id}`);
42
42
  const selected = catalog.select(ids);
43
- const resolve = capabilities.resolve.bind(capabilities);
43
+ const resolve = tools.resolve.bind(tools);
44
44
  return Object.freeze({
45
45
  values: () => selected.values(),
46
46
  resolve(selection, context) {
@@ -58,7 +58,7 @@ export function createStageModelTransport(registration) {
58
58
  adapter,
59
59
  options,
60
60
  requireStrictArguments,
61
- capabilities(stage) {
61
+ tools(stage) {
62
62
  breakWhile(!stages.has(stage), `Unregistered model stage: ${id} -> ${stage}`);
63
63
  return fixed
64
64
  ? fixed.get(stage)
@@ -1,6 +1,7 @@
1
1
  import type { ModelOptions } from '../../structs/model/messages.js';
2
2
  import type { ModelTransportDefinition } from '../../structs/model/runtime.js';
3
3
  export { createModelTransport } from '../../model/selection-transport.js';
4
+ export { createSessionModelTransport, prepareSessionFunctions, type PreparedSessionTransport, type ResolvedSessionCall, type ResolvedSessionResult, type SessionFunctionOptions, type SessionModelTransportRegistration, } from './session.js';
4
5
  /**
5
6
  * Create a plain-text transport that trims the assembled response.
6
7
  *
@@ -10,6 +11,7 @@ export { createModelTransport } from '../../model/selection-transport.js';
10
11
  export declare function createTextTransport<const Id extends string>(definition: {
11
12
  readonly id: Id;
12
13
  readonly options?: Pick<ModelOptions, 'temperature'>;
14
+ readonly trim?: boolean;
13
15
  }): ModelTransportDefinition<string> & {
14
16
  readonly id: Id;
15
17
  };
@@ -12,6 +12,7 @@ import { snapshotModelOptions } from '../../model/options.js';
12
12
  import { modelProtocolError } from '../../utils/model-protocol.js';
13
13
  import { createPlainTextTransport } from '../../model/transports.js';
14
14
  export { createModelTransport } from '../../model/selection-transport.js';
15
+ export { createSessionModelTransport, prepareSessionFunctions, } from './session.js';
15
16
  /**
16
17
  * Create a plain-text transport that trims the assembled response.
17
18
  *
@@ -19,7 +20,7 @@ export { createModelTransport } from '../../model/selection-transport.js';
19
20
  * @returns A frozen Core transport definition typed as string output.
20
21
  */
21
22
  export function createTextTransport(definition) {
22
- return createPlainTextTransport(definition.id, definition.options);
23
+ return createPlainTextTransport(definition.id, definition.options, definition.trim);
23
24
  }
24
25
  /**
25
26
  * Create a typed JSON transport without a capability-selection envelope.
@@ -1,3 +1,5 @@
1
+ import type { OperationContext } from '../structs/common.js';
2
+ import type { ExecutableTool } from '../structs/capabilities/tools.js';
1
3
  import type { ToolDefinition, ToolCatalog, CompiledTool } from '../structs/support/tools.js';
2
4
  /**
3
5
  * Validate one tool declaration and freeze a detached copy of it.
@@ -13,16 +15,22 @@ import type { ToolDefinition, ToolCatalog, CompiledTool } from '../structs/suppo
13
15
  */
14
16
  export declare function defineTool<Input, Output, App, const Id extends string = string>(definition: ToolDefinition<Input, Output, App> & {
15
17
  readonly id: Id;
16
- }): ToolDefinition<Input, Output, App, Id>;
18
+ }): ExecutableTool<Input, Output, App, Id>;
17
19
  /**
18
- * Compile tool declarations into a frozen catalog with model capabilities and runtime binding.
20
+ * Compile tool declarations into a frozen catalog with model tools and runtime binding.
19
21
  *
20
22
  * Each tool becomes a model capability whose resolver returns `{ toolId, input }`; the model only
21
23
  * chooses among registered tools, it never invokes them directly.
22
24
  *
23
25
  * @param definitions Tool declarations in catalog order.
24
- * @returns A frozen catalog with `capabilities`, `select` and `bind`.
26
+ * @returns A frozen catalog with `tools`, `select` and `bind`.
25
27
  * @throws {TypeError} When a tool declaration is invalid or a tool ID is duplicated.
26
28
  */
29
+ type DefinitionApp<Definition> = Definition extends {
30
+ authorize(input: any, context: OperationContext<infer App>): unknown;
31
+ } ? App : unknown;
32
+ /** Infer the host context from existing executable definitions, without widening it to unknown. */
33
+ export declare function defineToolCatalog<const Definitions extends readonly ToolDefinition<any, any, any>[]>(definitions: Definitions): ToolCatalog<DefinitionApp<Definitions[number]>, CompiledTool<DefinitionApp<Definitions[number]>, Definitions[number]>>;
34
+ /** Explicit host typing remains available for contextually typed declaration lists. */
27
35
  export declare function defineToolCatalog<App, const Definitions extends readonly ToolDefinition<any, any, App>[] = readonly ToolDefinition<any, any, App>[]>(definitions: Definitions): ToolCatalog<App, CompiledTool<App, Definitions[number]>>;
28
36
  export type * from '../structs/support/tools.js';
@@ -2,17 +2,18 @@
2
2
  * Tool support: turn typed application tool definitions into a Core-schedulable tool catalog.
3
3
  *
4
4
  * A tool declaration pairs an input schema with authorization, execution and output parsing. The
5
- * catalog projects those tools into model capabilities and binds them to the Core tool registry
5
+ * catalog projects those tools into model tools and binds them to the Core tool registry
6
6
  * when a runtime request supplies the application. Support only assembles the registration; Core
7
7
  * still performs authorization, invocation, budgets and cancellation.
8
8
  *
9
9
  * Main exports: `defineTool` and `defineToolCatalog`.
10
10
  */
11
- import { ModelCapabilityRegistry } from '../capabilities/model.js';
11
+ import { ModelToolRegistry } from '../capabilities/model.js';
12
12
  import { createToolRegistry } from './tool-runtime.js';
13
13
  import { defineSchema } from './schema.js';
14
14
  import { readonlyCatalog } from '../utils/catalog.js';
15
15
  import { maybeAssertion } from '../utils/synchronous.js';
16
+ import { snapshotIntent, toolActive, intentDescription, bindIntent, } from '../capabilities/tool-conditions.js';
16
17
  /**
17
18
  * Validate one tool declaration and freeze a detached copy of it.
18
19
  *
@@ -35,11 +36,24 @@ export function defineTool(definition) {
35
36
  throw new TypeError('Missing tool handler');
36
37
  const inputSchema = defineSchema(definition.inputSchema);
37
38
  const authorize = definition.authorize.bind(definition);
39
+ if (definition.active !== undefined &&
40
+ typeof definition.active !== 'boolean' &&
41
+ typeof definition.active !== 'function')
42
+ throw new TypeError('Invalid tool active condition');
43
+ const active = typeof definition.active === 'function'
44
+ ? definition.active.bind(definition)
45
+ : definition.active;
46
+ const asIntent = bindIntent(snapshotIntent(typeof definition.asIntent === 'function'
47
+ ? definition.asIntent.bind(definition)
48
+ : definition.asIntent), definition);
38
49
  return Object.freeze({
39
50
  id,
40
51
  kind,
41
52
  description,
42
53
  inputSchema,
54
+ active,
55
+ asIntent,
56
+ resolve: definition.resolve?.bind(definition) ?? ((input) => ({ toolId: id, input })),
43
57
  authorize(input, context) {
44
58
  return maybeAssertion(authorize(input, context), 'Authorization must return void; rejection must throw');
45
59
  },
@@ -48,22 +62,14 @@ export function defineTool(definition) {
48
62
  parseOutput: definition.parseOutput.bind(definition),
49
63
  });
50
64
  }
51
- /**
52
- * Compile tool declarations into a frozen catalog with model capabilities and runtime binding.
53
- *
54
- * Each tool becomes a model capability whose resolver returns `{ toolId, input }`; the model only
55
- * chooses among registered tools, it never invokes them directly.
56
- *
57
- * @param definitions Tool declarations in catalog order.
58
- * @returns A frozen catalog with `capabilities`, `select` and `bind`.
59
- * @throws {TypeError} When a tool declaration is invalid or a tool ID is duplicated.
60
- */
61
65
  export function defineToolCatalog(definitions) {
62
66
  const entries = definitions.map((definition) => defineTool(definition));
63
67
  const view = readonlyCatalog(entries, (id) => new TypeError(`Unknown tool: ${id}`));
64
- const capabilities = new ModelCapabilityRegistry(entries.map((tool) => ({
68
+ const tools = new ModelToolRegistry(entries.map((tool) => ({
65
69
  id: tool.id,
66
70
  description: tool.description,
71
+ active: tool.active,
72
+ asIntent: tool.asIntent,
67
73
  inputSchema: defineSchema({
68
74
  jsonSchema: tool.inputSchema.jsonSchema,
69
75
  parse: (input) => input,
@@ -72,7 +78,7 @@ export function defineToolCatalog(definitions) {
72
78
  }))).seal();
73
79
  return Object.freeze({
74
80
  ...view,
75
- capabilities,
81
+ tools,
76
82
  /**
77
83
  * Narrow the catalog to the given tool IDs, preserving their declaration order.
78
84
  *
@@ -80,9 +86,28 @@ export function defineToolCatalog(definitions) {
80
86
  * @returns A new catalog containing only the selected tools.
81
87
  * @throws {TypeError} When an ID is not registered in this catalog.
82
88
  */
83
- select(ids) {
84
- capabilities.select(ids);
85
- return defineToolCatalog(ids.map((id) => view.require(id)));
89
+ select(ids, ...context) {
90
+ const seen = new Set();
91
+ const selected = ids
92
+ .map((id) => {
93
+ if (seen.has(id))
94
+ throw new TypeError(`Duplicate tool selection: ${id}`);
95
+ seen.add(id);
96
+ if (!view.has(id))
97
+ throw new TypeError(`Tool is not registered: ${id}`);
98
+ return view.require(id);
99
+ })
100
+ .filter((tool) => !context.length || toolActive(tool.active, context[0]));
101
+ return defineToolCatalog(selected);
102
+ },
103
+ /** Discover demand-facing executable tools while preserving their execution contracts. */
104
+ withIntent(context) {
105
+ return defineToolCatalog(entries.flatMap((tool) => {
106
+ if (!toolActive(tool.active, context))
107
+ return [];
108
+ const description = intentDescription(tool.asIntent, tool.description, context);
109
+ return description === undefined ? [] : [{ ...tool, description }];
110
+ }));
86
111
  },
87
112
  /**
88
113
  * Bind the catalog to one application runtime request.
@@ -99,7 +124,7 @@ export function defineToolCatalog(definitions) {
99
124
  errors: request.errors,
100
125
  });
101
126
  return Object.freeze({
102
- capabilities,
127
+ tools,
103
128
  get events() {
104
129
  return registry.events;
105
130
  },
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Immutable id-keyed catalog snapshot.
3
3
  *
4
- * Modules that own registrable definitions (tools, capabilities, prompts) publish the
4
+ * Modules that own registrable definitions (tools, tools, prompts) publish the
5
5
  * snapshot produced here instead of exposing their mutable `Map`, so later mutations
6
6
  * by the owner cannot be observed and no consumer can mutate the registry.
7
7
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jangts/agent-core",
3
- "version": "0.3.6",
3
+ "version": "0.5.0",
4
4
  "type": "commonjs",
5
5
  "license": "Apache-2.0",
6
6
  "description": "Platform-independent agent runtime and configurable modules for evidence, delivery, policies and interactions",
@@ -162,10 +162,10 @@
162
162
  "import": "./dist/esm/kits/interaction/index.js",
163
163
  "require": "./dist/cjs/kits/interaction/index.js"
164
164
  },
165
- "./kits/intents": {
166
- "types": "./dist/esm/kits/intents/index.d.ts",
167
- "import": "./dist/esm/kits/intents/index.js",
168
- "require": "./dist/cjs/kits/intents/index.js"
165
+ "./kits/domains": {
166
+ "types": "./dist/esm/kits/domains/index.d.ts",
167
+ "import": "./dist/esm/kits/domains/index.js",
168
+ "require": "./dist/cjs/kits/domains/index.js"
169
169
  },
170
170
  "./kits/tools": {
171
171
  "types": "./dist/esm/kits/tools.d.ts",
@@ -197,6 +197,11 @@
197
197
  "import": "./dist/esm/kits/search.js",
198
198
  "require": "./dist/cjs/kits/search.js"
199
199
  },
200
+ "./kits/text-blocks": {
201
+ "types": "./dist/esm/kits/text-blocks.d.ts",
202
+ "import": "./dist/esm/kits/text-blocks.js",
203
+ "require": "./dist/cjs/kits/text-blocks.js"
204
+ },
200
205
  "./kits/inference": {
201
206
  "types": "./dist/esm/kits/inference.d.ts",
202
207
  "import": "./dist/esm/kits/inference.js",
@@ -250,15 +255,24 @@
250
255
  },
251
256
  "scripts": {
252
257
  "build": "node scripts/clean.mjs && tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && node scripts/finalize.mjs",
258
+ "build:dev": "tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && node scripts/finalize.mjs",
253
259
  "test": "node --test test/*.test.mjs",
254
260
  "docs:api": "node scripts/api-reference.mjs"
255
261
  },
256
262
  "dependencies": {
257
263
  "@jangts/streaming": "^0.1.2",
258
- "@jangts/mock-gpt": "0.2.2",
259
264
  "minisearch": "^7.2.0"
260
265
  },
266
+ "peerDependencies": {
267
+ "@jangts/mock-gpt": "0.2.2"
268
+ },
269
+ "peerDependenciesMeta": {
270
+ "@jangts/mock-gpt": {
271
+ "optional": true
272
+ }
273
+ },
261
274
  "devDependencies": {
275
+ "@jangts/mock-gpt": "0.2.2",
262
276
  "typescript": "~6.0.2",
263
277
  "esbuild": "0.28.2"
264
278
  },