@tachu/extensions 1.0.0-alpha.1

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 (210) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/LICENSE +201 -0
  3. package/README.md +1104 -0
  4. package/README_ZH.md +1082 -0
  5. package/dist/backends/file.d.ts +18 -0
  6. package/dist/backends/file.d.ts.map +1 -0
  7. package/dist/backends/file.js +85 -0
  8. package/dist/backends/file.js.map +1 -0
  9. package/dist/backends/index.d.ts +4 -0
  10. package/dist/backends/index.d.ts.map +1 -0
  11. package/dist/backends/index.js +4 -0
  12. package/dist/backends/index.js.map +1 -0
  13. package/dist/backends/terminal.d.ts +18 -0
  14. package/dist/backends/terminal.d.ts.map +1 -0
  15. package/dist/backends/terminal.js +81 -0
  16. package/dist/backends/terminal.js.map +1 -0
  17. package/dist/backends/web.d.ts +18 -0
  18. package/dist/backends/web.d.ts.map +1 -0
  19. package/dist/backends/web.js +55 -0
  20. package/dist/backends/web.js.map +1 -0
  21. package/dist/common/net.d.ts +39 -0
  22. package/dist/common/net.d.ts.map +1 -0
  23. package/dist/common/net.js +177 -0
  24. package/dist/common/net.js.map +1 -0
  25. package/dist/common/path.d.ts +51 -0
  26. package/dist/common/path.d.ts.map +1 -0
  27. package/dist/common/path.js +76 -0
  28. package/dist/common/path.js.map +1 -0
  29. package/dist/common/process.d.ts +19 -0
  30. package/dist/common/process.d.ts.map +1 -0
  31. package/dist/common/process.js +67 -0
  32. package/dist/common/process.js.map +1 -0
  33. package/dist/index.d.ts +13 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +13 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/mcp/index.d.ts +3 -0
  38. package/dist/mcp/index.d.ts.map +1 -0
  39. package/dist/mcp/index.js +3 -0
  40. package/dist/mcp/index.js.map +1 -0
  41. package/dist/mcp/sse-adapter.d.ts +82 -0
  42. package/dist/mcp/sse-adapter.d.ts.map +1 -0
  43. package/dist/mcp/sse-adapter.js +201 -0
  44. package/dist/mcp/sse-adapter.js.map +1 -0
  45. package/dist/mcp/stdio-adapter.d.ts +85 -0
  46. package/dist/mcp/stdio-adapter.d.ts.map +1 -0
  47. package/dist/mcp/stdio-adapter.js +203 -0
  48. package/dist/mcp/stdio-adapter.js.map +1 -0
  49. package/dist/memory/fs-memory-system.d.ts +147 -0
  50. package/dist/memory/fs-memory-system.d.ts.map +1 -0
  51. package/dist/memory/fs-memory-system.js +266 -0
  52. package/dist/memory/fs-memory-system.js.map +1 -0
  53. package/dist/memory/index.d.ts +2 -0
  54. package/dist/memory/index.d.ts.map +1 -0
  55. package/dist/memory/index.js +2 -0
  56. package/dist/memory/index.js.map +1 -0
  57. package/dist/observability/index.d.ts +3 -0
  58. package/dist/observability/index.d.ts.map +1 -0
  59. package/dist/observability/index.js +3 -0
  60. package/dist/observability/index.js.map +1 -0
  61. package/dist/observability/jsonl-emitter.d.ts +58 -0
  62. package/dist/observability/jsonl-emitter.d.ts.map +1 -0
  63. package/dist/observability/jsonl-emitter.js +96 -0
  64. package/dist/observability/jsonl-emitter.js.map +1 -0
  65. package/dist/observability/otel-emitter.d.ts +52 -0
  66. package/dist/observability/otel-emitter.d.ts.map +1 -0
  67. package/dist/observability/otel-emitter.js +143 -0
  68. package/dist/observability/otel-emitter.js.map +1 -0
  69. package/dist/providers/anthropic.d.ts +73 -0
  70. package/dist/providers/anthropic.d.ts.map +1 -0
  71. package/dist/providers/anthropic.js +521 -0
  72. package/dist/providers/anthropic.js.map +1 -0
  73. package/dist/providers/index.d.ts +5 -0
  74. package/dist/providers/index.d.ts.map +1 -0
  75. package/dist/providers/index.js +5 -0
  76. package/dist/providers/index.js.map +1 -0
  77. package/dist/providers/mock.d.ts +81 -0
  78. package/dist/providers/mock.d.ts.map +1 -0
  79. package/dist/providers/mock.js +160 -0
  80. package/dist/providers/mock.js.map +1 -0
  81. package/dist/providers/openai.d.ts +95 -0
  82. package/dist/providers/openai.d.ts.map +1 -0
  83. package/dist/providers/openai.js +529 -0
  84. package/dist/providers/openai.js.map +1 -0
  85. package/dist/providers/qwen.d.ts +145 -0
  86. package/dist/providers/qwen.d.ts.map +1 -0
  87. package/dist/providers/qwen.js +669 -0
  88. package/dist/providers/qwen.js.map +1 -0
  89. package/dist/rules/index.d.ts +9 -0
  90. package/dist/rules/index.d.ts.map +1 -0
  91. package/dist/rules/index.js +15 -0
  92. package/dist/rules/index.js.map +1 -0
  93. package/dist/rules/no-hallucination.md +11 -0
  94. package/dist/rules/no-sensitive-output.md +11 -0
  95. package/dist/rules/prefer-concise-response.md +11 -0
  96. package/dist/rules/require-tool-verification.md +11 -0
  97. package/dist/safety/default-gate.d.ts +112 -0
  98. package/dist/safety/default-gate.d.ts.map +1 -0
  99. package/dist/safety/default-gate.js +188 -0
  100. package/dist/safety/default-gate.js.map +1 -0
  101. package/dist/safety/index.d.ts +2 -0
  102. package/dist/safety/index.d.ts.map +1 -0
  103. package/dist/safety/index.js +2 -0
  104. package/dist/safety/index.js.map +1 -0
  105. package/dist/tools/_shared/web-client.d.ts +18 -0
  106. package/dist/tools/_shared/web-client.d.ts.map +1 -0
  107. package/dist/tools/_shared/web-client.js +46 -0
  108. package/dist/tools/_shared/web-client.js.map +1 -0
  109. package/dist/tools/apply-patch/descriptor.md +27 -0
  110. package/dist/tools/apply-patch/executor.d.ts +19 -0
  111. package/dist/tools/apply-patch/executor.d.ts.map +1 -0
  112. package/dist/tools/apply-patch/executor.js +193 -0
  113. package/dist/tools/apply-patch/executor.js.map +1 -0
  114. package/dist/tools/fetch-url/descriptor.md +44 -0
  115. package/dist/tools/fetch-url/executor.d.ts +28 -0
  116. package/dist/tools/fetch-url/executor.d.ts.map +1 -0
  117. package/dist/tools/fetch-url/executor.js +115 -0
  118. package/dist/tools/fetch-url/executor.js.map +1 -0
  119. package/dist/tools/index.d.ts +12 -0
  120. package/dist/tools/index.d.ts.map +1 -0
  121. package/dist/tools/index.js +286 -0
  122. package/dist/tools/index.js.map +1 -0
  123. package/dist/tools/list-dir/descriptor.md +29 -0
  124. package/dist/tools/list-dir/executor.d.ts +22 -0
  125. package/dist/tools/list-dir/executor.d.ts.map +1 -0
  126. package/dist/tools/list-dir/executor.js +48 -0
  127. package/dist/tools/list-dir/executor.js.map +1 -0
  128. package/dist/tools/read-file/descriptor.md +28 -0
  129. package/dist/tools/read-file/executor.d.ts +15 -0
  130. package/dist/tools/read-file/executor.d.ts.map +1 -0
  131. package/dist/tools/read-file/executor.js +22 -0
  132. package/dist/tools/read-file/executor.js.map +1 -0
  133. package/dist/tools/run-shell/descriptor.md +39 -0
  134. package/dist/tools/run-shell/executor.d.ts +20 -0
  135. package/dist/tools/run-shell/executor.d.ts.map +1 -0
  136. package/dist/tools/run-shell/executor.js +76 -0
  137. package/dist/tools/run-shell/executor.js.map +1 -0
  138. package/dist/tools/search-code/descriptor.md +31 -0
  139. package/dist/tools/search-code/executor.d.ts +23 -0
  140. package/dist/tools/search-code/executor.d.ts.map +1 -0
  141. package/dist/tools/search-code/executor.js +122 -0
  142. package/dist/tools/search-code/executor.js.map +1 -0
  143. package/dist/tools/shared.d.ts +47 -0
  144. package/dist/tools/shared.d.ts.map +1 -0
  145. package/dist/tools/shared.js +27 -0
  146. package/dist/tools/shared.js.map +1 -0
  147. package/dist/tools/web-fetch/descriptor.md +198 -0
  148. package/dist/tools/web-fetch/errors.d.ts +32 -0
  149. package/dist/tools/web-fetch/errors.d.ts.map +1 -0
  150. package/dist/tools/web-fetch/errors.js +91 -0
  151. package/dist/tools/web-fetch/errors.js.map +1 -0
  152. package/dist/tools/web-fetch/executor.d.ts +10 -0
  153. package/dist/tools/web-fetch/executor.d.ts.map +1 -0
  154. package/dist/tools/web-fetch/executor.js +191 -0
  155. package/dist/tools/web-fetch/executor.js.map +1 -0
  156. package/dist/tools/web-fetch/index.d.ts +4 -0
  157. package/dist/tools/web-fetch/index.d.ts.map +1 -0
  158. package/dist/tools/web-fetch/index.js +3 -0
  159. package/dist/tools/web-fetch/index.js.map +1 -0
  160. package/dist/tools/web-fetch/types.d.ts +157 -0
  161. package/dist/tools/web-fetch/types.d.ts.map +1 -0
  162. package/dist/tools/web-fetch/types.js +7 -0
  163. package/dist/tools/web-fetch/types.js.map +1 -0
  164. package/dist/tools/web-search/descriptor.md +89 -0
  165. package/dist/tools/web-search/errors.d.ts +33 -0
  166. package/dist/tools/web-search/errors.d.ts.map +1 -0
  167. package/dist/tools/web-search/errors.js +45 -0
  168. package/dist/tools/web-search/errors.js.map +1 -0
  169. package/dist/tools/web-search/executor.d.ts +10 -0
  170. package/dist/tools/web-search/executor.d.ts.map +1 -0
  171. package/dist/tools/web-search/executor.js +185 -0
  172. package/dist/tools/web-search/executor.js.map +1 -0
  173. package/dist/tools/web-search/index.d.ts +4 -0
  174. package/dist/tools/web-search/index.d.ts.map +1 -0
  175. package/dist/tools/web-search/index.js +3 -0
  176. package/dist/tools/web-search/index.js.map +1 -0
  177. package/dist/tools/web-search/types.d.ts +86 -0
  178. package/dist/tools/web-search/types.d.ts.map +1 -0
  179. package/dist/tools/web-search/types.js +7 -0
  180. package/dist/tools/web-search/types.js.map +1 -0
  181. package/dist/tools/write-file/descriptor.md +30 -0
  182. package/dist/tools/write-file/executor.d.ts +16 -0
  183. package/dist/tools/write-file/executor.d.ts.map +1 -0
  184. package/dist/tools/write-file/executor.js +18 -0
  185. package/dist/tools/write-file/executor.js.map +1 -0
  186. package/dist/transformers/document-to-text.d.ts +23 -0
  187. package/dist/transformers/document-to-text.d.ts.map +1 -0
  188. package/dist/transformers/document-to-text.js +69 -0
  189. package/dist/transformers/document-to-text.js.map +1 -0
  190. package/dist/transformers/image-to-text.d.ts +38 -0
  191. package/dist/transformers/image-to-text.d.ts.map +1 -0
  192. package/dist/transformers/image-to-text.js +82 -0
  193. package/dist/transformers/image-to-text.js.map +1 -0
  194. package/dist/transformers/index.d.ts +3 -0
  195. package/dist/transformers/index.d.ts.map +1 -0
  196. package/dist/transformers/index.js +3 -0
  197. package/dist/transformers/index.js.map +1 -0
  198. package/dist/vector/index.d.ts +3 -0
  199. package/dist/vector/index.d.ts.map +1 -0
  200. package/dist/vector/index.js +3 -0
  201. package/dist/vector/index.js.map +1 -0
  202. package/dist/vector/local-fs.d.ts +76 -0
  203. package/dist/vector/local-fs.d.ts.map +1 -0
  204. package/dist/vector/local-fs.js +153 -0
  205. package/dist/vector/local-fs.js.map +1 -0
  206. package/dist/vector/qdrant.d.ts +85 -0
  207. package/dist/vector/qdrant.d.ts.map +1 -0
  208. package/dist/vector/qdrant.js +208 -0
  209. package/dist/vector/qdrant.js.map +1 -0
  210. package/package.json +74 -0
package/README_ZH.md ADDED
@@ -0,0 +1,1082 @@
1
+ # Tachu
2
+
3
+ **正在积极开发中的 Agentic 引擎——目标是成为将任何 LLM 变为可靠、可观测 Agent 的 *Harness*。**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@tachu/core?label=%40tachu%2Fcore)](https://www.npmjs.com/package/@tachu/core)
6
+ [![status: alpha](https://img.shields.io/badge/status-alpha-orange)](#项目状态project-status)
7
+ [![license: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue)](#许可证license)
8
+ [![bun](https://img.shields.io/badge/runtime-bun-orange)](https://bun.sh)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue)](https://www.typescriptlang.org)
10
+
11
+ > **⚠️ 项目状态 —— Alpha。** 9 阶段主干、Registry、Prompt 组装、CLI、OpenAI / Anthropic / Qwen Adapter、MCP Adapter、向量存储与可观测性 Emitter 已完成搭建并均有单测覆盖。**Phase 3(意图分析)已是真实 LLM 调用**,`tachu chat` / `tachu run` 会产出真实对话回复。**Phase 5(任务规划)与 Phase 8(结果验证)仍是占位实现**——被判为 *complex* 的请求暂未获得 LLM 生成的多步规划与语义校验。详见[项目状态](#项目状态project-status)与[路线图](#路线图roadmap)。**请勿用于生产**。请使用 `@alpha` dist-tag 安装。
12
+
13
+ ---
14
+
15
+ ## 什么是 Tachu?
16
+
17
+ **太初有道,万物之始。以声明式描述符创造 Agent 万物。**
18
+
19
+ Tachu 的目标是成为一个**你可以基于它做真实产品的 Agentic 引擎**——不是 Demo 玩具,不是 API 薄封装。它是等式 **Agent = Model + Harness** 中的 *Harness*:提供结构骨架(协议、生命周期、安全、记忆、编排),让任何 LLM 都能成为可靠、可观测的 Agent。
20
+
21
+ 引擎本身刻意**不感知业务领域**——它不知道你的业务逻辑、用户身份或领域词汇。取而代之的是,它定义了一套极简的核心抽象(Rules、Skills、Tools、Agents),业务通过这些抽象注入所有智能。Tachu 被设计来处理那些真正困难的部分:9 阶段执行主干、双平面语义匹配、上下文窗口管理、精确 Token 计数的 Prompt 组装、结构化重试/降级、取消传播,以及端到端可观测性。
22
+
23
+ Tachu 以 Bun 原生 TypeScript Monorepo 形式发布,包含三个包:零依赖引擎核心(`@tachu/core`)、官方扩展库(`@tachu/extensions`),以及完整功能的 CLI 程序(`@tachu/cli`)——后者同时也是参考实现。
24
+
25
+ ---
26
+
27
+ ## 项目状态(Project Status)
28
+
29
+ **当前发布版本:** `1.0.0-alpha.1`(`alpha` dist-tag)
30
+
31
+ 这是一次**架构骨架**发布——基础设施基本就绪,但几个依赖 LLM 的阶段仍是占位实现。下表是唯一的事实来源;README 其他位置的任何声称都必须能在这张表里找到对应。
32
+
33
+ | 能力 | 状态 | 说明 |
34
+ |-----|------|-----|
35
+ | 9 阶段主干骨架(类型、编排器、状态机、Hook 链路) | ✅ 已实现 | `packages/core/src/engine` |
36
+ | Descriptor Registry(Rules / Skills / Tools / Agents) | ✅ 已实现 | Markdown + YAML frontmatter 加载、语义索引、启动校验 |
37
+ | Prompt 组装器(tiktoken、KV Cache 友好顺序) | ✅ 已实现 | `packages/core/src/prompt` |
38
+ | 任务调度器、DAG 校验、重试/降级簿记 | ✅ 已实现 | `packages/core/src/engine/scheduler.ts` |
39
+ | Session / Memory / Runtime-state / Safety / Model-router / Provider / Observability / Hooks 八大模块 | ✅ 已实现 | `packages/core/src/modules` |
40
+ | OpenAI / Anthropic / Mock Provider Adapter | ✅ 已实现 | 流式、函数调用、工具 Schema |
41
+ | `apiKey` / `baseURL` / `organization` / `timeoutMs` 配置(env var / `tachu.config.ts` / CLI flags) | ✅ 已实现 | 支持 Azure OpenAI / LiteLLM / OpenRouter / 自建网关 |
42
+ | 7 个内置 Tools + Terminal / File / Web Backend | ✅ 已实现 | `packages/extensions/src/{tools,backends}` |
43
+ | MCP stdio + SSE Adapter | ✅ 已实现 | `packages/extensions/src/mcp` |
44
+ | `LocalFsVectorStore`(文件持久化)+ `QdrantVectorStore`(REST) | ✅ 已实现 | |
45
+ | OTel / JSONL / Console Emitter | ✅ 已实现 | |
46
+ | `tachu init` / `tachu run` / `tachu chat` CLI、流式渲染、Session 持久化、Ctrl+C 语义 | ✅ 已实现 | |
47
+ | **CLI 终端 Markdown 渲染** | ✅ **已实现** | 基于 `marked` + `marked-terminal` + `cli-highlight` 栈。作用于 `tachu chat` / `tachu run --output text` 的最终回复:TTY 环境自动开启,`NO_COLOR` / 非 TTY / `--no-color` 下自动关闭;`tachu run` 支持通过 `--markdown` / `--no-markdown` 显式开关。专用封装 `renderMarkdownToAnsi`(`packages/cli/src/renderer/markdown.ts`),附 11 个单测(`markdown.test.ts`)。 |
48
+ | **Phase 3 意图分析(LLM 调用,纯分类)** | ✅ **已实现** | 通过 `ModelRouter.resolve("intent")` 路由到已注册的 `ProviderAdapter`。该阶段为**纯分类**——`IntentResult = { complexity, intent, contextRelevance, relevantContext? }`,System Prompt 明令禁止 `directAnswer` / `answer` / `reply` 字段,面向用户的最终答复由 Phase 7 的 `direct-answer` 子流程负责。内置 **5 条 few-shot 示例**(问候 / 创造性短文 / 写代码 / 写教案 / 真正的多工具复杂任务),复杂度判定以"是否需要真实工具 / 外部资源"为准、与输出长度无关。历史窗口 ≤10 条,30s 单次超时与阶段级 Abort 信号组合控制取消。JSON 提取支持 plain / fenced / embedded 三种形态;LLM 不遵循 JSON 协议但返回了自然语言时,该文本会被截断为 `intent` 摘要(≤200 字符),并在 Phase 5 转交 `direct-answer` 子流程重新生成答复。启发式 `intent = input.slice(0, 200)` 仅在**无可用内容**时使用(Provider 未注册 / 网络 / 超时 / 取消 / 空响应)。10 个专项用例见 `intent.test.ts`。 |
49
+ | **Phase 5 任务规划(兜底契约)** | ✅ **已实现** | 强制 `plans[0].tasks.length >= 1`。规则:(1) `simple` 意图 → 单步 `direct-answer` 子流程任务;(2) `complex` + 有匹配工具 → 前 N 个工具任务;(3) `complex` + 无匹配工具 → 单步 `direct-answer` 子流程任务(携带 `warn: true`,子流程会诚实说明未命中工具);(4) 后置守护:上游回归导致 `tasks` 为空时自动兜底。真正的 LLM-backed 多步计划生成器仍排期在后续 alpha。 |
50
+ | **`direct-answer` 内置子流程(Phase 7)** | ✅ **已实现** | `packages/core/src/engine/subflows/direct-answer.ts`。解析 `capabilityMapping.intent`(未命中时回退到 `fast-cheap`),组合 system + ≤10 条历史 + 用户 prompt,以合并后的 AbortSignal 调用 `ProviderAdapter.chat()`,单次超时 60s。System Prompt 强制**自然语言 + Markdown**、禁止 JSON 壳 / `"已识别请求:…"` 模板 / 4 空格缩进式代码块;`warn: true` 时子流程会坦诚说明"当前无匹配工具"。observability 事件统一以 `phase: "direct-answer"` 发出(`llm_call_start` / `llm_call_end`)。保留名机制:`DescriptorRegistry` 会把 `direct-answer` 列入保留名,业务侧注册 / 注销同名描述符将抛 `RegistryError.reservedName`。详见 [ADR 0001](docs/adr/decisions/0001-direct-answer-as-builtin-subflow.md)。 |
51
+ | **Phase 8 结果验证(LLM 调用)** | 🟡 **占位** | 仅检查步骤 `failed`,无语义校验。排期在后续 alpha。 |
52
+ | **Phase 9 输出装配** | ✅ **已实现** | 内容选择顺序:`taskResults['task-direct-answer']` → 结构化 `{intent, taskResults}` JSON(工具链成功路径,待 Phase 5/8 真实化后再重塑形态)→ 中文诚实回退文案(validation 未通过)。内部 state JSON 不会再外泄到用户侧。6 个专项用例见 `output.test.ts`。 |
53
+ | 真实环境端到端烟测(OpenAI / Anthropic / Azure) | 🔴 未开展 | Adapter 仅有 Mock 单测,尚未发布签署记录。 |
54
+ | 生产加固(SLO、错误预算、故障注入、签名 provenance) | 🔴 未开展 | v1 目标。 |
55
+
56
+ 图例:✅ 已实现并有测试 · 🟡 骨架存在、真实实现进行中 · 🔴 未开工。
57
+
58
+ ---
59
+
60
+ ## 核心亮点(Key Features)
61
+
62
+ > 带「**(占位)**」标注的条目已打通端到端链路,但目前尚未触发真实 LLM 调用——请对照[项目状态](#项目状态project-status)表。
63
+
64
+ - **9 阶段执行主干** — 会话管理 → 安全准入 → 意图分析(纯分类)→ 前置校验 → 任务规划(兜底契约)→ DAG 校验 → 子任务执行 → 结果验证 **(占位)** → 输出规范;每个阶段类型安全、可挂钩,且每个请求(simple 或 complex)都会完整穿过 9 个阶段,Rules / Hooks / Observability / 预算熔断统一生效
65
+ - **`direct-answer` 内置子流程** — 对 simple 请求(以及 complex 但无匹配工具的请求),最终答复由一个引擎内置的一等公民子流程在 Phase 7 产出,不再由意图分析阶段捎带。详见 [ADR 0001](docs/adr/decisions/0001-direct-answer-as-builtin-subflow.md)。
66
+ - **双平面匹配(Dual-Plane Matching)** — 语义发现(向量相似度)+ 确定性执行闸门(Scopes、白名单、审批),作用于所有 Rules、Skills、Tools 和 Agents
67
+ - **四大核心抽象** — 以 Markdown + YAML frontmatter 描述符声明 Rules、Skills、Tools、Agents;引擎自动解析、激活并编排
68
+ - **OpenAI 与 Anthropic Adapter** — 流式、函数调用、`baseURL` / `organization` / `timeoutMs` 可配置;可对接 Azure OpenAI / LiteLLM / OpenRouter / 任意自建网关
69
+ - **MCP 集成** — 通过 `McpToolAdapter` 接入任意 MCP 服务端(stdio 或 SSE);MCP Tools 成为引擎一等公民
70
+ - **精确 Token 计数** — 基于 tiktoken 的精确 Token 统计;KV Cache 友好的 Prompt 布局;自动上下文压缩(Head-Middle-Tail 策略)
71
+ - **结构化记忆(Memory System)** — 会话上下文窗口(含可配置上限);压缩前强制归档;长期向量记忆召回
72
+ - **OpenTelemetry 可观测性** — 每个阶段进入/退出、LLM 调用、Tool 调用、重试和降级都产出结构化 `EngineEvent`;内置 OTel 与 JSONL Emitter
73
+ - **交互式 CLI** — `tachu chat` / `tachu run` / `tachu init`,完整参数体系、流式渲染、Session 持久化、Ctrl+C 取消传播
74
+ - **终端 Markdown 渲染** —— 最终回复由 `marked` + `marked-terminal` + `cli-highlight` 渲染;支持标题、粗体 / 斜体、列表、块引用、链接、表格、带代码高亮的 fenced code block。`NO_COLOR` / 非 TTY / `--no-color` 下自动关闭;`tachu run` 可通过 `--markdown` / `--no-markdown` 显式控制。
75
+ - **Fail-Closed 安全基线** — 循环防护、预算熔断、基础输入校验硬编码于引擎核心,不可关闭
76
+ - **Qdrant 与 LocalFs 向量存储** — 多进程部署使用 Qdrant,本地/单进程使用文件持久化
77
+
78
+ ---
79
+
80
+ ## 愿景(Vision)
81
+
82
+ > 太初有道,万物之始。以声明式描述符创造 Agent 万物。
83
+
84
+ Tachu 的长期愿景是成为**通用 Agent 框架**:**引擎提供骨架,业务填充血肉**——任何组织都能基于稳定、可观测、可审计的基础设施构建生产级 Agentic 系统,而无需每次从头解决安全、上下文管理、重试逻辑和多 Provider 编排等困难问题。
85
+
86
+ Tachu 基于三个核心信念:
87
+
88
+ 1. **Harness 才是难点。** 模型智能已经商品化;可靠的编排机制尚未。Tachu 深度投资引擎基础设施,让应用开发者专注领域逻辑。
89
+ 2. **声明优于实现(Declaration over implementation)。** Rules、Skills、Tools、Agents 均以普通 Markdown 文件声明。引擎负责解析。无框架样板代码。
90
+ 3. **默认可观测。** 每个内部事件都是结构化且可发出的。生产系统需要完整 Trace——Tachu 无需额外埋点即可提供。
91
+
92
+ ---
93
+
94
+ ## 核心抽象(Core Abstractions)
95
+
96
+ Tachu 的四大核心抽象**平级独立、相互正交**——各自独立注册、独立激活,可在所有引擎阶段组合使用。
97
+
98
+ | 抽象 | 本质 | 激活闸门 | 作用 |
99
+ |------|------|----------|------|
100
+ | **Rules** | 约束与指导 | 语义发现 → 直接激活 | 注入各阶段 LLM System Prompt |
101
+ | **Skills** | 知识与指令 | 语义发现 → 直接激活 | 激活后注入 LLM 上下文 |
102
+ | **Tools** | 原子可执行操作 | 语义发现 → **必须过闸**(Scopes → 白名单 → 审批) | 带完整副作用追踪的执行 |
103
+ | **Agents** | 自然语言驱动的执行单元 | 语义发现 → 可激活 | 递归使用引擎能力;所有 Tool 调用仍走 Tool 闸门 |
104
+
105
+ 所有四类抽象共享统一的**描述符格式**(Markdown + YAML frontmatter):
106
+
107
+ ```yaml
108
+ name: unique-name # 必填,同类型内唯一
109
+ description: ... # 自然语言描述(用于语义发现)
110
+ tags: [tag1, tag2] # 标签,用于过滤和分类
111
+ trigger: { type: always } # 激活条件
112
+ requires:
113
+ - { kind: tool, name: read-file } # 显式依赖引用
114
+ ```
115
+
116
+ ### 双平面匹配模型(Dual-Plane Matching)
117
+
118
+ 每个核心抽象的激活都经历两个阶段:
119
+
120
+ ```mermaid
121
+ graph LR
122
+ Input[上下文输入] --> Discovery[语义发现面]
123
+ Discovery --> Index[(向量索引)]
124
+ Index --> Candidates[候选集]
125
+ Candidates --> Gate[确定性执行闸门]
126
+ Gate -- Scopes / 白名单 / 审批 --> Execution[执行面]
127
+ ```
128
+
129
+ - **语义发现面**:描述符的 `description` 在注册时向量化写入索引;运行时以当前上下文匹配索引,产出候选集
130
+ - **确定性执行闸门**:最终激活需通过确定性校验(显式引用、白名单/黑名单、权限 Scopes、审批检查)
131
+
132
+ Rules 和 Skills 无闸门直接激活(无副作用)。Tools 必须经过完整闸门。Agents 自由激活,但其内部调用的 Tools 仍需过 Tool 闸门。
133
+
134
+ ---
135
+
136
+ ## 架构总览(Architecture Overview)
137
+
138
+ ### 三层发布结构
139
+
140
+ ```mermaid
141
+ graph TD
142
+ subgraph "业务层(Business Layer)"
143
+ A[业务 Rules / 领域 Tools / 自定义 Adapter / 领域 Skills / Agents / Plan 模板]
144
+ end
145
+ subgraph "引擎扩展库 — @tachu/extensions"
146
+ B[OpenAI & Anthropic Adapter / 7 个常用 Tools / Terminal+File+Web Backend / Qdrant+LocalFs VectorStore / MCP Adapter / OTel+JSONL Emitter / 4 个通用 Rules]
147
+ end
148
+ subgraph "引擎核心 — @tachu/core"
149
+ C[协议定义 / 9 阶段主干 / 生命周期钩子 / Session / 记忆 / 安全 / 模型路由 / 运行状态]
150
+ end
151
+ A --> B
152
+ B --> C
153
+ ```
154
+
155
+ | 层级 | 包 | 职责 |
156
+ |------|----|----|
157
+ | 引擎核心 | `@tachu/core` | 协议接口、9 阶段主干骨架、8 个核心模块、Registry、Prompt 组装器、VectorStore 接口 + 内置轻量实现 |
158
+ | 扩展库 | `@tachu/extensions` | 官方具体实现:Provider Adapter、Tools、Backend、VectorStore Adapter、OTel/JSONL Emitter、通用 Rules |
159
+ | 业务/CLI | `@tachu/cli` 或业务代码 | 组装 core + extensions 为可工作的 Agent;提供领域 Rules/Skills/Tools/Agents |
160
+
161
+ ### 9 阶段执行主干
162
+
163
+ 每个请求都经历完整的 9 个阶段:
164
+
165
+ ```mermaid
166
+ graph TD
167
+ Start([业务请求]) --> S1[阶段 1:会话管理]
168
+ S1 --> S2[阶段 2:最小安全准入]
169
+ S2 --> S3[阶段 3:意图分析 — LLM]
170
+ S3 -- 简单 --> S9[阶段 9:输出规范]
171
+ S3 -- 复杂 --> S4[阶段 4:前置校验]
172
+ S4 --> S5[阶段 5:任务拆分]
173
+ S5 -- Plan 模式 --> PlanLoop{规划审阅循环}
174
+ S5 -- 模板匹配 --> S6
175
+ S5 -- 动态拆分 --> S6[阶段 6:依赖图校验]
176
+ PlanLoop -- 确认 --> S6
177
+ S6 --> S7[阶段 7:子任务执行]
178
+ S7 --> S8[阶段 8:结果验证 — LLM]
179
+ S8 -- 通过 --> S9
180
+ S8 -- 不通过 --> Retry{重试 / 重规划}
181
+ Retry -- 未达上限 --> S5
182
+ Retry -- 耗尽 --> S9
183
+ S9 --> End([输出])
184
+
185
+ style S2 fill:#ffeaa7,stroke:#fdcb6e
186
+ style S7 fill:#dfe6e9,stroke:#b2bec3
187
+ ```
188
+
189
+ | # | 阶段 | LLM 调用 | 关键输出 |
190
+ |---|------|----------|---------|
191
+ | 1 | 会话管理(Session Management) | 否 | 会话上下文加载 |
192
+ | 2 | 最小安全准入(Minimum Safety Check) | 否 | 通过 / 拒绝 |
193
+ | 3 | 意图分析(Intent Analysis) | **是** | `IntentResult`(简单/复杂,上下文相关性) |
194
+ | 4 | 前置校验(Pre-Check) | 否 | 资源可用性、深度安全校验 |
195
+ | 5 | 任务拆分(Task Planning) | **是** | `PlanningResult`(带排名的方案 + DAG) |
196
+ | 6 | 依赖图校验(DAG Validation) | 否 | 环检测、节点完整性(确定性) |
197
+ | 7 | 子任务执行(Sub-task Execution) | 视子任务 | `TaskResult[]`(可并行) |
198
+ | 8 | 结果验证(Result Validation) | **是** | `ValidationResult`(通过 / 执行问题 / 拆分问题) |
199
+ | 9 | 输出规范(Output Normalization) | 否 | `EngineOutput`(含步骤状态、元信息、附件) |
200
+
201
+ **主干关键特性:**
202
+
203
+ - **全路径安全准入** — 阶段 2 对所有请求路径执行,包括简单问题的快速通道
204
+ - **上下文门卫** — 阶段 3 判断会话历史是否与本轮相关;无关历史不向下传递
205
+ - **事不过三** — 任务级重试最多 3 次(可配置);系统级重试最多 2 次
206
+ - **取消传播(Last-message-wins)** — 同一 Session 收到新消息时,通过 `AbortController` 取消当前执行
207
+
208
+ ---
209
+
210
+ ## 安装(Installation)
211
+
212
+ Tachu 需要 [Bun](https://bun.sh) 作为运行时。
213
+
214
+ > **请使用 `@alpha` dist-tag 安装**(或固定到具体版本),直至 Tachu 进入稳定版。
215
+
216
+ ```bash
217
+ # 安装引擎核心(alpha)
218
+ bun add @tachu/core@alpha
219
+
220
+ # 安装扩展库(Provider、Tools、Backend、向量存储)
221
+ bun add @tachu/extensions@alpha
222
+
223
+ # 全局安装 CLI
224
+ bun add -g @tachu/cli@alpha
225
+ ```
226
+
227
+ 安装完成后验证:
228
+
229
+ ```bash
230
+ tachu --version # 预期输出 1.0.0-alpha.1 或更新
231
+ ```
232
+
233
+ ---
234
+
235
+ ## 快速开始(Quick Start)
236
+
237
+ ### CLI 方式
238
+
239
+ ```bash
240
+ # 1. 初始化项目工作空间
241
+ tachu init --template minimal --provider openai
242
+
243
+ # 2. 设置 API Key
244
+ export OPENAI_API_KEY=sk-...
245
+
246
+ # 3. 单次执行 Prompt
247
+ tachu run "帮我总结最近 5 条 git commit 的内容"
248
+
249
+ # 4. 进入交互式对话
250
+ tachu chat
251
+
252
+ # 恢复最近一次 Session
253
+ tachu chat --resume
254
+ ```
255
+
256
+ ### 编程式(Programmatic — TypeScript)
257
+
258
+ ```typescript
259
+ import { Engine } from '@tachu/core';
260
+ import { OpenAIProviderAdapter } from '@tachu/extensions/providers';
261
+ import type { EngineConfig, InputEnvelope, ExecutionContext } from '@tachu/core';
262
+
263
+ const config: EngineConfig = {
264
+ registry: {
265
+ descriptorPaths: ['.tachu'],
266
+ enableVectorIndexing: false,
267
+ },
268
+ runtime: {
269
+ planMode: false,
270
+ maxConcurrency: 4,
271
+ defaultTaskTimeoutMs: 120_000,
272
+ failFast: false,
273
+ },
274
+ memory: {
275
+ contextTokenLimit: 8000,
276
+ compressionThreshold: 0.8,
277
+ headKeep: 4,
278
+ tailKeep: 12,
279
+ archivePath: '.tachu/archive.jsonl',
280
+ vectorIndexLimit: 10_000,
281
+ },
282
+ budget: {
283
+ maxTokens: 50_000,
284
+ maxToolCalls: 50,
285
+ maxWallTimeMs: 300_000,
286
+ },
287
+ safety: {
288
+ maxInputSizeBytes: 1_000_000,
289
+ maxRecursionDepth: 10,
290
+ workspaceRoot: process.cwd(),
291
+ promptInjectionPatterns: [],
292
+ },
293
+ models: {
294
+ capabilityMapping: {
295
+ 'high-reasoning': { provider: 'openai', model: 'gpt-4o' },
296
+ 'fast-cheap': { provider: 'openai', model: 'gpt-4o-mini' },
297
+ },
298
+ providerFallbackOrder: ['openai'],
299
+ },
300
+ observability: { enabled: true, maskSensitiveData: true },
301
+ hooks: { writeHookTimeout: 5000, failureBehavior: 'continue' },
302
+ };
303
+
304
+ const engine = new Engine(config);
305
+ engine.useProvider(new OpenAIProviderAdapter({ apiKey: process.env.OPENAI_API_KEY! }));
306
+
307
+ const input: InputEnvelope = {
308
+ content: '写一个 TypeScript 函数,对异步操作做防抖处理',
309
+ metadata: { modality: 'text' },
310
+ };
311
+
312
+ const context: ExecutionContext = {
313
+ requestId: crypto.randomUUID(),
314
+ sessionId: 'session-001',
315
+ traceId: crypto.randomUUID(),
316
+ principal: { userId: 'user-001' },
317
+ budget: { maxTokens: 20_000, maxDurationMs: 60_000 },
318
+ scopes: ['read', 'write'],
319
+ };
320
+
321
+ for await (const chunk of engine.runStream(input, context)) {
322
+ if (chunk.type === 'delta') process.stdout.write(chunk.content);
323
+ if (chunk.type === 'done') console.log('\n\n完成,状态:', chunk.output.status);
324
+ }
325
+ ```
326
+
327
+ ---
328
+
329
+ ## 包结构(Package Layout)
330
+
331
+ ### 三包说明
332
+
333
+ | 包 | 说明 | 主要导出 |
334
+ |----|------|---------|
335
+ | `@tachu/core` | 零依赖引擎核心 | `Engine`、`Registry`、`PromptAssembler`、所有接口与类型 |
336
+ | `@tachu/extensions` | 官方具体实现 | `OpenAIProviderAdapter`、`AnthropicProviderAdapter`、`McpToolAdapter`、`QdrantVectorStore`、`OtelEmitter`、Backend、Tools、Rules |
337
+ | `@tachu/cli` | 生产级 CLI 程序 | `tachu chat`、`tachu run`、`tachu init` |
338
+
339
+ ### 依赖关系(Dependency Relationship)
340
+
341
+ ```mermaid
342
+ graph LR
343
+ cli["@tachu/cli"]
344
+ extensions["@tachu/extensions"]
345
+ core["@tachu/core"]
346
+
347
+ cli --> extensions
348
+ cli --> core
349
+ extensions --> core
350
+
351
+ style core fill:#74b9ff,stroke:#0984e3
352
+ style extensions fill:#a29bfe,stroke:#6c5ce7
353
+ style cli fill:#fd79a8,stroke:#e84393
354
+ ```
355
+
356
+ ### core 包内部结构
357
+
358
+ ```
359
+ @tachu/core / src/
360
+ ├── types/ # 所有 TypeScript 接口:描述符、上下文、I/O、配置
361
+ ├── engine/ # Engine 入口类、各阶段处理器、编排控制面、依赖调度器
362
+ ├── registry/ # Registry:注册/查询/启动校验(四类抽象统一管理)
363
+ ├── modules/ # 8 个核心模块(会话、记忆、运行状态、模型路由、
364
+ │ # Provider、安全、可观测性、Hooks)
365
+ ├── prompt/ # PromptAssembler:Token 预算分配、KV Cache 友好排列
366
+ └── vector/ # VectorStore 接口 + 内置轻量实现
367
+ ```
368
+
369
+ ---
370
+
371
+ ## Provider 与集成(Providers & Integrations)
372
+
373
+ ### LLM Provider
374
+
375
+ | Provider | 包 | 流式输出 | Function Calling | 备注 |
376
+ |----------|----|----|------|------|
377
+ | OpenAI | `@tachu/extensions/providers` | ✅ | ✅ | GPT-4o、GPT-4o-mini 及所有可枚举模型 |
378
+ | Anthropic | `@tachu/extensions/providers` | ✅ | ✅ | Claude 3.5 Sonnet 及所有可枚举模型 |
379
+ | Mock | `@tachu/extensions/providers` | ✅ | ✅ | 测试专用;可配置响应内容 |
380
+
381
+ 通过 `models.providerFallbackOrder` 配置降级顺序。系统级错误(超时、API 报错)时,引擎自动按顺序切换 Provider,无需重新规划。
382
+
383
+ ### Provider 连接配置
384
+
385
+ 内置 Provider 均支持 `apiKey`、`baseURL`、`organization`(仅 OpenAI)、`project`(仅 OpenAI)、`timeoutMs`。共有三种注入途径(优先级从低到高):
386
+
387
+ 1. **环境变量**(推荐用于密钥):
388
+
389
+ | 变量 | Provider | 用途 |
390
+ |------|----------|------|
391
+ | `OPENAI_API_KEY` | OpenAI | 未显式设置 `apiKey` 时的回退凭据 |
392
+ | `OPENAI_BASE_URL` | OpenAI | SDK 原生支持的 baseURL 覆盖 |
393
+ | `ANTHROPIC_API_KEY` | Anthropic | 未显式设置 `apiKey` 时的回退凭据 |
394
+ | `ANTHROPIC_BASE_URL` | Anthropic | SDK 原生支持的 baseURL 覆盖 |
395
+
396
+ 2. **`tachu.config.ts` 的 `providers` 段**(推荐用于非密钥类连接元信息):
397
+
398
+ ```typescript
399
+ const config: EngineConfig = {
400
+ // ...其它字段
401
+ providers: {
402
+ openai: {
403
+ // apiKey 建议继续走环境变量,保持配置文件可提交
404
+ baseURL: 'https://your-gateway.example.com/v1',
405
+ organization: 'org-xxxx',
406
+ timeoutMs: 60_000,
407
+ },
408
+ anthropic: {
409
+ baseURL: 'https://your-gateway.example.com/anthropic',
410
+ timeoutMs: 60_000,
411
+ },
412
+ },
413
+ };
414
+ ```
415
+
416
+ 3. **CLI 命令行参数**(优先级最高,适合一次性覆盖):
417
+
418
+ ```bash
419
+ tachu run "..." --provider openai \
420
+ --api-base https://gateway.example.com/v1 \
421
+ --api-key sk-dev \
422
+ --organization org-xxxx
423
+
424
+ tachu chat --provider anthropic \
425
+ --api-base https://gateway.example.com/anthropic
426
+ ```
427
+
428
+ CLI flag 始终作用于本次请求实际选中的 Provider(显式 `--provider` 或 `capabilityMapping` 解析结果),对 `mock` provider 不生效。
429
+
430
+ 典型用途:Azure OpenAI、自建 LiteLLM/OpenRouter/Kong 网关、企业出口代理、离线内网部署。
431
+
432
+ ### MCP(Model Context Protocol)
433
+
434
+ Tachu 官方提供两种 MCP transport 的 Adapter(`McpStdioAdapter` / `McpSseAdapter`,基于 `@modelcontextprotocol/sdk`),并在 CLI 层把它们连接到 `DescriptorRegistry` 与 `TaskExecutor`——你只需在 `tachu.config.ts` 里声明一段 `mcpServers`,CLI 会自动发现工具、路由调用、在进程退出时断连。
435
+
436
+ **CLI 声明式配置(推荐,字段命名对齐 OpenAI Agents SDK 与通用 MCP 客户端约定)**
437
+
438
+ ```typescript
439
+ // tachu.config.ts
440
+ const config: EngineConfig = {
441
+ // ... 其他字段
442
+ mcpServers: {
443
+ // 本地 stdio 进程(标准 MCP stdio 传输)
444
+ fs: {
445
+ command: 'npx',
446
+ args: ['-y', '@modelcontextprotocol/server-filesystem', process.cwd()],
447
+ env: { ...process.env },
448
+ },
449
+ // 远端 SSE 服务(标准 MCP SSE 传输)
450
+ remoteKb: {
451
+ url: 'https://mcp.example.com/sse/',
452
+ headers: { Authorization: `Bearer ${process.env.MCP_TOKEN ?? ''}` },
453
+ timeoutMs: 50_000, // 单次工具调用超时
454
+ connectTimeoutMs: 10_000, // 握手阶段超时
455
+ // 可选(tachu 扩展字段)
456
+ // description: '项目文档检索示例接口',
457
+ // keywords: ['文档', 'docs'],
458
+ // expandOnKeywordMatch: true,
459
+ // allowTools: ['getStatus'],
460
+ // denyTools: ['dangerousOp'],
461
+ // requiresApproval: true,
462
+ // disabled: false,
463
+ // tags: ['example'],
464
+ },
465
+ },
466
+ };
467
+ ```
468
+
469
+ 行为要点:
470
+
471
+ - **命名空间**:远端工具以 `<serverId>__<原工具名>`(例如 `remoteKb__getStatus`)形态注册到 `DescriptorRegistry`,对 LLM 可见,多 server 共存互不冲突
472
+ - **失败隔离**:任何一个 server 连接 / listTools 失败只在 stderr 打一行警告,不阻塞其余 server 与主流程
473
+ - **超时 & 取消**:`adapter.connect()` 受 `connectTimeoutMs` 保护;`ToolExecutionContext.abortSignal` 透传到 `adapter.executeTool({ signal })`,Ctrl+C / 预算熔断能沿着协议层传播到 MCP 服务端
474
+ - **审批闸门**:MCP 工具 `requiresApproval` 与工具自身 / server 级 `requiresApproval` 做逻辑 OR;与 CLI 的默认 `y/N` 审批提示一致
475
+ - **生命周期**:进程退出前 `tachu run` / `tachu chat` 都会 `engine.dispose()` 后调用 `mounted.disconnectAll()`,幂等;失败的 disconnect 只 emit warning
476
+ - **server 级 `description`(LLM 路由提示)**:若声明,装配时会自动拼到该 server 每个工具的 `description` 前(形如 `[<serverId>: <description>] <原 description>`),让规划阶段即便不读完整 JSON schema 也能判断工具归属
477
+ - **按关键词惰性暴露工具(压缩 prompt)**:`expandOnKeywordMatch: true` 且 `keywords` 非空的 server,启动时**不会**把工具注册到 Registry;`tachu run <prompt>` 会按本次 prompt、`tachu chat` 会按每轮 `you>` 输入做一次子串大小写不敏感匹配(结构化输入先 `JSON.stringify`),命中任一 keyword 才注册该 server 的工具,未命中则从 Registry 移除。适合 MCP server 暴露几十个工具但常规对话用不上的场景;schema 会拒绝 `expandOnKeywordMatch=true` 但 `keywords` 空缺的配置
478
+
479
+ **SDK 直用(绕过 CLI,自行组装时)**
480
+
481
+ ```typescript
482
+ import { McpSseAdapter, McpStdioAdapter } from '@tachu/extensions';
483
+
484
+ // 远端 SSE
485
+ const sse = new McpSseAdapter({
486
+ url: 'https://mcp.example.com/sse/',
487
+ serverId: 'remoteKb',
488
+ headers: { Authorization: 'Bearer ...' },
489
+ defaultTimeoutMs: 50_000,
490
+ });
491
+ await sse.connect('https://mcp.example.com/sse/');
492
+ const tools = await sse.listTools();
493
+ for (const tool of tools) await engine.registry.register(tool);
494
+
495
+ // 本地 stdio
496
+ const stdio = new McpStdioAdapter({
497
+ command: 'npx',
498
+ args: ['-y', '@modelcontextprotocol/server-filesystem', process.cwd()],
499
+ serverId: 'fs',
500
+ });
501
+ await stdio.connect('');
502
+ ```
503
+
504
+ 若你在自定义宿主里同样想要 CLI 的"一行配置自动装配"体验,可以直接复用
505
+ `@tachu/cli` 导出的 `mountMcpServers(config.mcpServers, { cwd })` / `setupMcpServersFromConfig(config, registry, { cwd })`——它们返回 `{ descriptors, executors, disconnectAll }`,把 `executors` 合并进 `createEngine({ extraToolExecutors })` 即可。
506
+
507
+ ### 向量存储(Vector Stores)
508
+
509
+ | Adapter | 包 | 适用场景 |
510
+ |---------|----|----|
511
+ | `InMemoryVectorStore` | `@tachu/core` | 开发/测试;零依赖内置实现 |
512
+ | `LocalFsVectorStore` | `@tachu/extensions/vector` | 单进程生产;文件持久化 |
513
+ | `QdrantVectorStore` | `@tachu/extensions/vector` | 多进程生产;完整 Qdrant REST API |
514
+
515
+ ```typescript
516
+ import { QdrantVectorStore } from '@tachu/extensions/vector';
517
+
518
+ const vectorStore = new QdrantVectorStore({
519
+ url: 'http://localhost:6333',
520
+ collectionName: 'tachu-descriptors',
521
+ });
522
+ engine.useVectorStore(vectorStore);
523
+ ```
524
+
525
+ ### 可观测性 Emitter
526
+
527
+ | Emitter | 包 | 输出目标 |
528
+ |---------|----|----|
529
+ | `OtelEmitter` | `@tachu/extensions/emitters` | OpenTelemetry Span(via `@opentelemetry/api`) |
530
+ | `JsonlEmitter` | `@tachu/extensions/emitters` | 追加写入 JSONL 文件 |
531
+ | `ConsoleEmitter` | `@tachu/extensions/emitters` | 结构化控制台输出(开发用) |
532
+
533
+ ### 执行 Backend
534
+
535
+ | Backend | 包 | 说明 |
536
+ |---------|----|----|
537
+ | `TerminalBackend` | `@tachu/extensions/backends` | 沙箱终端内的 Shell 命令执行 |
538
+ | `FileBackend` | `@tachu/extensions/backends` | 文件系统读写 |
539
+ | `WebBackend` | `@tachu/extensions/backends` | HTTP 请求至外部 API / Web 资源 |
540
+
541
+ ---
542
+
543
+ ## 设计原则(Design Principles)
544
+
545
+ Tachu 基于七条核心工程原则:
546
+
547
+ 1. **双平面匹配** — 所有四类核心抽象通过语义方式发现(向量相似度),但通过确定性方式激活(Scopes、白名单、审批)。语义发现是参考;执行闸门是权威。
548
+
549
+ 2. **全路径安全准入** — 最小安全检查(阶段 2)对*所有*请求路径执行,包括简单问题的快速通道。安全性绝不为性能让步。
550
+
551
+ 3. **事不过三** — 任务级重试循环和系统级重试循环都有严格上限。不允许无限重试。耗尽上限后,引擎输出步骤级完成状态而非笼统失败。
552
+
553
+ 4. **KV Cache 友好的 Prompt 组装** — System Prompt 按稳定顺序组装(硬约束 Rules → 软偏好 Rules → Skills → Tool 定义),使跨轮次的前缀保持不变,最大化 KV Cache 复用,降低 LLM 成本。
554
+
555
+ 5. **取消传播(Last-message-wins)** — 同一 Session 收到新消息时,通过 `AbortController` 取消当前执行,在已有上下文基础上处理新输入。保证上下文连贯,避免无效工作。
556
+
557
+ 6. **引擎不感知业务权限** — 引擎只在 Tool 执行闸门处校验执行上下文中的粗粒度 `scopes`。细粒度业务授权由 Tool 实现本身或专用的授权 Tool 负责。
558
+
559
+ 7. **Fail-Closed 安全基线** — 循环防护、预算熔断、基础输入校验硬编码于引擎核心,*不可*通过配置禁用。即使业务配置完全为空,引擎也不会失控运行。
560
+
561
+ ---
562
+
563
+ ## 配置(Configuration)
564
+
565
+ 引擎通过项目根目录的 `tachu.config.ts` 文件配置(由 `tachu init` 自动生成):
566
+
567
+ ```typescript
568
+ import type { EngineConfig } from '@tachu/core';
569
+
570
+ const config: EngineConfig = {
571
+ // 描述符注册中心:Rules/Skills/Tools/Agents 加载路径
572
+ registry: {
573
+ descriptorPaths: ['.tachu'],
574
+ enableVectorIndexing: false, // 设置 true 可在启动时把 descriptor 自动写入向量索引
575
+ },
576
+
577
+ // 运行时行为
578
+ runtime: {
579
+ planMode: false, // true 时只规划不执行任务
580
+ maxConcurrency: 4, // 最大并行子任务数
581
+ defaultTaskTimeoutMs: 120_000, // 单个任务默认超时(ms)
582
+ failFast: false, // 任意子任务失败立即中止整次运行
583
+ },
584
+
585
+ // 上下文窗口与记忆
586
+ memory: {
587
+ contextTokenLimit: 8000, // 上下文窗口 Token 上限
588
+ compressionThreshold: 0.8, // 达到 80% 容量时触发压缩
589
+ headKeep: 4, // 压缩时保留的最早消息条数
590
+ tailKeep: 12, // 压缩时保留的最新消息条数
591
+ archivePath: '.tachu/archive.jsonl',
592
+ vectorIndexLimit: 10_000, // 内置向量索引最大条目数
593
+ },
594
+
595
+ // 预算约束(每次执行)
596
+ budget: {
597
+ maxTokens: 50_000, // 单次执行总 Token 预算
598
+ maxToolCalls: 50, // 单次执行最大 Tool 调用次数
599
+ maxWallTimeMs: 300_000, // 5 分钟墙钟时间上限
600
+ },
601
+
602
+ // 安全基线(硬编码最小集;通过 SafetyModule.registerPolicy 追加业务策略)
603
+ safety: {
604
+ maxInputSizeBytes: 1_000_000,
605
+ maxRecursionDepth: 10,
606
+ workspaceRoot: process.cwd(), // 文件后端根目录(用于路径遍历防护)
607
+ promptInjectionPatterns: [], // 可选:注入告警的正则字符串;命中只报 warning
608
+ },
609
+
610
+ // 模型路由
611
+ models: {
612
+ capabilityMapping: {
613
+ 'high-reasoning': { provider: 'openai', model: 'gpt-4o' },
614
+ 'fast-cheap': { provider: 'openai', model: 'gpt-4o-mini' },
615
+ 'vision': { provider: 'openai', model: 'gpt-4o' },
616
+ },
617
+ providerFallbackOrder: ['openai', 'anthropic'],
618
+ },
619
+
620
+ // 可观测性(事件经 ObservabilityEmitter 发出)
621
+ observability: {
622
+ enabled: true,
623
+ maskSensitiveData: true, // 自动脱敏 PII
624
+ },
625
+
626
+ // Hooks
627
+ hooks: {
628
+ writeHookTimeout: 5_000, // ms;可写 Hook 超时即跳过
629
+ failureBehavior: 'continue', // 'abort' 表示任意 Hook 失败即整次运行失败
630
+ },
631
+ };
632
+
633
+ export default config;
634
+ ```
635
+
636
+ 所有字段均有合理默认值。`tachu init` 会根据你选择的 Provider 预填生成此文件。
637
+
638
+ > **Schema 参考**:完整的 `EngineConfig` 类型与 v1 vs 历史草案差异说明,详见 detailed-design §14.1。早期使用 `retry / planning / agent / context / execution / storage` 顶级键的草案已废弃,运行时会被 `validateConfig` 拒绝并抛出 `VALIDATION_INVALID_CONFIG`。
639
+
640
+ ---
641
+
642
+ ## CLI 参考(CLI Reference)
643
+
644
+ ### `tachu init`
645
+
646
+ 初始化 Tachu 项目工作空间。
647
+
648
+ ```
649
+ tachu init [options]
650
+
651
+ 选项:
652
+ --template <name> 脚手架模板:minimal | full (默认:minimal)
653
+ --force 已存在时强制覆盖(不询问)
654
+ --path <dir> 目标目录 (默认:当前目录)
655
+ --provider <name> 写入 config 的默认 Provider:openai | anthropic | mock (默认:mock)
656
+ --no-examples 跳过生成示例 Rule / Tool 描述符
657
+ -h, --help 显示帮助
658
+ ```
659
+
660
+ 生成 `.tachu/` 目录骨架 + `tachu.config.ts` + `.gitignore` 追加条目。
661
+
662
+ ---
663
+
664
+ ### `tachu run <prompt>`
665
+
666
+ 单次执行 Prompt,将结果流式输出到 stdout。
667
+
668
+ ```
669
+ tachu run <prompt> [options]
670
+
671
+ 参数:
672
+ <prompt> Prompt 文本(或通过 stdin 管道传入)
673
+
674
+ 选项:
675
+ --session <id> 指定 Session ID
676
+ --resume 恢复最近一次 Session
677
+ --model <name> 覆盖 high-reasoning 模型
678
+ --provider <name> 覆盖默认 Provider
679
+ --api-base <url> 覆盖 provider baseURL(网关 / Azure / LiteLLM 场景)
680
+ --api-key <key> 覆盖 provider apiKey(生产环境建议走环境变量)
681
+ --organization <id> 覆盖 OpenAI organization ID
682
+ --input <file> 从文件读取 Prompt
683
+ --json 将 Prompt 解析为 JSON(结构化输入)
684
+ --output <fmt> 输出格式:text | json | markdown (默认:text)
685
+ --markdown 在 --output text 下启用终端 Markdown 渲染
686
+ (默认:stdout 是 TTY 且未设 NO_COLOR 时开启)
687
+ --no-markdown 关闭终端 Markdown 渲染(强制输出原始文本)
688
+ --no-validation 跳过阶段 8 结果验证
689
+ --plan-mode 启用 Plan 模式(阶段 5 后暂停等待审批)
690
+ --verbose, -v 详细日志(phase 切换;每个 phase 尾部自动附 `(Nms)` 耗时)
691
+ --debug 调试模式:隐含 --verbose,并把引擎 observability 事件
692
+ (phase / llm / tool / MCP)按颜色分类打到 stderr。
693
+ 对 `-o json` 管道安全(不污染 stdout)
694
+ --no-color 禁用 ANSI 彩色输出(同 NO_COLOR 环境变量;
695
+ 由于 Markdown 渲染依赖彩色输出,此选项同时隐含 --no-markdown)
696
+ --timeout <ms> 墙钟时间上限(覆盖 budget.maxWallTimeMs)
697
+ -h, --help 显示帮助
698
+ ```
699
+
700
+ ---
701
+
702
+ ### `tachu chat`
703
+
704
+ 进入多轮交互式对话 Session。
705
+
706
+ ```
707
+ tachu chat [options]
708
+
709
+ 选项:
710
+ --session <id> 指定 Session ID
711
+ --resume 恢复最近一次 Session
712
+ --history 列出所有 Session 后退出(不进入交互)
713
+ --export <file> 将指定 Session 导出为 Markdown 后退出
714
+ --model <name> 覆盖 high-reasoning 模型
715
+ --provider <name> 覆盖默认 Provider
716
+ --api-base <url> 覆盖 provider baseURL(网关 / Azure / LiteLLM 场景)
717
+ --api-key <key> 覆盖 provider apiKey(生产环境建议走环境变量)
718
+ --organization <id> 覆盖 OpenAI organization ID
719
+ --plan-mode 启用 Plan 模式
720
+ --verbose, -v 详细日志(phase 尾部带 `(Nms)` 耗时)
721
+ --debug 调试模式:隐含 --verbose,把 observability 事件打到 stderr,
722
+ 并在每轮输入时打印 MCP gated group 的激活/注销摘要
723
+ --no-color 禁用彩色输出
724
+ -h, --help 显示帮助
725
+ ```
726
+
727
+ **交互内置命令**(输入时以 `/` 开头):
728
+
729
+ | 命令 | 说明 |
730
+ |------|------|
731
+ | `/exit` | 保存 Session 并退出 |
732
+ | `/reset` | 清空当前 Session 的 Memory |
733
+ | `/new` | 开启新 Session |
734
+ | `/list` | 列出所有已保存的 Session |
735
+ | `/load <id>` | 切换到指定 Session |
736
+ | `/save` | 手动持久化当前 Session |
737
+ | `/export <path>` | 将当前 Session 导出为 Markdown 文件 |
738
+ | `/history` | 显示本 Session 的消息历史 |
739
+ | `/stats` | 显示 Token 用量、Tool 调用次数、剩余预算 |
740
+ | `/help` | 显示所有命令 |
741
+
742
+ **Ctrl+C 行为:**
743
+ - 第一次:取消当前 LLM/Tool 调用(回到提示符,Session 不丢失)
744
+ - 1 秒内第二次:保存 Session 并正常退出
745
+ - 第三次:强制退出
746
+
747
+ **Session 持久化契约:**
748
+
749
+ `tachu chat` 默认使用 `@tachu/extensions` 提供的 `FsMemorySystem`。每次 `append` 时会把消息写入 `<cwd>/.tachu/memory/<session-id>.jsonl`(append-only,崩溃安全)。`--resume` 与 `--session <id>` 在启动时一次性从该文件 hydrate 全部历史,之后 engine 继续在同一个 `MemorySystem` 中运行——LLM 会看到完整的前置上下文。
750
+
751
+ - 通过 `tachu.config.ts` 中的 `memory.persistence` 开关控制(默认 `"fs"`;SDK 嵌入场景可用 `"memory"`)
752
+ - `persistDir` 默认 `.tachu/memory`
753
+ - 旧版 session 文件(`messages` 内嵌于 session JSON 里)在首次 resume 时自动迁移到新的 jsonl 布局(一次性、幂等)
754
+ - `/history`、`/export <path>`、`/stats`、`/reset`、`/clear`、`/new`、`/load <id>` 均以此唯一权威源为准
755
+
756
+ ---
757
+
758
+ ## 扩展指南(Extension Guide)
759
+
760
+ Tachu 通过在 `.tachu/` 目录下创建 Markdown 描述符文件来扩展。Rules、Skills 和 Tools 无需任何代码变更——只有 Agent 的执行函数需要在代码中单独注册。
761
+
762
+ ### 自定义 Rule
763
+
764
+ ```markdown
765
+ <!-- .tachu/rules/no-external-calls.md -->
766
+ ---
767
+ name: no-external-calls
768
+ description: 禁止 Agent 在未获明确审批前发起外部网络调用
769
+ type: rule
770
+ scope: [execution]
771
+ tags: [security, network]
772
+ ---
773
+
774
+ 除非被调用 Tool 的 requiresApproval 为 true 且用户已确认,
775
+ 否则不得发起 HTTP 请求、DNS 查询或任何其他外部网络调用。
776
+ ```
777
+
778
+ ### 自定义 Skill
779
+
780
+ ```markdown
781
+ <!-- .tachu/skills/git-workflow/SKILL.md -->
782
+ ---
783
+ name: git-workflow
784
+ description: 本仓库 Git 分支策略、Commit 规范与 PR 工作流知识
785
+ tags: [development, git]
786
+ requires:
787
+ - { kind: tool, name: run-command }
788
+ ---
789
+
790
+ ## Git 工作流
791
+
792
+ 本仓库采用基于主干的开发模式(trunk-based development),配合短生命周期特性分支。
793
+
794
+ ### 分支命名
795
+ - 功能分支:`feat/<ticket>-<short-desc>`
796
+ - 修复分支:`fix/<ticket>-<short-desc>`
797
+
798
+ ### Commit 规范
799
+ 使用 Conventional Commits:`type(scope): subject`
800
+ ...
801
+ ```
802
+
803
+ ### 自定义 Tool
804
+
805
+ ```markdown
806
+ <!-- .tachu/tools/query-db.md -->
807
+ ---
808
+ name: query-db
809
+ description: 对应用数据库执行只读 SQL 查询
810
+ sideEffect: readonly
811
+ idempotent: true
812
+ requiresApproval: false
813
+ timeout: 10000
814
+ inputSchema:
815
+ type: object
816
+ properties:
817
+ sql: { type: string, description: "SQL SELECT 语句" }
818
+ limit: { type: number, description: "最大返回行数", default: 100 }
819
+ required: [sql]
820
+ execute: queryDatabase
821
+ ---
822
+
823
+ 执行参数化只读 SQL 查询,结果以 JSON 数组形式返回。
824
+ ```
825
+
826
+ 在 `engine-factory.ts` 中注册执行函数:
827
+
828
+ ```typescript
829
+ engine.registry.registerExecutor('queryDatabase', async (input, ctx) => {
830
+ const { sql, limit = 100 } = input as { sql: string; limit?: number };
831
+ return db.query(sql).limit(limit).execute();
832
+ });
833
+ ```
834
+
835
+ ### 自定义 Agent
836
+
837
+ ```markdown
838
+ <!-- .tachu/agents/code-reviewer.md -->
839
+ ---
840
+ name: code-reviewer
841
+ description: 审查 Pull Request diff,产出结构化代码审查意见
842
+ sideEffect: readonly
843
+ idempotent: true
844
+ requiresApproval: false
845
+ timeout: 180000
846
+ maxDepth: 1
847
+ availableTools: [read-file, search-code, run-command]
848
+ ---
849
+
850
+ 你是一名严谨的代码审查者。接到 diff 或文件集后:
851
+ 1. 理解变更意图
852
+ 2. 从正确性、清晰度、安全性和性能角度逐项审查
853
+ 3. 输出带有严重程度分级的结构化审查意见:critical / major / minor / nit
854
+ ```
855
+
856
+ ---
857
+
858
+ ## 可观测性与安全(Observability & Safety)
859
+
860
+ ### OpenTelemetry 集成
861
+
862
+ 每个引擎事件映射为一条 OTel Span,实现完整的分布式追踪:
863
+
864
+ ```typescript
865
+ import { OtelEmitter } from '@tachu/extensions/emitters';
866
+ import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
867
+ import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
868
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
869
+
870
+ const provider = new NodeTracerProvider();
871
+ provider.addSpanProcessor(
872
+ new SimpleSpanProcessor(new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces' }))
873
+ );
874
+ provider.register();
875
+
876
+ engine.useEmitter(new OtelEmitter());
877
+ ```
878
+
879
+ **每次请求产出的事件类型:**
880
+
881
+ | 事件类型 | 时机 |
882
+ |---------|------|
883
+ | `phase_enter` / `phase_exit` | 每个流程阶段进入/退出 |
884
+ | `llm_call_start` / `llm_call_end` | 每次 LLM 调用 |
885
+ | `tool_call_start` / `tool_call_end` | 每次 Tool 执行 |
886
+ | `retry` | 任务级或系统级重试触发 |
887
+ | `provider_fallback` | Provider 降级启动 |
888
+ | `budget_warning` | 预算已用到上限的 80% |
889
+ | `budget_exhausted` | 预算熔断激活 |
890
+ | `error` | 任何 `EngineError` 子类 |
891
+
892
+ ### 安全模块(Safety Module)
893
+
894
+ 安全模块分两层独立运行:
895
+
896
+ **引擎固有基线(不可禁用):**
897
+ - 输入大小上限(`maxInputSize` 字节)
898
+ - 递归深度限制(`maxRecursionDepth`)
899
+ - 预算熔断(Token/时间预算耗尽时立即终止)
900
+
901
+ **业务可注入策略**(通过 Hooks 或配置):
902
+ - Prompt 注入检测(`enablePromptInjectionCheck: true`)
903
+ - 敏感操作拦截(通过 `engine.registerSafetyPolicy()` 注册)
904
+ - 输出内容合规检查
905
+
906
+ ```typescript
907
+ // 注册自定义安全策略
908
+ engine.registerSafetyPolicy(async (input, ctx) => {
909
+ if (containsPersonalData(input.content)) {
910
+ return { passed: false, violations: [{ type: 'pii', message: '输入中检测到个人隐私数据' }] };
911
+ }
912
+ return { passed: true, violations: [] };
913
+ });
914
+ ```
915
+
916
+ ### 兜底与用户可见契约(Graceful Degradation Policy)
917
+
918
+ Tachu 保证 **用户看到的每一次响应都是可读的自然语言答复** —— 引擎绝不返回孤零零的 "failed",也不会把内部步骤 ID / Phase 编号 / 子流程名泄漏给终端用户。这由三道防线共同保证:
919
+
920
+ 1. **源头**:所有 `EngineError` 自带 `userMessage` 字段,由中文模板表解析(覆盖 46 个错误码);对 UI 暴露的 `toUserFacing()` 投影只返回 `{ code, userMessage, retryable }`,不含 `message` / `stack` / `cause` / `context`。
921
+ 2. **聚合**:当 `validation.passed === false` 且内置 `direct-answer` 子流程也未产出时,Phase 9 的 `ensureFallbackText()` 先尝试一次 best-effort LLM 摘要(5 秒超时 / 0 重试),失败静默降级到本地确定性模板。返回文本始终 **≥ 30 字**、带可执行下一步、且已过脱敏。
922
+ 3. **最终屏蔽**:CLI `StreamRenderer` 对所有面向用户的字符串(`finalize(text|markdown)` + `error` chunk)过一遍正则黑名单(`sanitizeUserText`),兜住任何上游漏过的内部术语。
923
+
924
+ 契约由 `packages/core/src/engine/phases/fallback-contract.test.ts` 强制执行(55 条断言)。任何把 `task-tool-N` / `Phase N` / `direct-answer 子流程` / `capability 路由` / `Tool / Agent 描述符` 泄漏到用户可见路径的回归,都会让 CI 变红。
925
+
926
+ ---
927
+
928
+ ## 发展路线(Roadmap)
929
+
930
+ Tachu 按 `1.0.0-alpha.n` → `1.0.0-beta.n` → `1.0.0` 三条通道演进。下面每个里程碑都对应真实、可发布、有测试的交付物,不是愿望清单。
931
+
932
+ ### 1.0.0-alpha.1 —— 首个公开 alpha(当前)
933
+
934
+ - [x] 9 阶段主干、Registry、Prompt 组装、调度器、8 个核心模块
935
+ - [x] OpenAI / Anthropic / Qwen / Mock Provider Adapter,`apiKey` / `baseURL` / `organization` / `timeoutMs` 可通过 env、`tachu.config.ts` 或 CLI flag 配置
936
+ - [x] CLI(`tachu init` / `run` / `chat`)流式渲染、Session 持久化、双击 Ctrl+C 退出、终端 Markdown 渲染
937
+ - [x] MCP stdio + SSE Adapter,按 `tachu.config.ts` 自动装配
938
+ - [x] 向量存储(`LocalFsVectorStore`、`QdrantVectorStore`)+ 可观测性 Emitter(OTel / JSONL / Console)
939
+ - [x] `direct-answer` 内置子流程 —— 在 Registry 保留名机制下于 Phase 7 驱动面向用户的 LLM 回复,与普通子流程共享同一套安全与可观测钩子
940
+ - [x] `tool-use` 内置子流程 —— 完整的 Agentic Loop:工具选择、审批、执行、反馈、终止
941
+ - [x] Phase 3(意图分析)真实 LLM 调用:结构化 JSON Schema、few-shot 示例、有界历史窗口、组合超时
942
+ - [x] Phase 5 兜底契约 —— 任何请求路径都保证 `plans[0].tasks.length >= 1`;LLM-backed 排序规划器排期在后续 alpha
943
+ - [x] Phase 9 输出装配 —— 内部 state JSON 不会外泄
944
+ - [x] 可选的 `@tachu/web-fetch-server` Sidecar —— 支撑 `web-fetch` / `web-search` 工具,SDK 不引入浏览器依赖
945
+ - [x] 结构化文生图契约(`ChatResponse.images` / `EngineOutput.metadata.generatedImages`)与 `tachu run --save-image`
946
+
947
+ ### 后续 alpha 迭代
948
+
949
+ - [ ] LLM-backed Phase 5 规划器:为 tool-chain 场景产出排序多步计划
950
+ - [ ] Phase 8 真实 LLM 调用:结构化 `ValidationResult` 驱动重试 / 重新规划循环
951
+ - [ ] `tachu run --plan-mode` 真实 Plan 预览
952
+ - [ ] 引擎级 `delta` 流,使 CLI 在 Phase 3 / 7 / 8 能做 Token-by-Token 渲染
953
+ - [ ] `tachu run --json` 输出 Schema 锁定
954
+ - [ ] 故障注入测试框架
955
+ - [ ] 端到端烟测记录存档至 `docs/smoke/`
956
+
957
+ ### 1.0.0-beta —— 毕业标准
958
+
959
+ - [ ] 连续两个 alpha 版本无回退
960
+ - [ ] 至少有 1 位第三方用户对真实 LLM 完整跑通并反馈
961
+ - [ ] 公开覆盖率与基准性能基线
962
+ - [ ] 公开自 `1.0.0-alpha.1` 以来所有 Breaking Change 的升级指南
963
+ - [ ] 在稳定协议背后引入更多 Provider Adapter(Gemini、Mistral)
964
+
965
+ ### 1.0.0 —— 稳定
966
+
967
+ - [ ] SLO / 错误预算文档
968
+ - [ ] 签名发布 provenance
969
+ - [ ] 向后兼容策略
970
+ - [ ] 生产部署案例文档
971
+
972
+ ### 1.0 之后 —— 愿景
973
+
974
+ - 多 Agent 协作(Agent 间通信协议)
975
+ - 跨部署重启的长期记忆持久化
976
+ - 子任务粒度的精细预算分配
977
+ - 更多 VectorStore Adapter(Pinecone、pgvector)
978
+ - Plan 模板库
979
+ - 更多压缩策略
980
+
981
+ ---
982
+
983
+ ## 贡献指南(Contributing)
984
+
985
+ ### 环境要求
986
+
987
+ - [Bun](https://bun.sh) >= 1.1.0
988
+ - TypeScript 5.x(通过 devDependencies 提供)
989
+
990
+ ### 开发工作流
991
+
992
+ ```bash
993
+ # 克隆并安装
994
+ git clone https://github.com/dangaogit/tachu.git
995
+ cd tachu
996
+ bun install
997
+
998
+ # 运行所有测试
999
+ bun test
1000
+
1001
+ # 类型检查
1002
+ bun run typecheck
1003
+
1004
+ # 构建所有包
1005
+ bun run build
1006
+
1007
+ # 运行指定包的测试
1008
+ bun test --filter packages/core
1009
+ ```
1010
+
1011
+ ### 项目规范
1012
+
1013
+ - 文件名:`kebab-case`
1014
+ - 类名/类型名:`PascalCase`
1015
+ - 函数/变量名:`camelCase`
1016
+ - 常量名:`SCREAMING_SNAKE_CASE`
1017
+ - 所有公开 API 必须有 TSDoc 注释(`@param`、`@returns`、`@throws`、`@example`)
1018
+ - 测试文件与源码同目录,命名 `*.test.ts`
1019
+ - 集成测试放 `__tests__/`
1020
+
1021
+ Pull Request 要求:
1022
+ - 所有测试通过(`bun test`)
1023
+ - TypeScript 零错误(`bun run typecheck`)
1024
+ - 覆盖率达标(行 ≥80%,分支 ≥70%)
1025
+ - 新增公开 API 有完整 TSDoc
1026
+
1027
+ 详见 `CONTRIBUTING.md`。
1028
+
1029
+ ---
1030
+
1031
+ ## 基准测试(Benchmarks)
1032
+
1033
+ 性能基准位于 `packages/core/benchmarks/`,通过 `bun test` 执行:
1034
+
1035
+ | 基准 | 度量指标 | 基线数据 |
1036
+ |------|---------|---------|
1037
+ | `scheduler.bench.ts` — 100 个并行任务 | 调度吞吐量 | *由 verifier 阶段填充* |
1038
+ | `vector-store.bench.ts` — 10,000 条索引,topK=10 | 搜索 QPS | *由 verifier 阶段填充* |
1039
+ | `prompt-assembler.bench.ts` — 4K Token 窗口组装 | 组装延迟(p99) | *由 verifier 阶段填充* |
1040
+
1041
+ 基准测试提供回归检测基线;v1 不设定最低性能指标要求。
1042
+
1043
+ ---
1044
+
1045
+ ## 文档(Documentation)
1046
+
1047
+ | 文档 | 说明 |
1048
+ |------|------|
1049
+ | [架构设计(Architecture Design)](./docs/adr/architecture-design.md) | 愿景、三层结构、四大核心抽象、9 阶段主干设计 |
1050
+ | [详细设计(Detailed Design)](./docs/adr/detailed-design.md) | TypeScript 接口、模块规格、配置 Schema |
1051
+ | [技术设计(Technical Design)](./docs/adr/technical-design.md) | 技术选型、工程结构、实现指南 |
1052
+
1053
+ ---
1054
+
1055
+ ## Web Fetch Server(可选)
1056
+
1057
+ **Web Fetch Server**(`@tachu/web-fetch-server`)是可选的 HTTP 侧车服务,为 `@tachu/extensions` 中的 `web-fetch` / `web-search` 工具提供远端浏览器渲染与结构化页面抽取。它**不会**随引擎或 CLI 默认启动——仅在需要针对线上页面使用上述工具时再单独运行。
1058
+
1059
+ ### 快速启动(仓库根目录)
1060
+
1061
+ ```bash
1062
+ bun install
1063
+ bun run dev:server:install-browser # 首次:为 Playwright 安装 Chromium
1064
+ bun run dev:server
1065
+ ```
1066
+
1067
+ ### 工具说明
1068
+
1069
+ - **`web-fetch`** — 通过服务端拉取 URL,并返回面向 LLM 的 Markdown(Readability + Turndown 管线)。
1070
+ - **`web-search`** — v0.1 仅为 **stub**,尚未接入真实搜索 Provider。
1071
+
1072
+ 完整环境变量、安全默认(例如未配置 token 时仅绑定 `127.0.0.1`)与生产/Docker 说明见 [packages/web-fetch-server/README.md](./packages/web-fetch-server/README.md)。
1073
+
1074
+ ---
1075
+
1076
+ ## 许可证(License)
1077
+
1078
+ [Apache License 2.0](./LICENSE) © 2026 Tachu Contributors
1079
+
1080
+ 本项目采用 Apache License 2.0 许可证发布。许可证全文见 [LICENSE](./LICENSE) 文件,也可在 <http://www.apache.org/licenses/LICENSE-2.0> 获取。
1081
+
1082
+ 除非适用法律要求或书面同意,按照本许可证分发的软件是按"原样"分发的,不附带任何明示或暗示的担保或条件。请参阅许可证以了解特定语言的管理权限和限制。