@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.
- package/CHANGELOG.md +30 -0
- package/README.md +384 -50
- package/development/docs/api/README.en.md +2 -0
- package/development/docs/api/README.md +2 -0
- package/development/docs/api/decorators.en.md +83 -0
- package/development/docs/api/decorators.md +108 -0
- package/development/docs/api/reference.md +322 -257
- package/development/docs/api/workflow.en.md +10 -0
- package/development/docs/api/workflow.md +22 -0
- package/development/skills/agent-core-app/SKILL.md +8 -0
- package/dist/cjs/execution/cache.js +162 -0
- package/dist/cjs/execution/engine.js +10 -0
- package/dist/cjs/kits/vector-search.js +4 -7
- package/dist/cjs/structs/execution/cache.js +6 -0
- package/dist/cjs/support/decorators/definition.js +42 -0
- package/dist/cjs/support/decorators/index.js +63 -0
- package/dist/cjs/support/decorators/pool.js +87 -0
- package/dist/cjs/support/decorators/types.js +2 -0
- package/dist/esm/execution/cache.d.ts +20 -0
- package/dist/esm/execution/cache.js +156 -0
- package/dist/esm/execution/engine.d.ts +5 -0
- package/dist/esm/execution/engine.js +10 -0
- package/dist/esm/kits/vector-search.js +4 -7
- package/dist/esm/structs/execution/cache.d.ts +54 -0
- package/dist/esm/structs/execution/cache.js +5 -0
- package/dist/esm/structs/execution/engine.d.ts +6 -1
- package/dist/esm/structs/execution/workflow.d.ts +2 -1
- package/dist/esm/structs/index.d.ts +1 -0
- package/dist/esm/support/decorators/definition.d.ts +19 -0
- package/dist/esm/support/decorators/definition.js +38 -0
- package/dist/esm/support/decorators/index.d.ts +39 -0
- package/dist/esm/support/decorators/index.js +48 -0
- package/dist/esm/support/decorators/pool.d.ts +97 -0
- package/dist/esm/support/decorators/pool.js +83 -0
- package/dist/esm/support/decorators/types.d.ts +22 -0
- package/dist/esm/support/decorators/types.js +1 -0
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
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
|
-
[
|
|
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
|
-
|
|
188
|
+
## Add knowledge, context and caching
|
|
41
189
|
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
206
|
+
## Continue by task
|
|
49
207
|
|
|
50
|
-
|
|
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
|
-
|
|
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
|
-
|
|
233
|
+
Agent Core 用于在应用中构建有明确工具、状态、分支和结束条件的 Agent。你声明业务处理与流程,Core 负责模型调用、工具调用、状态提交、预算、取消和执行记录。既可以只调用一次模型,也可以逐步加入工具、知识资料、工作流与类装饰器。
|
|
67
234
|
|
|
68
|
-
|
|
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
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
404
|
+
独立运行可安装 `npm install -D tsx typescript`,再执行 `npx tsx greeting.mts`。使用项目编译流程时,保持标准装饰器语义;开启 `experimentalDecorators` 的 NestJS 编译单元不能直接使用这套语法。
|
|
89
405
|
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
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
|
-
[
|
|
410
|
+
[装饰器完整合同与示例](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/decorators)说明方法绑定、命名空间、多空间登记和实例作用域。对象写法与装饰器产物使用相同的 Core 接口。
|
|
96
411
|
|
|
97
|
-
|
|
412
|
+
## 加入资料、上下文与缓存
|
|
98
413
|
|
|
99
|
-
|
|
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
|
-
|
|
426
|
+
资料由 App 提供;知识目录负责标识、版本和选择,不自动抓取网站或建立数据库。需要检索、证据检查、生成、修正与交付时,按[知识回答完整示例](https://agent-core-docs.pages.jangts.cafe/zh/manual/api/knowledge-answering)组合。
|
|
102
427
|
|
|
103
|
-
|
|
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
|
-
|
|
430
|
+
## 按任务继续阅读
|
|
106
431
|
|
|
107
|
-
|
|
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
|
-
|
|
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)
|
|
@@ -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.
|