@zooique/memora 2.0.0 → 2.0.3
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/README.en.md +272 -0
- package/README.md +150 -38
- package/dist/agent/agent.d.ts +233 -58
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +651 -359
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/assembler.d.ts +29 -13
- package/dist/agent/assembler.d.ts.map +1 -1
- package/dist/agent/assembler.js +79 -44
- package/dist/agent/assembler.js.map +1 -1
- package/dist/agent/builtinToolHandlers.d.ts +26 -1
- package/dist/agent/builtinToolHandlers.d.ts.map +1 -1
- package/dist/agent/builtinToolHandlers.js +73 -1
- package/dist/agent/builtinToolHandlers.js.map +1 -1
- package/dist/agent/constants.d.ts +4 -0
- package/dist/agent/constants.d.ts.map +1 -1
- package/dist/agent/constants.js +4 -0
- package/dist/agent/constants.js.map +1 -1
- package/dist/agent/contextManager.d.ts +8 -0
- package/dist/agent/contextManager.d.ts.map +1 -1
- package/dist/agent/contextManager.js +7 -2
- package/dist/agent/contextManager.js.map +1 -1
- package/dist/agent/guardrail.d.ts +4 -2
- package/dist/agent/guardrail.d.ts.map +1 -1
- package/dist/agent/guardrail.js +13 -5
- package/dist/agent/guardrail.js.map +1 -1
- package/dist/agent/loop.d.ts +58 -14
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +184 -131
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/managers/archiveCoordinator.d.ts +126 -22
- package/dist/agent/managers/archiveCoordinator.d.ts.map +1 -1
- package/dist/agent/managers/archiveCoordinator.js +239 -44
- package/dist/agent/managers/archiveCoordinator.js.map +1 -1
- package/dist/agent/managers/autoConfigRefiner.d.ts.map +1 -1
- package/dist/agent/managers/autoConfigRefiner.js +4 -8
- package/dist/agent/managers/autoConfigRefiner.js.map +1 -1
- package/dist/agent/managers/configManager.d.ts +87 -3
- package/dist/agent/managers/configManager.d.ts.map +1 -1
- package/dist/agent/managers/configManager.js +139 -2
- package/dist/agent/managers/configManager.js.map +1 -1
- package/dist/agent/managers/dedupManager.d.ts +169 -0
- package/dist/agent/managers/dedupManager.d.ts.map +1 -0
- package/dist/agent/managers/dedupManager.js +336 -0
- package/dist/agent/managers/dedupManager.js.map +1 -0
- package/dist/agent/managers/insightExtractor.d.ts.map +1 -1
- package/dist/agent/managers/insightExtractor.js +11 -11
- package/dist/agent/managers/insightExtractor.js.map +1 -1
- package/dist/agent/managers/llmJudgeHelper.d.ts +38 -0
- package/dist/agent/managers/llmJudgeHelper.d.ts.map +1 -0
- package/dist/agent/managers/llmJudgeHelper.js +49 -0
- package/dist/agent/managers/llmJudgeHelper.js.map +1 -0
- package/dist/agent/managers/memoryAdvisor.d.ts +3 -3
- package/dist/agent/managers/memoryAdvisor.d.ts.map +1 -1
- package/dist/agent/managers/memoryAdvisor.js +53 -67
- package/dist/agent/managers/memoryAdvisor.js.map +1 -1
- package/dist/agent/managers/memoryDecayScheduler.d.ts +46 -5
- package/dist/agent/managers/memoryDecayScheduler.d.ts.map +1 -1
- package/dist/agent/managers/memoryDecayScheduler.js +127 -63
- package/dist/agent/managers/memoryDecayScheduler.js.map +1 -1
- package/dist/agent/managers/memoryGovernance.d.ts +56 -0
- package/dist/agent/managers/memoryGovernance.d.ts.map +1 -0
- package/dist/agent/managers/memoryGovernance.js +63 -0
- package/dist/agent/managers/memoryGovernance.js.map +1 -0
- package/dist/agent/managers/memoryInspector.d.ts +32 -157
- package/dist/agent/managers/memoryInspector.d.ts.map +1 -1
- package/dist/agent/managers/memoryInspector.js +70 -363
- package/dist/agent/managers/memoryInspector.js.map +1 -1
- package/dist/agent/managers/relationBuilder.js +2 -2
- package/dist/agent/managers/relationBuilder.js.map +1 -1
- package/dist/agent/managers/sessionArchiver.d.ts +6 -1
- package/dist/agent/managers/sessionArchiver.d.ts.map +1 -1
- package/dist/agent/managers/sessionArchiver.js +19 -22
- package/dist/agent/managers/sessionArchiver.js.map +1 -1
- package/dist/agent/managers/streamAccumulator.d.ts +45 -0
- package/dist/agent/managers/streamAccumulator.d.ts.map +1 -0
- package/dist/agent/managers/streamAccumulator.js +40 -0
- package/dist/agent/managers/streamAccumulator.js.map +1 -0
- package/dist/agent/managers/textPolishManager.d.ts.map +1 -1
- package/dist/agent/managers/textPolishManager.js +4 -7
- package/dist/agent/managers/textPolishManager.js.map +1 -1
- package/dist/agent/managers/workProjection.d.ts +16 -1
- package/dist/agent/managers/workProjection.d.ts.map +1 -1
- package/dist/agent/managers/workProjection.js +48 -24
- package/dist/agent/managers/workProjection.js.map +1 -1
- package/dist/agent/toolExecutor.d.ts +22 -2
- package/dist/agent/toolExecutor.d.ts.map +1 -1
- package/dist/agent/toolExecutor.js +28 -3
- package/dist/agent/toolExecutor.js.map +1 -1
- package/dist/agent/types.d.ts +10 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/userFactExtractor.d.ts.map +1 -1
- package/dist/agent/userFactExtractor.js +7 -0
- package/dist/agent/userFactExtractor.js.map +1 -1
- package/dist/config/loader.d.ts +124 -236
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +273 -117
- package/dist/config/loader.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/llm/embedding.d.ts +13 -1
- package/dist/llm/embedding.d.ts.map +1 -1
- package/dist/llm/embedding.js.map +1 -1
- package/dist/llm/factory.d.ts +19 -5
- package/dist/llm/factory.d.ts.map +1 -1
- package/dist/llm/factory.js +19 -37
- package/dist/llm/factory.js.map +1 -1
- package/dist/llm/openaiCompatible.d.ts.map +1 -1
- package/dist/llm/openaiCompatible.js +2 -9
- package/dist/llm/openaiCompatible.js.map +1 -1
- package/dist/logging/logger.d.ts +3 -1
- package/dist/logging/logger.d.ts.map +1 -1
- package/dist/logging/logger.js +47 -50
- package/dist/logging/logger.js.map +1 -1
- package/dist/memory/governance.d.ts +50 -0
- package/dist/memory/governance.d.ts.map +1 -0
- package/dist/memory/governance.js +70 -0
- package/dist/memory/governance.js.map +1 -0
- package/dist/memory/hybridMerge.d.ts +0 -4
- package/dist/memory/hybridMerge.d.ts.map +1 -1
- package/dist/memory/hybridMerge.js +19 -4
- package/dist/memory/hybridMerge.js.map +1 -1
- package/dist/memory/inMemoryRelationStore.d.ts +7 -0
- package/dist/memory/inMemoryRelationStore.d.ts.map +1 -1
- package/dist/memory/inMemoryRelationStore.js +15 -0
- package/dist/memory/inMemoryRelationStore.js.map +1 -1
- package/dist/memory/inMemoryStorage.d.ts +36 -1
- package/dist/memory/inMemoryStorage.d.ts.map +1 -1
- package/dist/memory/inMemoryStorage.js +66 -16
- package/dist/memory/inMemoryStorage.js.map +1 -1
- package/dist/memory/loader.d.ts +2 -0
- package/dist/memory/loader.d.ts.map +1 -1
- package/dist/memory/loader.js +8 -1
- package/dist/memory/loader.js.map +1 -1
- package/dist/memory/lockManager.d.ts +7 -2
- package/dist/memory/lockManager.d.ts.map +1 -1
- package/dist/memory/lockManager.js +31 -5
- package/dist/memory/lockManager.js.map +1 -1
- package/dist/memory/projectManager.d.ts +2 -1
- package/dist/memory/projectManager.d.ts.map +1 -1
- package/dist/memory/projectManager.js +21 -3
- package/dist/memory/projectManager.js.map +1 -1
- package/dist/memory/projectRegistry.d.ts +34 -1
- package/dist/memory/projectRegistry.d.ts.map +1 -1
- package/dist/memory/projectRegistry.js +99 -22
- package/dist/memory/projectRegistry.js.map +1 -1
- package/dist/memory/recall.d.ts +16 -0
- package/dist/memory/recall.d.ts.map +1 -1
- package/dist/memory/recall.js +33 -18
- package/dist/memory/recall.js.map +1 -1
- package/dist/memory/relationStore.d.ts +20 -3
- package/dist/memory/relationStore.d.ts.map +1 -1
- package/dist/memory/sourceValidation.d.ts +11 -0
- package/dist/memory/sourceValidation.d.ts.map +1 -1
- package/dist/memory/sourceValidation.js +24 -2
- package/dist/memory/sourceValidation.js.map +1 -1
- package/dist/memory/storageInterface.d.ts +26 -1
- package/dist/memory/storageInterface.d.ts.map +1 -1
- package/dist/memory/store.d.ts +22 -1
- package/dist/memory/store.d.ts.map +1 -1
- package/dist/memory/store.js +58 -20
- package/dist/memory/store.js.map +1 -1
- package/dist/memory/types.d.ts +44 -31
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/memory/types.js +63 -24
- package/dist/memory/types.js.map +1 -1
- package/dist/memory/userProfile.d.ts +32 -8
- package/dist/memory/userProfile.d.ts.map +1 -1
- package/dist/memory/userProfile.js +105 -44
- package/dist/memory/userProfile.js.map +1 -1
- package/dist/memory/vectorStore.d.ts +16 -22
- package/dist/memory/vectorStore.d.ts.map +1 -1
- package/dist/memory/vectorStore.js +49 -22
- package/dist/memory/vectorStore.js.map +1 -1
- package/dist/persona/personaManager.d.ts +36 -87
- package/dist/persona/personaManager.d.ts.map +1 -1
- package/dist/persona/personaManager.js +131 -230
- package/dist/persona/personaManager.js.map +1 -1
- package/dist/skill/skillManager.d.ts +11 -57
- package/dist/skill/skillManager.d.ts.map +1 -1
- package/dist/skill/skillManager.js +46 -142
- package/dist/skill/skillManager.js.map +1 -1
- package/dist/skill/types.d.ts +2 -3
- package/dist/skill/types.d.ts.map +1 -1
- package/dist/utils/configResourceManager.d.ts +111 -0
- package/dist/utils/configResourceManager.d.ts.map +1 -0
- package/dist/utils/configResourceManager.js +148 -0
- package/dist/utils/configResourceManager.js.map +1 -0
- package/dist/utils/errors.d.ts +17 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +19 -0
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/eventEmitter.d.ts +83 -6
- package/dist/utils/eventEmitter.d.ts.map +1 -1
- package/dist/utils/eventEmitter.js +23 -0
- package/dist/utils/eventEmitter.js.map +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +4 -2
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/math.d.ts +11 -0
- package/dist/utils/math.d.ts.map +1 -1
- package/dist/utils/math.js +17 -0
- package/dist/utils/math.js.map +1 -1
- package/dist/utils/segmenter.d.ts +0 -10
- package/dist/utils/segmenter.d.ts.map +1 -1
- package/dist/utils/segmenter.js +10 -1
- package/dist/utils/segmenter.js.map +1 -1
- package/docs/memora-api-reference.md +1235 -0
- package/docs/memora-/346/216/245/345/205/245/346/214/207/345/215/227.md +808 -0
- package/package.json +39 -22
|
@@ -0,0 +1,808 @@
|
|
|
1
|
+
# Memora · 接入指南 v2.0.3
|
|
2
|
+
|
|
3
|
+
> 帮助宿主项目开发者快速理解 Memora 的设计理念和接入方法。
|
|
4
|
+
>
|
|
5
|
+
> **版本**:v2.0.3(最后更新:2026-08-01)
|
|
6
|
+
>
|
|
7
|
+
> **1.0.0 之前:核心能力演进**(原内部里程碑 v3.0–v3.3,于 npm 0.2.0 前后完成):
|
|
8
|
+
> - **Agent God Object 拆分(原 v3.0)**:记忆查询、规则注入、工具注册等方法迁移到专职 Manager,通过 `agent.<manager>.xxx()` 访问。详见 [API 参考手册](./memora-api-reference.md)。
|
|
9
|
+
> - **可观测性与护栏(原 v3.1)**:新增可观测性(ITracer)、内容护栏(Guardrails)、工具错误反思(Reflection)、评估体系(Eval)支持。
|
|
10
|
+
> - **关系图谱与画像(原 v3.2)**:新增 ADR-014 记忆关系图谱(IMemoryRelationStore 侧车接口)、UserProfile 用户画像管理、WorkProjectionManager 作品投影、AutoConfigRefiner 自进化配置建议。
|
|
11
|
+
> - **npm 正式包与基础工具(原 v3.3)**:内核发布 v0.2.0(npm 正式包),精灵切换至 npm alias 依赖。Phase 1-4 全部核心完成。新增 EmbeddingProvider、安全定时器(safeSetTimeout/safeSetInterval)、Frontmatter 工具、事件系统(TypedEventEmitter)、记忆关系常量(RELATION_TYPES/RELATION_WEIGHTS)、审计类型(AuditEvent 等)、评估框架(EvalScenario/collectAgentChunks/evaluateResult)。
|
|
12
|
+
>
|
|
13
|
+
> **v1.0.0 变更**:1.0 正式发布。P0 阻塞修复全量收敛:DEFAULT_CONFIG 由 `config/loader.ts` 常量声明单一真理源(不再维护独立 schema)、IVectorStore 接口提取(JsonVectorStore 内置实现)、AbortSignal 合并工具、Logger 懒初始化(移除模块顶层副作用)、评估框架结构化信号(guardrailBlocked 替代文案匹配)、文档全量对齐(包名 @zooique/memora)。
|
|
14
|
+
>
|
|
15
|
+
> **v2.0.0 变更**:版本号提升(维护性质,无破坏性 API 变更)。
|
|
16
|
+
>
|
|
17
|
+
> **v2.0.1 变更**:文档版本号对齐(v1.0.2 → v2.0.1)。无 API 破坏性变更,仅同步文档与版本戳。
|
|
18
|
+
>
|
|
19
|
+
> **v2.0.2 变更**:万物皆记忆 v2(双轨模型——设定记忆 + 对话记忆)。Persona/Skill 从 SQLite 索引解耦,改为纯文件 + 内存缓存。Skill 匹配改为当轮实时注入。详见 [CHANGELOG](../CHANGELOG.md)。
|
|
20
|
+
>
|
|
21
|
+
> **v2.0.3 变更**:npm 发布配置修复与质量加固。新增 `publishConfig.access = "public"`、`exports` 增加 `default` 回退条件、`keywords` 扩充至 18 个。无 API 破坏性变更。
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 目录
|
|
26
|
+
|
|
27
|
+
- [一、核心理念](#一核心理念)
|
|
28
|
+
- [二、三重数据存续路径](#二三重数据存续路径)
|
|
29
|
+
- [三、最小接入步骤](#三最小接入步骤)
|
|
30
|
+
- [四、会话持久化](#四会话持久化)
|
|
31
|
+
- [五、API 速查](#五api-速查)
|
|
32
|
+
- [六、宿主工具函数](#六宿主工具函数)
|
|
33
|
+
- [七、可观测性接入(ITracer)](#七可观测性接入itracer)
|
|
34
|
+
- [八、内容护栏(Guardrails)](#八内容护栏guardrails)
|
|
35
|
+
- [九、评估体系(Eval)](#九评估体系eval)
|
|
36
|
+
- [十、多步骤编排](#十多步骤编排)
|
|
37
|
+
- [十一、关键约束](#十一关键约束)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 一、核心理念
|
|
42
|
+
|
|
43
|
+
**Memora 是一个无法独立运行的智能大脑内核。** 它只有接口,没有"形态"——宿主负责给它身体(UI)、血管(Provider)、神经网络(事件回路)。
|
|
44
|
+
|
|
45
|
+
**万物皆记忆 v2。** Memora 有两类记忆:**设定记忆**(Persona/Skill/Rule —— Agent 的骨骼,.md 文件 + 内存缓存,确定性注入不经过召回)和**对话记忆**(Conversation/Insight/UserProfile —— Agent 的血肉,SQLite + VectorStore,语义召回)。二者通过 `autoConfigRefiner` 连接——对话洞察可生长为设定文件。
|
|
46
|
+
|
|
47
|
+
**单 Agent 模型。** 所有对话、所有记忆存在同一个数据库中,**切换子项目不会丢失记忆**。
|
|
48
|
+
|
|
49
|
+
**配置文件是真理源,对话记忆走 SQLite 索引。** Persona/Skill 为纯文件 + 内存缓存;Rule 文件写入 SQLite 供 bootstrap 读取;对话记忆(insight/profile)走 SQLite + 语义召回。
|
|
50
|
+
|
|
51
|
+
**内核零越界。** 核心库不调用 `console.*`、不读 `process.stdin`、不管理 API Key、不写用户配置文件。
|
|
52
|
+
|
|
53
|
+
**Manager 委托模式(1.0.0)。** Agent 面类只做编排,领域操作委托给 9 个专职 Manager:`agent.persona` / `agent.tools` / `agent.skills` / `agent.config` / `agent.insight` / `agent.memory` / `agent.userProfile` / `agent.works` / `agent.polish`(文本润色)。
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
┌────────────────────────────────────────────────────────────┐
|
|
57
|
+
│ 宿主程序 │
|
|
58
|
+
│ ┌─────────────────┐ ┌──────────────────┐ │
|
|
59
|
+
│ │ LLM Provider 实例 │◄───│ API Key / baseUrl │ ← 宿主职责 │
|
|
60
|
+
│ └────────┬────────┘ └──────────────────┘ │
|
|
61
|
+
│ │ 注入 │
|
|
62
|
+
│ ▼ │
|
|
63
|
+
│ ┌──────────────────────────────────────────┐ │
|
|
64
|
+
│ │ Memora 内核(Agent) │ │
|
|
65
|
+
│ │ - chat(input) → 流式响应 │ │
|
|
66
|
+
│ │ - 9 个 Manager getter(委托模式,含文本润色) │ │
|
|
67
|
+
│ │ ⚠️ 不包含:UI / LLM 配置 / 用户配置模板 │ │
|
|
68
|
+
│ └──────────────────────────────────────────┘ │
|
|
69
|
+
└────────────────────────────────────────────────────────────┘
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 二、三重数据存续路径
|
|
75
|
+
|
|
76
|
+
| 路径 | 用途 | 示例 |
|
|
77
|
+
|------|------|------|
|
|
78
|
+
| `AgentOptions.configDir` | Agent 级配置(personas/rules/skills) | 嵌入宿主程序 |
|
|
79
|
+
| `AgentOptions.dataDir` | 记忆数据(memora.db + sessions/) | 跟作品走 |
|
|
80
|
+
| `projectPath/.memora/` | 项目级配置(rules/skills) | 跟作品走 |
|
|
81
|
+
|
|
82
|
+
**小说生成器推荐布局:**
|
|
83
|
+
```
|
|
84
|
+
小说项目/
|
|
85
|
+
├── .memora/ ← 项目级配置(rules + skills)
|
|
86
|
+
└── .memora-data/ ← 项目级记忆(dataDir 指向此处)
|
|
87
|
+
├── memora.db
|
|
88
|
+
└── sessions/
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 三、最小接入步骤
|
|
94
|
+
|
|
95
|
+
### 1. 安装
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
npm install @zooique/memora
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 2. 创建 Provider + Agent
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { Agent, createLlmProvider, JsonVectorStore, setLogger } from '@zooique/memora';
|
|
105
|
+
import type { IMemoryStorage, ILogger, EmbeddingService } from '@zooique/memora';
|
|
106
|
+
|
|
107
|
+
// 宿主职责:创建 LLM Provider(Agent 不关心 API Key)
|
|
108
|
+
const provider = createLlmProvider({
|
|
109
|
+
provider: 'openaiCompatible',
|
|
110
|
+
apiKey: process.env.LLM_API_KEY!,
|
|
111
|
+
baseUrl: 'https://api.deepseek.com/v1',
|
|
112
|
+
model: 'deepseek-chat',
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// 可选:后台 Provider(投影等后台操作)
|
|
116
|
+
const backgroundProvider = createLlmProvider({
|
|
117
|
+
provider: 'openaiCompatible',
|
|
118
|
+
apiKey: process.env.LLM_API_KEY!,
|
|
119
|
+
baseUrl: 'https://api.deepseek.com/v1',
|
|
120
|
+
model: 'deepseek-chat', // 可用更便宜的模型
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// 可选:注入存储层(不传则使用 InMemoryStorage)
|
|
124
|
+
const storage: IMemoryStorage = new MySqliteStorage('/path/to/memora.db');
|
|
125
|
+
|
|
126
|
+
// 可选:全局替换日志实现(不调用则使用内置 console logger;pino 为可选 peer 依赖,动态 import 懒加载)
|
|
127
|
+
setLogger(myCustomLogger);
|
|
128
|
+
|
|
129
|
+
// 可选:向量存储(提供后启用语义搜索召回)
|
|
130
|
+
const embeddingService: EmbeddingService = myEmbeddingService;
|
|
131
|
+
const vectorStore = new JsonVectorStore('/path/to/vectors.json', embeddingService);
|
|
132
|
+
|
|
133
|
+
// 创建 Agent
|
|
134
|
+
const agent = new Agent({
|
|
135
|
+
projectPath: '/path/to/novel-project',
|
|
136
|
+
provider, // 前台 Provider(必须)
|
|
137
|
+
backgroundProvider, // 后台 Provider(可选)
|
|
138
|
+
configDir: '/path/to/agent-config',
|
|
139
|
+
dataDir: '.memora',
|
|
140
|
+
maxContextTokens: 120000,
|
|
141
|
+
persona: '作家',
|
|
142
|
+
permission: 'owner',
|
|
143
|
+
allowedPaths: ['.'],
|
|
144
|
+
confirmWrites: false,
|
|
145
|
+
storage, // 存储层注入(可选)
|
|
146
|
+
vectorStore, // 向量存储(可选,启用语义搜索)
|
|
147
|
+
tracer: myOtelTracer, // 可观测性 Tracer(可选,不传则静默丢弃所有 span)
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
await agent.init();
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 3. 对话
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// 流式对话(生产推荐)
|
|
157
|
+
for await (const chunk of agent.chat('帮我写一段玄幻小说开头')) {
|
|
158
|
+
switch (chunk.type) {
|
|
159
|
+
case 'text': ui.appendText(chunk.content); break;
|
|
160
|
+
case 'thinking': ui.showThinking(chunk.phase); break;
|
|
161
|
+
case 'tool_start': ui.showToolStart(chunk.name); break;
|
|
162
|
+
case 'tool_result':ui.showToolResult(chunk.ok); break;
|
|
163
|
+
case 'aborted': ui.showCancelled(chunk.reason); break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 同步对话(测试用)
|
|
168
|
+
const reply = await agent.chatSync('你好');
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 3.5 事件订阅(可选)
|
|
172
|
+
|
|
173
|
+
Agent 向宿主广播对话外事件(记忆变更、角色切换、衰减完成、会话分叉等)。
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import type { AgentEventMap } from '@zooique/memora';
|
|
177
|
+
|
|
178
|
+
agent.on('memoryAdded', (e) => console.log(`新记忆: ${e.source}:${e.name}`));
|
|
179
|
+
agent.on('personaSwitched', (e) => console.log(`角色: ${e.from} → ${e.to}`));
|
|
180
|
+
agent.on('decayCompleted', (e) => console.log(`衰减 ${e.decayedCount} 条记忆`));
|
|
181
|
+
agent.on('memoryRecalled', (e) => console.log(`想起 ${e.count} 条记忆`));
|
|
182
|
+
agent.on('sessionForked', (e) => console.log(`分叉: ${e.from} → ${e.to},${e.messageCount} 条消息`));
|
|
183
|
+
|
|
184
|
+
// close() 自动移除所有监听器
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 4. 注册领域工具
|
|
188
|
+
|
|
189
|
+
> 1.0.0:工具注册走 `agent.tools.xxx()`。
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
agent.tools.registerTool(
|
|
193
|
+
{
|
|
194
|
+
name: 'create_chapter',
|
|
195
|
+
description: '创建一个新章节',
|
|
196
|
+
parameters: {
|
|
197
|
+
type: 'object',
|
|
198
|
+
properties: { title: { type: 'string', description: '章节标题' } },
|
|
199
|
+
required: ['title'],
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
async (args) => {
|
|
203
|
+
const chapter = await myNovel.createChapter(args.title);
|
|
204
|
+
return `章节 "${args.title}" 已创建`;
|
|
205
|
+
},
|
|
206
|
+
);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 5. 注入写入扩展 + 记忆关键词
|
|
210
|
+
|
|
211
|
+
> 1.0.0:写入扩展和关键词走 `agent.insight.xxx()`。
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// 写入前 diff 确认回调
|
|
215
|
+
agent.insight.setWriteExtensions({
|
|
216
|
+
onBeforeWrite: async (path, before, after) => {
|
|
217
|
+
showDiff(path, before, after);
|
|
218
|
+
return await userConfirm(`确认写入 ${path}?`);
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// 记忆关键词(领域 + 用户专属)
|
|
223
|
+
agent.insight.setKeywords({
|
|
224
|
+
domain: ['主角', '角色', '情节', '设定'],
|
|
225
|
+
personal: ['我', '我的', '记住', '帮我'],
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### 6. 注入项目规则
|
|
230
|
+
|
|
231
|
+
> 1.0.0:规则注入走 `agent.config.xxx()`。
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
await agent.config.addSimpleRule(
|
|
235
|
+
'世界观规则',
|
|
236
|
+
'这是一个东方玄幻世界,修真等级分为炼气、筑基、金丹……',
|
|
237
|
+
);
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 7. 查询记忆
|
|
241
|
+
|
|
242
|
+
> 1.0.0:记忆查询走 `agent.memory.xxx()`。
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
// 3 层记忆快照
|
|
246
|
+
const snap = agent.memory.snapshot();
|
|
247
|
+
console.log('工作记忆:', snap.working.total, '条');
|
|
248
|
+
console.log('引导记忆:', snap.bootstrap.total, '条');
|
|
249
|
+
|
|
250
|
+
// 关键词搜索
|
|
251
|
+
const hits = agent.memory.search('世界观');
|
|
252
|
+
hits.forEach(h => console.log(`${h.source}:${h.name} (${h.score})`));
|
|
253
|
+
|
|
254
|
+
// 记忆库统计
|
|
255
|
+
const stats = agent.memory.stats();
|
|
256
|
+
console.log('记忆总数:', stats.total);
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### 8. 管理角色
|
|
260
|
+
|
|
261
|
+
> 1.0.0:角色管理走 `agent.persona.xxx`。
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
// 列出所有角色
|
|
265
|
+
const names = agent.persona.list.map(p => p.name);
|
|
266
|
+
|
|
267
|
+
// 手动切换(返回新角色的 system prompt,可用于 UI 展示)
|
|
268
|
+
const personaPrompt = agent.persona.switchPersona('作家');
|
|
269
|
+
|
|
270
|
+
// 锁定手动模式(禁止自动匹配)
|
|
271
|
+
agent.persona.setMode('manual');
|
|
272
|
+
|
|
273
|
+
// 查询当前状态
|
|
274
|
+
console.log(agent.persona.activeName); // '作家'
|
|
275
|
+
console.log(agent.persona.currentMode); // 'manual'
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### 9. 切换项目
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
// switchProject() 自动 rebuild,无需手动调用 rebuildComponents()
|
|
282
|
+
const ctx = await agent.switchProject('another-novel');
|
|
283
|
+
console.log(`已切换到:${ctx.projectName}`);
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### 10. 关闭
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
await agent.close(); // 释放项目锁 + 关闭数据库
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## 四、会话持久化(ISessionStore)
|
|
295
|
+
|
|
296
|
+
Memora 通过 `ISessionStore` 接口支持会话消息的持久化。宿主实现此接口,注入到 Agent。
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
import type { ISessionStore, SessionMessage } from '@zooique/memora';
|
|
300
|
+
|
|
301
|
+
// 宿主实现接口
|
|
302
|
+
class FileSessionStore implements ISessionStore {
|
|
303
|
+
appendMessage(date: string, session: string, message: SessionMessage): void {
|
|
304
|
+
// 写入文件或数据库
|
|
305
|
+
}
|
|
306
|
+
loadMessages(date: string, session: string): SessionMessage[] {
|
|
307
|
+
// 从文件或数据库读取
|
|
308
|
+
return [];
|
|
309
|
+
}
|
|
310
|
+
listSessions(): string[] {
|
|
311
|
+
// 返回所有会话列表
|
|
312
|
+
return [];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// 注入到 Agent
|
|
317
|
+
const agent = new Agent({
|
|
318
|
+
// ...其他配置
|
|
319
|
+
sessionStore: new FileSessionStore('./sessions'),
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**会话持久化特性:**
|
|
324
|
+
- 日期使用 `todayDate()` 动态获取,确保跨日后消息写入当天目录
|
|
325
|
+
- `appendUser()` / `appendAssistant()` 自动调用 `appendMessage()`
|
|
326
|
+
- `loadSessionMessages()` 自动调用 `loadMessages()`
|
|
327
|
+
- `SessionMessage.role` 支持 `'user' | 'assistant' | 'system'`,宿主直接调用 `appendMessage()` 时可传入任意角色
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## 四.5、会话分叉(Fork Session)
|
|
332
|
+
|
|
333
|
+
Memora 支持会话分叉功能,允许用户从当前对话创建独立分支,继承完整消息历史后各自独立发展。
|
|
334
|
+
|
|
335
|
+
**使用场景**:
|
|
336
|
+
- 用户在对话中建立了丰富的上下文后,可以分叉到多个并行任务
|
|
337
|
+
- 每个分支继承已建立的共识,避免从零开始
|
|
338
|
+
- 分支完全独立,互不干扰
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
// 自动生成分支名(main-b1, main-b2, ...)
|
|
342
|
+
const result = agent.forkSession();
|
|
343
|
+
console.log(`已分叉到: ${result.newSession},复制了 ${result.messageCount} 条消息`);
|
|
344
|
+
|
|
345
|
+
// 自定义分支名
|
|
346
|
+
const result2 = agent.forkSession('experiment');
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**命名规则**:
|
|
350
|
+
- 自动生成:`{原始会话名}-b{序号}`(如 `main-b1`、`main-b2`)
|
|
351
|
+
- 支持分叉的分叉:`main-b1-b1`
|
|
352
|
+
- 自定义名称:直接传入目标名称
|
|
353
|
+
|
|
354
|
+
**记忆处理策略**:
|
|
355
|
+
- 已有记忆:全局共享(记忆是全局知识库,不属于单个会话)
|
|
356
|
+
- 分叉后的 Insight:各自独立(不同分支探索不同方向)
|
|
357
|
+
- 用户画像:全局共享(UserProfile 是全局的)
|
|
358
|
+
|
|
359
|
+
**事件监听**:
|
|
360
|
+
```typescript
|
|
361
|
+
agent.on('sessionForked', (event) => {
|
|
362
|
+
console.log(`从 ${event.from} 分叉到 ${event.to}`);
|
|
363
|
+
console.log(`复制了 ${event.messageCount} 条消息`);
|
|
364
|
+
});
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**边界情况**:
|
|
368
|
+
- 当前会话无消息时抛出错误
|
|
369
|
+
- `ISessionStore` 未注入时抛出错误
|
|
370
|
+
- 对话正在进行中(`chatBusy`)时抛出错误
|
|
371
|
+
- 自定义名称已存在时抛出错误
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## 五、API 速查
|
|
376
|
+
|
|
377
|
+
> 完整定义见 [memora-api-reference.md](./memora-api-reference.md)。
|
|
378
|
+
|
|
379
|
+
### 构造选项 `AgentOptions`
|
|
380
|
+
|
|
381
|
+
| 选项 | 类型 | 必须 | 说明 |
|
|
382
|
+
|------|------|------|------|
|
|
383
|
+
| `projectPath` | `string` | ✅ | 项目路径 |
|
|
384
|
+
| `provider` | `LlmProvider` | ✅ | 前台 LLM Provider |
|
|
385
|
+
| `backgroundProvider` | `LlmProvider` | ❌ | 后台 Provider(投影) |
|
|
386
|
+
| `configDir` | `string` | ❌ | 配置目录(personas/rules/skills) |
|
|
387
|
+
| `dataDir` | `string` | ❌ | 记忆数据目录(默认 ~/.memora) |
|
|
388
|
+
| `registryDir` | `string` | ❌ | 项目注册表目录(默认与 dataDir 相同) |
|
|
389
|
+
| `maxContextTokens` | `number` | ❌ | 上下文窗口上限(默认 120000) |
|
|
390
|
+
| `persona` | `string` | ❌ | 默认角色名 |
|
|
391
|
+
| `permission` | `'owner' \| 'guest'` | ❌ | 安全权限(默认 'owner') |
|
|
392
|
+
| `allowedPaths` | `string[]` | ❌ | 路径白名单(默认 [] = 全部允许) |
|
|
393
|
+
| `confirmWrites` | `boolean` | ❌ | 写入确认(默认 false) |
|
|
394
|
+
| `storage` | `IMemoryStorage` | ❌ | 存储层注入 |
|
|
395
|
+
| `relationStore` | `IMemoryRelationStore` | ❌ | 记忆关系存储(ADR-014 侧车,不传则跳过关系构建) |
|
|
396
|
+
| `vectorStore` | `IVectorStore` | ❌ | 向量存储接口(提供时启用语义搜索;内置实现 `JsonVectorStore`) |
|
|
397
|
+
| `recallExcludeSources` | `string[]` | ❌ | 召回时排除的 source 标签(默认 `['persona', 'rule', 'skill']`) |
|
|
398
|
+
| `sessionStore` | `ISessionStore` | ❌ | 会话存储注入 |
|
|
399
|
+
| `tracer` | `ITracer` | ❌ | 可观测性 Tracer 注入(不传则使用 NoopTracer 静默丢弃所有 span) |
|
|
400
|
+
| `messages` | `UIMessages` | ❌ | 宿主可覆盖的 UI 消息文本(默认英文,宿主覆盖为中文等) |
|
|
401
|
+
| `enableContextSummary` | `boolean` | ❌ | 上下文超限时是否自动生成摘要(默认 true,开启后首次截断时增加 ~1-2s 延迟) |
|
|
402
|
+
|
|
403
|
+
### Agent 生命周期与状态
|
|
404
|
+
|
|
405
|
+
| 成员 | 说明 |
|
|
406
|
+
|------|------|
|
|
407
|
+
| `agent.init()` | 初始化(创建存储、加载配置、组装组件),返回 `AgentContext` |
|
|
408
|
+
| `agent.close()` | 安全关闭(释放锁 + 关闭数据库) |
|
|
409
|
+
| `agent.initialized` | 只读 getter,`boolean` |
|
|
410
|
+
| `agent.isBusy` | 只读 getter,`boolean`(是否正在对话中) |
|
|
411
|
+
| `agent.lastInteractionAt` | 只读 getter,`Date \| null`,最近一次对话时间 |
|
|
412
|
+
| `agent.context` | 只读 getter,`AgentContext \| null`,当前项目上下文 |
|
|
413
|
+
|
|
414
|
+
### 对话
|
|
415
|
+
|
|
416
|
+
| 方法 | 说明 |
|
|
417
|
+
|------|------|
|
|
418
|
+
| `agent.chat(input, signal?)` | 流式对话,返回 `AsyncGenerator<AgentChunk>` |
|
|
419
|
+
| `agent.chatSync(input, signal?)` | 同步对话(测试用) |
|
|
420
|
+
|
|
421
|
+
### 项目 / 会话
|
|
422
|
+
|
|
423
|
+
| 方法 | 说明 |
|
|
424
|
+
|------|------|
|
|
425
|
+
| `agent.projects.listProjects()` / `agent.projects.list` | 列出已注册的子项目 |
|
|
426
|
+
| `agent.switchProject(name)` | 切换到其他子项目 |
|
|
427
|
+
| `agent.rebuildComponents()` | 通常不需要手动调用(`switchProject` 已自动执行),仅在强制刷新配置时使用 |
|
|
428
|
+
| `agent.switchSession(name)` | 切换当前会话(同步,返回新会话名) |
|
|
429
|
+
| `agent.forkSession(name?)` | 分叉当前会话(复制完整消息历史到新分支) |
|
|
430
|
+
| `agent.loadSessionMessages(date, session)` | 加载指定日期/会话的消息 |
|
|
431
|
+
| `agent.restoreSession(date, session)` | 恢复指定日期/会话 |
|
|
432
|
+
| `agent.restoreMostRecentSession()` | 启动时恢复最近一次会话 |
|
|
433
|
+
| `agent.agentHistory.listAllSessions()` | 列出所有会话文件名 |
|
|
434
|
+
|
|
435
|
+
### Manager 速查表
|
|
436
|
+
|
|
437
|
+
| 路径 | Manager | 主要成员 |
|
|
438
|
+
|------|---------|---------|
|
|
439
|
+
| `agent.memory.xxx()` | MemoryInspector | 读:`snapshot()` / `search(q, n)` / `searchHybrid(q, n)` / `stats()` / `list()` / `getById(id)` / `listDeleted()` / 关系查询;写:`writeUpsert()` / `writeDelete()` / `writeRestore()` / `writePurge()` / `writeAddRelation()` 等(`writeXxx` 前缀)。`suggest()` / `sourceHealth()` 已上移至 `agent.suggest()` / `agent.sourceHealth()` |
|
|
440
|
+
| `agent.config.xxx()` | ConfigManager | `addRule(m)` / `addSimpleRule(n, c)` / `addSkill(m)` / `addSimpleSkill(n, c, k?)` / `onSuggestion(h)` / `confirm(s)` |
|
|
441
|
+
| `agent.tools.xxx()` | ToolExecutor | `registerTool(d, h)` / `getToolDefinitions()` / `execute(n, a)` / `list` |
|
|
442
|
+
| `agent.insight.xxx()` | InsightExtractor | `setWriteExtensions(e)` / `setKeywords(k)` / `classify(i)` |
|
|
443
|
+
| `agent.persona.xxx` | PersonaManager | `.list` / `.activeName` / `.currentMode` / `.switchPersona(n)` / `.setMode(m)` |
|
|
444
|
+
| `agent.skills.xxx` | SkillManager | `.list` / `.match(i)` / `.register(skill)` / `.buildSystemPrompt()` |
|
|
445
|
+
| `agent.userProfile.xxx()` | UserProfile | `load()` / `archiveFacts(f)` / `getConfirmed()` / `getPending()` / `buildSystemPrompt()` / `confirm(id)` / `reject(id)` |
|
|
446
|
+
| `agent.works.xxx()` | WorkProjectionManager | `ensureProjection(path, content)` / `getProjection(path)` / `loadAll()` |
|
|
447
|
+
| `agent.on()` / `agent.off()` / `agent.once()` | TypedEventEmitter | `memoryAdded` / `personaSwitched` / `decayCompleted` / `memoryRecalled` / `sessionForked` / `insightExtracted` / `conflictDetected` / `projectSwitched` / `skillMatched` / `archiveFailed` |
|
|
448
|
+
|
|
449
|
+
### Provider 管理
|
|
450
|
+
|
|
451
|
+
| 方法 | 说明 |
|
|
452
|
+
|------|------|
|
|
453
|
+
| `agent.setProvider(provider)` | 运行时切换前台 Provider |
|
|
454
|
+
| `agent.setBackgroundProvider(provider)` | 运行时切换后台 Provider |
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## 六、宿主工具函数
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
import {
|
|
462
|
+
createLlmProvider,
|
|
463
|
+
createProviderFromConfig,
|
|
464
|
+
loadConfig,
|
|
465
|
+
InMemoryStorage,
|
|
466
|
+
InMemoryRelationStore,
|
|
467
|
+
JsonVectorStore,
|
|
468
|
+
EmbeddingProvider,
|
|
469
|
+
setLogger,
|
|
470
|
+
logger,
|
|
471
|
+
segmentText,
|
|
472
|
+
parseFrontmatter,
|
|
473
|
+
serializeFrontmatter,
|
|
474
|
+
safeSetTimeout,
|
|
475
|
+
safeSetInterval,
|
|
476
|
+
clearSafeTimeout,
|
|
477
|
+
clearSafeInterval,
|
|
478
|
+
recall,
|
|
479
|
+
extractKeywords,
|
|
480
|
+
SOURCE_LABELS,
|
|
481
|
+
RELATION_TYPES,
|
|
482
|
+
RELATION_WEIGHTS,
|
|
483
|
+
inferSource,
|
|
484
|
+
escapeLike,
|
|
485
|
+
validateSource,
|
|
486
|
+
MemoraError,
|
|
487
|
+
toError,
|
|
488
|
+
NOOP_TRACER,
|
|
489
|
+
TRACE_SPANS,
|
|
490
|
+
ToolErrorCode,
|
|
491
|
+
isRetryableErrorCode,
|
|
492
|
+
TypedEventEmitter,
|
|
493
|
+
collectAgentChunks,
|
|
494
|
+
evaluateResult,
|
|
495
|
+
} from '@zooique/memora';
|
|
496
|
+
import type {
|
|
497
|
+
ProviderConfig,
|
|
498
|
+
Config,
|
|
499
|
+
IMemoryStorage,
|
|
500
|
+
IMemoryRelationStore,
|
|
501
|
+
MemoryRelation,
|
|
502
|
+
RelationDirection,
|
|
503
|
+
ILogger,
|
|
504
|
+
ISessionStore,
|
|
505
|
+
SessionMessage,
|
|
506
|
+
Memory,
|
|
507
|
+
SourceValidationSeverity,
|
|
508
|
+
LlmProvider,
|
|
509
|
+
LlmChunk,
|
|
510
|
+
ChatOptions,
|
|
511
|
+
AgentChunk,
|
|
512
|
+
ThinkingPhase,
|
|
513
|
+
UIMessages,
|
|
514
|
+
ArchiveMode,
|
|
515
|
+
AgentOptions,
|
|
516
|
+
AgentContext,
|
|
517
|
+
AgentProjectEntry,
|
|
518
|
+
AgentForkResult,
|
|
519
|
+
ToolDefinition,
|
|
520
|
+
ToolHandler,
|
|
521
|
+
ToolContext,
|
|
522
|
+
WriteExtensions,
|
|
523
|
+
MemoryKeywords,
|
|
524
|
+
MemorySnapshot,
|
|
525
|
+
WorkingMemorySnapshot,
|
|
526
|
+
BootstrapSnapshot,
|
|
527
|
+
ArchiveSnapshot,
|
|
528
|
+
AgentSearchHit,
|
|
529
|
+
AgentStats,
|
|
530
|
+
SuggestOptions,
|
|
531
|
+
SuggestHit,
|
|
532
|
+
SourceHealthStatus,
|
|
533
|
+
SourceHealthEntry,
|
|
534
|
+
SourceHealthReport,
|
|
535
|
+
ConfigSuggestion,
|
|
536
|
+
ConfigSuggestionHandler,
|
|
537
|
+
AutoConfigRefinerOptions,
|
|
538
|
+
SessionArchiveResult,
|
|
539
|
+
WorkProjectionEntry,
|
|
540
|
+
UserProfileEntry,
|
|
541
|
+
ProfileCategory,
|
|
542
|
+
ExtractedFact,
|
|
543
|
+
PersonaMode,
|
|
544
|
+
Persona,
|
|
545
|
+
SkillEntry,
|
|
546
|
+
SkillMatch,
|
|
547
|
+
RecallOptions,
|
|
548
|
+
EmbeddingService,
|
|
549
|
+
EmbeddingConfig,
|
|
550
|
+
EmbeddingResult,
|
|
551
|
+
AgentEventMap,
|
|
552
|
+
AgentEventName,
|
|
553
|
+
AgentEventHandler,
|
|
554
|
+
ForkResult,
|
|
555
|
+
ITracer,
|
|
556
|
+
ISpan,
|
|
557
|
+
AgentMetrics,
|
|
558
|
+
ToolErrorCodeValue,
|
|
559
|
+
EvalScenario,
|
|
560
|
+
EvalExpectation,
|
|
561
|
+
EvalResult,
|
|
562
|
+
AuditEvent,
|
|
563
|
+
AuditListener,
|
|
564
|
+
Permission,
|
|
565
|
+
WriteDecision,
|
|
566
|
+
WriteConfirmationInfo,
|
|
567
|
+
WriteConfirmationRequest,
|
|
568
|
+
OpenAICompatibleProvider,
|
|
569
|
+
OpenAICompatibleConfig,
|
|
570
|
+
} from '@zooique/memora';
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
| 函数/类型 | 用途 |
|
|
574
|
+
|-----------|------|
|
|
575
|
+
| `createLlmProvider(config)` | 从扁平配置创建 LlmProvider 实例 |
|
|
576
|
+
| `createProviderFromConfig(name, config)` | 从命名配置创建 LlmProvider 实例 |
|
|
577
|
+
| `loadConfig(path?)` | 加载 memora.json 配置文件 |
|
|
578
|
+
| `InMemoryStorage` | IMemoryStorage 的纯内存实现(测试用) |
|
|
579
|
+
| `InMemoryRelationStore` | IMemoryRelationStore 的纯内存实现(测试用) |
|
|
580
|
+
| `JsonVectorStore` | 向量存储内置实现(实现 IVectorStore 接口,宿主注入 EmbeddingService 后创建,启用语义搜索) |
|
|
581
|
+
| `EmbeddingProvider` | OpenAI 兼容 Embedding 端点实现(满足 EmbeddingService 接口) |
|
|
582
|
+
| `setLogger(logger)` | 替换全局日志实现 |
|
|
583
|
+
| `logger` | 全局日志实例 |
|
|
584
|
+
| `segmentText(text)` | 中文分词工具 |
|
|
585
|
+
| `parseFrontmatter(text)` | 解析 Markdown frontmatter |
|
|
586
|
+
| `serializeFrontmatter(fm, body)` | 序列化 frontmatter + body 为 Markdown |
|
|
587
|
+
| `safeSetTimeout(fn, ms)` | 安全定时器(可跟踪清理) |
|
|
588
|
+
| `safeSetInterval(fn, ms)` | 安全间隔器(可跟踪清理) |
|
|
589
|
+
| `clearSafeTimeout(id)` | 清除安全定时器 |
|
|
590
|
+
| `clearSafeInterval(id)` | 清除安全间隔器 |
|
|
591
|
+
| `recall(storage, query, options?)` | 记忆召回(async,双通道:语义 + 关键词) |
|
|
592
|
+
| `extractKeywords(text)` | 提取关键词 |
|
|
593
|
+
| `SOURCE_LABELS` | source 标签常量(PERSONA / RULE / SKILL / INSIGHT / PROFILE / WORK_PROJECTION / GUARDRAIL) |
|
|
594
|
+
| `RELATION_TYPES` | 记忆关系类型常量(CONTRADICTS / SUPPORTS / FOLLOWS / REFINES / CAUSED / RELATED) |
|
|
595
|
+
| `RELATION_WEIGHTS` | 关系强度常量(NONE / WEAK / UNDEFINED / STRONG / CERTAIN) |
|
|
596
|
+
| `inferSource(content)` | 从内容推断 source 标签 |
|
|
597
|
+
| `escapeLike(query)` | 转义 SQLite LIKE 通配符 |
|
|
598
|
+
| `validateSource(source)` | 校验 source 标签是否为已知标签(返回 warning,不阻止写入) |
|
|
599
|
+
| `MemoraError` | 统一错误类型(结构化错误码 + 上下文) |
|
|
600
|
+
| `toError(err)` | 将任意值转为 Error(浏览器端安全,不引入 pino) |
|
|
601
|
+
| `NOOP_TRACER` | ITracer 的空实现(静默丢弃所有 span,零开销) |
|
|
602
|
+
| `TRACE_SPANS` | AgentLoop 预定义 Span 名称常量(RECALL / LLM_CALL / TOOL_EXEC / RESPONSE) |
|
|
603
|
+
| `ToolErrorCode` | 工具错误码枚举(10 种,含 PATH_NOT_ALLOWED / FILE_NOT_FOUND 等) |
|
|
604
|
+
| `isRetryableErrorCode(code)` | 判断错误码是否可重试(5 种 retryable) |
|
|
605
|
+
| `TypedEventEmitter` | 类型安全的事件发射器(Agent 继承此类) |
|
|
606
|
+
| `collectAgentChunks(gen)` | 从 AgentChunk 流收集行为数据(Mock Eval 用) |
|
|
607
|
+
| `evaluateResult(name, collected, expected)` | 比对期望与结果(Mock Eval 用) |
|
|
608
|
+
|
|
609
|
+
**注意**:`SqliteStorage` 已移出到宿主项目,不再从 memora 导出。宿主需自行实现 `IMemoryStorage` 接口。
|
|
610
|
+
|
|
611
|
+
`IMemoryStorage` 接口要求实现 `count()` 和 `countBySource(source)` 方法,用于高效统计记忆数量(避免全量加载数据)。详见 [API 参考手册](./memora-api-reference.md)。
|
|
612
|
+
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
## 七、可观测性接入(ITracer)
|
|
616
|
+
|
|
617
|
+
Memora 内置了轻量的 Span/Trace 抽象,宿主可注入 OpenTelemetry 等实现来观测 AgentLoop 行为。
|
|
618
|
+
|
|
619
|
+
### 接口定义
|
|
620
|
+
|
|
621
|
+
```typescript
|
|
622
|
+
interface ITracer {
|
|
623
|
+
startSpan(name: string, attributes?: Record<string, string | number | boolean>): ISpan;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
interface ISpan {
|
|
627
|
+
setAttribute(key: string, value: string | number | boolean): void;
|
|
628
|
+
end(): void;
|
|
629
|
+
recordException(error: Error): void;
|
|
630
|
+
}
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### AgentLoop 预定义 Span
|
|
634
|
+
|
|
635
|
+
| Span 名称 | 常量 | 触发时机 | 关键属性 |
|
|
636
|
+
|-----------|------|---------|---------|
|
|
637
|
+
| `recall.recall` | `TRACE_SPANS.RECALL` | 记忆召回阶段 | `recallCount` |
|
|
638
|
+
| `llm.call` | `TRACE_SPANS.LLM_CALL` | LLM API 调用 | `model`, `messageCount`, `iteration` |
|
|
639
|
+
| `tool.execute` | `TRACE_SPANS.TOOL_EXEC` | 工具执行 | `toolName` |
|
|
640
|
+
| `response.generate` | `TRACE_SPANS.RESPONSE` | 整轮响应 | `inputLength` |
|
|
641
|
+
|
|
642
|
+
### 宿主接入示例(OpenTelemetry)
|
|
643
|
+
|
|
644
|
+
```typescript
|
|
645
|
+
import { trace } from '@opentelemetry/api';
|
|
646
|
+
import type { ITracer, ISpan } from '@zooique/memora';
|
|
647
|
+
|
|
648
|
+
// 宿主实现 ITracer 接口(桥接 OpenTelemetry)
|
|
649
|
+
class OtelTracer implements ITracer {
|
|
650
|
+
private tracer = trace.getTracer('memora-agent');
|
|
651
|
+
|
|
652
|
+
startSpan(name: string, attributes?: Record<string, string | number | boolean>): ISpan {
|
|
653
|
+
const otelSpan = this.tracer.startSpan(name, { attributes });
|
|
654
|
+
return {
|
|
655
|
+
setAttribute: (key, value) => otelSpan.setAttribute(key, value),
|
|
656
|
+
end: () => otelSpan.end(),
|
|
657
|
+
recordException: (error) => otelSpan.recordException(error),
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// 注入到 Agent
|
|
663
|
+
const agent = new Agent({
|
|
664
|
+
// ...其他配置
|
|
665
|
+
tracer: new OtelTracer(),
|
|
666
|
+
});
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
> **不注入时**:默认使用 `NOOP_TRACER`(静默丢弃所有 span,零运行时开销)。
|
|
670
|
+
|
|
671
|
+
---
|
|
672
|
+
|
|
673
|
+
## 八、内容护栏(Guardrails)
|
|
674
|
+
|
|
675
|
+
Memora 支持基于正则的内容护栏,在对话输入和 LLM 输出阶段分别检查,防止恶意输入和敏感信息泄露。
|
|
676
|
+
|
|
677
|
+
### 护栏规则格式
|
|
678
|
+
|
|
679
|
+
护栏规则以 `source: "guardrail"` 记忆形式存储,放在 `configDir/rules/guardrails/` 目录下:
|
|
680
|
+
|
|
681
|
+
```markdown
|
|
682
|
+
---
|
|
683
|
+
name: 禁止执行代码
|
|
684
|
+
source: guardrail
|
|
685
|
+
---
|
|
686
|
+
|
|
687
|
+
pattern: /执行|运行|eval|exec/
|
|
688
|
+
action: block
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
- `pattern`:正则表达式(可选加 `/` 定界符)
|
|
692
|
+
- `action`:`block`(阻断对话)或 `warn`(仅警告)
|
|
693
|
+
|
|
694
|
+
### 护栏行为
|
|
695
|
+
|
|
696
|
+
| 阶段 | 命中 block | 命中 warn | 规则异常 |
|
|
697
|
+
|------|-----------|----------|---------|
|
|
698
|
+
| 输入 | 阻断对话,返回阻止消息 | 追加警告文本,继续对话 | 降级放行 + 记日志 |
|
|
699
|
+
| 输出 | 阻断输出,返回阻止消息 | 追加警告文本,继续输出 | 降级放行 + 记日志 |
|
|
700
|
+
|
|
701
|
+
> **降级优先**:护栏自身异常(如正则编译失败)永远不阻断用户对话。
|
|
702
|
+
|
|
703
|
+
### 工具错误反思(Reflection)
|
|
704
|
+
|
|
705
|
+
当工具执行失败时,错误结果包含 `[ERR:TOOL:code]` 前缀。如果错误码标记为 retryable(如 `FILE_NOT_FOUND`、`ARGUMENT_ERROR`),AgentLoop 会自动注入 `[REFLECTION_HINT]` 系统消息,引导 LLM 修正参数后重试。
|
|
706
|
+
|
|
707
|
+
```typescript
|
|
708
|
+
import { ToolErrorCode, isRetryableErrorCode } from '@zooique/memora';
|
|
709
|
+
|
|
710
|
+
// 判断错误码是否可重试
|
|
711
|
+
isRetryableErrorCode(ToolErrorCode.FILE_NOT_FOUND); // true
|
|
712
|
+
isRetryableErrorCode(ToolErrorCode.PATH_NOT_ALLOWED); // false
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
Reflection 默认最多重试 2 次(`maxReflectionRetries`),防止无限循环。
|
|
716
|
+
|
|
717
|
+
---
|
|
718
|
+
|
|
719
|
+
## 九、评估体系(Eval)
|
|
720
|
+
|
|
721
|
+
Memora 提供了 Mock Eval 框架,用于 Agent 行为回归测试(不发起真实 LLM 调用)。
|
|
722
|
+
|
|
723
|
+
### 类型定义
|
|
724
|
+
|
|
725
|
+
```typescript
|
|
726
|
+
import type { EvalScenario, EvalExpectation, EvalResult } from '@zooique/memora';
|
|
727
|
+
// Eval 类型已从 memora 主包导出,宿主项目可直接 import
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### 评估场景示例
|
|
731
|
+
|
|
732
|
+
```typescript
|
|
733
|
+
const scenario: EvalScenario = {
|
|
734
|
+
name: '只读查询不应调用 write_file',
|
|
735
|
+
description: '用户只查询信息时,Agent 不应写入文件',
|
|
736
|
+
input: '帮我看看第一章写了什么',
|
|
737
|
+
expect: {
|
|
738
|
+
toolsCalled: ['read_file'], // 期望调用 read_file
|
|
739
|
+
toolsNotCalled: ['write_file'], // 不应调用 write_file
|
|
740
|
+
},
|
|
741
|
+
};
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
### 评估工具函数
|
|
745
|
+
|
|
746
|
+
```typescript
|
|
747
|
+
import { collectAgentChunks, evaluateResult } from '@zooique/memora';
|
|
748
|
+
|
|
749
|
+
// 从 AgentChunk 流中收集行为数据
|
|
750
|
+
const collected = await collectAgentChunks(agent.chat('帮我看看第一章'));
|
|
751
|
+
|
|
752
|
+
// 比对期望
|
|
753
|
+
const result = evaluateResult(scenario.name, collected, scenario.expect);
|
|
754
|
+
console.log(result.passed ? '✅ 通过' : `❌ 失败: ${result.failures.join('; ')}`);
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
### 两种评估层次
|
|
758
|
+
|
|
759
|
+
| 层次 | 工具 | LLM 调用 | 用途 |
|
|
760
|
+
|------|------|---------|------|
|
|
761
|
+
| Mock Eval | `collectAgentChunks` + `evaluateResult` | 不调用(MSW Mock) | 行为回归(工具调用、护栏、召回) |
|
|
762
|
+
| 真实 LLM Eval | 宿主自建 | 真实调用 | 回复质量、指令遵循度 |
|
|
763
|
+
|
|
764
|
+
> Mock Eval 在 CI 中运行,真实 LLM Eval 由宿主项目手动触发。
|
|
765
|
+
|
|
766
|
+
---
|
|
767
|
+
|
|
768
|
+
## 十、多步骤编排
|
|
769
|
+
|
|
770
|
+
Memora 是单 Agent 模型(ADR-011),不内置多 Agent 编排。宿主项目可通过多次调用 `agent.chat()` 实现复杂工作流:
|
|
771
|
+
|
|
772
|
+
```typescript
|
|
773
|
+
// 示例:分析项目 → 生成大纲 → 逐章写作
|
|
774
|
+
const analysis = await agent.chatSync('分析这个项目的风格和主题');
|
|
775
|
+
const outline = await agent.chatSync('基于分析结果,生成章节大纲');
|
|
776
|
+
for (const chapter of chapters) {
|
|
777
|
+
const content = await agent.chatSync(`根据大纲,写第${chapter.num}章:${chapter.title}`);
|
|
778
|
+
// 写入文件...
|
|
779
|
+
}
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
**编排要点**:
|
|
783
|
+
- 每次 `chat()` 共享同一个 AgentLoop 上下文(记忆、角色、技能)
|
|
784
|
+
- 宿主负责流程控制(条件分支、并行、错误处理)
|
|
785
|
+
- 如需隔离上下文,使用 `agent.switchSession()` 或 `agent.forkSession()`
|
|
786
|
+
|
|
787
|
+
---
|
|
788
|
+
|
|
789
|
+
## 十一、关键约束
|
|
790
|
+
|
|
791
|
+
1. **`provider` 是必填项** — Agent 无法独立运行
|
|
792
|
+
2. **configDir** 指向 Agent 级配置目录,所有子项目共享
|
|
793
|
+
3. **项目级 `.memora/`** 只放 `rules/`、`skills/` 和 `guardrails/`
|
|
794
|
+
4. **角色由关键词自动触发**
|
|
795
|
+
5. **对话历史跨子项目持久化**
|
|
796
|
+
6. **Manager 访问器在 `init()` 前返回 `null`** — 所有 `agent.config.xxx()` / `agent.memory.xxx()` 等调用必须在 `init()` 之后
|
|
797
|
+
7. **作品原始内容不进 SQLite**,Agent 通过工具按需读取
|
|
798
|
+
8. **配置文件是真理源**,`agent-config/` 下的配置由 MemoryLoader 启动时扫描加载
|
|
799
|
+
9. **禁止**为每个子项目创建独立的 memora.db
|
|
800
|
+
10. **禁止**项目切换时关闭/重建数据库
|
|
801
|
+
11. **禁止**将配置直接写入 SQLite 作为持久化存储
|
|
802
|
+
12. **项目切换** `switchProject()` 已自动 rebuild,通常无需手动调用 `rebuildComponents()`
|
|
803
|
+
13. **护栏规则**以 `source: "guardrail"` 记忆形式存储,不创建独立子系统
|
|
804
|
+
14. **Tracer 未注入时**自动降级为 NoopTracer,零运行时开销
|
|
805
|
+
|
|
806
|
+
---
|
|
807
|
+
|
|
808
|
+
> 更多细节参见 [memora-api-reference.md](./memora-api-reference.md)(完整 API 参考)
|