@migor/agentia 0.2.0 → 0.2.2

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 (191) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +144 -0
  3. package/README.md +202 -76
  4. package/dist/AGENTS.md +811 -0
  5. package/dist/container/container.d.ts +10 -2
  6. package/dist/container/container.js +27 -3
  7. package/dist/container/container.js.map +1 -1
  8. package/dist/core/abort.d.ts +10 -0
  9. package/dist/core/abort.js +28 -0
  10. package/dist/core/abort.js.map +1 -0
  11. package/dist/core/blackboard.d.ts +37 -0
  12. package/dist/core/blackboard.js +2 -0
  13. package/dist/core/blackboard.js.map +1 -0
  14. package/dist/core/json.d.ts +2 -0
  15. package/dist/core/json.js +4 -0
  16. package/dist/core/json.js.map +1 -1
  17. package/dist/core/run.d.ts +18 -0
  18. package/dist/core/run.js +2 -0
  19. package/dist/core/run.js.map +1 -0
  20. package/dist/core/schema.js +2 -2
  21. package/dist/core/schema.js.map +1 -1
  22. package/dist/core/tool.d.ts +62 -7
  23. package/dist/core/trace.d.ts +20 -4
  24. package/dist/engine/budget.d.ts +49 -0
  25. package/dist/engine/budget.js +30 -0
  26. package/dist/engine/budget.js.map +1 -0
  27. package/dist/engine/concurrency.d.ts +43 -0
  28. package/dist/engine/concurrency.js +95 -0
  29. package/dist/engine/concurrency.js.map +1 -0
  30. package/dist/engine/errors.d.ts +2 -0
  31. package/dist/engine/errors.js +7 -0
  32. package/dist/engine/errors.js.map +1 -1
  33. package/dist/engine/loop.d.ts +35 -10
  34. package/dist/engine/loop.js +336 -66
  35. package/dist/engine/loop.js.map +1 -1
  36. package/dist/engine/policy.d.ts +9 -1
  37. package/dist/engine/policy.js +8 -5
  38. package/dist/engine/policy.js.map +1 -1
  39. package/dist/engine/replay.d.ts +10 -4
  40. package/dist/engine/replay.js +57 -27
  41. package/dist/engine/replay.js.map +1 -1
  42. package/dist/engine/retry.d.ts +47 -0
  43. package/dist/engine/retry.js +51 -0
  44. package/dist/engine/retry.js.map +1 -0
  45. package/dist/engine/spec.d.ts +61 -0
  46. package/dist/{run → engine}/spec.js +4 -1
  47. package/dist/engine/spec.js.map +1 -0
  48. package/dist/engine/tracer.d.ts +9 -0
  49. package/dist/engine/tracer.js +57 -1
  50. package/dist/engine/tracer.js.map +1 -1
  51. package/dist/engine/{context.d.ts → trimming.d.ts} +19 -20
  52. package/dist/engine/trimming.js +238 -0
  53. package/dist/engine/trimming.js.map +1 -0
  54. package/dist/engine/types.d.ts +109 -13
  55. package/dist/engine/types.js +9 -1
  56. package/dist/engine/types.js.map +1 -1
  57. package/dist/engine/usage.d.ts +28 -2
  58. package/dist/engine/usage.js +39 -6
  59. package/dist/engine/usage.js.map +1 -1
  60. package/dist/eval/defineEval.d.ts +73 -0
  61. package/dist/eval/defineEval.js +44 -0
  62. package/dist/eval/defineEval.js.map +1 -0
  63. package/dist/eval/scripted.d.ts +26 -0
  64. package/dist/eval/scripted.js +43 -0
  65. package/dist/eval/scripted.js.map +1 -0
  66. package/dist/index.d.ts +60 -35
  67. package/dist/index.js +38 -20
  68. package/dist/index.js.map +1 -1
  69. package/dist/integrations/anthropic.d.ts +53 -0
  70. package/dist/integrations/anthropic.js +24 -0
  71. package/dist/integrations/anthropic.js.map +1 -0
  72. package/dist/integrations/mcp.d.ts +79 -0
  73. package/dist/integrations/mcp.js +108 -0
  74. package/dist/integrations/mcp.js.map +1 -0
  75. package/dist/integrations/metrics.d.ts +131 -0
  76. package/dist/integrations/metrics.js +488 -0
  77. package/dist/integrations/metrics.js.map +1 -0
  78. package/dist/{run → integrations}/openai.d.ts +12 -5
  79. package/dist/integrations/openai.js +386 -0
  80. package/dist/integrations/openai.js.map +1 -0
  81. package/dist/integrations/otlp.js.map +1 -0
  82. package/dist/integrations/report.d.ts +78 -0
  83. package/dist/integrations/report.js +257 -0
  84. package/dist/integrations/report.js.map +1 -0
  85. package/dist/runtime/context.d.ts +25 -0
  86. package/dist/{run → runtime}/context.js +8 -1
  87. package/dist/runtime/context.js.map +1 -0
  88. package/dist/{run → runtime}/memory.d.ts +1 -1
  89. package/dist/{run → runtime}/memory.js +3 -1
  90. package/dist/runtime/memory.js.map +1 -0
  91. package/dist/{run → runtime}/run.d.ts +22 -5
  92. package/dist/runtime/run.js +218 -0
  93. package/dist/runtime/run.js.map +1 -0
  94. package/dist/runtime/session.d.ts +27 -0
  95. package/dist/runtime/session.js +16 -0
  96. package/dist/runtime/session.js.map +1 -0
  97. package/dist/{run → runtime}/spec.d.ts +16 -2
  98. package/dist/runtime/spec.js +28 -0
  99. package/dist/runtime/spec.js.map +1 -0
  100. package/dist/{run → runtime}/systemPrompt.d.ts +12 -0
  101. package/dist/{run → runtime}/systemPrompt.js +16 -3
  102. package/dist/runtime/systemPrompt.js.map +1 -0
  103. package/dist/{run → runtime}/types.js.map +1 -1
  104. package/dist/{run → store}/fsStore.d.ts +15 -0
  105. package/dist/{run → store}/fsStore.js +43 -1
  106. package/dist/store/fsStore.js.map +1 -0
  107. package/dist/{run → store}/redisStore.d.ts +23 -1
  108. package/dist/{run → store}/redisStore.js +33 -6
  109. package/dist/store/redisStore.js.map +1 -0
  110. package/dist/{run → store}/sqliteStore.js +22 -1
  111. package/dist/store/sqliteStore.js.map +1 -0
  112. package/dist/{run → store}/store.d.ts +25 -3
  113. package/dist/store/store.js +63 -0
  114. package/dist/store/store.js.map +1 -0
  115. package/dist/toolkit/asset.d.ts +7 -6
  116. package/dist/toolkit/asset.js +7 -6
  117. package/dist/toolkit/asset.js.map +1 -1
  118. package/dist/toolkit/collect.d.ts +20 -7
  119. package/dist/toolkit/collect.js +21 -7
  120. package/dist/toolkit/collect.js.map +1 -1
  121. package/dist/toolkit/discover.d.ts +21 -1
  122. package/dist/toolkit/discover.js +59 -12
  123. package/dist/toolkit/discover.js.map +1 -1
  124. package/dist/toolkit/middleware.d.ts +10 -10
  125. package/dist/toolkit/middleware.js +17 -4
  126. package/dist/toolkit/middleware.js.map +1 -1
  127. package/dist/toolkit/module.d.ts +100 -34
  128. package/dist/toolkit/module.js +112 -36
  129. package/dist/toolkit/module.js.map +1 -1
  130. package/dist/toolkit/prompt.d.ts +4 -6
  131. package/dist/toolkit/prompt.js +11 -10
  132. package/dist/toolkit/prompt.js.map +1 -1
  133. package/dist/toolkit/skill.d.ts +14 -16
  134. package/dist/toolkit/skill.js +32 -25
  135. package/dist/toolkit/skill.js.map +1 -1
  136. package/dist/toolkit/subagent.d.ts +10 -12
  137. package/dist/toolkit/subagent.js +23 -21
  138. package/dist/toolkit/subagent.js.map +1 -1
  139. package/dist/toolkit/tool.d.ts +19 -11
  140. package/dist/toolkit/tool.js +11 -8
  141. package/dist/toolkit/tool.js.map +1 -1
  142. package/dist/toolkit/zod.d.ts +4 -3
  143. package/dist/toolkit/zod.js +2 -1
  144. package/dist/toolkit/zod.js.map +1 -1
  145. package/dist/transport/async.d.ts +133 -0
  146. package/dist/transport/async.js +415 -0
  147. package/dist/transport/async.js.map +1 -0
  148. package/dist/transport/http.d.ts +146 -0
  149. package/dist/transport/http.js +387 -0
  150. package/dist/transport/http.js.map +1 -0
  151. package/dist/{run → transport}/scheduler.d.ts +9 -1
  152. package/dist/transport/scheduler.js +133 -0
  153. package/dist/transport/scheduler.js.map +1 -0
  154. package/dist/transport/sse.d.ts +43 -0
  155. package/dist/transport/sse.js +51 -0
  156. package/dist/transport/sse.js.map +1 -0
  157. package/dist/{run → transport}/transport.d.ts +1 -1
  158. package/dist/{run → transport}/transport.js +1 -1
  159. package/dist/transport/transport.js.map +1 -0
  160. package/package.json +24 -9
  161. package/dist/engine/context.js +0 -146
  162. package/dist/engine/context.js.map +0 -1
  163. package/dist/run/async.d.ts +0 -59
  164. package/dist/run/async.js +0 -185
  165. package/dist/run/async.js.map +0 -1
  166. package/dist/run/context.d.ts +0 -16
  167. package/dist/run/context.js.map +0 -1
  168. package/dist/run/fsStore.js.map +0 -1
  169. package/dist/run/http.d.ts +0 -47
  170. package/dist/run/http.js +0 -119
  171. package/dist/run/http.js.map +0 -1
  172. package/dist/run/memory.js.map +0 -1
  173. package/dist/run/openai.js +0 -181
  174. package/dist/run/openai.js.map +0 -1
  175. package/dist/run/otlp.js.map +0 -1
  176. package/dist/run/redisStore.js.map +0 -1
  177. package/dist/run/run.js +0 -129
  178. package/dist/run/run.js.map +0 -1
  179. package/dist/run/scheduler.js +0 -85
  180. package/dist/run/scheduler.js.map +0 -1
  181. package/dist/run/spec.js.map +0 -1
  182. package/dist/run/sqliteStore.js.map +0 -1
  183. package/dist/run/store.js +0 -28
  184. package/dist/run/store.js.map +0 -1
  185. package/dist/run/systemPrompt.js.map +0 -1
  186. package/dist/run/transport.js.map +0 -1
  187. /package/dist/{run → integrations}/otlp.d.ts +0 -0
  188. /package/dist/{run → integrations}/otlp.js +0 -0
  189. /package/dist/{run → runtime}/types.d.ts +0 -0
  190. /package/dist/{run → runtime}/types.js +0 -0
  191. /package/dist/{run → store}/sqliteStore.d.ts +0 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 retrychx
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.en.md ADDED
@@ -0,0 +1,144 @@
1
+ # Agentia
2
+
3
+ [![CI](https://github.com/retrychx/agentia/actions/workflows/ci.yml/badge.svg)](https://github.com/retrychx/agentia/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
4
+
5
+ [中文 README](./README.md) · **English**
6
+
7
+ **A declarative framework for building production agent services.** You declare four kinds of capability
8
+ with decorators + DI and a main agent orchestrates them; every run yields structured output and an
9
+ observable call tree (trace, cost, metrics).
10
+
11
+ > This is a **summary**. The authoritative and always-current documentation is Chinese:
12
+ > [`docs/usage-guide.md`](./docs/usage-guide.md) (API reference, type wiring, known limits) and the
13
+ > [website](https://agentia-web.pages.dev). We keep this file short on purpose — a hand-maintained
14
+ > full translation drifts.
15
+
16
+ ## Requirements
17
+
18
+ Node.js **≥ 18** (the only `engines` requirement; CI runs 18 / 20 / 22). Deno and edge runtimes are
19
+ **not** validated. The only store touching a Node builtin is `SqliteTaskStore` (needs Node ≥ 22.5 for
20
+ `node:sqlite`) — it fails with a readable error at construction time, and never breaks importing the package.
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ npm i @migor/agentia # the framework
26
+ npm i -g @migor/cli # CLI: scaffold / generate / dev inspector
27
+ export ANTHROPIC_API_KEY=sk-... # or ANTHROPIC_AUTH_TOKEN; ANTHROPIC_BASE_URL for compatible gateways
28
+ ```
29
+
30
+ ## Quick start
31
+
32
+ ### A. CLI
33
+
34
+ ```bash
35
+ agentia create my-app
36
+ cd my-app && npm install
37
+ agentia g tool weather # create src/tools/weather/index.ts and register it
38
+ agentia dev # tsx watch + local inspector panel
39
+ ```
40
+
41
+ Four self-describing directories hold capabilities — the directory name **is** the kind:
42
+ `src/tools/` · `src/skills/` · `src/prompts/` · `src/subagents/`; the registry is `src/registry.ts`.
43
+
44
+ ### B. By hand
45
+
46
+ ```ts
47
+ import { Tool, createApp, SystemPrompt } from '@migor/agentia';
48
+
49
+ class WeatherTools {
50
+ @Tool({
51
+ description: 'Look up the weather for a city',
52
+ schema: {
53
+ type: 'object',
54
+ properties: { city: { type: 'string' } },
55
+ required: ['city'],
56
+ additionalProperties: false,
57
+ },
58
+ })
59
+ get_weather(input: { city: string }): string {
60
+ return `city=${input.city}`;
61
+ }
62
+ }
63
+
64
+ const app = createApp({
65
+ name: 'weather-app',
66
+ providers: [{ provide: 'weather', useClass: WeatherTools }],
67
+ system: new SystemPrompt().add('role', 'You are a helpful weather assistant.', true),
68
+ });
69
+
70
+ const { result } = await app.run([{ role: 'user', content: 'Weather in Shanghai?' }]);
71
+ console.log(result.finalText); // final text
72
+ console.log(result.trace); // call tree + per-step tokens/cost (traceId === runId)
73
+ ```
74
+
75
+ Or point `createApp` at the directories instead of passing providers:
76
+ `createApp({ discover: ['src/tools', 'src/skills', 'src/prompts', 'src/subagents'], system })`.
77
+
78
+ ## The four capability kinds
79
+
80
+ The model picks from one shared "menu" by `description`; the decorator decides **who controls the flow**:
81
+
82
+ | Kind | Decorator | Who controls the flow | Typical use |
83
+ |---|---|---|---|
84
+ | Tool | `@Tool` | your code (one call = one function) | deterministic work: DB, math, HTTP |
85
+ | Skill | `@Skill` | your code (scripted; model calls only at explicit `ctx.llm()`) | fixed "fetch → let the model write → post-process" pipelines |
86
+ | Sub-agent | `@SubAgent` | **the model** (own loop, trimmed context) | multi-step autonomy without polluting the main context |
87
+ | Prompt asset | `@Prompt` | pulled by the model on demand | long specs/templates that shouldn't sit in context by default |
88
+
89
+ ## Runtime features
90
+
91
+ - **Triggering** — `app.run()` (sync RPC) · `AsyncRunner` (idempotency-keyed, retryable, resumable via a
92
+ store) · `Scheduler` (cron-like) · `createHttpHandler` (`POST /run`, `POST /tasks`, `GET /tasks/:id`,
93
+ `GET /healthz`, optional `GET /metrics`, graceful `drain()`)
94
+ - **Context budget** — `createBudgetPolicy({ budgetTokens, summarize })`
95
+ - **Hard cost caps** — `maxTotalTokens` / `maxCostUsd` (+ `priceOverrides` to price non-Anthropic models)
96
+ - **Structured output** — `resultSchema`; `result.typed` is validated, or use `fromZod<T>()` for full type inference
97
+ - **Middleware** — an onion chain around every capability call (auth, rate limiting, caching, audit)
98
+ - **Cancellation / retries / streaming / tool concurrency** — `signal`, retry policy, `onText`, `maxToolConcurrency`
99
+
100
+ ## Observability & cost
101
+
102
+ One run == one trace (`traceId === runId`), **built in from turn 0** — not a bolt-on third-party tracing SDK:
103
+
104
+ - **Per-step accounting** — every span carries model, input/output/cache tokens, cost estimate, status and error type
105
+ - **One seam out** — `TraceSink { export(trace) }`, delivered on **both** the success and failure paths; a throwing
106
+ sink never breaks the run. Persistence / sampling / redaction are composed outside the seam
107
+ (`examples/observability/`, [`docs/observability.md`](./docs/observability.md))
108
+ - **Cost you can cap** — `priceOverrides` patches the price table; unpriced models emit an explicit
109
+ `usage.unpriced` event (never a silent zero); `maxCostUsd` / `maxTotalTokens` stop the run
110
+ - **Replay** — `traceToMessages(trace)` linearises a finished trace back into model messages
111
+ - **Export** — `createOtlpExporter({ endpoint })`; `metricsSink()` (Prometheus text or OTLP metrics), zero dependency
112
+ - **Locally visible** — `agentia dev` opens an inspector panel sharing one renderer with the website Playground;
113
+ `agentia report <trace.jsonl>` ranks which capability is slow / expensive / error-prone
114
+
115
+ ## Integrations
116
+
117
+ - **Models** — `createAnthropicClient()` (default) and `createOpenAIClient()` for any OpenAI-compatible
118
+ endpoint (DeepSeek, **Ollama**, gateways). You never need to touch a vendor SDK: pass
119
+ `createAnthropicClient({ baseURL })` / `createOpenAIClient({ baseURL })`.
120
+ - **MCP** — `mcpTools()` bridges an MCP server's tools into the menu (duck-typed, zero dependency)
121
+ - **Memory** — `memory: { store, keys }` for cross-run state; task stores: memory / JSONL / SQLite / Redis
122
+ - **Evals** — `scriptedClient` + `defineEval` turn mocked runs into a first-class diagnostic loop
123
+ - **Platforms** — send traces to Langfuse / Phoenix / etc. via OTLP or a tiny custom `TraceSink`
124
+ (see [`docs/observability.md`](./docs/observability.md) §2.6)
125
+
126
+ ## Documentation
127
+
128
+ | | |
129
+ |---|---|
130
+ | Usage guide (authoritative, zh) | [`docs/usage-guide.md`](./docs/usage-guide.md) |
131
+ | Production observability recipes | [`docs/observability.md`](./docs/observability.md) |
132
+ | Examples (complete app / minimal deploy / observability) | [`examples/`](./examples/) |
133
+ | Design spec & roadmap | [`docs/spec.md`](./docs/spec.md) · [`docs/roadmap.md`](./docs/roadmap.md) |
134
+ | Website · Playground | [agentia-web.pages.dev](https://agentia-web.pages.dev) · [playground](https://agentia-web.pages.dev/playground.html) |
135
+
136
+ ## Contributing
137
+
138
+ See [`CONTRIBUTING.md`](./CONTRIBUTING.md) — and note that [`AGENTS.md`](./AGENTS.md) is the single
139
+ source for this repo's engineering conventions. Security issues: [`SECURITY.md`](./SECURITY.md)
140
+ (please don't open a public issue).
141
+
142
+ ## License
143
+
144
+ [MIT](./LICENSE)
package/README.md CHANGED
@@ -1,44 +1,66 @@
1
1
  # Agentia
2
2
 
3
- 声明式 agent 服务开发框架:TS 装饰器 + DI,主 agent 调度 `@Tool` / `@Skill` / `@SubAgent` / `@Prompt` 单元执行任务,产出结构化结果与调用树(trace)。
3
+ [中文](./README.md) · [English](./README.en.md)
4
4
 
5
- ## 环境准备
5
+ [![CI](https://github.com/retrychx/agentia/actions/workflows/ci.yml/badge.svg)](https://github.com/retrychx/agentia/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+
7
+ 面向应用开发的声明式 agent 服务开发框架:装饰器 + DI 声明四类能力,主 agent 编排执行;每次 run 产出结构化结果与可观测调用树(trace、成本、指标),交付可直接上线的服务。
8
+
9
+ - [安装与配置](#安装与配置)
10
+ - [快速开始](#快速开始)
11
+ - [四类能力](#四类能力)
12
+ - [运行时特性](#运行时特性)
13
+ - [可观测性与成本](#可观测性与成本)
14
+ - [集成](#集成)
15
+ - [API 速查](#api-速查)
16
+ - [开发本仓库](#开发本仓库)
17
+ - [延伸阅读](#延伸阅读)
18
+
19
+ ## 安装与配置
6
20
 
7
21
  ```bash
8
- export ANTHROPIC_API_KEY=sk-... # 或 ANTHROPIC_AUTH_TOKEN
22
+ npm i @migor/agentia # 框架(项目依赖)
23
+ npm i -g @migor/cli # 命令行工具(脚手架 / 生成 / 调试)
24
+
25
+ export ANTHROPIC_API_KEY=sk-... # 或 ANTHROPIC_AUTH_TOKEN
9
26
  # 可选:ANTHROPIC_BASE_URL(兼容端点)、AGENTIA_MODEL(缺省 claude-opus-5)
10
27
  ```
11
28
 
12
- ## 快速开始(CLI)
29
+ > **版本**:`0.2.2`(`@migor/agentia` 与 `@migor/cli` 均已发布到 npm)。`examples/` **刻意**用
30
+ > `file:../..` 指向本仓库而不是 npm 版本 —— 跑的是**工作区代码**,理由见
31
+ > [`examples/README.md`](examples/README.md) 的「依赖说明」。
32
+
33
+ > **运行时**:Node ≥ 18(`engines` 唯一要求,CI 在 18/20/22 上守)。按 Node 设计并测试,
34
+ > **未对 Deno / edge 做验证**。唯一碰内置模块的 store 是 `SqliteTaskStore`(需 Node ≥ 22.5 的
35
+ > `node:sqlite`)—— 未提供时**构造期给可读报错**,不影响包本身被导入。
36
+
37
+
38
+ ## 快速开始
39
+
40
+ 两条路线,按需选一即可(也可混用)。
41
+
42
+ ### 路线 A:CLI 脚手架
13
43
 
14
44
  ```bash
15
- npm i -g @migor/cli # 安装 CLI(提供 agentia 命令)
16
45
  agentia create my-app # 脚手架新项目(依赖 @migor/agentia)
17
46
  cd my-app && npm install
18
- agentia g tool weather # 生成 units/weather/index.ts 并登记 units.ts
19
- agentia g subagent doc-reviewer # 生成 units/doc-reviewer/{index.ts,system.md}
20
- agentia g skill note-writer # 生成 units/note-writer/index.ts
21
- agentia g prompt style-guide # 生成 units/style-guide/{index.ts,asset.md}
22
- npm run dev # 运行 src/main.ts
47
+ agentia g tool weather # 生成 src/tools/weather/index.ts 并登记 src/registry.ts
48
+ agentia g subagent doc-reviewer # 生成 src/subagents/doc-reviewer/{index.ts,system.md}
49
+ agentia g skill note-writer # 生成 src/skills/note-writer/index.ts
50
+ agentia g prompt style-guide # 生成 src/prompts/style-guide/{index.ts,asset.md}
51
+ agentia dev # tsx watch + 本地 inspector 面板
23
52
  ```
24
53
 
25
- **目录约定**:`units/<name>/` 一单元一文件夹,`index.ts` default export 一个 provider 类,DI token 缺省 = 文件夹名;长文本放文件夹内 `.md`,代码里用 `asset(import.meta.url, './system.md')` 读取。
26
-
27
- **装配两条路(可混用)**:
54
+ **目录约定**:四分类目录,一能力一文件夹 —— `src/tools/` · `src/skills/` · `src/prompts/` · `src/subagents/`。
55
+ 目录名就是类型,不用记别名。每个文件夹的 `index.ts` default export 一个 provider 类,DI token 缺省 = 文件夹名;
56
+ 长文本放文件夹内 `.md`,代码里用 `asset(import.meta.url, './system.md')` 读取。
28
57
 
29
- ```ts
30
- // 1) 目录扫描:启动期扫描 units/*/ 自动装配(返回 Promise)
31
- const app = await createApp({ name: 'my-app', discover: 'units', system });
58
+ ### 路线 B:手写装配
32
59
 
33
- // 2) 显式注册表:units.ts 由 CLI 自动维护
34
- import { providers } from './units.js';
35
- const app = createApp({ name: 'my-app', providers, system });
36
- ```
37
-
38
- ## 手写单元
60
+ 不依赖 CLI,直接声明能力并装配成应用:
39
61
 
40
62
  ```ts
41
- import { Tool, SubAgent, createApp, SystemPrompt, RunContext } from '@migor/agentia';
63
+ import { Tool, createApp, SystemPrompt, RunContext } from '@migor/agentia';
42
64
 
43
65
  class WeatherTools {
44
66
  // 工具名缺省取方法名(建议 snake_case);入参 = 模型按 schema 解析的结构化 input
@@ -53,30 +75,17 @@ class WeatherTools {
53
75
  strict: true,
54
76
  })
55
77
  get_weather(input: { city: string }): string {
56
- // 方法体内随时可读本次 run 的上下文(blackboard)
57
- const token = RunContext.current()?.get<string>('authToken');
78
+ // 方法体内随时可读本次 run 的上下文(blackboard)。
79
+ // 想让键有补全/校验:在一次 declare module 里合并 Blackboard(见 docs/usage-guide.md §5.1);
80
+ // 未声明时键为 string、值为 unknown,这里按需断言。
81
+ const token = RunContext.current()?.get('authToken') as string | undefined;
58
82
  return `city=${input.city};token=${token ?? 'none'}`;
59
83
  }
60
84
  }
61
85
 
62
- class Pipeline {
63
- // 子 agent:独立循环 + 裁剪上下文,只有最终报告回流主上下文(方法体不执行)
64
- @SubAgent({
65
- name: 'reviewer',
66
- description: '审查给定文档并输出书面评审意见',
67
- schema: { type: 'object', properties: { doc: { type: 'string' } }, required: ['doc'], additionalProperties: false },
68
- system: '你是评审 agent。结论必须以“审查通过/不通过”开头。',
69
- tools: ['weather'], // 子 agent 自己的工具菜单(provider token)
70
- })
71
- reviewer(_input: { doc: string }): void {}
72
- }
73
-
74
86
  const app = createApp({
75
87
  name: 'weather-app',
76
- providers: [
77
- { provide: 'weather', useClass: WeatherTools },
78
- { provide: 'pipeline', useClass: Pipeline },
79
- ],
88
+ providers: [{ provide: 'weather', useClass: WeatherTools }],
80
89
  system: new SystemPrompt().add('role', '你是天气助手。', true),
81
90
  });
82
91
 
@@ -88,9 +97,33 @@ console.log(result.finalText); // 最终文本
88
97
  console.log(result.trace); // 调用树 + 每步 token/成本(traceId == runId)
89
98
  ```
90
99
 
91
- 另外两类单元:
100
+ 装配还有**目录扫描**这条路(与显式注册表可混用):
101
+
102
+ ```ts
103
+ // 按给定顺序扫各目录(返回 Promise);也可用 CLI 维护的 src/registry.ts 显式注册
104
+ const app = await createApp({
105
+ name: 'my-app',
106
+ discover: ['src/tools', 'src/skills', 'src/prompts', 'src/subagents'],
107
+ system,
108
+ });
109
+ ```
110
+
111
+ ## 四类能力
112
+
113
+ 主 agent 按 `description` 从同一张「能力菜单」自选;装饰器只决定**谁控制流程**:
114
+
115
+ | 能力 | 装饰器 | 谁决定流程 | 典型用途 |
116
+ |---|---|---|---|
117
+ | 工具 | `@Tool` | 你的代码(一次调用 = 一个函数) | 确定性操作:查库、算数、调 API |
118
+ | 技能 | `@Skill` | 你的代码(脚本式,显式 `ctx.llm()`) | 「先取数 → 再让模型写 → 再加工」的固定流程 |
119
+ | 子 agent | `@SubAgent` | **模型自己**(独立循环 + 裁剪上下文) | 自主多步、且中间过程不该污染主上下文 |
120
+ | 提示资产 | `@Prompt` | 模型拉取(按需注入的文本) | 长文规范/模板,平时不进上下文 |
121
+
122
+ `@Tool` 的写法见上方路线 B;其余三类:
92
123
 
93
124
  ```ts
125
+ import { Skill, SubAgent, Prompt, asset, type SkillContext } from '@migor/agentia';
126
+
94
127
  // @Skill:代码控制的流程,模型调用只发生在显式 ctx.llm()
95
128
  class Notes {
96
129
  @Skill({ description: '按主题整理要点' })
@@ -100,20 +133,53 @@ class Notes {
100
133
  }
101
134
  }
102
135
 
136
+ // @SubAgent:独立循环 + 裁剪上下文,只有最终报告回流主上下文(方法体不执行)
137
+ class Pipeline {
138
+ @SubAgent({
139
+ name: 'reviewer',
140
+ description: '审查给定文档并输出书面评审意见',
141
+ schema: { type: 'object', properties: { doc: { type: 'string' } }, required: ['doc'], additionalProperties: false },
142
+ system: '你是评审 agent。结论必须以“审查通过/不通过”开头。',
143
+ tools: ['weather'], // 子 agent 自己的工具菜单(provider token)
144
+ })
145
+ reviewer(_input: { doc: string }): void {}
146
+ }
147
+
103
148
  // @Prompt:纯文本资产,模型判定需要时拉取进上下文
104
149
  class Assets {
105
150
  @Prompt({ description: '品牌基调文案规范' })
106
151
  style_guide(): string {
107
- return asset(import.meta.url, './asset.md'); // 从单元文件夹读 .md
152
+ return asset(import.meta.url, './asset.md'); // 从能力文件夹读 .md
108
153
  }
109
154
  }
110
155
  ```
111
156
 
112
- ## 触发方式
157
+ 四类一起装配(`providers` 里逐个登记;token 即子 agent / 技能引用工具的菜单名):
158
+
159
+ ```ts
160
+ import { createApp, SystemPrompt } from '@migor/agentia';
161
+
162
+ const app = createApp({
163
+ name: 'weather-app',
164
+ providers: [
165
+ { provide: 'weather', useClass: WeatherTools },
166
+ { provide: 'notes', useClass: Notes },
167
+ { provide: 'pipeline', useClass: Pipeline },
168
+ { provide: 'assets', useClass: Assets },
169
+ ],
170
+ system: new SystemPrompt().add('role', '你是天气助手。', true),
171
+ });
172
+ ```
173
+
174
+ ## 运行时特性
175
+
176
+ ### 触发方式
113
177
 
114
178
  同一份应用,三种触发任选:
115
179
 
116
180
  ```ts
181
+ import { AsyncRunner, FileTaskStore, Scheduler } from '@migor/agentia';
182
+
117
183
  // 同步 RPC
118
184
  const { run, result } = await app.run(messages);
119
185
 
@@ -127,7 +193,7 @@ const scheduler = new Scheduler(runner);
127
193
  scheduler.every(60_000, '巡检一次', { idempotencyKey: 'patrol' });
128
194
  ```
129
195
 
130
- ## 长上下文预算
196
+ ### 长上下文预算
131
197
 
132
198
  ```ts
133
199
  import { createBudgetPolicy } from '@migor/agentia';
@@ -135,22 +201,37 @@ import { createBudgetPolicy } from '@migor/agentia';
135
201
  const app = createApp({
136
202
  // ...
137
203
  contextPolicy: createBudgetPolicy({
138
- budgetTokens: 60_000, // 超预算先丢旧工具对,仍超且有 summarize 才压缩
204
+ budgetTokens: 60_000, // 超预算先丢旧工具对,仍超且有 summarize 才压缩
139
205
  summarize: (text) => mySummarizer(text), // 可选,框架不替你调模型
140
206
  }),
141
207
  });
142
208
  ```
143
209
 
144
- ## 中间件
210
+ ### 结构化结果
145
211
 
146
- 挂在每一次单元调用前后的洋葱链——鉴权、限流、缓存、审计都走这里:
212
+ ```ts
213
+ const { result } = await app.run(messages, {
214
+ resultSchema: {
215
+ type: 'object',
216
+ properties: { pass: { type: 'boolean' }, reason: { type: 'string' } },
217
+ required: ['pass', 'reason'],
218
+ additionalProperties: false,
219
+ },
220
+ });
221
+ console.log(result.typed); // 校验过的结构化结果,不再从文本里猜 JSON
222
+ // schema 也可来自 zod(peer 可选):fromZod(z.toJSONSchema(S), S)
223
+ ```
224
+
225
+ ### 中间件
226
+
227
+ 挂在每一次能力调用前后的洋葱链——鉴权、限流、缓存、审计都走这里:
147
228
 
148
229
  ```ts
149
230
  const app = createApp({
150
231
  // ...
151
232
  middleware: [
152
233
  async (call, next) => {
153
- if (call.unit.name === 'danger_op' && !RunContext.current()?.get('isAdmin')) {
234
+ if (call.capability.name === 'danger_op' && !RunContext.current()?.get('isAdmin')) {
154
235
  return 'forbidden'; // 短路,不调 next 即拦截
155
236
  }
156
237
  return next(); // next(newInput) 还可改写入参
@@ -159,52 +240,86 @@ const app = createApp({
159
240
  });
160
241
  ```
161
242
 
162
- ## 结构化结果
243
+ ## 可观测性与成本
244
+
245
+ 一次 run == 一条 trace(`traceId === runId`),**Turn 0 起内建** —— 不是外挂的第三方追踪 SDK 集成:
163
246
 
164
247
  ```ts
165
- const { result } = await app.run(messages, {
166
- resultSchema: {
167
- type: 'object',
168
- properties: { pass: { type: 'boolean' }, reason: { type: 'string' } },
169
- required: ['pass', 'reason'],
170
- additionalProperties: false,
171
- },
172
- });
173
- console.log(result.typed); // 校验过的结构化结果,不再从文本里猜 JSON
174
- // schema 也可来自 zod(peer 可选):fromZod(z.toJSONSchema(S), S)
248
+ const { run, result } = await app.run(messages);
249
+ result.trace.spans; // 调用树:llm.turn / 能力 span / 事件
250
+ result.trace.totalUsage; // token 汇总(只累加 llm.turn;能力 span 是子孙聚合,不参与求和)
175
251
  ```
176
252
 
177
- ## 宿主、多模型与记忆
253
+ - **每步记账**:span 属性带 model、input/output/cache tokens、成本估计、状态、错误类型
254
+ - **出口是一条缝**:`TraceSink { export(trace) }` —— run 收尾(成功/失败两条路径)都投递,sink 抛错不影响 run。落库 / 采样 / 脱敏都在缝外用 sink 组合(实码见 `examples/observability/`,说明见 `docs/observability.md`)
255
+ - **指标**:`metricsSink` 满足 `TraceSink` 即可接入(Prometheus 文本 / OTLP metrics),零依赖
256
+ - **成本**:`priceOverrides` 注入价目表;未定价模型显式发 `usage.unpriced` 事件;`createBudgetGuard` 做**硬管控**(超限 run 以 `budget_exceeded` 收尾、算失败)
257
+ - **调优闭环**:`buildRunReport` 出「能力 / 模型的耗时·token·成本·错误率排行」,CLI `agentia report <trace.jsonl>` 直接渲染
258
+ - **回放**:`traceToMessages` 把已完成的 trace 线性化喂回模型(调试基底)
259
+ - **本地开发**:`agentia dev` 的 inspector 面板与 `@migor/trace-view` 共用同一份渲染器(避免两处漂移)
260
+ - **导出 OTLP**:
178
261
 
179
262
  ```ts
180
- // HTTP 宿主:POST /run(同步) POST /tasks(异步) GET /tasks/:id(轮询)
263
+ import { createOtlpExporter } from '@migor/agentia';
264
+
265
+ await createOtlpExporter({ endpoint: 'http://localhost:4318' }).export(result.trace);
266
+ ```
267
+
268
+ > 权威口径见 `docs/usage-guide.md` 的「观测」与「成本硬管控」两节。
269
+
270
+ ## 集成
271
+
272
+ ### HTTP 宿主
273
+
274
+ ```ts
275
+ import { createServer } from 'node:http';
276
+ import { createHttpHandler } from '@migor/agentia';
277
+
278
+ // POST /run(同步) POST /tasks(异步) GET /tasks/:id(轮询)
181
279
  createServer(createHttpHandler(app, { runner })).listen(8080);
280
+ ```
281
+
282
+ ### 多模型(OpenAI 兼容端点)
283
+
284
+ ```ts
285
+ import { createOpenAIClient } from '@migor/agentia';
182
286
 
183
- // OpenAI 兼容端点(DeepSeek 等)+ 跨 run 记忆
184
287
  const { result } = await app.run(messages, {
185
288
  client: createOpenAIClient({ baseURL: 'https://api.deepseek.com' }),
186
289
  model: 'deepseek-chat',
187
- memory: { store: new InMemoryMemoryStore(), keys: ['profile'] },
188
290
  });
291
+ ```
189
292
 
190
- // trace 导出到 OTLP 收集器
191
- await createOtlpExporter({ endpoint: 'http://localhost:4318' }).export(result.trace);
293
+ > **本地模型(Ollama 等)**:Ollama 暴露 OpenAI 兼容端点,用同一个适配器即可 ——
294
+ > `createOpenAIClient({ baseURL: 'http://localhost:11434/v1' })` + `model: 'qwen3'`,
295
+ > **不需要任何新代码或新依赖**。
296
+
297
+
298
+ ### 跨 run 记忆
299
+
300
+ ```ts
301
+ import { InMemoryMemoryStore } from '@migor/agentia';
302
+
303
+ const { result } = await app.run(messages, {
304
+ memory: { store: new InMemoryMemoryStore(), keys: ['profile'] },
305
+ });
192
306
  ```
193
307
 
194
- ## 常用 API
308
+ ## API 速查
195
309
 
196
310
  | 导出 | 用途 |
197
311
  |---|---|
198
- | `createApp` / `discoverProviders` | 装配应用 / 扫描单元目录 |
312
+ | `createApp` / `discoverProviders` | 装配应用 / 扫描能力目录 |
199
313
  | `defineModule` | 能力包(providers + middleware 打包分发) |
200
- | `Tool` / `Skill` / `SubAgent` / `Prompt` | 四类单元装饰器 |
201
- | `UnitMiddleware`(`middleware` 选项) | 单元调用拦截器链 |
202
- | `asset` | 读单元文件夹内的文本资产 |
314
+ | `Tool` / `Skill` / `SubAgent` / `Prompt` | 四类能力装饰器 |
315
+ | `CapabilityMiddleware`(`middleware` 选项) | 能力调用拦截器链 |
316
+ | `asset` | 读能力文件夹内的文本资产 |
203
317
  | `SystemPrompt` | 拼装系统提示(自动打缓存 breakpoint) |
204
318
  | `RunContext.current()` | 取本次 run 的 blackboard / runId |
205
319
  | `AsyncRunner` / `Scheduler` / `runSync` / `createHttpHandler` | 异步 / 定时 / 同步 / HTTP 触发 |
206
320
  | `FileTaskStore` / `SqliteTaskStore` / `RedisTaskStore` / `InMemoryTaskStore` | 任务记录存储 |
207
321
  | `createBudgetPolicy` | 长上下文预算护栏 |
322
+ | `createAnthropicClient` | 默认 ModelClient(Anthropic):自定义只传 `apiKey` / `baseURL`,不必直接依赖厂商 SDK |
208
323
  | `createOpenAIClient` | OpenAI 兼容端点适配(多模型) |
209
324
  | `InMemoryMemoryStore`(`memory` 选项) | 跨 run 记忆水合/回写 |
210
325
  | `createOtlpExporter` | trace 导出 OTLP |
@@ -212,16 +327,27 @@ await createOtlpExporter({ endpoint: 'http://localhost:4318' }).export(result.tr
212
327
  | `fromZod` | zod schema 接入(peer 可选) |
213
328
  | `runAgent` / `executeRun` | 裸引擎入口(不走装配) |
214
329
 
215
- 完整导出见 [`src/index.ts`](src/index.ts),设计规格见 [`docs/spec.md`](docs/spec.md),roadmap 见 [`docs/roadmap.md`](docs/roadmap.md),官网见 [agentia-web.pages.dev](https://agentia-web.pages.dev)(含[在线 Playground](https://agentia-web.pages.dev/playground.html) 与[文档](https://agentia-web.pages.dev/docs.html))。
216
-
217
- ## 本仓库脚本
330
+ ## 开发本仓库
218
331
 
219
332
  ```bash
220
333
  npm install
221
334
  npm run build # 编译框架(dist/)
222
335
  npm run typecheck # 类型检查
336
+ npm run lint # lint + 格式检查(Biome)
223
337
  npm test # 单元测试(node:test)
224
- npm run e2e # 端到端:CLI 脚手架 → 目录发现/注册表装配 → mock run
338
+ npm run e2e # 端到端:CLI 脚手架 → 装配 mock run;再真跑 examples/complete 的完整服务
225
339
  ```
226
340
 
227
- > 注:`npm run dev`(tsx)前需先 `npm approve-scripts` 批准 esbuild/tsx 的 postinstall。
341
+ > 注:本仓库的 `npm run dev`(tsx)前需先 `npm approve-scripts` 批准 esbuild/tsx 的 postinstall;
342
+ > 脚手架项目里的 `agentia dev` 不受此限。
343
+
344
+ ## 延伸阅读
345
+
346
+ - **使用者向完整说明**(API 速查 / 类型链路 / 已知边界 / 反例):[`docs/usage-guide.md`](docs/usage-guide.md)
347
+ - 完整导出清单:[`src/index.ts`](src/index.ts)
348
+ - 设计规格:[`docs/spec.md`](docs/spec.md)
349
+ - 生产可观测配方(落库检索 / 日志关联 / 采样 / 脱敏):[`docs/observability.md`](docs/observability.md)
350
+ - 完整示例(四类能力 + 三种触发 + 全观测栈):[`examples/complete/`](examples/complete/)
351
+ - 最小部署示例:[`examples/deploy/`](examples/deploy/)
352
+ - 方向与状态:[`docs/roadmap.md`](docs/roadmap.md)
353
+ - 官网:[agentia-web.pages.dev](https://agentia-web.pages.dev)([在线 Playground](https://agentia-web.pages.dev/playground.html) · [文档](https://agentia-web.pages.dev/docs.html))