@jangts/agent-core 0.2.1 → 0.3.5

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 (37) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +384 -50
  3. package/development/docs/api/README.en.md +2 -0
  4. package/development/docs/api/README.md +2 -0
  5. package/development/docs/api/decorators.en.md +83 -0
  6. package/development/docs/api/decorators.md +108 -0
  7. package/development/docs/api/reference.md +322 -257
  8. package/development/docs/api/workflow.en.md +10 -0
  9. package/development/docs/api/workflow.md +22 -0
  10. package/development/skills/agent-core-app/SKILL.md +8 -0
  11. package/dist/cjs/execution/cache.js +162 -0
  12. package/dist/cjs/execution/engine.js +10 -0
  13. package/dist/cjs/kits/vector-search.js +4 -7
  14. package/dist/cjs/structs/execution/cache.js +6 -0
  15. package/dist/cjs/support/decorators/definition.js +42 -0
  16. package/dist/cjs/support/decorators/index.js +63 -0
  17. package/dist/cjs/support/decorators/pool.js +87 -0
  18. package/dist/cjs/support/decorators/types.js +2 -0
  19. package/dist/esm/execution/cache.d.ts +20 -0
  20. package/dist/esm/execution/cache.js +156 -0
  21. package/dist/esm/execution/engine.d.ts +5 -0
  22. package/dist/esm/execution/engine.js +10 -0
  23. package/dist/esm/kits/vector-search.js +4 -7
  24. package/dist/esm/structs/execution/cache.d.ts +54 -0
  25. package/dist/esm/structs/execution/cache.js +5 -0
  26. package/dist/esm/structs/execution/engine.d.ts +6 -1
  27. package/dist/esm/structs/execution/workflow.d.ts +2 -1
  28. package/dist/esm/structs/index.d.ts +1 -0
  29. package/dist/esm/support/decorators/definition.d.ts +19 -0
  30. package/dist/esm/support/decorators/definition.js +38 -0
  31. package/dist/esm/support/decorators/index.d.ts +39 -0
  32. package/dist/esm/support/decorators/index.js +48 -0
  33. package/dist/esm/support/decorators/pool.d.ts +97 -0
  34. package/dist/esm/support/decorators/pool.js +83 -0
  35. package/dist/esm/support/decorators/types.d.ts +22 -0
  36. package/dist/esm/support/decorators/types.js +1 -0
  37. package/package.json +11 -3
package/CHANGELOG.md CHANGED
@@ -2,6 +2,36 @@
2
2
 
3
3
  本文件记录 `@jangts/agent-core` 的行为变更。接口合同与使用方式见[API 手册](development/docs/api/README.md)。
4
4
 
5
+ ## 0.3.5
6
+
7
+ - Add decorators and typescript-decorators keywords for npm discovery; preserve the English-first getting-started README.
8
+
9
+ ## 0.3.2
10
+
11
+ - Expand the English-first bilingual README with runnable workflows, model configuration, tools, decorators, knowledge and task-based documentation links.
12
+
13
+ ## 0.3.1
14
+
15
+ - Shared per-kind decorator readers with namespace isolation: ns defaults to 'default', accepts multiple namespaces, and leaves original ids unchanged. Read via get(id, ns?), getAll(ns?) and pick(ids, ns?). No public pool factories or owner lookups.
16
+ - Host-method decorators automatically bind and register during instance initialization. Constructor failures are wiring failures and do not roll back completed initialization registrations.
17
+
18
+ - Named decorator implementation types: Node, Tool, Fragment, Workflow, Agent and Model; class examples no longer repeat Omit.
19
+ - Decorator class constraints preserve union branches, including required App dependencies in Engine configurations.
20
+
21
+ ## 0.3.0
22
+
23
+ - Optional standard class and instance-method decorators in `/support/decorators` for nodes, tools and fragments; class decorators for workflow, Agent configuration and ModelRunner options.
24
+ - Classes are constructed once as definitions; methods bind the real host and preserve private state. The decorator supplies id without creating Engines, Runners or request budgets.
25
+ - Explicit DefinitionPool registration/read/selection/sealing and owner-local definitionOf reads, including ESM/CJS cross-reading of the same decorated owner.
26
+ - Original object APIs, execution, authorization, cancellation and 0.2.5 cache semantics remain unchanged. Bottom-level function converters are internal only.
27
+
28
+ ## 0.2.5
29
+
30
+ - Engine-owned, bounded LRU `context.cache` with node partitions and optional write TTL.
31
+ - Optional asynchronous App-owned `context.agentCache`; persistent and volatile spaces are explicit, independent and never silently fall back.
32
+ - Both workflow and `$step` contexts expose the same cache operations; forks have fresh memory and only use an explicitly restored App cache port.
33
+ - Vector filter, grouping and returned-hit metadata use independent snapshots so callback mutations cannot affect later consumers.
34
+
5
35
  ## 0.2.1
6
36
 
7
37
  ### 变更
package/README.md CHANGED
@@ -6,50 +6,217 @@
6
6
 
7
7
  <img src="https://agent-core-docs.pages.jangts.cafe/branding/agent-core-logo.png" alt="Agent Core" width="420">
8
8
 
9
- A platform-independent agent runtime with a runtime API, companion Support utilities, and optional Kits. Supports ESM, CommonJS, browsers, and Node.js.
9
+ Agent Core builds application-owned agents with explicit tools, state, routes and completion conditions. You define business handlers and orchestration; Core handles model/tool calls, state commits, budgets, cancellation and execution facts. Start with a single model call or add workflows, knowledge and class decorators as needed.
10
10
 
11
- [Full developer documentation](https://agent-core-docs.pages.jangts.cafe)
11
+ ## Install and run an Agent
12
+
13
+ Use **Node.js ≥ 22.12.0**. The package ships ESM, CommonJS and TypeScript declarations. Browser integrations require the Web APIs in use; keep model credentials on your server.
12
14
 
13
15
  ```sh
16
+ mkdir agent-demo
17
+ cd agent-demo
18
+ npm init -y
14
19
  npm install @jangts/agent-core
15
20
  ```
16
21
 
17
- A minimal Core call needs only a Provider and raw input. Support is optional:
22
+ Save as `app.mjs` and run `node app.mjs`. This runs a real workflow against a fixed offline Provider without credentials or network requests.
23
+
24
+ ```js
25
+ import { AgentCoreEngine, defineWorkflow, route } from '@jangts/agent-core';
26
+
27
+ const workflow = defineWorkflow({
28
+ id: 'greeting',
29
+ nodes: [{
30
+ id: 'reply',
31
+ description: 'Generate a greeting',
32
+ async run(state, { model }) {
33
+ const { value } = await model.invoke({ input: state.question });
34
+ return { answer: value };
35
+ },
36
+ routes: [route.deliver('answer')],
37
+ }],
38
+ });
39
+
40
+ // An offline Provider: no credentials, network or real model inference.
41
+ const provider = { async *stream() { yield 'Hello, Agent Core!'; } };
42
+ const agent = new AgentCoreEngine({ workflow, model: { provider, maxCalls: 1 } });
43
+ console.log(await agent.run({ question: 'Hello' }));
44
+ // Hello, Agent Core!
45
+ ```
46
+
47
+ A node returns a state patch. After commit, routes read the updated state: `route.to('next')` continues to another node; `route.deliver('answer')` returns the final result. The first node is the default entry, and routes match in declaration order.
18
48
 
19
- ```ts
20
- import { CompatibleModelProvider, ModelRunner } from '@jangts/agent-core';
49
+ The Provider above returns fixed text. Replace it with a real Provider without changing the workflow. The [complete offline example](https://agent-core-docs.pages.jangts.cafe/en/manual/examples/offline-agent) adds tools, multiple nodes and progress observation.
50
+
51
+ ## Connect a real model
52
+
53
+ For a Chat Completions-compatible service, save this as `provider.mjs`. `baseUrl` is the API base URL, excluding `/chat/completions`.
54
+
55
+ ```js
56
+ import { Support } from '@jangts/agent-core';
57
+
58
+ const { AI_BASE_URL, AI_API_KEY, AI_MODEL } = process.env;
59
+ if (!AI_BASE_URL || !AI_API_KEY || !AI_MODEL) {
60
+ throw new Error('Set AI_BASE_URL, AI_API_KEY and AI_MODEL');
61
+ }
62
+ export const provider = new Support.CompatibleModelProvider({
63
+ config: { baseUrl: AI_BASE_URL, apiKey: AI_API_KEY, model: AI_MODEL },
64
+ });
65
+ ```
66
+
67
+ For a single question, use ModelRunner directly. Save as `model.mjs`:
68
+
69
+ ```js
70
+ import { ModelRunner } from '@jangts/agent-core';
71
+ import { provider } from './provider.mjs';
72
+
73
+ const runner = new ModelRunner({
74
+ provider,
75
+ maxCalls: 2,
76
+ callTimeoutMs: 15000,
77
+ execution: { signal: AbortSignal.timeout(30000) },
78
+ });
79
+ const result = await runner.invoke('Explain what an Agent is in one sentence.');
80
+ console.log(result.value);
81
+ ```
82
+
83
+ Configure your service and run:
21
84
 
22
- const provider = new CompatibleModelProvider({ config: {
23
- baseUrl: process.env.AI_BASE_URL!,
24
- apiKey: process.env.AI_API_KEY!,
25
- model: process.env.AI_MODEL!,
26
- } });
27
- const model = new ModelRunner({ provider });
28
- const text = (await model.invoke('Hello')).value;
85
+ ```sh
86
+ export AI_BASE_URL="https://your-provider.example/v1"
87
+ export AI_API_KEY="your-api-key"
88
+ export AI_MODEL="your-model-id"
89
+ node model.mjs
90
+ ```
91
+
92
+ To connect the first workflow, replace its offline provider declaration with `import { provider } from './provider.mjs'`. Model `invoke` returns `{ value, invocation }`; `value` contains the complete result and `invocation` records the call. Failures throw. Configure Runner `sink.output` to consume live chunks while retaining the complete `value`. See [Core model calls](https://agent-core-docs.pages.jangts.cafe/en/manual/api/core).
93
+
94
+ ## Define and execute a tool
95
+
96
+ Save as `tools.mjs` and run `node tools.mjs`. One tool declaration provides model-visible schema, real input parsing, authorization, execution and output checking:
97
+
98
+ ```js
99
+ import { Support } from '@jangts/agent-core';
100
+
101
+ const catalog = Support.defineToolCatalog([{
102
+ id: 'double', kind: 'pure', description: 'Double a finite number.',
103
+ inputSchema: {
104
+ jsonSchema: {
105
+ type: 'object', required: ['value'], additionalProperties: false,
106
+ properties: { value: { type: 'number' } },
107
+ },
108
+ parse(input) {
109
+ if (!input || typeof input !== 'object' || !Number.isFinite(input.value)) {
110
+ throw new TypeError('value must be a finite number');
111
+ }
112
+ return input.value;
113
+ },
114
+ },
115
+ authorize() {}, // Public arithmetic; user data tools check App permissions here.
116
+ execute: value => value * 2,
117
+ parseOutput(value) {
118
+ if (!Number.isFinite(value)) throw new TypeError('Invalid result');
119
+ return value;
120
+ },
121
+ }]);
122
+
123
+ const tools = catalog.bind({ app: undefined });
124
+ const result = await tools.invoke({ toolId: 'double', input: { value: 21 } });
125
+ console.log(result.value); // 42
126
+ ```
127
+
128
+ Reuse static tool definitions and bind request dependencies and cancellation with `catalog.bind({ app, execution })`. Successful tool invocation also returns `{ value, invocation }`.
129
+
130
+ To let the model select a tool, append this to `tools.mjs` and use the `provider.mjs` above. The same catalog supplies model capabilities and actual execution:
131
+
132
+ ```js
133
+ import { ModelRunner } from '@jangts/agent-core';
134
+ import { provider } from './provider.mjs';
135
+
136
+ const selection = Support.createModelTransport({
137
+ id: 'choose-tool', capabilities: catalog.capabilities,
138
+ });
139
+ const runner = new ModelRunner({ provider, transports: [selection], maxCalls: 1 });
140
+ const proposal = await runner.invoke({
141
+ input: 'Use double to calculate twice 21.', transport: selection,
142
+ });
143
+ const executed = await tools.invoke({
144
+ toolId: proposal.value.toolId, input: proposal.value.input,
145
+ });
146
+ console.log(executed.value); // 42
147
+ ```
148
+
149
+ The model proposes an id and arguments. `tools.invoke` performs parsing, authorization and business execution. For multi-step behavior, put selection, execution and reply into Workflow nodes using `context.model.invoke` and `context.tools.invoke`. See [model and tool integration](https://agent-core-docs.pages.jangts.cafe/en/manual/basic-usage).
150
+
151
+ ## Organize handlers as classes
152
+
153
+ With standard TypeScript decorators, classes own configuration, handlers and private helpers. The decorator supplies id, constructs the definition and registers it. Save this standalone example as `greeting.mts`:
154
+
155
+ ```ts
156
+ import { AgentCoreEngine, defineWorkflow } from '@jangts/agent-core';
157
+ import { node, nodePool } from '@jangts/agent-core/support/decorators';
158
+ import type { Node } from '@jangts/agent-core/support/decorators';
159
+
160
+ type State = { name: string; answer?: string };
161
+
162
+ @node<State, string>('greet', { ns: 'welcome' })
163
+ class Greeting implements Node<State, string> {
164
+ readonly description = 'Greet a visitor';
165
+ #prefix = 'Hello, ';
166
+ get routes(): Node<State, string>['routes'] {
167
+ return [{ complete: state => state.answer! }];
168
+ }
169
+ run(state: Readonly<State>) { return { answer: this._format(state.name) }; }
170
+ private _format(name: string) { return this.#prefix + name.trim() + '!'; }
171
+ }
172
+
173
+ const workflow = defineWorkflow<State, string>({
174
+ id: 'welcome', nodes: nodePool.getAll('welcome'),
175
+ });
176
+ console.log(await new AgentCoreEngine({ workflow }).run({ name: 'Ivan' }));
177
+ // Hello, Ivan!
29
178
  ```
30
179
 
31
- This connects to a real Chat Completions-compatible model; the application supplies all three connection settings. See [Basic usage](development/docs/basic-usage.md) to override settings or add tools, context policies, and workflows.
180
+ Install `npm install -D tsx typescript`, then run `npx tsx greeting.mts`. Existing projects can use their standard-decorator compilation pipeline. NestJS units using `experimentalDecorators` cannot use this syntax directly.
32
181
 
33
- - [How it works](development/docs/mechanisms.md): collaboration, tasks, execution flow, model/tool sequences, and an application knowledge-answering example.
34
- - [Developer guide](development/docs/README.md): new applications, existing project integration, manual and agent-assisted development, knowledge resources, and runtime growth.
35
- - [API reference](development/docs/api/README.md): examples, parameters, return values, and exceptions.
36
- - [Complete knowledge-answering example](development/docs/api/knowledge-answering.md): reading sources, context, generation, checking, and template-based delivery.
182
+ - Each kind has one shared reader. `ns` defaults to `default` and accepts a string array. Read with `nodePool.get(id, ns?)`, `getAll(ns?)` or `pick(ids, ns?)`. Ids are unique within a kind and namespace.
183
+ - `@tool` and `@fragment` support classes and existing instance methods; method decorators retain the original name and bind the real host. `@workflow`, `@agent` and `@model` define original options without creating Engines or Runners.
184
+ - Getters can organize routes and private helpers. The route table is fixed during assembly; `when/complete` callbacks receive the latest execution state.
37
185
 
38
- [MockGPT Kit](development/docs/api/mock.md) provides direct mock generation, Provider protocol injection, a minimal Node server, and web text sources through `@jangts/agent-core/mock`, `/mock/node`, and `/mock/web`, without a separate mock dependency import.
186
+ The [decorator guide](https://agent-core-docs.pages.jangts.cafe/en/manual/api/decorators) covers host binding, namespace reads, multi-namespace registration and instance scope. Object definitions and decorator outputs use the same Core contracts.
39
187
 
40
- Import Core and Support from the package root. Import Kits by module, or use the aggregate `/kits` entry point.
188
+ ## Add knowledge, context and caching
41
189
 
42
- The package manager installs streaming, mock-gpt, and other runtime dependencies automatically. See [Installation](development/docs/getting-started.md).
190
+ Import optional Kits by module. For example, register and read versioned knowledge:
191
+
192
+ ```js
193
+ import { defineKnowledgeCatalog } from '@jangts/agent-core/kits/knowledge';
194
+
195
+ const knowledge = defineKnowledgeCatalog([
196
+ { id: 'manual', revision: 'r1', parts: ['Support hours: 09:00–18:00.'] },
197
+ ]);
198
+ const snapshot = knowledge.read({ documentId: 'manual', selection: { mode: 'document' } });
199
+ console.log(snapshot);
200
+ ```
43
201
 
44
- The `agent-core-app` Skill provides resource preparation and validation tools. See [Agent-assisted development](development/docs/agent-development.md).
202
+ App supplies the material; knowledge catalogs handle identity, versions and selection without automatically crawling websites or creating databases. The [knowledge-answering example](https://agent-core-docs.pages.jangts.cafe/en/manual/api/knowledge-answering) connects retrieval, evidence checking, generation, repair and delivery.
45
203
 
46
- Regular Workflow nodes assemble, select, trim, or compress context, with replaceable implementations from Support. Core retains generic trust/structure auditing, actual request measurement, budgets, and cancellation guarantees. To retain recent verbatim messages or ongoing task summaries, apply a recommended Support policy to the same configuration and override individual parameters. See [Context nodes](development/docs/api/context-processing.md).
204
+ Workflow `context.cache` provides synchronous Engine-lifetime memory partitioned by node, using `get/has/set/delete/clear`. App-owned asynchronous `context.agentCache` connects longer-lived storage; workflow state remains in state. Ordinary nodes and Support policies handle history selection, trimming and summaries. See [context processing](https://agent-core-docs.pages.jangts.cafe/en/manual/api/context-processing) and [cache contracts](https://agent-core-docs.pages.jangts.cafe/en/manual/api/workflow).
47
205
 
48
- Bind fixed model definitions, Workflows, and tools ahead of time, passing only per-request state. Existing request-level Runners can join the same Engine through `bindModelRuntime` and reuse its budget and scope. Applications register `execution.observe.event` to receive execution facts; persistent logging is independently optional.
206
+ ## Continue by task
49
207
 
50
- `ModelRunner.sink.output` receives actual generated chunks while preserving call budgets, cancellation, and protocol validation; `invoke` still returns the complete result. Applications can use `Support.createReplyPreview` to register previewable functions and body JSON paths, then send in-progress previews with `Support.streamEvents`. Confirm the final body after business validation, or retract it on failure. Previews cannot serve as authorization, tool execution, or official history. See [Core API](development/docs/api/core.md).
208
+ | Task | Documentation |
209
+ | --- | --- |
210
+ | Create an app or integrate with a project | [Developer guide](https://agent-core-docs.pages.jangts.cafe/en/manual/) · [Installation](https://agent-core-docs.pages.jangts.cafe/en/manual/getting-started) |
211
+ | Routes, models, budgets, cancellation and branches | [Workflow](https://agent-core-docs.pages.jangts.cafe/en/manual/api/workflow) · [Core](https://agent-core-docs.pages.jangts.cafe/en/manual/api/core) |
212
+ | Tools, schemas, context and integration policies | [Support](https://agent-core-docs.pages.jangts.cafe/en/manual/api/support) · [Context nodes](https://agent-core-docs.pages.jangts.cafe/en/manual/api/context-processing) |
213
+ | Knowledge, intents, retrieval, artifacts and persistent tasks | [Kits](https://agent-core-docs.pages.jangts.cafe/en/manual/api/kits) · [Recipes](https://agent-core-docs.pages.jangts.cafe/en/recipes/) |
214
+ | Mock model replies, tool proposals, streams and failures | [MockGPT Kit](https://agent-core-docs.pages.jangts.cafe/en/manual/api/mock) |
215
+ | Execution facts, call chains and Journal | [Observability](https://agent-core-docs.pages.jangts.cafe/en/manual/api/observability) |
216
+ | Integrate with a development agent | [Agent-assisted development and Skill](https://agent-core-docs.pages.jangts.cafe/en/manual/agent-development) |
217
+ | Exact signatures, overloads and result types | [API directory](https://agent-core-docs.pages.jangts.cafe/en/api/) · [Local API handbook](development/docs/api/README.en.md) |
51
218
 
52
- In this repository, `npm run test:agent-audit` builds Agent Core and MockGPT and runs logic, security, and performance regressions. Use `-- --repeat=2` for two consecutive rounds or `--no-build` to reuse existing builds. Coverage merges V8 ranges with c8/Istanbul and includes every generated ESM module, including modules not imported by existing tests. Statements, lines, functions, and branches must all reach 100%; uncovered logic fails the audit even if assertions pass. Reports are written to root `.tmp/agent-audit/`. Builds remove stale package output so moved sources cannot leave obsolete modules. Regressions use offline resources, injected ports, and loopback HTTP, without real models or public websites; they do not verify real-model comprehension or decision quality.
219
+ Import Core and Support from the package root, Kits from `/kits/<name>`, and decorators from `/support/decorators`. App owns identity, business permissions, external effects and storage; Core provides generic runtime guarantees. Support and Kits remain optional.
53
220
 
54
221
  ## License
55
222
 
@@ -63,50 +230,217 @@ Apache License 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
63
230
 
64
231
  <img src="https://agent-core-docs.pages.jangts.cafe/branding/agent-core-logo.png" alt="Agent Core" width="420">
65
232
 
66
- 平台无关的 Agent 运行库,提供运行 API、配套 Support 与可选 Kit。支持 ESM、CommonJS,以及浏览器/Node 环境。
233
+ Agent Core 用于在应用中构建有明确工具、状态、分支和结束条件的 Agent。你声明业务处理与流程,Core 负责模型调用、工具调用、状态提交、预算、取消和执行记录。既可以只调用一次模型,也可以逐步加入工具、知识资料、工作流与类装饰器。
67
234
 
68
- [完整网页开发文档](https://agent-core-docs.pages.jangts.cafe)
235
+ ## 安装并跑通第一个 Agent
236
+
237
+ 需要 **Node.js ≥ 22.12.0**。包提供 ESM、CommonJS 和 TypeScript 声明;浏览器接入需具备所用 Web API,模型密钥保留在服务端。
69
238
 
70
239
  ```sh
240
+ mkdir agent-demo
241
+ cd agent-demo
242
+ npm init -y
71
243
  npm install @jangts/agent-core
72
244
  ```
73
245
 
74
- Core 的最小调用只需 Provider 和原始输入,Support 保持可选:
246
+ 把下面代码保存为 `app.mjs`,运行 `node app.mjs`。它会实际运行一个工作流并调用离线 Provider,无需密钥或网络。
247
+
248
+ ```js
249
+ import { AgentCoreEngine, defineWorkflow, route } from '@jangts/agent-core';
250
+
251
+ const workflow = defineWorkflow({
252
+ id: 'greeting',
253
+ nodes: [{
254
+ id: 'reply',
255
+ description: 'Generate a greeting',
256
+ async run(state, { model }) {
257
+ const { value } = await model.invoke({ input: state.question });
258
+ return { answer: value };
259
+ },
260
+ routes: [route.deliver('answer')],
261
+ }],
262
+ });
263
+
264
+ // An offline Provider: no credentials, network or real model inference.
265
+ const provider = { async *stream() { yield 'Hello, Agent Core!'; } };
266
+ const agent = new AgentCoreEngine({ workflow, model: { provider, maxCalls: 1 } });
267
+ console.log(await agent.run({ question: 'Hello' }));
268
+ // Hello, Agent Core!
269
+ ```
270
+
271
+ 节点的 `run` 返回状态补丁;Engine 提交后,路由读取更新后的状态。`route.to('next')` 跳到下一节点,`route.deliver('answer')` 交付结果并结束。入口默认是首节点。有多个分支时,`routes` 按声明顺序匹配。
75
272
 
76
- ```ts
77
- import { CompatibleModelProvider, ModelRunner } from '@jangts/agent-core';
273
+ 这份 Provider 只返回固定文本;接入真实模型只需替换 provider,工作流不变。[完整离线示例](https://agent-core-docs.pages.jangts.cafe/zh/manual/examples/offline-agent)进一步展示工具查询、多个节点和过程监听。
274
+
275
+ ## 接入真实模型
276
+
277
+ 支持兼容 Chat Completions 的服务。将连接配置保存为 `provider.mjs`;`baseUrl` 是服务 API 根地址,不包含 `/chat/completions`。
278
+
279
+ ```js
280
+ import { Support } from '@jangts/agent-core';
281
+
282
+ const { AI_BASE_URL, AI_API_KEY, AI_MODEL } = process.env;
283
+ if (!AI_BASE_URL || !AI_API_KEY || !AI_MODEL) {
284
+ throw new Error('Set AI_BASE_URL, AI_API_KEY and AI_MODEL');
285
+ }
286
+ export const provider = new Support.CompatibleModelProvider({
287
+ config: { baseUrl: AI_BASE_URL, apiKey: AI_API_KEY, model: AI_MODEL },
288
+ });
289
+ ```
290
+
291
+ 只需一次问答时,可以直接使用 ModelRunner。保存为 `model.mjs`:
292
+
293
+ ```js
294
+ import { ModelRunner } from '@jangts/agent-core';
295
+ import { provider } from './provider.mjs';
296
+
297
+ const runner = new ModelRunner({
298
+ provider,
299
+ maxCalls: 2,
300
+ callTimeoutMs: 15000,
301
+ execution: { signal: AbortSignal.timeout(30000) },
302
+ });
303
+ const result = await runner.invoke('Explain what an Agent is in one sentence.');
304
+ console.log(result.value);
305
+ ```
306
+
307
+ 配置 `AI_BASE_URL`、`AI_API_KEY`、`AI_MODEL` 后运行 `node model.mjs`,例如:
78
308
 
79
- const provider = new CompatibleModelProvider({ config: {
80
- baseUrl: process.env.AI_BASE_URL!,
81
- apiKey: process.env.AI_API_KEY!,
82
- model: process.env.AI_MODEL!,
83
- } });
84
- const model = new ModelRunner({ provider });
85
- const text = (await model.invoke('你好')).value;
309
+ ```sh
310
+ export AI_BASE_URL="https://your-provider.example/v1"
311
+ export AI_API_KEY="your-api-key"
312
+ export AI_MODEL="your-model-id"
313
+ node model.mjs
314
+ ```
315
+
316
+ 接入首个工作流时,用 `import { provider } from './provider.mjs'` 替换其中的离线 provider 声明即可。模型 `invoke` 返回 `{ value, invocation }`:`value` 是完整结果,`invocation` 是调用记录;失败抛错。需要实时文本时配置 Runner 的 `sink.output`,完整结果仍从 `value` 读取。详见[模型调用](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/core)。
317
+
318
+ ## 定义工具并实际执行
319
+
320
+ 将下面代码保存为 `tools.mjs`,运行 `node tools.mjs`。工具同时声明模型可见 schema、真实输入解析、授权、执行和结果检查:
321
+
322
+ ```js
323
+ import { Support } from '@jangts/agent-core';
324
+
325
+ const catalog = Support.defineToolCatalog([{
326
+ id: 'double', kind: 'pure', description: 'Double a finite number.',
327
+ inputSchema: {
328
+ jsonSchema: {
329
+ type: 'object', required: ['value'], additionalProperties: false,
330
+ properties: { value: { type: 'number' } },
331
+ },
332
+ parse(input) {
333
+ if (!input || typeof input !== 'object' || !Number.isFinite(input.value)) {
334
+ throw new TypeError('value must be a finite number');
335
+ }
336
+ return input.value;
337
+ },
338
+ },
339
+ authorize() {}, // Public arithmetic; user data tools check App permissions here.
340
+ execute: value => value * 2,
341
+ parseOutput(value) {
342
+ if (!Number.isFinite(value)) throw new TypeError('Invalid result');
343
+ return value;
344
+ },
345
+ }]);
346
+
347
+ const tools = catalog.bind({ app: undefined });
348
+ const result = await tools.invoke({ toolId: 'double', input: { value: 21 } });
349
+ console.log(result.value); // 42
350
+ ```
351
+
352
+ 工具定义可复用;`catalog.bind({ app, execution })` 在请求中绑定服务端依赖和取消信号。工具执行成功同样返回 `{ value, invocation }`。
353
+
354
+ 让模型选择工具时,将下面代码接在 `tools.mjs` 末尾,并使用上面的 `provider.mjs`。同一份 catalog 同时生成模型可见能力和真实执行入口:
355
+
356
+ ```js
357
+ import { ModelRunner } from '@jangts/agent-core';
358
+ import { provider } from './provider.mjs';
359
+
360
+ const selection = Support.createModelTransport({
361
+ id: 'choose-tool', capabilities: catalog.capabilities,
362
+ });
363
+ const runner = new ModelRunner({ provider, transports: [selection], maxCalls: 1 });
364
+ const proposal = await runner.invoke({
365
+ input: 'Use double to calculate twice 21.', transport: selection,
366
+ });
367
+ const executed = await tools.invoke({
368
+ toolId: proposal.value.toolId, input: proposal.value.input,
369
+ });
370
+ console.log(executed.value); // 42
371
+ ```
372
+
373
+ 模型只提出工具 ID 和参数,`tools.invoke` 才会执行解析、授权与业务操作。需要多步调用时,把选择、执行、回答组织成上面学过的 Workflow 节点,继续使用 `context.model.invoke` 与 `context.tools.invoke`。详见[模型与工具接入](https://agent-core-docs.pages.jangts.cafe/zh/manual/basic-usage)。
374
+
375
+ ## 用类组织节点与内部方法
376
+
377
+ 使用 TypeScript 标准装饰器时,节点类提供配置与实现,装饰器补上 id、实例化并登记;无需手写 new 或 bind。下面是一份独立的 `greeting.mts`:
378
+
379
+ ```ts
380
+ import { AgentCoreEngine, defineWorkflow } from '@jangts/agent-core';
381
+ import { node, nodePool } from '@jangts/agent-core/support/decorators';
382
+ import type { Node } from '@jangts/agent-core/support/decorators';
383
+
384
+ type State = { name: string; answer?: string };
385
+
386
+ @node<State, string>('greet', { ns: 'welcome' })
387
+ class Greeting implements Node<State, string> {
388
+ readonly description = 'Greet a visitor';
389
+ #prefix = 'Hello, ';
390
+ get routes(): Node<State, string>['routes'] {
391
+ return [{ complete: state => state.answer! }];
392
+ }
393
+ run(state: Readonly<State>) { return { answer: this._format(state.name) }; }
394
+ private _format(name: string) { return this.#prefix + name.trim() + '!'; }
395
+ }
396
+
397
+ const workflow = defineWorkflow<State, string>({
398
+ id: 'welcome', nodes: nodePool.getAll('welcome'),
399
+ });
400
+ console.log(await new AgentCoreEngine({ workflow }).run({ name: 'Ivan' }));
401
+ // Hello, Ivan!
86
402
  ```
87
403
 
88
- 以上是兼容 Chat Completions 的真实模型接入;三个连接值由应用提供。接下来按[基础调用说明](development/docs/basic-usage.md)覆盖设置或接入工具、上下文策略和工作流。
404
+ 独立运行可安装 `npm install -D tsx typescript`,再执行 `npx tsx greeting.mts`。使用项目编译流程时,保持标准装饰器语义;开启 `experimentalDecorators` 的 NestJS 编译单元不能直接使用这套语法。
89
405
 
90
- - [工作机制图解](development/docs/mechanisms.md):总体协作、任务概念、执行流程、模型与工具时序,以及 App 知识回答示例。
91
- - [第三方开发指南](development/docs/README.md):新应用创建、已有项目接入、手工与 Agent 开发、知识资料及运行增长。
92
- - [API 手册](development/docs/api/README.md):调用示例、参数、返回值与异常。
93
- - [知识回答完整调用](development/docs/api/knowledge-answering.md):资料读取、上下文、生成、检查与母板交付。
406
+ - 每类各一个共享池;`ns` 默认 `default`,可传字符串数组。`nodePool.get(id, ns?)`、`getAll(ns?)`、`pick(ids, ns?)` 读取定义,同类型同命名空间内 id 唯一。
407
+ - `@tool`、`@fragment` 同时支持类和已有实例方法;方法装饰保留原方法名并绑定真实宿主。`@workflow`、`@agent`、`@model` 定义原配置,不创建 Engine 或 Runner。
408
+ - getter 可组织路由及私有辅助方法。路由表在装配时固定,`when/complete` 回调读取运行中的最新 state。
94
409
 
95
- [MockGPT Kit](development/docs/api/mock.md) 提供直接模拟生成、Provider 协议注入、最小 Node Server 和网页文本来源;使用 `@jangts/agent-core/mock`、`/mock/node`、`/mock/web`,无需单独导入模拟器依赖。
410
+ [装饰器完整合同与示例](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/decorators)说明方法绑定、命名空间、多空间登记和实例作用域。对象写法与装饰器产物使用相同的 Core 接口。
96
411
 
97
- Core 与 Support 从包根调用。Kit 默认按模块引入,也保留独立的 `/kits` 全量入口。
412
+ ## 加入资料、上下文与缓存
98
413
 
99
- 包管理器会自动安装 streaming、mock-gpt 及其他运行依赖,具体步骤见[安装指南](development/docs/getting-started.md)。
414
+ 可选 Kit 按模块导入。例如直接登记并读取有版本的资料:
415
+
416
+ ```js
417
+ import { defineKnowledgeCatalog } from '@jangts/agent-core/kits/knowledge';
418
+
419
+ const knowledge = defineKnowledgeCatalog([
420
+ { id: 'manual', revision: 'r1', parts: ['Support hours: 09:00–18:00.'] },
421
+ ]);
422
+ const snapshot = knowledge.read({ documentId: 'manual', selection: { mode: 'document' } });
423
+ console.log(snapshot);
424
+ ```
100
425
 
101
- 资料准备与校验工具由 `agent-core-app` Skill 提供,使用方式见[Agent 辅助开发](development/docs/agent-development.md)。
426
+ 资料由 App 提供;知识目录负责标识、版本和选择,不自动抓取网站或建立数据库。需要检索、证据检查、生成、修正与交付时,按[知识回答完整示例](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/knowledge-answering)组合。
102
427
 
103
- 上下文通过普通 Workflow 节点装配、选择、裁切或压缩,Support 提供可替换实现;Core 保留通用信任/结构审计、真实请求测量、预算与取消保证。需要保留近期原文或连续任务摘要时,可在同一配置上使用 Support 推荐策略,再精确覆盖参数,见[上下文节点](development/docs/api/context-processing.md)。
428
+ 工作流节点的 `context.cache` 提供 Engine 生命周期内、按节点分区的同步缓存,可用 `get/has/set/delete/clear`。长期存储通过 App 提供的异步 `context.agentCache` 接入;工作流状态仍放在 state。历史消息的选择、裁切与摘要通过普通节点和 Support 策略组织,见[上下文处理](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/context-processing)与[缓存合同](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/workflow)。
104
429
 
105
- 固定模型定义、Workflow 和工具可提前绑定,请求只传本次状态。已有请求级 Runner 可通过 `bindModelRuntime` 接入同一 Engine,复用其预算与作用域;App 注册 `execution.observe.event` 获取过程事实,日志持久化独立可选。
430
+ ## 按任务继续阅读
106
431
 
107
- `ModelRunner.sink.output` 可在保留调用预算、取消和协议校验的同时接收真实生成分片,`invoke` 仍返回完整结果。App 可选用 `Support.createReplyPreview` 登记允许预览的函数与正文 JSON 路径,配合 `Support.streamEvents` 发送生成中预览;业务校验通过后再确认正式正文,失败时撤回。预览不能用作授权、工具执行或正式历史,详见[Core API](development/docs/api/core.md)。
432
+ | 要做什么 | 入口 |
433
+ | --- | --- |
434
+ | 从空项目开始或接入现有应用 | [开发指南](https://agent-core-docs.pages.jangts.cafe/zh/manual/) · [安装与配置](https://agent-core-docs.pages.jangts.cafe/zh/manual/getting-started) |
435
+ | 编排条件路由、多模型、预算、取消和分支 | [Workflow](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/workflow) · [Core](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/core) |
436
+ | 管理工具、schema、上下文与接入策略 | [Support](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/support) · [上下文节点](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/context-processing) |
437
+ | 使用知识、意图、检索、产物和持久任务 | [Kit 手册](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/kits) · [场景示例](https://agent-core-docs.pages.jangts.cafe/zh/recipes/) |
438
+ | 模拟模型、工具提议、流式回复与故障 | [MockGPT Kit](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/mock) |
439
+ | 接收执行事实、记录调用链和 Journal | [观察与日志](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/observability) |
440
+ | 让开发 Agent 辅助接入 SDK | [Agent 辅助开发与 Skill](https://agent-core-docs.pages.jangts.cafe/zh/manual/agent-development) |
441
+ | 查精确参数、重载和返回值 | [API 目录](https://agent-core-docs.pages.jangts.cafe/zh/api/) · [本地 API 手册](development/docs/api/README.md) |
108
442
 
109
- 仓库内运行 `npm run test:agent-audit` 可构建 Agent Core 与 MockGPT 并执行逻辑、安全和性能回归;`-- --repeat=2` 连续执行两轮,`--no-build` 复用已有构建。覆盖统计通过 c8/Istanbul 合并 V8 区间,包含全部生成的 ESM 模块,未被现有测试导入的模块也参与统计;语句、行、函数与分支覆盖率均以 100% 为通过门槛,存在未覆盖逻辑即失败,测试断言通过不能替代此门槛;报告写入根 `.tmp/agent-audit/`。构建清理本包旧产物,避免源码移动后残留失效模块。回归使用离线资料、注入端口与本机回环 HTTP,不调用真实模型或公网网站;不验证真实模型的理解与决策质量。
443
+ Core 与 Support 从包根导入,Kit 从 `/kits/<name>` 导入,装饰器从 `/support/decorators` 导入。App 拥有身份、业务权限、外部副作用和存储;Core 提供通用运行保证,Support 与 Kit 按需使用。
110
444
 
111
445
  ## 许可
112
446
 
@@ -60,3 +60,5 @@ Synchronous algorithms remain synchronous. Source schema, permissions, budget, c
60
60
  ## Mock model
61
61
 
62
62
  The [MockGPT Kit](mock.md) describes `@jangts/agent-core/mock` and its `/node` and `/web` entries: rules and generators, direct return values, HTTP/SSE, tool proposals, web sources, errors, cancellation, and budget.
63
+
64
+ - [Decorators and definition pools](decorators.en.md)
@@ -60,3 +60,5 @@ Core 服务及共同合同从根入口,接入辅助从 `Support`,Kit 从各
60
60
  ## 模拟模型
61
61
 
62
62
  [MockGPT Kit](mock.md) 说明 `@jangts/agent-core/mock` 及其 `/node`、`/web` 入口:规则与生成器、直接返回值、HTTP/SSE、工具提议、网页来源、错误、取消与预算。
63
+
64
+ - [装饰器与定义池](decorators.md)
@@ -0,0 +1,83 @@
1
+ # Decorators and definition pools
2
+
3
+ Import decorators and readers from `@jangts/agent-core/support/decorators`. Only standard TypeScript decorators are supported; NestJS compilation units using experimentalDecorators cannot use this syntax directly. Original object, define, constructor and bind paths remain available. No runtime dependency, reflection metadata or automatic DI is added.
4
+
5
+ Class decorators construct a definition once after static initialization and supply id. Classes own their original fields, handlers, private helpers and getters; do not repeat complete options in decorator metadata. Classes require zero-argument construction. Constructors initialize definitions without business operations. No Engine, Runner, request budget or model call is created.
6
+
7
+ ## Named class contracts
8
+
9
+ Import Node, Tool, Fragment, Workflow, Agent and Model from the decorator subpath. These contracts omit the decorator-owned id. Object-shaped contracts support implements; Agent preserves the original union and is checked by its decorator rather than requiring a class to implement a union. Getters, private fields and prototype methods retain their original receiver.
10
+
11
+ ```ts
12
+ import { AgentCoreEngine, defineWorkflow } from '@jangts/agent-core';
13
+ import { node, nodePool } from '@jangts/agent-core/support/decorators';
14
+ import type { Node } from '@jangts/agent-core/support/decorators';
15
+ type State = { text: string; answer?: string };
16
+ @node<State, string>('greet', { ns: 'chat' })
17
+ class Greeting implements Node<State, string> {
18
+ readonly description = 'Greeting';
19
+ readonly routes = [{ complete: (state: Readonly<State>) => state.answer! }];
20
+ #prefix = 'Hello, ';
21
+ run(state: Readonly<State>) { return { answer: this._format(state.text) }; }
22
+ private _format(text: string) { return this.#prefix + text.trim(); }
23
+ }
24
+ const workflow = defineWorkflow<State, string>({ id: 'greeting', nodes: nodePool.getAll('chat') });
25
+ console.log(await new AgentCoreEngine({ workflow }).run({ text: 'visitor' }));
26
+ ```
27
+
28
+ ## Namespaces and reads
29
+
30
+ Each kind has one shared reader: nodePool, toolPool, fragmentPool, workflowPool, agentPool and modelPool. Consumers do not create pools or register definitions manually. Every decorator accepts optional `{ ns: string | readonly string[] }`, defaulting to `'default'`.
31
+
32
+ ```ts
33
+ nodePool.get('greet', 'chat');
34
+ nodePool.getAll('chat');
35
+ nodePool.pick(['greet', 'answer'], 'chat');
36
+ nodePool.get('greet'); // default namespace
37
+ nodePool.getAll(); // only default, not every namespace
38
+ nodePool.pick(['greet']);
39
+ ```
40
+
41
+ Ids are unique within one kind and namespace. Other namespaces and kinds may reuse an id. Names match exactly, without hierarchy, wildcard or fallback; blank names and empty namespace arrays reject. Repeated namespaces are deduplicated. An array registers the same definition in multiple namespaces without copying or reconstructing it. All destinations are checked before writing; a conflict leaves no partial registration.
42
+
43
+ get returns undefined on a miss. getAll returns a frozen registration-order snapshot, or an empty array for an unknown namespace. pick takes an id array, preserves caller order and rejects missing or repeated ids; an empty id array returns an empty snapshot. Reads accept original-definition generics, for example `nodePool.get<WorkflowNode<State, string>>('greet', 'chat')`. The generic describes the caller's expected contract, not a runtime type proof.
44
+
45
+ ns is external registration metadata, excluded from Core options. Returned ids remain unchanged. Combining same-id definitions from different namespaces in one Workflow or ToolRegistry still fails original uniqueness checks. App owns explicit node ordering and routes. Readers expose no constructors, registration, reset, sealing, tags or owner lookups.
46
+
47
+ ## Existing instance methods
48
+
49
+ ```ts
50
+ class GreetingService {
51
+ constructor(private readonly prefix: string) {}
52
+ @node<State, string>('reply', {
53
+ ns: 'chat-service', description: 'Use an existing service',
54
+ routes: [{ complete: (state: Readonly<State>) => state.answer! }],
55
+ })
56
+ answer(state: Readonly<State>) { return { answer: this.prefix + state.text }; }
57
+ }
58
+ const service = new GreetingService('Hello, ');
59
+ const definition = nodePool.get('reply', 'chat-service');
60
+ ```
61
+
62
+ Standard instance initializers automatically bind and register methods. No registerFrom, manual bind, renamed handler or extra class decorator is needed. Initializers run before instance fields and constructor bodies, so they bind without invoking handlers or reading business fields. Read and execute only after successful host construction. Constructor failures do not roll back completed initializer registrations and must be treated as wiring failures. Pools retain host references; use long-lived services, not request-scoped hosts. A second instance with the same kind, namespace and id rejects without replacing the original binding.
63
+
64
+ Direct metadata callbacks also bind the host. Nested schema/routes retain their original receiver, and arrow functions retain lexical this. Only public instance methods are supported; static/private methods, top-level function decorator syntax and implicit inheritance merging are unsupported. A class-owned id rejects because its decorator supplies id.
65
+
66
+ ## Original consumers
67
+
68
+ | Decorator | Class contract | Adapted method | Reader | Original consumer |
69
+ | --- | --- | --- | --- | --- |
70
+ | node | Node<State, Result, App> | run | nodePool | defineWorkflow |
71
+ | tool | Tool<Input, Output, App> | execute | toolPool | defineTool / defineToolCatalog |
72
+ | fragment | Fragment<Input> | format | fragmentPool | defineContextFragments |
73
+ | workflow | Workflow<State, Result, App> | None | workflowPool | defineWorkflow |
74
+ | agent | Agent<State, Result, App> | None | agentPool | Engine constructor |
75
+ | model | Model | None | modelPool | ModelRunner constructor |
76
+
77
+ agent/model ids are registration keys, not Core branch, model or transport identities. Original schema, graph, trust, authorization, result, budget and cancellation boundaries remain in force. Nodes are validated in the final graph. No public metadata-plus-free-function adapter is provided; top-level functions belong directly in original options.
78
+
79
+ ## Getter-defined routes
80
+
81
+ A routes getter may return `when: state => this._ready(state)` and `complete: state => this._reply(state)`. Workflow assembly reads and snapshots the table, potentially reading the getter multiple times. Keep getters pure and independent of request state. After state patches commit, route callbacks receive the latest state and can call private helpers. The getter is not re-evaluated each run; do not store request state on shared nodes.
82
+
83
+ ESM/CJS module copies share roots within one JavaScript realm. Processes, workers and separate realms do not share roots. Independently evaluated classes registering the same kind, namespace and id reject rather than merge. Explicitly retain definition modules in the bundle: discarded side-effect-only imports cannot guarantee registration. Shared definitions must not retain request identity, signal or budget. Reading is neither execution nor authorization.