@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
@@ -0,0 +1,26 @@
1
+ import type { AssociatedRegistration, AssociationOptions } from '../structs/support/associations.js';
2
+ /** Compile independent and owner-derived Tool declarations, validating all references eagerly. */
3
+ export declare function defineAssociatedCatalog<Entry extends AssociatedRegistration>(entries: readonly Entry[], options?: AssociationOptions<Entry>): Readonly<{
4
+ tools: import("../index.js").ModelToolCatalog<any>;
5
+ bindings: import("../index.js").ReadonlyCatalog<{
6
+ id: Entry["id"];
7
+ toolIds: readonly string[];
8
+ }>;
9
+ sources: import("../index.js").ReadonlyCatalog<{
10
+ id: string;
11
+ sources: readonly Readonly<{
12
+ toolIds: readonly string[];
13
+ kind: "standalone" | "registration";
14
+ id: string;
15
+ description: string;
16
+ }>[];
17
+ }>;
18
+ definitions: readonly Readonly<Entry>[];
19
+ ids(): readonly string[];
20
+ values(): IterableIterator<Readonly<Entry>>;
21
+ entries(): IterableIterator<readonly [string, Readonly<Entry>]>;
22
+ has(id: string): boolean;
23
+ get(id: string): Readonly<Entry> | undefined;
24
+ require(id: string): Readonly<Entry>;
25
+ }>;
26
+ export type * from '../structs/support/associations.js';
@@ -0,0 +1,76 @@
1
+ /** Compile owner-to-tool relations without parallel intent identities or execution side effects. */
2
+ import { readonlyCatalog } from '../utils/catalog.js';
3
+ import { synchronous } from '../utils/synchronous.js';
4
+ import { defineModelTools } from './model/capabilities.js';
5
+ /** Compile independent and owner-derived Tool declarations, validating all references eagerly. */
6
+ export function defineAssociatedCatalog(entries, options = {}) {
7
+ const owners = readonlyCatalog(entries, (id) => new TypeError(`Unknown tool owner: ${id}`));
8
+ const definitions = new Map();
9
+ const sources = new Map();
10
+ const declare = (tool, source) => {
11
+ if (definitions.has(tool.id))
12
+ throw new TypeError(`Duplicate model tool: ${tool.id}`);
13
+ definitions.set(tool.id, tool);
14
+ sources.set(tool.id, [source]);
15
+ };
16
+ const independent = new Set();
17
+ for (const tool of options.tools ?? []) {
18
+ independent.add(tool.id);
19
+ declare(tool, {
20
+ kind: 'standalone',
21
+ id: tool.id,
22
+ description: tool.description,
23
+ toolIds: [tool.id],
24
+ });
25
+ }
26
+ const bindings = owners.definitions.map((owner) => {
27
+ const fallback = options.toolDefaults
28
+ ? synchronous(options.toolDefaults(owner), 'Tool defaults must be synchronous')
29
+ : undefined;
30
+ const declarations = owner.modelTools ?? (fallback ? [{}] : []);
31
+ const toolIds = [];
32
+ for (const declaration of declarations) {
33
+ if (typeof declaration === 'string') {
34
+ if (!independent.has(declaration))
35
+ throw new TypeError(`Tool reference must name an independent tool: ${owner.id} -> ${declaration}`);
36
+ sources.get(declaration).push({
37
+ kind: 'registration',
38
+ id: owner.id,
39
+ description: owner.description,
40
+ toolIds: [declaration],
41
+ });
42
+ toolIds.push(declaration);
43
+ }
44
+ else {
45
+ if (!declaration || typeof declaration !== 'object' || Array.isArray(declaration))
46
+ throw new TypeError('Invalid tool association');
47
+ const tool = {
48
+ ...fallback,
49
+ ...declaration,
50
+ id: declaration.id ?? fallback?.id ?? owner.id,
51
+ description: declaration.description ?? fallback?.description ?? owner.description,
52
+ resolve: declaration.resolve?.bind(declaration) ?? fallback?.resolve?.bind(fallback),
53
+ };
54
+ declare(tool, {
55
+ kind: 'registration',
56
+ id: owner.id,
57
+ description: owner.description,
58
+ toolIds: [tool.id],
59
+ });
60
+ toolIds.push(tool.id);
61
+ }
62
+ }
63
+ if (new Set(toolIds).size !== toolIds.length)
64
+ throw new TypeError(`Duplicate tool reference: ${owner.id}`);
65
+ return Object.freeze({ id: owner.id, toolIds: Object.freeze(toolIds) });
66
+ });
67
+ return Object.freeze({
68
+ ...owners,
69
+ tools: defineModelTools([...definitions.values()]),
70
+ bindings: readonlyCatalog(bindings, (id) => new TypeError(`Unknown tool binding: ${id}`)),
71
+ sources: readonlyCatalog([...sources].map(([id, values]) => Object.freeze({
72
+ id,
73
+ sources: Object.freeze(values.map((source) => Object.freeze({ ...source, toolIds: Object.freeze([...source.toolIds]) }))),
74
+ })), (id) => new TypeError(`Unknown tool source: ${id}`)),
75
+ });
76
+ }
@@ -17,7 +17,7 @@ export function snapshotFragment(fragment) {
17
17
  * unsupported `detail` value.
18
18
  */
19
19
  export function snapshotMessage(message) {
20
- const { role, content, images } = message;
20
+ const { role, content, images, toolCalls, toolCallId } = message;
21
21
  if (images !== undefined && !Array.isArray(images))
22
22
  throw new TypeError('Context images must be an array');
23
23
  return {
@@ -34,5 +34,15 @@ export function snapshotMessage(message) {
34
34
  return { url, ...(detail === undefined ? {} : { detail }) };
35
35
  }),
36
36
  }),
37
+ ...(toolCalls === undefined
38
+ ? {}
39
+ : {
40
+ toolCalls: toolCalls.map((call) => ({
41
+ id: call.id,
42
+ name: call.name,
43
+ arguments: call.arguments,
44
+ })),
45
+ }),
46
+ ...(toolCallId === undefined ? {} : { toolCallId }),
37
47
  };
38
48
  }
@@ -7,6 +7,7 @@ import type { AgentCoreEngineSetup } from '../../execution/engine.js';
7
7
  import type { ToolDefinition } from '../../structs/capabilities/tools.js';
8
8
  import type { ContextFragmentConfig } from '../../structs/support/context.js';
9
9
  import type { ModelRunnerOptions } from '../../structs/model/runtime.js';
10
+ import type { AsIntent, ModelTool } from '../../structs/capabilities/model.js';
10
11
  import { type ClassDecoration, type MethodDecoration, type DecorationOptions } from './definition.js';
11
12
  import type { IdentifiedDefinition } from './pool.js';
12
13
  export { nodePool, toolPool, fragmentPool, workflowPool, agentPool, modelPool } from './pool.js';
@@ -15,14 +16,24 @@ export type { ClassDecoration, MethodDecoration, DecorationOptions } from './def
15
16
  export type { Node, Tool, Fragment, Workflow, Agent, Model } from './types.js';
16
17
  /** Method metadata describes the adapted handler, with optional external namespaces. */
17
18
  type MethodOptions<Definition extends IdentifiedDefinition, Key extends keyof Definition> = Omit<Definition, 'id' | Key> & DecorationOptions;
19
+ /** Intent composition belongs to its own decorator, including on definition classes. */
20
+ type WithoutIntent<Definition> = Definition extends unknown ? Omit<Definition, 'asIntent'> & {
21
+ readonly asIntent?: never;
22
+ } : never;
23
+ /** Mark a WorkflowTool for demand discovery; alone this decorator registers nothing. */
24
+ export declare function Intent<Context = any>(metadata?: AsIntent<Context>): (value: object, context: ClassDecoratorContext | ClassMethodDecoratorContext) => void;
18
25
  /** Instantiate a node definition class once, injecting its id; graph validation stays in Workflow. */
19
26
  export declare function node<State = any, Result = unknown, App = any>(id: string, options?: DecorationOptions): ClassDecoration<WorkflowNode<State, Result, App>>;
20
27
  /** Bind a named host method as run without renaming or manually binding the original object. */
21
28
  export declare function node<State = any, Result = unknown, App = any>(id: string, options: MethodOptions<WorkflowNode<State, Result, App>, 'run'>): MethodDecoration<NonNullable<WorkflowNode<State, Result, App>['run']>>;
22
29
  /** Instantiate a tool definition class; schema and authorization stay with existing defineTool. */
23
- export declare function tool<Input = unknown, Output = unknown, App = any>(id: string, options?: DecorationOptions): ClassDecoration<ToolDefinition<Input, Output, App>>;
30
+ export declare function tool<Input = any, Output = any, App = any>(id: string, options?: DecorationOptions): ClassDecoration<WithoutIntent<ToolDefinition<Input, Output, App> | ModelTool<Input, Output, App>>>;
24
31
  /** Bind an existing host method as the tool's execute callback. */
25
- export declare function tool<Input = unknown, Output = unknown, App = any>(id: string, options: MethodOptions<ToolDefinition<Input, Output, App>, 'execute'>): MethodDecoration<ToolDefinition<Input, Output, App>['execute']>;
32
+ export declare function tool<Input = unknown, Output = unknown, App = any>(id: string, options: MethodOptions<Omit<ToolDefinition<Input, Output, App>, 'asIntent'>, 'execute'>): MethodDecoration<ToolDefinition<Input, Output, App>['execute']>;
33
+ /** A model-only tool method provides its synchronous resolver. */
34
+ export declare function tool<Input = unknown, Output = Input, App = any>(id: string, options: MethodOptions<Omit<ModelTool<Input, Output, App>, 'asIntent'>, 'resolve'>): MethodDecoration<ModelTool<Input, Output, App>['resolve']>;
35
+ /** Explicit workflow names share the same implementation and pools. */
36
+ export { tool as WorkflowTool, node as WorkflowNode };
26
37
  /** Instantiate a self-describing fragment class; the original builder owns formatting checks. */
27
38
  export declare function fragment<Input = unknown>(id: string, options?: DecorationOptions): ClassDecoration<ContextFragmentConfig<Input>>;
28
39
  /** Bind a host's formatter method into an original fragment configuration. */
@@ -1,18 +1,48 @@
1
1
  import { defineTool } from '../tools.js';
2
+ import { defineModelTools } from '../model/capabilities.js';
3
+ import { snapshotIntent } from '../../capabilities/tool-conditions.js';
2
4
  import { defineWorkflow } from '../../execution/workflow.js';
3
5
  import { defineContextFragments } from '../context/assembly.js';
4
6
  import { snapshotModelBinding } from '../../model/binding.js';
5
7
  import { classDecoration, methodDecoration, } from './definition.js';
6
8
  export { nodePool, toolPool, fragmentPool, workflowPool, agentPool, modelPool } from './pool.js';
9
+ /** Metadata follows the actual decorated target, independently of decorator order. */
10
+ const intentKey = Symbol.for('@jangts/agent-core/tool-intent-metadata/v1');
11
+ const realm = globalThis;
12
+ const intentMetadata = realm[intentKey] ?? new WeakMap();
13
+ if (!realm[intentKey])
14
+ Object.defineProperty(globalThis, intentKey, { value: intentMetadata });
15
+ /** Mark a WorkflowTool for demand discovery; alone this decorator registers nothing. */
16
+ export function Intent(metadata = true) {
17
+ const normalized = snapshotIntent(metadata);
18
+ return (value, context) => {
19
+ if (context.kind !== 'class' && context.kind !== 'method')
20
+ throw new TypeError('Intent requires a class or method');
21
+ if (intentMetadata.has(value))
22
+ throw new TypeError('Duplicate Intent decoration');
23
+ intentMetadata.set(value, normalized);
24
+ };
25
+ }
7
26
  /** Internal conversion shared by node/tool/fragment; never a public free-function adapter. */
8
27
  function decorate(kind, id, options, key, compile) {
9
28
  return (value, context) => {
29
+ const convert = (definition) => {
30
+ if (kind !== 'tool')
31
+ return compile(definition);
32
+ if ('asIntent' in definition)
33
+ throw new TypeError('Use @Intent instead of asIntent in @WorkflowTool');
34
+ const metadata = intentMetadata.get(value);
35
+ // Intent metadata is collected before class/method initializers compile definitions.
36
+ if (metadata !== undefined)
37
+ Object.defineProperty(definition, 'asIntent', { value: metadata, enumerable: true });
38
+ return compile(definition);
39
+ };
10
40
  if (context?.kind === 'class') {
11
- classDecoration(kind, id, options, compile)(value, context);
41
+ classDecoration(kind, id, options, convert)(value, context);
12
42
  }
13
43
  else {
14
44
  const { ns, ...metadata } = options;
15
- methodDecoration(kind, id, metadata, key, { ns }, compile)(value, context);
45
+ methodDecoration(kind, id, metadata, key, { ns }, convert)(value, context);
16
46
  }
17
47
  };
18
48
  }
@@ -20,8 +50,15 @@ export function node(id, options = {}) {
20
50
  return decorate('node', id, options, 'run', (value) => value);
21
51
  }
22
52
  export function tool(id, options = {}) {
23
- return decorate('tool', id, options, 'execute', (value) => defineTool(value));
53
+ if ('asIntent' in options)
54
+ throw new TypeError('Use @Intent instead of asIntent in @WorkflowTool');
55
+ const handlerKey = 'inputSchema' in options && !('authorize' in options) ? 'resolve' : 'execute';
56
+ return decorate('tool', id, options, handlerKey, (value) => 'kind' in value || 'authorize' in value || 'execute' in value
57
+ ? defineTool(value)
58
+ : defineModelTools([value]).require(value.id));
24
59
  }
60
+ /** Explicit workflow names share the same implementation and pools. */
61
+ export { tool as WorkflowTool, node as WorkflowNode };
25
62
  export function fragment(id, options = {}) {
26
63
  return decorate('fragment', id, options, 'format', (value) => {
27
64
  defineContextFragments([value]);
@@ -1,5 +1,6 @@
1
1
  import type { WorkflowNode, AgentWorkflowDefinition } from '../../structs/execution/workflow.js';
2
2
  import type { ToolDefinition } from '../../structs/capabilities/tools.js';
3
+ import type { ModelTool } from '../../structs/capabilities/model.js';
3
4
  import type { ContextFragmentConfig } from '../../structs/support/context.js';
4
5
  /** Registration identity; ids are unique within one kind and namespace. */
5
6
  export interface IdentifiedDefinition {
@@ -19,7 +20,7 @@ export declare function registerDefinition(kind: DefinitionKind, definition: Ide
19
20
  /** Decorated nodes; ids are unique within each namespace. */
20
21
  export declare const nodePool: DefinitionReader<WorkflowNode<any, any, any>>;
21
22
  /** Decorated tools; namespaces isolate otherwise identical ids. */
22
- export declare const toolPool: DefinitionReader<ToolDefinition<any, any, any, string>>;
23
+ export declare const toolPool: DefinitionReader<ModelTool<any, any, any> | ToolDefinition<any, any, any>>;
23
24
  /** Decorated fragment configurations; use the original builder to assemble them. */
24
25
  export declare const fragmentPool: DefinitionReader<ContextFragmentConfig<any>>;
25
26
  /** Decorated workflow definitions; execution still belongs to the original Engine. */
@@ -29,7 +30,7 @@ export declare const agentPool: DefinitionReader<(Omit<import("../../index.js").
29
30
  readonly branch?: import("../../index.js").AgentBranch;
30
31
  readonly tools?: {
31
32
  invoke: (request: import("../../index.js").ToolInvocationRequest) => Promise<import("../../index.js").ToolResult<unknown>>;
32
- } | Pick<import("../../index.js").ToolRegistry<import("../../index.js").ExecutableTool>, "invokeAsync">;
33
+ } | Pick<import("../../index.js").ToolRegistry<import("../../index.js").ErasedTool>, "invokeAsync">;
33
34
  } & {
34
35
  model?: import("../../index.js").AgentModelBinding;
35
36
  models?: never;
@@ -42,7 +43,7 @@ export declare const agentPool: DefinitionReader<(Omit<import("../../index.js").
42
43
  readonly branch?: import("../../index.js").AgentBranch;
43
44
  readonly tools?: {
44
45
  invoke: (request: import("../../index.js").ToolInvocationRequest) => Promise<import("../../index.js").ToolResult<unknown>>;
45
- } | Pick<import("../../index.js").ToolRegistry<import("../../index.js").ExecutableTool>, "invokeAsync">;
46
+ } | Pick<import("../../index.js").ToolRegistry<import("../../index.js").ErasedTool>, "invokeAsync">;
46
47
  } & {
47
48
  model?: string;
48
49
  models: Readonly<Record<string, import("../../index.js").AgentModelBinding>>;
@@ -56,7 +57,7 @@ export declare const agentPool: DefinitionReader<(Omit<import("../../index.js").
56
57
  readonly branch?: import("../../index.js").AgentBranch;
57
58
  readonly tools?: {
58
59
  invoke: (request: import("../../index.js").ToolInvocationRequest) => Promise<import("../../index.js").ToolResult<unknown>>;
59
- } | Pick<import("../../index.js").ToolRegistry<import("../../index.js").ExecutableTool>, "invokeAsync">;
60
+ } | Pick<import("../../index.js").ToolRegistry<import("../../index.js").ErasedTool>, "invokeAsync">;
60
61
  } & {
61
62
  model?: import("../../index.js").AgentModelBinding;
62
63
  models?: never;
@@ -70,7 +71,7 @@ export declare const agentPool: DefinitionReader<(Omit<import("../../index.js").
70
71
  readonly branch?: import("../../index.js").AgentBranch;
71
72
  readonly tools?: {
72
73
  invoke: (request: import("../../index.js").ToolInvocationRequest) => Promise<import("../../index.js").ToolResult<unknown>>;
73
- } | Pick<import("../../index.js").ToolRegistry<import("../../index.js").ExecutableTool>, "invokeAsync">;
74
+ } | Pick<import("../../index.js").ToolRegistry<import("../../index.js").ErasedTool>, "invokeAsync">;
74
75
  } & {
75
76
  model?: string;
76
77
  models: Readonly<Record<string, import("../../index.js").AgentModelBinding>>;
@@ -11,7 +11,9 @@ import type { DefinitionBody } from './definition.js';
11
11
  /** A node implementation; its public id is supplied by @node. */
12
12
  export type Node<State, Result, App = undefined> = DefinitionBody<WorkflowNode<State, Result, App>>;
13
13
  /** A tool implementation with the original schema, authorization and execution contracts. */
14
- export type Tool<Input = unknown, Output = unknown, App = unknown> = DefinitionBody<ToolDefinition<Input, Output, App>>;
14
+ export type Tool<Input = unknown, Output = unknown, App = unknown> = DefinitionBody<Omit<ToolDefinition<Input, Output, App>, 'asIntent'>> & {
15
+ readonly asIntent?: never;
16
+ };
15
17
  /** A formatter and its original provenance, trust and budget configuration. */
16
18
  export type Fragment<Input = unknown> = DefinitionBody<ContextFragmentConfig<Input>>;
17
19
  /** A complete graph definition whose workflow id is supplied by @workflow. */
@@ -21,3 +21,4 @@ export type { ReplyPreviewRule, ReplyPreviewOptions } from './model/reply-previe
21
21
  export * from './capabilities.js';
22
22
  export { retryMultipleModelCalls } from '../model/decision-retry.js';
23
23
  export type { RegistrationDefinition } from '../structs/support/registration.js';
24
+ export * from './associations.js';
@@ -18,3 +18,4 @@ export { streamEvents } from './stream-events.js';
18
18
  export { createReplyPreview } from './model/reply-preview.js';
19
19
  export * from './capabilities.js';
20
20
  export { retryMultipleModelCalls } from '../model/decision-retry.js';
21
+ export * from './associations.js';
@@ -1,8 +1,13 @@
1
- import type { ModelCapabilityRegistration, ModelCapabilityCatalog } from '../../structs/capabilities/model.js';
1
+ import type { ModelToolRegistration, ModelToolCatalog } from '../../structs/capabilities/model.js';
2
+ import type { ToolProposal } from '../../structs/capabilities/model.js';
2
3
  /** A sealed typed snapshot. Mutating the original list cannot widen its result contract. */
3
4
  type CapabilityOutput<Definition> = Definition extends {
5
+ execute(...args: any[]): unknown;
6
+ } ? ToolProposal : Definition extends {
4
7
  resolve(...args: any[]): infer Output;
5
- } ? Output : never;
8
+ } ? Output : Definition extends {
9
+ inputSchema: import('../../structs/common.js').SchemaAdapter<infer Input>;
10
+ } ? Input : never;
6
11
  /**
7
12
  * Build a sealed capability catalog from typed declarations.
8
13
  *
@@ -13,5 +18,5 @@ type CapabilityOutput<Definition> = Definition extends {
13
18
  * unknown ID.
14
19
  * @throws {Error} When a resolver is asynchronous.
15
20
  */
16
- export declare function defineModelCapabilities<const Definitions extends readonly ModelCapabilityRegistration[]>(definitions: Definitions): ModelCapabilityCatalog<CapabilityOutput<Definitions[number]>>;
21
+ export declare function defineModelTools<const Definitions extends readonly ModelToolRegistration[]>(definitions: Definitions): ModelToolCatalog<CapabilityOutput<Definitions[number]>>;
17
22
  export {};
@@ -2,13 +2,13 @@
2
2
  * Model capability catalog: seal a typed declaration list into a reusable catalog.
3
3
  *
4
4
  * The catalog is a frozen snapshot, so mutating the original declaration list cannot widen the
5
- * result type or add capabilities at runtime. Resolution stays inside Core's registry; Support only
5
+ * result type or add tools at runtime. Resolution stays inside Core's registry; Support only
6
6
  * projects the declarations and their output type.
7
7
  *
8
- * Main export: `defineModelCapabilities`.
8
+ * Main export: `defineModelTools`.
9
9
  */
10
10
  import { readonlyCatalog } from '../../utils/catalog.js';
11
- import { ModelCapabilityRegistry } from '../../capabilities/model.js';
11
+ import { ModelToolRegistry } from '../../capabilities/model.js';
12
12
  /**
13
13
  * Build a sealed capability catalog from typed declarations.
14
14
  *
@@ -19,10 +19,40 @@ import { ModelCapabilityRegistry } from '../../capabilities/model.js';
19
19
  * unknown ID.
20
20
  * @throws {Error} When a resolver is asynchronous.
21
21
  */
22
- export function defineModelCapabilities(definitions) {
23
- const registry = new ModelCapabilityRegistry(definitions).seal();
22
+ export function defineModelTools(definitions) {
23
+ const registry = new ModelToolRegistry(definitions.map(modelDefinition)).seal();
24
+ return project(registry);
25
+ }
26
+ /** Executable tools propose raw arguments; business parsing occurs once at execution. */
27
+ function modelDefinition(definition) {
28
+ const executable = definition;
29
+ if (typeof executable.execute !== 'function')
30
+ return definition;
31
+ if (typeof executable.authorize !== 'function' || typeof executable.parseOutput !== 'function')
32
+ throw new TypeError('Missing executable tool handler');
33
+ const id = definition.id;
34
+ return {
35
+ id,
36
+ description: definition.description,
37
+ active: typeof definition.active === 'function'
38
+ ? definition.active.bind(definition)
39
+ : definition.active,
40
+ asIntent: typeof definition.asIntent === 'function'
41
+ ? definition.asIntent.bind(definition)
42
+ : definition.asIntent,
43
+ inputSchema: {
44
+ jsonSchema: definition.inputSchema.jsonSchema,
45
+ parse: (input) => input,
46
+ },
47
+ resolve: (input) => ({ toolId: id, input }),
48
+ };
49
+ }
50
+ /** Project existing immutable entries without re-registering schemas or rebinding handlers. */
51
+ function project(registry) {
24
52
  return Object.freeze({
25
53
  ...readonlyCatalog(registry.definitions, (id) => new TypeError(`Unknown model capability: ${id}`)),
26
54
  resolve: (selection, stage) => registry.resolve(selection, stage),
55
+ select: (ids, ...context) => project(context.length ? registry.select(ids, context[0]) : registry.select(ids)),
56
+ withIntent: (context) => project(registry.withIntent(context)),
27
57
  });
28
58
  }
@@ -14,10 +14,19 @@ export function chatCompletionFunctionOptions(options) {
14
14
  return {};
15
15
  if (!options.functions.length)
16
16
  throw new TypeError('Empty model function catalog');
17
+ if (options.toolChoice !== undefined &&
18
+ !['auto', 'required', 'none'].includes(options.toolChoice))
19
+ throw new TypeError('Invalid toolChoice');
20
+ if (options.parallelToolCalls !== undefined &&
21
+ options.parallelToolCalls !== 'omit' &&
22
+ typeof options.parallelToolCalls !== 'boolean')
23
+ throw new TypeError('Invalid parallelToolCalls');
17
24
  return {
18
25
  tools: options.functions.map((fn) => ({ type: 'function', function: fn })),
19
- tool_choice: 'required',
20
- parallel_tool_calls: false,
26
+ tool_choice: options.toolChoice ?? 'required',
27
+ ...(options.parallelToolCalls === 'omit'
28
+ ? {}
29
+ : { parallel_tool_calls: options.parallelToolCalls ?? false }),
21
30
  };
22
31
  }
23
32
  /**
@@ -1,40 +1,12 @@
1
1
  /**
2
- * Tool-call delta aggregation.
2
+ * Tool-call delta aggregation, re-exported from Core.
3
3
  *
4
- * One algorithm is shared by completion policies and direct callers: fragments are keyed by their
5
- * provider index, IDs may not conflict, and a complete call requires both an ID and a name. A
6
- * complete call never hides another started but incomplete one.
4
+ * The algorithm lives in `model/interactions/calls.ts` so session transports and
5
+ * completion policies share one implementation. This module keeps the existing
6
+ * Support import path stable.
7
7
  *
8
8
  * Exports: `AggregatedToolCall`, `ToolCallCollector`, `ToolCallFailure` and
9
9
  * `createToolCallCollector`.
10
10
  */
11
- import type { ModelPart } from '../../../structs/model/messages.js';
12
- /** One completed native tool call in provider index order. */
13
- export interface AggregatedToolCall {
14
- readonly index: number;
15
- readonly id: string;
16
- readonly name: string;
17
- readonly arguments: string;
18
- }
19
- /** Report a protocol violation and stop; callers decide how the failure is classified. */
20
- export type ToolCallFailure = (message: string) => never;
21
- /** Aggregation entry point for streamed function-call deltas. */
22
- export interface ToolCallCollector {
23
- /** Feed one part; text parts are ignored and cannot satisfy or break a call. */
24
- push(part: ModelPart): void;
25
- /** Calls started so far, including incomplete ones, in index order. */
26
- readonly calls: readonly AggregatedToolCall[];
27
- /**
28
- * Finalize the calls.
29
- *
30
- * @throws When any started call is still missing its ID or name.
31
- */
32
- complete(): readonly AggregatedToolCall[];
33
- }
34
- /**
35
- * Create a collector for one response.
36
- *
37
- * @param fail - Protocol failure factory; defaults to the Core model protocol error.
38
- * @returns A collector that keeps its own state and never shares it with another response.
39
- */
40
- export declare function createToolCallCollector(fail?: ToolCallFailure): ToolCallCollector;
11
+ export { createToolCallCollector } from '../../../model/interactions/calls.js';
12
+ export type { AggregatedToolCall, ToolCallCollector, ToolCallFailure, } from '../../../model/interactions/calls.js';
@@ -1,58 +1,11 @@
1
- import { modelProtocolError } from '../../../utils/model-protocol.js';
2
1
  /**
3
- * Create a collector for one response.
2
+ * Tool-call delta aggregation, re-exported from Core.
4
3
  *
5
- * @param fail - Protocol failure factory; defaults to the Core model protocol error.
6
- * @returns A collector that keeps its own state and never shares it with another response.
4
+ * The algorithm lives in `model/interactions/calls.ts` so session transports and
5
+ * completion policies share one implementation. This module keeps the existing
6
+ * Support import path stable.
7
+ *
8
+ * Exports: `AggregatedToolCall`, `ToolCallCollector`, `ToolCallFailure` and
9
+ * `createToolCallCollector`.
7
10
  */
8
- export function createToolCallCollector(fail = modelProtocolError) {
9
- const pending = new Map();
10
- const ids = new Set();
11
- const calls = () => [...pending.entries()]
12
- .sort(([left], [right]) => left - right)
13
- .map(([index, call]) => ({ index, ...call }));
14
- return {
15
- push(part) {
16
- if (typeof part === 'string')
17
- return;
18
- if (!part || typeof part !== 'object' || Array.isArray(part))
19
- fail('Expected a native model call');
20
- const { type, index, id, name, arguments: args } = part;
21
- if (type !== 'function-call-delta')
22
- fail('Expected a native model call');
23
- if (!Number.isInteger(index) || index < 0)
24
- fail('Invalid model call index');
25
- if ((id !== undefined && (typeof id !== 'string' || !id)) ||
26
- (name !== undefined && typeof name !== 'string') ||
27
- (args !== undefined && typeof args !== 'string'))
28
- fail('Invalid model call fields');
29
- let call = pending.get(index);
30
- if (!call) {
31
- call = { id: '', name: '', arguments: '' };
32
- pending.set(index, call);
33
- }
34
- if (id !== undefined) {
35
- if (call.id && call.id !== id)
36
- fail('Conflicting model call IDs');
37
- if (!call.id) {
38
- if (ids.has(id))
39
- fail('Duplicate model call ID');
40
- ids.add(id);
41
- call.id = id;
42
- }
43
- }
44
- call.name += name ?? '';
45
- call.arguments += args ?? '';
46
- },
47
- get calls() {
48
- return calls();
49
- },
50
- complete() {
51
- const completed = calls();
52
- for (const call of completed)
53
- if (!call.id || !call.name)
54
- fail('Incomplete model call');
55
- return completed;
56
- },
57
- };
58
- }
11
+ export { createToolCallCollector } from '../../../model/interactions/calls.js';
@@ -22,7 +22,7 @@ export * from './capabilities.js';
22
22
  export { createStageModelTransport } from './stage-transport.js';
23
23
  export { createProviderObservationScope } from './observer.js';
24
24
  export { createReplyPreviewRules } from './preview-rules.js';
25
- export type { ReplyPreviewCapability, ReplyPreviewStage } from './preview-rules.js';
25
+ export type { PreviewTool, ReplyPreviewTool, ReplyPreviewStage } from './preview-rules.js';
26
26
  export { runChildren } from './children.js';
27
27
  export type { ModelChildTask, ModelChildrenOptions } from './children.js';
28
28
  export { createModelStrategy, modelBudgetStrategies } from './strategies.js';
@@ -1,11 +1,16 @@
1
1
  import type { JsonSchema } from '../../structs/common.js';
2
2
  import type { ReplyPreviewRule } from './reply-preview.js';
3
+ import type { ModelTool } from '../../structs/capabilities/model.js';
4
+ /** A model tool with an explicit, presentation-only streaming preview contract. */
5
+ export interface PreviewTool<Input = unknown, Selection = Input, Context = any> extends ModelTool<Input, Selection, Context> {
6
+ readonly preview?: true | Omit<ReplyPreviewRule, 'stageId' | 'toolId'>;
7
+ }
3
8
  /**
4
9
  * Capability declaration used to derive preview rules.
5
10
  *
6
11
  * Omitted `preview` means the capability never previews, so previewing is an explicit opt-in.
7
12
  */
8
- export interface ReplyPreviewCapability {
13
+ export interface ReplyPreviewTool {
9
14
  /** Capability ID, which must equal the native function wire name used for transport. */
10
15
  readonly id: string;
11
16
  /** Input schema used to prove that preview and eligibility paths really exist. */
@@ -14,16 +19,16 @@ export interface ReplyPreviewCapability {
14
19
  * Explicit preview opt-in: `true` uses the default text/bubble paths, an object narrows the
15
20
  * paths and eligibility, and omission means the capability never previews.
16
21
  */
17
- readonly preview?: true | Omit<ReplyPreviewRule, 'stageId' | 'capabilityId'>;
22
+ readonly preview?: true | Omit<ReplyPreviewRule, 'stageId' | 'toolId'>;
18
23
  }
19
- /** Stage declaration: which capabilities it exposes and whether it previews text or arguments. */
24
+ /** Stage declaration: which tools it exposes and whether it previews text or arguments. */
20
25
  export interface ReplyPreviewStage {
21
26
  /** Stage ID used by the workflow and transport projection. */
22
27
  readonly id: string;
23
28
  /** Capabilities exposed at this stage; must be unique and registered. */
24
- readonly capabilityIds?: readonly string[];
25
- /** `text` previews plain model text; `capabilities` previews opted-in capability arguments. */
26
- readonly preview?: 'text' | 'capabilities';
29
+ readonly toolIds?: readonly string[];
30
+ /** `text` previews plain model text; `tools` previews opted-in capability arguments. */
31
+ readonly preview?: 'text' | 'tools';
27
32
  }
28
33
  /**
29
34
  * Generate frozen preview rules from capability and stage declarations.
@@ -31,12 +36,12 @@ export interface ReplyPreviewStage {
31
36
  * Capabilities without preview metadata are skipped even when their stage opts in. Default paths
32
37
  * are `text` and `bubbles[*]`, each kept only when the capability schema declares it.
33
38
  *
34
- * @param options Stage declarations and the capabilities they may reference.
39
+ * @param options Stage declarations and the tools they may reference.
35
40
  * @returns Frozen rules in stage order, each with deep-frozen paths and eligibility.
36
41
  * @throws {Error} When a capability or stage ID repeats, a stage references an unknown capability,
37
42
  * a preview mode is unknown, or a preview path or eligibility field is absent from the schema.
38
43
  */
39
44
  export declare function createReplyPreviewRules(options: {
40
45
  readonly stages: readonly ReplyPreviewStage[];
41
- readonly capabilities: readonly ReplyPreviewCapability[];
46
+ readonly tools: readonly ReplyPreviewTool[];
42
47
  }): readonly ReplyPreviewRule[];