@zooique/memora 3.0.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +161 -1033
- package/README.en.md +46 -39
- package/README.md +40 -35
- package/config.example.json +1 -8
- package/dist/agent/agent.d.ts +88 -80
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +272 -221
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/assembler.d.ts +22 -21
- package/dist/agent/assembler.d.ts.map +1 -1
- package/dist/agent/assembler.js +120 -46
- package/dist/agent/assembler.js.map +1 -1
- package/dist/agent/backgroundTasks.d.ts +194 -0
- package/dist/agent/backgroundTasks.d.ts.map +1 -0
- package/dist/agent/backgroundTasks.js +314 -0
- package/dist/agent/backgroundTasks.js.map +1 -0
- package/dist/agent/budget.d.ts +23 -5
- package/dist/agent/budget.d.ts.map +1 -1
- package/dist/agent/budget.js +8 -2
- package/dist/agent/budget.js.map +1 -1
- package/dist/agent/builtinToolHandlers.d.ts +29 -9
- package/dist/agent/builtinToolHandlers.d.ts.map +1 -1
- package/dist/agent/builtinToolHandlers.js +53 -13
- package/dist/agent/builtinToolHandlers.js.map +1 -1
- package/dist/agent/builtinTools.d.ts +15 -1
- package/dist/agent/builtinTools.d.ts.map +1 -1
- package/dist/agent/builtinTools.js +111 -30
- package/dist/agent/builtinTools.js.map +1 -1
- package/dist/agent/constants.d.ts +31 -6
- package/dist/agent/constants.d.ts.map +1 -1
- package/dist/agent/constants.js +38 -8
- 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 +45 -3
- package/dist/agent/contextManager.js.map +1 -1
- package/dist/agent/contextPreparer.d.ts +1 -1
- package/dist/agent/contextPreparer.d.ts.map +1 -1
- package/dist/agent/contextPreparer.js +15 -10
- package/dist/agent/contextPreparer.js.map +1 -1
- package/dist/agent/guardRail.d.ts +12 -1
- package/dist/agent/guardRail.d.ts.map +1 -1
- package/dist/agent/guardRail.js +37 -2
- package/dist/agent/guardRail.js.map +1 -1
- package/dist/agent/loop.d.ts +319 -34
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +713 -110
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/managers/archiveCoordinator.d.ts +19 -4
- package/dist/agent/managers/archiveCoordinator.d.ts.map +1 -1
- package/dist/agent/managers/archiveCoordinator.js +25 -4
- package/dist/agent/managers/archiveCoordinator.js.map +1 -1
- package/dist/agent/managers/chatLockManager.d.ts +3 -9
- package/dist/agent/managers/chatLockManager.d.ts.map +1 -1
- package/dist/agent/managers/chatLockManager.js +7 -25
- package/dist/agent/managers/chatLockManager.js.map +1 -1
- package/dist/agent/managers/llmCaller.d.ts.map +1 -1
- package/dist/agent/managers/llmCaller.js +27 -1
- package/dist/agent/managers/llmCaller.js.map +1 -1
- package/dist/agent/managers/loopMetrics.d.ts +14 -0
- package/dist/agent/managers/loopMetrics.d.ts.map +1 -1
- package/dist/agent/managers/loopMetrics.js +15 -0
- package/dist/agent/managers/loopMetrics.js.map +1 -1
- package/dist/agent/managers/memoryInspector.d.ts +13 -15
- package/dist/agent/managers/memoryInspector.d.ts.map +1 -1
- package/dist/agent/managers/memoryInspector.js +38 -49
- package/dist/agent/managers/memoryInspector.js.map +1 -1
- package/dist/agent/managers/roundSummaryGenerator.d.ts +31 -1
- package/dist/agent/managers/roundSummaryGenerator.d.ts.map +1 -1
- package/dist/agent/managers/roundSummaryGenerator.js +81 -6
- package/dist/agent/managers/roundSummaryGenerator.js.map +1 -1
- package/dist/agent/managers/sessionArchiver.d.ts +35 -3
- package/dist/agent/managers/sessionArchiver.d.ts.map +1 -1
- package/dist/agent/managers/sessionArchiver.js +34 -3
- package/dist/agent/managers/sessionArchiver.js.map +1 -1
- package/dist/agent/managers/sessionManager.d.ts +21 -88
- package/dist/agent/managers/sessionManager.d.ts.map +1 -1
- package/dist/agent/managers/sessionManager.js +94 -278
- package/dist/agent/managers/sessionManager.js.map +1 -1
- package/dist/agent/managers/toolCallHelpers.d.ts +109 -28
- package/dist/agent/managers/toolCallHelpers.d.ts.map +1 -1
- package/dist/agent/managers/toolCallHelpers.js +93 -37
- package/dist/agent/managers/toolCallHelpers.js.map +1 -1
- package/dist/agent/messageHistory.d.ts.map +1 -1
- package/dist/agent/messageHistory.js +9 -5
- package/dist/agent/messageHistory.js.map +1 -1
- package/dist/agent/seed/orchestrator.d.ts +12 -1
- package/dist/agent/seed/orchestrator.d.ts.map +1 -1
- package/dist/agent/seed/orchestrator.js +15 -4
- package/dist/agent/seed/orchestrator.js.map +1 -1
- package/dist/agent/seed/prepare.d.ts.map +1 -1
- package/dist/agent/seed/prepare.js +9 -4
- package/dist/agent/seed/prepare.js.map +1 -1
- package/dist/agent/seed/types.d.ts +11 -4
- package/dist/agent/seed/types.d.ts.map +1 -1
- package/dist/agent/seed/types.js +2 -2
- package/dist/agent/textSanitize.d.ts +36 -0
- package/dist/agent/textSanitize.d.ts.map +1 -0
- package/dist/agent/textSanitize.js +55 -0
- package/dist/agent/textSanitize.js.map +1 -0
- package/dist/agent/toolExecutor.d.ts +97 -26
- package/dist/agent/toolExecutor.d.ts.map +1 -1
- package/dist/agent/toolExecutor.js +444 -78
- package/dist/agent/toolExecutor.js.map +1 -1
- package/dist/agent/toolLedger.d.ts +93 -41
- package/dist/agent/toolLedger.d.ts.map +1 -1
- package/dist/agent/toolLedger.js +114 -42
- package/dist/agent/toolLedger.js.map +1 -1
- package/dist/agent/toolResultCache.js +1 -1
- package/dist/agent/toolResultOffload.d.ts +8 -0
- package/dist/agent/toolResultOffload.d.ts.map +1 -1
- package/dist/agent/toolResultOffload.js +10 -3
- package/dist/agent/toolResultOffload.js.map +1 -1
- package/dist/agent/toolRunner.d.ts +16 -7
- package/dist/agent/toolRunner.d.ts.map +1 -1
- package/dist/agent/toolRunner.js +74 -29
- package/dist/agent/toolRunner.js.map +1 -1
- package/dist/agent/tracer.d.ts +13 -1
- package/dist/agent/tracer.d.ts.map +1 -1
- package/dist/agent/types.d.ts +74 -30
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/code-exec/types.d.ts +9 -0
- package/dist/code-exec/types.d.ts.map +1 -1
- package/dist/index.d.ts +28 -41
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +65 -54
- package/dist/index.js.map +1 -1
- package/dist/logging/logger.d.ts +4 -1
- package/dist/logging/logger.d.ts.map +1 -1
- package/dist/logging/logger.js +5 -2
- package/dist/logging/logger.js.map +1 -1
- package/dist/memory/gcService.d.ts.map +1 -1
- package/dist/memory/gcService.js +3 -5
- package/dist/memory/gcService.js.map +1 -1
- package/dist/memory/inMemorySessionStore.d.ts +2 -2
- package/dist/memory/inMemorySessionStore.js +2 -2
- package/dist/memory/inMemoryStorage.d.ts +4 -3
- package/dist/memory/inMemoryStorage.d.ts.map +1 -1
- package/dist/memory/inMemoryStorage.js +2 -2
- package/dist/memory/inMemoryStorage.js.map +1 -1
- package/dist/memory/nodeSqliteStorage.d.ts +17 -0
- package/dist/memory/nodeSqliteStorage.d.ts.map +1 -0
- package/dist/memory/nodeSqliteStorage.js +393 -0
- package/dist/memory/nodeSqliteStorage.js.map +1 -0
- package/dist/memory/projectManager.d.ts +10 -20
- package/dist/memory/projectManager.d.ts.map +1 -1
- package/dist/memory/projectManager.js +27 -41
- package/dist/memory/projectManager.js.map +1 -1
- package/dist/memory/roundStore.d.ts +143 -82
- package/dist/memory/roundStore.d.ts.map +1 -1
- package/dist/memory/roundStore.js +4 -15
- package/dist/memory/roundStore.js.map +1 -1
- package/dist/memory/roundSummaryLookup.d.ts +26 -0
- package/dist/memory/roundSummaryLookup.d.ts.map +1 -0
- package/dist/memory/roundSummaryLookup.js +19 -0
- package/dist/memory/roundSummaryLookup.js.map +1 -0
- package/dist/memory/sessionStore.d.ts +19 -2
- package/dist/memory/sessionStore.d.ts.map +1 -1
- package/dist/memory/sessionStore.js.map +1 -1
- package/dist/memory/sourceValidation.d.ts +2 -13
- package/dist/memory/sourceValidation.d.ts.map +1 -1
- package/dist/memory/sourceValidation.js +5 -16
- package/dist/memory/sourceValidation.js.map +1 -1
- package/dist/memory/storageInterface.d.ts +26 -16
- package/dist/memory/storageInterface.d.ts.map +1 -1
- package/dist/memory/supersedeResolve.d.ts +39 -0
- package/dist/memory/supersedeResolve.d.ts.map +1 -0
- package/dist/memory/supersedeResolve.js +16 -0
- package/dist/memory/supersedeResolve.js.map +1 -0
- package/dist/memory/types.d.ts +10 -2
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/memory/types.js +6 -1
- package/dist/memory/types.js.map +1 -1
- package/dist/role-pack/rolePackManager.d.ts +74 -33
- package/dist/role-pack/rolePackManager.d.ts.map +1 -1
- package/dist/role-pack/rolePackManager.js +112 -53
- package/dist/role-pack/rolePackManager.js.map +1 -1
- package/dist/role-pack/strategyKeys.d.ts +44 -0
- package/dist/role-pack/strategyKeys.d.ts.map +1 -1
- package/dist/role-pack/strategyKeys.js +55 -0
- package/dist/role-pack/strategyKeys.js.map +1 -1
- package/dist/role-pack/strategyResolver.d.ts +6 -1
- package/dist/role-pack/strategyResolver.d.ts.map +1 -1
- package/dist/role-pack/strategyResolver.js +20 -2
- package/dist/role-pack/strategyResolver.js.map +1 -1
- package/dist/role-pack/types.d.ts +5 -1
- package/dist/role-pack/types.d.ts.map +1 -1
- package/dist/security/confirmEntries.d.ts +44 -0
- package/dist/security/confirmEntries.d.ts.map +1 -0
- package/dist/security/confirmEntries.js +59 -0
- package/dist/security/confirmEntries.js.map +1 -0
- package/dist/security/pathGuard.d.ts +42 -6
- package/dist/security/pathGuard.d.ts.map +1 -1
- package/dist/security/pathGuard.js +126 -5
- package/dist/security/pathGuard.js.map +1 -1
- package/dist/skill/skillScriptRunner.d.ts +147 -15
- package/dist/skill/skillScriptRunner.d.ts.map +1 -1
- package/dist/skill/skillScriptRunner.js +479 -68
- package/dist/skill/skillScriptRunner.js.map +1 -1
- package/dist/utils/backgroundTask.d.ts +56 -34
- package/dist/utils/backgroundTask.d.ts.map +1 -1
- package/dist/utils/backgroundTask.js +130 -99
- package/dist/utils/backgroundTask.js.map +1 -1
- package/dist/utils/configResourceManager.d.ts +6 -2
- package/dist/utils/configResourceManager.d.ts.map +1 -1
- package/dist/utils/configResourceManager.js +8 -2
- package/dist/utils/configResourceManager.js.map +1 -1
- package/dist/utils/errors.d.ts +12 -2
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +12 -2
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/eventEmitter.d.ts +76 -23
- package/dist/utils/eventEmitter.d.ts.map +1 -1
- package/dist/utils/eventEmitter.js +23 -3
- package/dist/utils/eventEmitter.js.map +1 -1
- package/dist/utils/time.d.ts +8 -5
- package/dist/utils/time.d.ts.map +1 -1
- package/dist/utils/time.js +8 -5
- package/dist/utils/time.js.map +1 -1
- package/dist/utils/toError.d.ts +1 -1
- package/dist/utils/toError.js +1 -1
- package/dist/web-fetch/loginWall.d.ts +39 -0
- package/dist/web-fetch/loginWall.d.ts.map +1 -0
- package/dist/web-fetch/loginWall.js +78 -0
- package/dist/web-fetch/loginWall.js.map +1 -0
- package/dist/web-fetch/types.d.ts +8 -0
- package/dist/web-fetch/types.d.ts.map +1 -1
- package/dist/web-fetch/webFetchProvider.d.ts.map +1 -1
- package/dist/web-fetch/webFetchProvider.js +3 -1
- package/dist/web-fetch/webFetchProvider.js.map +1 -1
- package/dist/web-search/fetchWebSearchProvider.js +28 -23
- package/dist/web-search/fetchWebSearchProvider.js.map +1 -1
- package/docs/architecture/role-pack-authoring-guide.md +3 -1
- package/docs/architecture/role-pack-spec.md +2 -1
- package/docs/memora-api-reference.md +1349 -1175
- package/docs/memora-/345/215/207/347/272/247/346/214/207/345/215/227-4.x-/345/210/260-5.0.0.md +385 -0
- package/docs/memora-/346/216/245/345/205/245/346/214/207/345/215/227.md +91 -52
- package/docs/role-pack-/345/274/200/346/224/276/351/224/256/346/214/207/345/215/227.md +148 -148
- package/package.json +9 -4
- package/role-packs/README.md +41 -40
- package/role-packs/memora/345/212/251/346/211/213/rules.md +4 -4
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/manifest.json +1 -0
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/persona.md +1 -1
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/rules.md +1 -0
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/emotion-wave.md +1 -1
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/foreshadow.md +1 -1
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/outline-expand.md +32 -5
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/project-init/scripts/init-novel-project.mjs +10 -6
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/story-bible.md +3 -1
- package/role-packs//347/231/275/350/257/235/346/226/271/346/241/210/350/256/276/350/256/241/345/270/210/manifest.json +1 -0
- package/dist/agent/managers/dedupManager.d.ts +0 -85
- package/dist/agent/managers/dedupManager.d.ts.map +0 -1
- package/dist/agent/managers/dedupManager.js +0 -248
- package/dist/agent/managers/dedupManager.js.map +0 -1
- package/dist/agent/managers/goalConsistencyChecker.d.ts +0 -42
- package/dist/agent/managers/goalConsistencyChecker.d.ts.map +0 -1
- package/dist/agent/managers/goalConsistencyChecker.js +0 -178
- package/dist/agent/managers/goalConsistencyChecker.js.map +0 -1
- package/dist/agent/managers/llmJudgeHelper.d.ts +0 -21
- package/dist/agent/managers/llmJudgeHelper.d.ts.map +0 -1
- package/dist/agent/managers/llmJudgeHelper.js +0 -32
- package/dist/agent/managers/llmJudgeHelper.js.map +0 -1
- package/dist/agent/managers/memoryAdvisor.d.ts +0 -105
- package/dist/agent/managers/memoryAdvisor.d.ts.map +0 -1
- package/dist/agent/managers/memoryAdvisor.js +0 -322
- package/dist/agent/managers/memoryAdvisor.js.map +0 -1
- package/dist/agent/managers/memoryGovernance.d.ts +0 -24
- package/dist/agent/managers/memoryGovernance.d.ts.map +0 -1
- package/dist/agent/managers/memoryGovernance.js +0 -46
- package/dist/agent/managers/memoryGovernance.js.map +0 -1
- package/dist/memory/governance.d.ts +0 -17
- package/dist/memory/governance.d.ts.map +0 -1
- package/dist/memory/governance.js +0 -17
- package/dist/memory/governance.js.map +0 -1
- package/dist/memory/projectRegistry.d.ts +0 -47
- package/dist/memory/projectRegistry.d.ts.map +0 -1
- package/dist/memory/projectRegistry.js +0 -151
- package/dist/memory/projectRegistry.js.map +0 -1
- package/dist/utils/recallDefaults.d.ts +0 -16
- package/dist/utils/recallDefaults.d.ts.map +0 -1
- package/dist/utils/recallDefaults.js +0 -16
- package/dist/utils/recallDefaults.js.map +0 -1
|
@@ -1,1175 +1,1349 @@
|
|
|
1
|
-
# Memora 内核 API 参考手册(
|
|
2
|
-
|
|
3
|
-
> **核心定位**:Memora 是一个**无法独立运行**的智能大脑内核——它只有接口,没有"形态"。CLI、WebUI、桌面精灵、小说生成器都是它的"宿主",宿主负责给它身体(UI)、血管(Provider)、神经网络(事件回路)。
|
|
4
|
-
>
|
|
5
|
-
> **本文件用途**:列出内核对外暴露的**全部公开接口**——从最基础的接入接口(〇),到 Agent 面类、对话、记忆、角色包、工具、各 Manager,再到类型导出与安全约束。
|
|
6
|
-
>
|
|
7
|
-
> **版本**:
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## 〇、接入基础接口
|
|
12
|
-
|
|
13
|
-
> **定位**:一个新宿主接入 memora 的**最小接入面**。其余各章是 `Agent` 初始化后暴露的运行时能力;本章回答"接入前必须提供什么"。
|
|
14
|
-
>
|
|
15
|
-
> **一句话总结**:必做三件事——① 实现 `IMemoryStorage` + `ISessionStore` + `LlmProvider`;② 准备 `configDir`(含 `config.json` 模型表 + `role-packs/` + `skills/`);③ 传 `projectPath` / `dataDir` / `configDir` 构造 `Agent`。其余接口按需注入,缺省都有降级兜底。
|
|
16
|
-
|
|
17
|
-
### 〇.1 宿主实现的接口(注入)
|
|
18
|
-
|
|
19
|
-
| 接口 | 必选 | 声明位置 | 用途 |
|
|
20
|
-
|------|------|---------|------|
|
|
21
|
-
| `LlmProvider` | ✅ 必选 | `src/llm/provider.ts` | 前台 LLM 流式对话(`stream()`),宿主创建 |
|
|
22
|
-
| `IMemoryStorage` | ✅ 必选* | `src/memory/storageInterface.ts` | 记忆持久化,15 方法,同步语义(对齐 better-sqlite3);**后端由宿主自选** |
|
|
23
|
-
| `ISessionStore` | ✅ 必选* | `src/memory/sessionStore.ts` | 会话消息持久化,3 必需 + 6 可选方法 |
|
|
24
|
-
| `ITracer` | 可选 | `src/agent/tracer.ts` | 可观测性,不传用 `NoopTracer` |
|
|
25
|
-
| `IWebSearchProvider` | 可选 | `src/web-search/types.ts` | 网络搜索,不注入则不启用 |
|
|
26
|
-
| `IFetchProvider` | 可选 | `src/web-fetch/types.ts` | 网页抓取(搜索→抓取闭环第二段),不注入则不启用 |
|
|
27
|
-
| `ICodeExecutionProvider` | 可选 | `src/code-exec/types.ts` | 通用代码执行(沙箱由宿主提供),不注入则不启用 |
|
|
28
|
-
| `IProjectSearchProvider` | 可选 | `src/project-search/types.ts` | 项目内搜索(等价 IDE 全局搜索),不注入则不暴露 `search_project`(见 §8.6) |
|
|
29
|
-
| `ILogger` | 可选 | `src/logging/loggerInterface.ts` | 日志,默认内置 |
|
|
30
|
-
| `backgroundProvider` (`LlmProvider`) | 可选 | AgentOptions | 后台通道(归档/投影),不配复用前台 |
|
|
31
|
-
|
|
32
|
-
\*
|
|
33
|
-
|
|
34
|
-
### 〇.2 宿主提供的配置资源(`configDir` 下)
|
|
35
|
-
|
|
36
|
-
`configDir` 是唯一的配置目录入口(含角色包 / 全局技能 / 配置文件):
|
|
37
|
-
|
|
38
|
-
```
|
|
39
|
-
configDir/
|
|
40
|
-
├── config.json ← ★ LLM 配置真理源:providers + active + background + taskRouter
|
|
41
|
-
├── role-packs/ ← 角色包目录(每个包一个文件夹,含 manifest.json)
|
|
42
|
-
│ └── 工程师/
|
|
43
|
-
│ ├── manifest.json ← 必填:元数据 + strategy + capabilities
|
|
44
|
-
│ ├── persona.md ← 约定名,可省(身份设定)
|
|
45
|
-
│ ├── rules.md ← 约定名,可省(安全契约)
|
|
46
|
-
│ └── skills/ ← 角色包内嵌技能(目录动态扫描,可选)
|
|
47
|
-
│ └── ... ← 形式与全局技能池一致(见下)
|
|
48
|
-
├── skills/ ← 全局技能池(所有角色共享,可选)
|
|
49
|
-
│ ├── search.md ← 单文件形式
|
|
50
|
-
│ └── code-review/ ← 文件夹形式(统一大众公认的 Agent Skills 格式)
|
|
51
|
-
│ ├── SKILL.md ← 技能正文(frontmatter 声明 name/description)
|
|
52
|
-
│ ├── resources/ ← L3 参考资源(参考材料/规范)
|
|
53
|
-
│ ├── scripts/ ← L3 可执行脚本(运行时按需执行)
|
|
54
|
-
│ ├── references/ ← 技能内参考资料
|
|
55
|
-
│ └── assets/ ← 技能内资源(模板/图片/示例)
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
> **skills 两种形式(两级技能共用统一格式)**:全局技能池(`configDir/skills/`)与角色包内嵌技能(`role-packs/<名>/skills/`)采用**同一套**技能格式,仅激活条件不同(全局始终激活,角色包技能随角色激活)。每个技能为单文件 `*.md` **或** 文件夹 `SKILL.md` 两种形式之一;`references/` / `assets/` 属于**技能内部**的资源目录(文件夹形式的组成部分),非 configDir 或角色包顶层目录。渐进披露:L1 元数据常驻 / L2 `read_skill` 按需读正文 / L3 `read_resource` + `run_skill_script`。
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
**config.json 大模型列表**(不是独立目录,是配置文件中的映射表):
|
|
62
|
-
|
|
63
|
-
```jsonc
|
|
64
|
-
{
|
|
65
|
-
"llm": {
|
|
66
|
-
"providers": { "deepseek": { "baseUrl": "...", "model": "...", "apiKey": "" },
|
|
67
|
-
"openai": { "baseUrl": "...", "model": "...", "apiKey": "" } },
|
|
68
|
-
"active": "deepseek", // 激活别名,不配取第一个 key
|
|
69
|
-
"background": { ... }, // 可选后台通道,节省成本
|
|
70
|
-
"taskRouter": { "simple": "deepseek", "reasoning": "openai" }
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
- API Key **不写文件**,从环境变量读取。
|
|
76
|
-
- memora 内核仅内置 `mock` Provider(无 API Key 的测试/降级),其余厂商需宿主在 config.json 显式配置。
|
|
77
|
-
|
|
78
|
-
### 〇.3 `dataDir` vs `storage` 的区别
|
|
79
|
-
|
|
80
|
-
两个易混淆的参数:**`storage` 管"如何存取"(接口实例),`dataDir` 管"存到哪个目录"(路径字符串)**。
|
|
81
|
-
|
|
82
|
-
| | `storage`(IMemoryStorage) | `dataDir` |
|
|
83
|
-
|---|---|---|
|
|
84
|
-
| 本质 | 接口实例(宿主写的类) | 文件系统目录路径(字符串) |
|
|
85
|
-
| 内核怎么用它 | 调方法:`upsert` / `getById` / `search` / `getAllSources`… |
|
|
86
|
-
| 管什么 | "怎么存取记忆"(逻辑),内核不关心内部是 SQLite 还是内存 | "记忆库与项目注册表放哪个目录"(物理位置) |
|
|
87
|
-
| 谁实现 | 宿主实现(如 SqliteMemoryStorage) | 宿主传路径 |
|
|
88
|
-
| 关系 | `dataDir` 指向目录;宿主按自己的持久化形态构造 storage(JSON 文件 / SQLite 皆可) | 内核用 `dataDir` 推导注册表路径;**项目锁文件不由 `dataDir` 推导**,它固定落 `<projectPath>/.memora/.lock` |
|
|
89
|
-
| 缺省 | 不传 →
|
|
90
|
-
|
|
91
|
-
一句话:`storage` 是宿主**怎么**存取的实现,`dataDir` 是存取内容**落在哪个目录**的配置——一个管"如何",一个管"何处"。
|
|
92
|
-
|
|
93
|
-
> **`config.json` 里的 `memory.dataDir` 内核不读**:它只是「宿主约定的载体」——宿主可自行从配置取出后传给
|
|
94
|
-
> `new Agent({ dataDir })`。内核不消费它,也没有任何默认值;`config.example.json` 里写 `~/.memora` 只是一个示例值,
|
|
95
|
-
> 不等于内核的缺省行为。
|
|
96
|
-
|
|
97
|
-
### 〇.4 多来源双路径编排(内置 + 用户)
|
|
98
|
-
|
|
99
|
-
内核**刻意保持"单 `configDir` 输入"**——`SkillManager`/`RolePackManager` 只扫 `<configDir>/skills/`、`<configDir>/role-packs/`,无"多来源"概念。宿主若想开放"内置(随插件打包)+ 用户自定义"双路径,由宿主在传入内核**之前**自行编排归一,两种形态:
|
|
100
|
-
|
|
101
|
-
| 形态 | 做法 | 适用 |
|
|
102
|
-
|------|------|------|
|
|
103
|
-
| **A. 宿主文件层汇总(推荐,零内核改动)** | 宿主在文件系统层把"内置目录 + 用户目录"合并/软链到**一个 `configDir`** 再传内核 | 角色包、全局技能均可;内容本质同构、希望同池匹配 |
|
|
104
|
-
| **B. 宿主多 Manager 实例聚合** | 宿主建多个 `RolePackManager(configDirA/B)` 各管一个来源,聚合 `listMeta()` 在 UI 层分组展示,激活仍逐个调用 | 来源语义需要区分(UI 分组、只读标记) |
|
|
105
|
-
|
|
106
|
-
选择依据:内容**不必区分来源**走 A(合并到同一 configDir);**必须区分来源**(只读/可编辑、分组)走 B(多实例聚合展示)。内核两种都支持。
|
|
107
|
-
|
|
108
|
-
### 〇.5 构造 `Agent` 的参数
|
|
109
|
-
|
|
110
|
-
```ts
|
|
111
|
-
new Agent({
|
|
112
|
-
projectPath, // ✅ 必选:工作区
|
|
113
|
-
provider, // ✅ 必选:前台 LLM
|
|
114
|
-
// 常用可选项
|
|
115
|
-
configDir, // 配置根目录(role-packs / skills;缺省用内置默认)
|
|
116
|
-
dataDir, // ✅ 必选:记忆数据落地目录(内核不提供默认值)
|
|
117
|
-
backgroundProvider, // 后台 LLM
|
|
118
|
-
storage, // IMemoryStorage
|
|
119
|
-
sessionStore, // ISessionStore 实现(缺省仅内存保存)
|
|
120
|
-
webSearchProvider, // 网络搜索
|
|
121
|
-
tracer, // 可观测
|
|
122
|
-
maxContextTokens, //
|
|
123
|
-
permission, allowedPaths, confirmWrites, // 安全
|
|
124
|
-
activeRolePack, // 启动激活的角色包
|
|
125
|
-
})
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## 一、设计哲学
|
|
131
|
-
|
|
132
|
-
```
|
|
133
|
-
┌────────────────────────────────────────────────────────────┐
|
|
134
|
-
│ 宿主程序(CLI / 桌面精灵 / 小说生成器 / WebUI) │
|
|
135
|
-
│ ┌─────────────────┐ ┌──────────────────┐ │
|
|
136
|
-
│ │ LLM Provider 实例 │◄───│ API Key / baseUrl │ ← 宿主职责 │
|
|
137
|
-
│ └────────┬────────┘ └──────────────────┘ │
|
|
138
|
-
│ │ 注入 │
|
|
139
|
-
│ ▼ │
|
|
140
|
-
│ ┌──────────────────────────────────────────┐ │
|
|
141
|
-
│ │ Memora 内核(Agent) │ │
|
|
142
|
-
│ │ ┌──────────────────────────────────────┐│ │
|
|
143
|
-
│ │ │ Agent 面类(编排层) ││ │
|
|
144
|
-
│ │ │ - init/close · chat ·
|
|
145
|
-
│ │ │ - .rolePack / .tools / .skills ││ │
|
|
146
|
-
│ │ │ - .
|
|
147
|
-
│ │ └──────────┬───────────────────────────┘│ │
|
|
148
|
-
│ │ │ 委托 │ │
|
|
149
|
-
│ │ ┌──────────┼───────────────────────────┐│ │
|
|
150
|
-
│ │ │ RolePackManager / SkillManager ││ │
|
|
151
|
-
│ │ │ ToolExecutor / MemoryInspector ││ │
|
|
152
|
-
│ │
|
|
153
|
-
│ │
|
|
154
|
-
│
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
-
|
|
161
|
-
-
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
| `
|
|
175
|
-
| `
|
|
176
|
-
| `
|
|
177
|
-
| `
|
|
178
|
-
| `
|
|
179
|
-
| `
|
|
180
|
-
| `
|
|
181
|
-
| `
|
|
182
|
-
| `activeRolePack` | `string` | ❌ | 启动激活的角色包名(缺失/不存在回退默认激活首个) |
|
|
183
|
-
| `
|
|
184
|
-
| `
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
187
|
-
|
|
|
188
|
-
|
|
|
189
|
-
| `
|
|
190
|
-
|
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
193
|
-
| `
|
|
194
|
-
| `
|
|
195
|
-
| `
|
|
196
|
-
| `
|
|
197
|
-
| `
|
|
198
|
-
| `
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
| `
|
|
215
|
-
| `
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
|
249
|
-
|
|
250
|
-
| `
|
|
251
|
-
| `
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
agent.memory
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
### 4.
|
|
387
|
-
|
|
388
|
-
```typescript
|
|
389
|
-
agent.
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
//
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
> `
|
|
506
|
-
|
|
507
|
-
###
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
|
619
|
-
|
|
620
|
-
| `
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
//
|
|
635
|
-
agent.
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
>
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
//
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
### 8.
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
//
|
|
775
|
-
interface
|
|
776
|
-
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
//
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
//
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
###
|
|
917
|
-
|
|
918
|
-
`
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
>
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
|
999
|
-
|
|
1000
|
-
| `
|
|
1001
|
-
| `
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
//
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
//
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1
|
+
# Memora 内核 API 参考手册(v5.0.0)
|
|
2
|
+
|
|
3
|
+
> **核心定位**:Memora 是一个**无法独立运行**的智能大脑内核——它只有接口,没有"形态"。CLI、WebUI、桌面精灵、小说生成器都是它的"宿主",宿主负责给它身体(UI)、血管(Provider)、神经网络(事件回路)。
|
|
4
|
+
>
|
|
5
|
+
> **本文件用途**:列出内核对外暴露的**全部公开接口**——从最基础的接入接口(〇),到 Agent 面类、对话、记忆、角色包、工具、各 Manager,再到类型导出与安全约束。
|
|
6
|
+
>
|
|
7
|
+
> **版本**:v5.0.0(对齐当前内核包版本 `package.json`;npm 已发布最新为 v4.0.0、v5.0.0 待发布。纯净接口文档,不含历史变更流水)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 〇、接入基础接口
|
|
12
|
+
|
|
13
|
+
> **定位**:一个新宿主接入 memora 的**最小接入面**。其余各章是 `Agent` 初始化后暴露的运行时能力;本章回答"接入前必须提供什么"。
|
|
14
|
+
>
|
|
15
|
+
> **一句话总结**:必做三件事——① 实现 `IMemoryStorage` + `ISessionStore` + `LlmProvider`;② 准备 `configDir`(含 `config.json` 模型表 + `role-packs/` + `skills/`);③ 传 `projectPath` / `dataDir` / `configDir` 构造 `Agent`。其余接口按需注入,缺省都有降级兜底。
|
|
16
|
+
|
|
17
|
+
### 〇.1 宿主实现的接口(注入)
|
|
18
|
+
|
|
19
|
+
| 接口 | 必选 | 声明位置 | 用途 |
|
|
20
|
+
|------|------|---------|------|
|
|
21
|
+
| `LlmProvider` | ✅ 必选 | `src/llm/provider.ts` | 前台 LLM 流式对话(`stream()`),宿主创建 |
|
|
22
|
+
| `IMemoryStorage` | ✅ 必选* | `src/memory/storageInterface.ts` | 记忆持久化,15 方法,同步语义(对齐 better-sqlite3);**后端由宿主自选** |
|
|
23
|
+
| `ISessionStore` | ✅ 必选* | `src/memory/sessionStore.ts` | 会话消息持久化,3 必需 + 6 可选方法 |
|
|
24
|
+
| `ITracer` | 可选 | `src/agent/tracer.ts` | 可观测性,不传用 `NoopTracer` |
|
|
25
|
+
| `IWebSearchProvider` | 可选 | `src/web-search/types.ts` | 网络搜索,不注入则不启用 |
|
|
26
|
+
| `IFetchProvider` | 可选 | `src/web-fetch/types.ts` | 网页抓取(搜索→抓取闭环第二段),不注入则不启用 |
|
|
27
|
+
| `ICodeExecutionProvider` | 可选 | `src/code-exec/types.ts` | 通用代码执行(沙箱由宿主提供),不注入则不启用 |
|
|
28
|
+
| `IProjectSearchProvider` | 可选 | `src/project-search/types.ts` | 项目内搜索(等价 IDE 全局搜索),不注入则不暴露 `search_project`(见 §8.6) |
|
|
29
|
+
| `ILogger` | 可选 | `src/logging/loggerInterface.ts` | 日志,默认内置 |
|
|
30
|
+
| `backgroundProvider` (`LlmProvider`) | 可选 | AgentOptions | 后台通道(归档/投影),不配复用前台 |
|
|
31
|
+
|
|
32
|
+
\* 不传则内核自动用内置内存实现 / 内存会话(仅内存不落盘;内存实现类为内部机制,不挂公共面——PUB-API-PRUNE-2 收面);做产品必须实现。
|
|
33
|
+
|
|
34
|
+
### 〇.2 宿主提供的配置资源(`configDir` 下)
|
|
35
|
+
|
|
36
|
+
`configDir` 是唯一的配置目录入口(含角色包 / 全局技能 / 配置文件):
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
configDir/
|
|
40
|
+
├── config.json ← ★ LLM 配置真理源:providers + active + background + taskRouter
|
|
41
|
+
├── role-packs/ ← 角色包目录(每个包一个文件夹,含 manifest.json)
|
|
42
|
+
│ └── 工程师/
|
|
43
|
+
│ ├── manifest.json ← 必填:元数据 + strategy + capabilities
|
|
44
|
+
│ ├── persona.md ← 约定名,可省(身份设定)
|
|
45
|
+
│ ├── rules.md ← 约定名,可省(安全契约)
|
|
46
|
+
│ └── skills/ ← 角色包内嵌技能(目录动态扫描,可选)
|
|
47
|
+
│ └── ... ← 形式与全局技能池一致(见下)
|
|
48
|
+
├── skills/ ← 全局技能池(所有角色共享,可选)
|
|
49
|
+
│ ├── search.md ← 单文件形式
|
|
50
|
+
│ └── code-review/ ← 文件夹形式(统一大众公认的 Agent Skills 格式)
|
|
51
|
+
│ ├── SKILL.md ← 技能正文(frontmatter 声明 name/description)
|
|
52
|
+
│ ├── resources/ ← L3 参考资源(参考材料/规范)
|
|
53
|
+
│ ├── scripts/ ← L3 可执行脚本(运行时按需执行)
|
|
54
|
+
│ ├── references/ ← 技能内参考资料
|
|
55
|
+
│ └── assets/ ← 技能内资源(模板/图片/示例)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
> **skills 两种形式(两级技能共用统一格式)**:全局技能池(`configDir/skills/`)与角色包内嵌技能(`role-packs/<名>/skills/`)采用**同一套**技能格式,仅激活条件不同(全局始终激活,角色包技能随角色激活)。每个技能为单文件 `*.md` **或** 文件夹 `SKILL.md` 两种形式之一;`references/` / `assets/` 属于**技能内部**的资源目录(文件夹形式的组成部分),非 configDir 或角色包顶层目录。渐进披露:L1 元数据常驻 / L2 `read_skill` 按需读正文 / L3 `read_resource` + `run_skill_script`。
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**config.json 大模型列表**(不是独立目录,是配置文件中的映射表):
|
|
62
|
+
|
|
63
|
+
```jsonc
|
|
64
|
+
{
|
|
65
|
+
"llm": {
|
|
66
|
+
"providers": { "deepseek": { "baseUrl": "...", "model": "...", "apiKey": "" },
|
|
67
|
+
"openai": { "baseUrl": "...", "model": "...", "apiKey": "" } },
|
|
68
|
+
"active": "deepseek", // 激活别名,不配取第一个 key
|
|
69
|
+
"background": { ... }, // 可选后台通道,节省成本
|
|
70
|
+
"taskRouter": { "simple": "deepseek", "reasoning": "openai" }
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- API Key **不写文件**,从环境变量读取。
|
|
76
|
+
- memora 内核仅内置 `mock` Provider(无 API Key 的测试/降级),其余厂商需宿主在 config.json 显式配置。
|
|
77
|
+
|
|
78
|
+
### 〇.3 `dataDir` vs `storage` 的区别
|
|
79
|
+
|
|
80
|
+
两个易混淆的参数:**`storage` 管"如何存取"(接口实例),`dataDir` 管"存到哪个目录"(路径字符串)**。
|
|
81
|
+
|
|
82
|
+
| | `storage`(IMemoryStorage) | `dataDir` |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| 本质 | 接口实例(宿主写的类) | 文件系统目录路径(字符串) |
|
|
85
|
+
| 内核怎么用它 | 调方法:`upsert` / `getById` / `search` / `getAllSources`… | 记忆库落哪、叫什么名,由宿主自定,内核不参与(`dataDir` 只是 Agent 级资源目录,内核不假设其下文件形态) |
|
|
86
|
+
| 管什么 | "怎么存取记忆"(逻辑),内核不关心内部是 SQLite 还是内存 | "记忆库与项目注册表放哪个目录"(物理位置) |
|
|
87
|
+
| 谁实现 | 宿主实现(如 SqliteMemoryStorage) | 宿主传路径 |
|
|
88
|
+
| 关系 | `dataDir` 指向目录;宿主按自己的持久化形态构造 storage(JSON 文件 / SQLite 皆可) | 内核用 `dataDir` 推导注册表路径;**项目锁文件不由 `dataDir` 推导**,它固定落 `<projectPath>/.memora/.lock` |
|
|
89
|
+
| 缺省 | 不传 → 内置内存实现(仅内存,不挂公共面) | **必填,无默认值**(目录位置与层级语义是宿主的产品决策,内核不假设) |
|
|
90
|
+
|
|
91
|
+
一句话:`storage` 是宿主**怎么**存取的实现,`dataDir` 是存取内容**落在哪个目录**的配置——一个管"如何",一个管"何处"。
|
|
92
|
+
|
|
93
|
+
> **`config.json` 里的 `memory.dataDir` 内核不读**:它只是「宿主约定的载体」——宿主可自行从配置取出后传给
|
|
94
|
+
> `new Agent({ dataDir })`。内核不消费它,也没有任何默认值;`config.example.json` 里写 `~/.memora` 只是一个示例值,
|
|
95
|
+
> 不等于内核的缺省行为。
|
|
96
|
+
|
|
97
|
+
### 〇.4 多来源双路径编排(内置 + 用户)
|
|
98
|
+
|
|
99
|
+
内核**刻意保持"单 `configDir` 输入"**——`SkillManager`/`RolePackManager` 只扫 `<configDir>/skills/`、`<configDir>/role-packs/`,无"多来源"概念。宿主若想开放"内置(随插件打包)+ 用户自定义"双路径,由宿主在传入内核**之前**自行编排归一,两种形态:
|
|
100
|
+
|
|
101
|
+
| 形态 | 做法 | 适用 |
|
|
102
|
+
|------|------|------|
|
|
103
|
+
| **A. 宿主文件层汇总(推荐,零内核改动)** | 宿主在文件系统层把"内置目录 + 用户目录"合并/软链到**一个 `configDir`** 再传内核 | 角色包、全局技能均可;内容本质同构、希望同池匹配 |
|
|
104
|
+
| **B. 宿主多 Manager 实例聚合** | 宿主建多个 `RolePackManager(configDirA/B)` 各管一个来源,聚合 `listMeta()` 在 UI 层分组展示,激活仍逐个调用 | 来源语义需要区分(UI 分组、只读标记) |
|
|
105
|
+
|
|
106
|
+
选择依据:内容**不必区分来源**走 A(合并到同一 configDir);**必须区分来源**(只读/可编辑、分组)走 B(多实例聚合展示)。内核两种都支持。
|
|
107
|
+
|
|
108
|
+
### 〇.5 构造 `Agent` 的参数
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
new Agent({
|
|
112
|
+
projectPath, // ✅ 必选:工作区
|
|
113
|
+
provider, // ✅ 必选:前台 LLM
|
|
114
|
+
// 常用可选项
|
|
115
|
+
configDir, // 配置根目录(role-packs / skills;缺省用内置默认)
|
|
116
|
+
dataDir, // ✅ 必选:记忆数据落地目录(内核不提供默认值)
|
|
117
|
+
backgroundProvider, // 后台 LLM
|
|
118
|
+
storage, // IMemoryStorage 实现(缺省内置内存实现,不挂公共面)
|
|
119
|
+
sessionStore, // ISessionStore 实现(缺省仅内存保存)
|
|
120
|
+
webSearchProvider, // 网络搜索
|
|
121
|
+
tracer, // 可观测
|
|
122
|
+
maxContextTokens, // 默认见 AGENT_CONSTANTS.DEFAULT_MAX_CONTEXT_TOKENS(数字以该常量为真源,此处不落账)
|
|
123
|
+
permission, allowedPaths, confirmWrites, // 安全
|
|
124
|
+
activeRolePack, // 启动激活的角色包
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 一、设计哲学
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
┌────────────────────────────────────────────────────────────┐
|
|
134
|
+
│ 宿主程序(CLI / 桌面精灵 / 小说生成器 / WebUI) │
|
|
135
|
+
│ ┌─────────────────┐ ┌──────────────────┐ │
|
|
136
|
+
│ │ LLM Provider 实例 │◄───│ API Key / baseUrl │ ← 宿主职责 │
|
|
137
|
+
│ └────────┬────────┘ └──────────────────┘ │
|
|
138
|
+
│ │ 注入 │
|
|
139
|
+
│ ▼ │
|
|
140
|
+
│ ┌──────────────────────────────────────────┐ │
|
|
141
|
+
│ │ Memora 内核(Agent) │ │
|
|
142
|
+
│ │ ┌──────────────────────────────────────┐│ │
|
|
143
|
+
│ │ │ Agent 面类(编排层) ││ │
|
|
144
|
+
│ │ │ - init/close · chat · forkSession ││ │
|
|
145
|
+
│ │ │ - .rolePack / .tools / .skills ││ │
|
|
146
|
+
│ │ │ - .memory / .works / .polish ││ │
|
|
147
|
+
│ │ └──────────┬───────────────────────────┘│ │
|
|
148
|
+
│ │ │ 委托 │ │
|
|
149
|
+
│ │ ┌──────────┼───────────────────────────┐│ │
|
|
150
|
+
│ │ │ RolePackManager / SkillManager ││ │
|
|
151
|
+
│ │ │ ToolExecutor / MemoryInspector ││ │
|
|
152
|
+
│ │ └──────────────────────────────────────┘│ │
|
|
153
|
+
│ │ ⚠️ 不包含:UI / LLM 配置 / 用户配置模板 │ │
|
|
154
|
+
│ └──────────────────────────────────────────┘ │
|
|
155
|
+
└────────────────────────────────────────────────────────────┘
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**设计原则**:
|
|
159
|
+
- **零运行时依赖**(核心层零 npm 运行时依赖、**零运行时模块解析**;日志默认内置 console fallback,宿主经 `setLogger()` 注入自定义实现;持久化由宿主通过 `IMemoryStorage` 接口注入)
|
|
160
|
+
- **内核模块不直接调用 `console.*`**(唯一日志出口是 `logging/` 单例 `logger`;默认实现为内置 console fallback,写 stderr)
|
|
161
|
+
- **零写用户文件**(配置文件是真理源,Agent 只读)
|
|
162
|
+
- **零 LLM 配置加载**(Agent 不知道 `apiKey`,宿主传入 `LlmProvider` 实例)
|
|
163
|
+
- **Manager 委托模式**:Agent 面类只做编排,领域操作委托给专职 Manager
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 二、构造与生命周期
|
|
168
|
+
|
|
169
|
+
### 2.1 构造选项 `AgentOptions`
|
|
170
|
+
|
|
171
|
+
| 字段 | 类型 | 必须 | 说明 |
|
|
172
|
+
|------|------|------|------|
|
|
173
|
+
| `projectPath` | `string` | ✅ | 项目路径(必须) |
|
|
174
|
+
| `provider` | `LlmProvider` | ✅ | 前台 LLM Provider(必须) |
|
|
175
|
+
| `backgroundProvider` | `LlmProvider` | ❌ | 后台 Provider(投影等后台操作) |
|
|
176
|
+
| `providerRouter` | `ProviderRouter` | ❌ | 按任务类型返回 Provider 的路由器(不配时全部使用同一 Provider,向后兼容) |
|
|
177
|
+
| `configDir` | `string` | ❌ | 配置目录(role-packs / skills,设定记忆唯一归角色包) |
|
|
178
|
+
| `dataDir` | `string` | ✅ | 记忆数据目录(必填,内核不提供默认值;传项目级还是用户级目录由宿主决定) |
|
|
179
|
+
| `maxContextTokens` | `number` | ❌ | 上下文窗口上限(缺省 = 内核 `AGENT_CONSTANTS.DEFAULT_MAX_CONTEXT_TOKENS`,数字以该常量为真源,此处不落账) |
|
|
180
|
+
| `maxTokens` | `number` | ❌ | per-LLM 输出预算(token;宿主配置面板「输出上限」透传,undefined = 回服务端默认)。与角色包策略 `act.outputLimit` **取更小值**,`buildChatOptions` 单点裁决,宿主经 `agent.getEffectiveMaxTokens()` 读生效值 |
|
|
181
|
+
| `confirmScripts` | `boolean` | ❌ | 脚本/代码执行确认(独立于写入确认;true 时 `run_code` / `run_project_script` 执行前弹窗,默认 false 不弹窗) |
|
|
182
|
+
| `activeRolePack` | `string` | ❌ | 启动激活的角色包名(缺失/不存在回退默认激活首个) |
|
|
183
|
+
| `rolePackTeams` | `RolePackTeam[]` | ❌ | 组(宿主装配级):组长角色包 + 组员名单(会议名单容器;组长唯一、组员可跨组引用,仅用于小组会议,不用于日常) |
|
|
184
|
+
| `builtinFallbackRole` | `string` | ❌ | 程序级内置兜底角色(覆盖内核常量 `BUILTIN_FALLBACK_PACK`;覆盖值须指向存在的包,否则回退内核常量) |
|
|
185
|
+
| `strategyOverride` | `Partial<BehaviorStrategy>` | ❌ | 宿主装配级策略覆盖:经 `resolveActiveStrategy` 压过角色包声明(只影响 override 声明过的键),表达宿主产品能力边界 |
|
|
186
|
+
| `permission` | `'owner' \| 'guest'` | ❌ | 安全权限(默认 'owner') |
|
|
187
|
+
| `allowedPaths` | `string[]` | ❌ | 路径白名单(默认 [] = 全部允许) |
|
|
188
|
+
| `confirmWrites` | `boolean` | ❌ | 写入确认(默认 false) |
|
|
189
|
+
| `storage` | `IMemoryStorage` | ❌ | 存储层注入(默认内置内存实现,不挂公共面) |
|
|
190
|
+
| ~~`vectorStore`~~ | ~~`IVectorStore`~~ | — | **已删除(2026-09-18 B0 收编)**:向量语义召回通道此前**写端缺失、从未在生产生效**(`upsert` 零调用 → 库恒空 → 语义分支永不触发 = 僵尸能力)。经主流 agent 调研(Anthropic Memory/Claude Code/Librarian Pattern 实证「LLM 消费者 + 小语料」纯关键词足用)拍板收编:`IVectorStore` 接口、`JsonVectorStore`、`EmbeddingProvider` 及 `config.embedding` 段全链删除;`search_memories` 走纯关键词,未命中提示 LLM 换词重试 |
|
|
191
|
+
| ~~`recallExcludeSources`~~ | ~~`string[]`~~ | — | **已删除(2026-09-11)**:该配置随召回编排 `recall()` 退役后成为零消费者死配置,全链(AgentOptions → AgentConfig → AssembleInput → ContextPreparerDeps)物理删除。**原消费者已彻底消失**:它当时服务的关联推荐通道 `Agent.governance.suggest(query, { excludeSources })` 于 2026-10-18 随治理链整链退役(见 §四 注记),无替代通道 |
|
|
192
|
+
| `sessionStore` | `ISessionStore` | ❌ | 会话存储注入 |
|
|
193
|
+
| `roundStore` | `IRoundStore` | ❌ | 问答闭环独立存储注入(round-based 落盘真源;未注入则消息仅内存保存,与 `sessionStore` 配套) |
|
|
194
|
+
| `tracer` | `ITracer` | ❌ | 可观测性 Tracer 注入(不传则使用 NoopTracer 静默丢弃所有 span) |
|
|
195
|
+
| `messages` | `UIMessages` | ❌ | 宿主可覆盖的 UI 消息文本(默认英文,宿主覆盖为中文等) |
|
|
196
|
+
| `enableContextSummary` | `boolean` | ❌ | 上下文超限时是否自动生成摘要(默认 true,开启后首次截断时增加 ~1-2s 延迟) |
|
|
197
|
+
| `archiveMode` | `ArchiveMode` | ❌ | 归档模式(ADR-015,默认 `'full'`)。`'full'`:会话内容在会话切换前自动归档;`'manual'`:全部需手动触发(2026-08-14 洞察层移除后三态收敛为二态,原 `'insights-only'` 已移除) |
|
|
198
|
+
| `webSearchProvider` | `IWebSearchProvider` | ❌ | 网络搜索提供者注入(提供时自动暴露 `web_search` 工具给 LLM,不传则不暴露) |
|
|
199
|
+
| `fetchProvider` | `IFetchProvider` | ❌ | 网页抓取提供者注入(提供时自动暴露 `web_fetch` 工具给 LLM,与 `webSearchProvider` 成对构成「搜索→抓取」闭环,不传则不暴露) |
|
|
200
|
+
| `codeExecutionProvider` | `ICodeExecutionProvider` | ❌ | 代码执行提供者注入(提供时自动暴露 `run_code` 工具给 LLM,沙箱执行能力完全由宿主 provider 决定,内核零运行时依赖,不传则不暴露) |
|
|
201
|
+
| `projectSearchProvider` | `IProjectSearchProvider` | ❌ | 项目内搜索提供者注入(提供时 LLM 获项目文件检索能力,不传则不暴露) |
|
|
202
|
+
| `environmentProvider` | `IEnvironmentProvider` | ❌ | 宿主环境提供者(不配则 system prompt 不注入环境段):宿主上报运行环境事实(OS / shell / 可用运行时),内核零解释转发 |
|
|
203
|
+
| `scriptNodePath` | `string` | ❌ | node 可执行文件路径:宿主注入真实 node 路径给 L3 脚本执行器(`run_skill_script` / `run_project_script` 的 node 分支);缺省走 `'node'`(PATH 查找),宿主机无独立 node 时注入可避免 ENOENT |
|
|
204
|
+
| `disabledSkills` | `string[]` | ❌ | 禁用的技能名清单:命中的技能从 L1 清单消失、L2/L3 访问不可用(对 LLM 语义 = 技能不存在,宿主 UI 据同名设置标「已禁用」徽章) |
|
|
205
|
+
| `preExecutionCheck` | `(name, args) => PreExecutionResult` | ❌ | 工具执行前检查回调(宿主审批/审计/参数改写通道;装配时与内部幂等检查组合为单点入口) |
|
|
206
|
+
|
|
207
|
+
> **Logger 注入方式**:v1.0 起 `AgentOptions` 不再含 `logger` 字段。日志通过全局 `setLogger(customLogger)` 注入(详见 §十七 类型导出);未注入时使用内核内置 console fallback(写 stderr,级别由 `MEMORA_LOG_LEVEL` 控制),内核不做任何运行时模块解析。注入即内核唯一日志出口,对**所有内核模块(含 utils 层)**生效。
|
|
208
|
+
|
|
209
|
+
### 2.2 生命周期方法
|
|
210
|
+
|
|
211
|
+
| 方法 | 用途 |
|
|
212
|
+
|------|------|
|
|
213
|
+
| `new Agent(opts)` | 构造函数(无副作用,不连接 LLM) |
|
|
214
|
+
| `init()` → `Promise<ProjectContext>` | 初始化:建立存储、加载配置、组装组件。**项目在构造时钉死**(`AgentOptions.projectPath`)——换项目请新建一个 Agent 实例,单实例内不可改绑 |
|
|
215
|
+
| `close()` → `Promise<void>` | 关闭:释放项目锁、关闭数据库 |
|
|
216
|
+
|
|
217
|
+
### 2.3 Agent 只读访问器
|
|
218
|
+
|
|
219
|
+
| 访问器 | 类型 | 说明 |
|
|
220
|
+
|--------|------|------|
|
|
221
|
+
| `agent.initialized` | `boolean` | 是否已初始化 |
|
|
222
|
+
| `agent.context` | `AgentContext \| null` | 当前项目上下文 |
|
|
223
|
+
| `agent.provider` | `LlmProvider` | 当前前台 Provider |
|
|
224
|
+
| `agent.isBusy` | `boolean` | 是否正在对话中 |
|
|
225
|
+
| `agent.lastInteractionAt` | `Date \| null` | 最近一次 `chat()` 调用时间 |
|
|
226
|
+
|
|
227
|
+
### 2.4 Manager 访问器(委托模式)
|
|
228
|
+
|
|
229
|
+
Agent 通过一组 getter 暴露专职 Manager 与组件。详见后续章节。
|
|
230
|
+
|
|
231
|
+
| 访问器 | 类型 | 职责 |
|
|
232
|
+
|--------|------|------|
|
|
233
|
+
| `agent.rolePack` | `RolePackManager \| null` | 角色包管理 |
|
|
234
|
+
| `agent.tools` | `ToolExecutor \| null` | 工具注册与执行 |
|
|
235
|
+
| `agent.skills` | `SkillManager \| null` | 技能匹配与注入 |
|
|
236
|
+
| `agent.memory` | `MemoryInspector \| null` | 记忆查询 + 写入(`writeXxx` 前缀) |
|
|
237
|
+
| `agent.works` | `WorkProjectionManager \| null` | 作品投影(项目文件指针索引) |
|
|
238
|
+
| `agent.polish` | `TextPolishManager \| null` | 文本润色(LLM 语法修正 + 表达优化) |
|
|
239
|
+
|
|
240
|
+
> **历史留痕(2026-10-18 · 5.0.0)**:本表原有 `agent.governance` 一行(类型 `MemoryGovernance | null`,职责「记忆治理:去重/冲突检测/建议」),已随治理链**整链退役**删除——
|
|
241
|
+
> 理由为**结构性恒空**(非「暂时没人用」):`deduplicate()` / `detectConflicts()` / `suggest()` 逐 `GOVERNANCE_SOURCES` 取样,而该常量是字面量空数组、非注入项,代码路径上永远拿不到输入。
|
|
242
|
+
> 唯一有效的 `sourceHealth()` 已有等价替代 `agent.memory.stats().bySource`。连带删除 `MemoryAdvisor` / `DedupManager` / `llmJudgeHelper` / `recallDefaults` 与 `dedupCompleted` 事件。详见 §四 注记。
|
|
243
|
+
|
|
244
|
+
> **读写统一入口**:`agent.memory`(MemoryInspector)同时负责记忆的查询与写入——只读方法(snapshot/searchByKeyword/stats/list/getById/getBySource/listDeleted 等;**`search()` 已于 4.0.0 移除**,见 §4.2)与写方法(`writeXxx` 前缀:writeUpsert/writeDelete/writeRestore/writePurge/writePurgeExpired。`writeBoost` 已随 score 字段退役删除,2026-09-09)。旧的 `memoryMutator`/`MemoryMutator` 拆分已在后续迭代中合并回 `MemoryInspector`,二者均不再存在。
|
|
245
|
+
|
|
246
|
+
### 2.5 内部组件访问器(高级)
|
|
247
|
+
|
|
248
|
+
| 访问器 | 类型 | 说明 |
|
|
249
|
+
|--------|------|------|
|
|
250
|
+
| `agent.agentLoop` | `AgentLoop \| null` | Agent 循环体(`getMessages()` / `getRecentHistory()`) |
|
|
251
|
+
| `agent.agentHistory` | `MessageHistory \| null` | 消息历史(`listAllSessions()` 等) |
|
|
252
|
+
|
|
253
|
+
### 2.6 `ProjectContext` 字段(`init()` 返回值)
|
|
254
|
+
|
|
255
|
+
| 字段 | 类型 | 说明 |
|
|
256
|
+
|------|------|------|
|
|
257
|
+
| `projectPath` | `string` | 项目根目录的绝对路径(构造时钉死,不可改绑) |
|
|
258
|
+
| `projectName` | `string` | 项目名称(显式传入优先,否则取目录名;内核不读任何注册表) |
|
|
259
|
+
| `memoraDir` | `string` | `.memora/` 目录的绝对路径 |
|
|
260
|
+
| `index` | `IMemoryStorage` | 记忆存储接口 |
|
|
261
|
+
| `security` | `SecurityGuard \| null` | 安全守卫(未注入 `createSecurityGuard` 工厂时为 `null`) |
|
|
262
|
+
| `bootstrapMemories` | `Memory[]` | 启动必召记忆——**恒为空数组**(设定记忆归角色包内容层,ADR-025) |
|
|
263
|
+
|
|
264
|
+
### 2.7 事件订阅(`agent.on()` / `agent.off()` / `agent.once()`)
|
|
265
|
+
|
|
266
|
+
Agent 继承 `TypedEventEmitter<AgentEventMap>`,向宿主项目广播对话外事件。
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
agent.on<K extends AgentEventName>(event: K, handler: (payload: AgentEventMap[K]) => void): void
|
|
270
|
+
agent.off<K extends AgentEventName>(event: K, handler: (payload: AgentEventMap[K]) => void): void
|
|
271
|
+
agent.once<K extends AgentEventName>(event: K, handler: (payload: AgentEventMap[K]) => void): void
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
| 事件名 | 载荷 | 触发时机 |
|
|
275
|
+
|--------|------|----------|
|
|
276
|
+
| `memoryAdded` | `{ id, source, name, content? }` | 记忆被写入存储(round-summary 沉淀等);`content` = 记忆正文(5.0.0 起可选携带,UI 提示按内容显示) |
|
|
277
|
+
| `rolePackSwitched` | `{ from: string \| null, to }` | 角色包被切换(自动匹配 / 手动切换共用唯一切换入口) |
|
|
278
|
+
| `memoryRecalled` | `{ count, query, hits?, toolCallId? }` | LLM 经 `search_memories` 命中记忆(`hits` = 命中明细 `{ id, name, source, contentPreview? }`,4.1.0 起可选、`contentPreview` 5.0.0 起携带;`toolCallId` = 本次调用的配对键,4.1.x 起可选,宿主据此把明细挂回对应工具行,缺省回退轮次级落位) |
|
|
279
|
+
| `sessionForked` | `{ from, to, roundCount }` | 会话被分叉(`roundCount` = 新会话 Round 数) |
|
|
280
|
+
| `sessionSwitched` | `{ date, session, fromSessionId, toSessionId }` | 会话身份切换完成(载荷指向被切走的旧会话;内核自消费,宿主零消费为刻意设计) |
|
|
281
|
+
| `archiveFailed` | `{ stage: 'session', message }` | 归档异常(fire-and-forget catch 分支发射,宿主可通知用户) |
|
|
282
|
+
| `sessionArchived` | `{ sessionId, updatedFields }` | 会话归档写入成功(宿主据此重拉会话列表刷新摘要) |
|
|
283
|
+
| `contextTruncated` | `{ skippedCount, keptCount }` | 内核自动截断上下文 |
|
|
284
|
+
| `contextCompressed` | `{ target, replacedCount, summaryLength }` | LLM 主动压缩完成(第二级压缩) |
|
|
285
|
+
| `configReloaded` | `{ source }` | 配置重载 |
|
|
286
|
+
| `archiveModeChanged` | `{ from, to }` | 归档模式切换 |
|
|
287
|
+
| `rolePackSwitchLocked` | `{ reason, lockedSeconds }` | 角色包切换被锁定(如切换冷却期) |
|
|
288
|
+
| `workProjectionGenerated` | `{ sourcePath, summary }` | 作品投影生成完成 |
|
|
289
|
+
| ~~`dedupCompleted`~~ | ~~`{ deduplicatedCount, demotedIds }`~~ | **已移除(2026-10-18 · 5.0.0)**:随治理链整链退役,`AGENT_EVENTS` 与 `AgentEventMap` 两处同删。宿主侧的订阅与 `suggestions` 渲染通道一并拆除,勿加回 |
|
|
290
|
+
| `sessionPauseTimedOut` | `{ sessionId, pauseDuration, date?, session? }` | 暂停超时(达到 `PAUSE_TIMEOUT_MS` 自动归档) |
|
|
291
|
+
| `sessionResumeBlocked` | `{ sessionId, reason }` | 恢复被拒绝(如锁冲突) |
|
|
292
|
+
| `sessionResumeFailed` | `{ sessionId?, reason }` | 恢复失败(宿主据此 toast 提示) |
|
|
293
|
+
| `inputTooLarge` | `{ inputLength, remainingTokens, hint }` | 装配前判负:触发输入过大,剩余预算不足一轮正文 |
|
|
294
|
+
| `questionPending` | `AskQuestion[]` | LLM 调 `ask_user` 主动提问(Agent 暂停等待回答) |
|
|
295
|
+
| `sessionPaused` | `{ reason, source, sessionId? }` | 会话进入暂停态 |
|
|
296
|
+
| `sessionResumed` | `{ sessionId? }` | 会话恢复运行 |
|
|
297
|
+
| `sessionError` | `{ cause, sessionId? }` | 会话进入异常态 |
|
|
298
|
+
| `sessionRecovered` | `{ sessionId? }` | 会话从异常态恢复 |
|
|
299
|
+
| `sessionTitleUpdated` | `{ sessionId, title }` | LLM 自动更新会话标题(宿主据此刷新 UI) |
|
|
300
|
+
| `roundSummaryGenerated` | `{ roundId, success }` | 轮次摘要生成收口(宿主据此解锁删除/分叉按钮,防孤儿摘要) |
|
|
301
|
+
| `backgroundTaskSettled` | `{ taskId, command, status }` | 后台任务自然终态(自行跑完 / 超时强杀;主动 kill 刻意不发) |
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
// 使用示例
|
|
305
|
+
agent.on('memoryAdded', (e) => console.log(`新记忆: ${e.source}:${e.name}`));
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
> `close()` 自动移除所有事件监听器。
|
|
309
|
+
|
|
310
|
+
**状态机**:
|
|
311
|
+
```
|
|
312
|
+
[构造] --init()--> [已初始化] --chat()/其他方法...--> [已初始化]
|
|
313
|
+
--close()--> [已关闭]
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
未初始化时调用任何方法**抛 `configError`**。Manager 访问器在 `init()` 前返回 `null`。
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 三、对话 API
|
|
321
|
+
|
|
322
|
+
### 3.1 `chat(input, signal?)` — 流式对话(唯一入口)
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
async *chat(input: string, signal?: AbortSignal): AsyncGenerator<AgentChunk, void, unknown>
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
流式返回 `AgentChunk` 事件,可选传入 `signal` 支持取消。
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
type AgentChunk =
|
|
332
|
+
| { type: 'thinking'; phase: ThinkingPhase } // 推理阶段
|
|
333
|
+
| { type: 'text'; content: string } // LLM 文本片段(流式输出内容)
|
|
334
|
+
| { type: 'thought'; content: string; stepIndex?: number } // 模型思考增量(不进正文/记忆);stepIndex = 所属 step 轮内序号(loop 打标)
|
|
335
|
+
| { type: 'tool_start'; toolCallId: string; name: string; args?: string; stepIndex?: number } // 工具调用开始(stepIndex 同 thought;tool_result 经 toolCallId 归属,不重复携带)
|
|
336
|
+
| { type: 'tool_result'; toolCallId: string; name: string; ok: boolean; summary?: string } // 工具调用结果
|
|
337
|
+
| { type: 'aborted'; reason: string } // 对话被取消
|
|
338
|
+
| { type: 'error'; message: string } // 流式过程中发生错误(LLM 超时/连接断开)
|
|
339
|
+
| { type: 'retry'; attempt: number; maxRetries: number; delayMs: number; error: string } // 指数退避重试
|
|
340
|
+
| { type: 'done' }; // 结束标记
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
> 上表为核心事件子集(含边界/提问等更多成员的 `AgentChunk` 全集以 [types.ts](../src/agent/types.ts) 为唯一真理源)。
|
|
344
|
+
|
|
345
|
+
> **记忆召回展示链已退役(2026-09-10)**:`recall` chunk 分支与 `RecalledMemorySummary` 类型已随自动注入退役**物理删除**。记忆纯工具化后,「召回了什么」由 `search_memories` 工具的 `tool_start` / `tool_result` 过程事件天然展示;检索命中含 `accessedAt` / 溯源字段(`sessionId`/`roundId`)。
|
|
346
|
+
|
|
347
|
+
`ThinkingPhase` 取值:`'recalling' | 'processing' | 'archiving'`
|
|
348
|
+
|
|
349
|
+
### 3.2 `chatSync(input, signal?)` — 同步版(聚合完整回复)
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
async chatSync(input: string, signal?: AbortSignal): Promise<string>
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
收集所有 `text` 事件拼接成完整字符串返回。适合 CLI / 脚本宿主等不需要流式处理的场景;
|
|
356
|
+
需要中间过程可观测或长任务可中断时用流式 `chat()`。
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## 四、记忆查询与写入(`agent.memory` · MemoryInspector)
|
|
361
|
+
|
|
362
|
+
> Manager 访问路径:`agent.memory.xxx()`。`init()` 前返回 `null`。
|
|
363
|
+
|
|
364
|
+
### 4.1 `snapshot()` — 3 层记忆快照
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
agent.memory.snapshot(): MemorySnapshot
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
同步返回当前 3 层记忆快照(纯只读、无副作用):
|
|
371
|
+
|
|
372
|
+
| 层 | 键 | 内容 |
|
|
373
|
+
|----|-----|------|
|
|
374
|
+
| 第 1 层 | `snapshot.working` | `WorkingMemorySnapshot` — 当前 AgentLoop 消息(最近 5 条预览 + 总数) |
|
|
375
|
+
| 第 2 层 | `snapshot.bootstrap` | `BootstrapSnapshot` — 规则记忆(名称 + 来源 + 权重,Persona/Skill 已解耦为设定记忆,不进 bootstrap) |
|
|
376
|
+
| 第 3 层 | `snapshot.archive` | `ArchiveSnapshot` — 归档记忆计数(round-summary)+ 当前会话信息 |
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
interface MemorySnapshot {
|
|
380
|
+
working: WorkingMemorySnapshot;
|
|
381
|
+
bootstrap: BootstrapSnapshot;
|
|
382
|
+
archive: ArchiveSnapshot;
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### 4.2 `searchByKeyword(query, limit?, excludeRoundIds?)` — 记忆搜索(唯一入口)
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
agent.memory.searchByKeyword(
|
|
390
|
+
query: string,
|
|
391
|
+
limit?: number, // 默认 10
|
|
392
|
+
excludeRoundIds?: ReadonlySet<string>, // 可选:这些轮次的 round-summary 已在正文,不重复返回
|
|
393
|
+
): Promise<AgentSearchHit[]>
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
纯关键词单通道(分词后任一词对 `content`/`name` 子串命中;**无向量通道、无融合排序、无 FTS 索引**)。
|
|
397
|
+
返回顺序 = **`accessedAt` 倒序**(最近写入 / 最近被想起者靠前;`memory-tool-recall-design.md` §5.2 2026-10-19 改定案),
|
|
398
|
+
**不按相关度排序**。返回前做两级过滤:
|
|
399
|
+
`superseded` 过滤(被 `supersededBy` 取代的摘要不作为当前事实返回,仍可经 `trace_summary`
|
|
400
|
+
回溯原文)与 `excludeRoundIds` 互斥(工具召回与装配期正文不重复)。
|
|
401
|
+
|
|
402
|
+
> ⚠️ **4.0.0 已移除 `search()`**:原同步方法 `search(query, limit?)` **已删除**——
|
|
403
|
+
> 此前它只标了 `@deprecated`,却仍作为正常方法列在随包文档里(退役不彻底的僵尸出口)。
|
|
404
|
+
> 其能力由 `searchByKeyword()` 完全覆盖(后者还多出 superseded 过滤 / `excludeRoundIds`
|
|
405
|
+
> 互斥 / accessedAt 刷新 + 溯源揭示),且移除前已实测**零生产消费、零宿主消费**。
|
|
406
|
+
> **一律改用 `searchByKeyword()`。**
|
|
407
|
+
|
|
408
|
+
返回值 `AgentSearchHit`:
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
interface AgentSearchHit {
|
|
412
|
+
id: string; // 记忆唯一标识(source:name 格式,供 showMemory/deleteMemory 等操作使用)
|
|
413
|
+
name: string; // 记忆名称
|
|
414
|
+
source: string; // 来源标签
|
|
415
|
+
contentPreview: string; // 内容预览(截断到 120 字符)
|
|
416
|
+
createdAt?: string; // 创建时间(ISO 8601,供 UI 层时间筛选/排序使用)
|
|
417
|
+
accessedAt?: string; // 最近使用时间(命中即刷新;LLM 按此判断「最近使用优先」)
|
|
418
|
+
sessionId?: string; // 溯源(round-summary 命中项):会话标识,trace_summary 参数直通
|
|
419
|
+
roundId?: string; // 溯源(round-summary 命中项):轮次 ID,LLM 零解析直用
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### 4.3 `stats()` — 记忆库统计
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
agent.memory.stats(): AgentStats
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
interface AgentStats {
|
|
431
|
+
bySource: Record<string, number>; // 按来源标签分组的记忆数量
|
|
432
|
+
total: number; // 记忆总数
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### 4.4 `agent.agentLoop.getMessages()` — 工作记忆原始消息
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
agent.agentLoop.getMessages(): readonly Message[]
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### 4.5 写入方法
|
|
443
|
+
|
|
444
|
+
记忆的写入统一收口在 `agent.memory`,写方法以 `writeXxx` 前缀命名(同步返回、不调 LLM、不触发异步 IO):
|
|
445
|
+
|
|
446
|
+
```typescript
|
|
447
|
+
// ─── 写入(writeXxx 前缀) ───
|
|
448
|
+
agent.memory.writeUpsert(memory: Memory): void; // 插入或更新记忆
|
|
449
|
+
agent.memory.writeDelete(id: string): void; // 软删除(写入 deletedAt)
|
|
450
|
+
agent.memory.writeRestore(id: string): void; // 恢复软删除
|
|
451
|
+
agent.memory.writePurge(id: string): void; // 物理删除(不可恢复)
|
|
452
|
+
agent.memory.writePurgeExpired(before: Date): number; // 清理过期回收站
|
|
453
|
+
|
|
454
|
+
// ─── 只读扩展查询 ───
|
|
455
|
+
agent.memory.list(limit?: number): Memory[]; // 列出所有记忆(按 accessedAt 降序;score 已随 2026-09-09 退役)
|
|
456
|
+
agent.memory.getById(id: string): Memory | null; // 按 ID 获取活跃记忆
|
|
457
|
+
agent.memory.getBySource(source: string): Memory[]; // 按 source 获取
|
|
458
|
+
agent.memory.listDeleted(limit?: number): Memory[]; // 回收站(软删除记忆)
|
|
459
|
+
agent.memory.getDeletedById(id: string): Memory | null;
|
|
460
|
+
agent.memory.searchByKeyword(query: string, limit?: number): Promise<AgentSearchHit[]>; // 纯关键词通道
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
> **历史留痕 · 治理门面整链退役(2026-10-18 · 5.0.0)**:`agent.governance` 曾暴露 `deduplicate()` / `detectConflicts()` / `sourceHealth()` / `suggest()`。
|
|
464
|
+
> 其中前三者逐 `GOVERNANCE_SOURCES`(`src/memory/governance.ts`)取样,而该常量是**字面量空数组、非注入项** ⇒ 三者**结构性恒空**(不是「暂时没人用」,是代码路径上永远拿不到输入)。
|
|
465
|
+
> 唯一有效的 `sourceHealth()` 已有等价替代:`agent.memory.stats().bySource`(宿主 `memora.memoryStats` 命令即消费此字段)。
|
|
466
|
+
> 故按「结构性恒空」判据整链退役——**这是能力退回,不是 API 兼容性妥协**:原有的去重/冲突检测/建议三条能力,从 5.0.0 起**不存在**,不会「偶发不生效」。
|
|
467
|
+
> 写时治理由 `supersede`(写时取代)承担,不经本门面。退役决策与代价见 `tasks/待完成任务.md` `GOVERNANCE-SRC-1`,删后注记见 `src/agent/agent.ts`。
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## 五、Memory 模型(基元驱动)
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
interface Memory {
|
|
475
|
+
id: string; // 唯一标识(source:name 格式,如 'rule:core')
|
|
476
|
+
content: string; // 记忆内容(Markdown 文本)
|
|
477
|
+
source: string; // 来源标签(开放字符串,非枚举)
|
|
478
|
+
name: string; // 可读名称
|
|
479
|
+
createdAt: string; // 创建时间(ISO 8601)
|
|
480
|
+
accessedAt: string; // 最后访问时间(每次召回时刷新)
|
|
481
|
+
deletedAt?: string; // 软删除时间(ISO 8601,可选;非 undefined 表示已软删除。回收站**无自动清理**:保留期清理由宿主入口显式触发,见 writePurgeExpired)
|
|
482
|
+
metadata?: Record<string, string>; // 配置文件 frontmatter 额外元数据(仅配置文件写入路径使用,不进记忆库)
|
|
483
|
+
summaryType?: 'preference' | 'fact' | 'decision' | 'intent' | 'general'; // round-summary 摘要类型(顶层持久化字段;类型随 Memory 签名推断,不单独导出)
|
|
484
|
+
sessionName?: string; // round-summary 归属会话标识(顶层持久化字段,仅 round-summary 有意义)
|
|
485
|
+
roundId?: string; // round-summary 归属轮次标识(顶层持久化字段,仅 round-summary 有意义)
|
|
486
|
+
isModified?: boolean; // 摘要是否已被人工修改(仅 round-summary 有意义)
|
|
487
|
+
supersededBy?: string; // 写路径取代标记:非 undefined 表示已被更新的摘要覆盖,召回时确定性过滤
|
|
488
|
+
materialFingerprint?: string; // 摘要原料指纹(sha256(原文+分隔符+回复)),写路径前置精确去重:原料全等则跳过生成、不调 LLM。仅 round-summary 有意义,存量条目无此字段
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
> **字段基线**(score 已退役):`score` 字段已随 2026-09-09 阶段3 物理删除(无持久化排序分字段,使用轨迹唯一事实源为 `accessedAt`);向量语义通道已随 2026-09-18 B0 收编(检索为纯关键词单通道)。round-summary 溯源/分类字段(summaryType/sessionName/roundId)已提升为顶层持久化字段(metadata 不进记忆库)。所有查询方法(getById/getBySource/search/count/countBySource/getAllSources)自动过滤 `deletedAt != undefined` 的记忆。详见 ADR-004 GAP-6 + ADR-002 §IMemoryStorage。
|
|
493
|
+
|
|
494
|
+
**常用 source 标签(`SOURCE_LABELS` 常量):**
|
|
495
|
+
|
|
496
|
+
| 常量 | 值 | 用途 |
|
|
497
|
+
|------|----|------|
|
|
498
|
+
| `SOURCE_LABELS.PERSONA` | `'persona'` | 角色人格(残留兼容标签,已随 ADR-025 归角色包、不进记忆库) |
|
|
499
|
+
| `SOURCE_LABELS.RULE` | `'rule'` | 创作规则(残留兼容标签,已随 ADR-025 归角色包、不进记忆库) |
|
|
500
|
+
| `SOURCE_LABELS.SKILL` | `'skill'` | 技能定义(残留兼容标签,已随 ADR-025 归角色包、不进记忆库) |
|
|
501
|
+
| `SOURCE_LABELS.WORK_PROJECTION` | `'work-projection'` | 作品投影(**残留兼容标签**:对应内容不归记忆库管理;现行投影为项目级 `work-projections.json` 指针索引,见 §九) |
|
|
502
|
+
| `SOURCE_LABELS.ROUND_SUMMARY` | `'round-summary'` | 轮次摘要(当前实际写入记忆库的主要 source) |
|
|
503
|
+
| `SOURCE_LABELS.UNKNOWN` | `'unknown'` | 未知来源(未被已知标签覆盖时的兜底值) |
|
|
504
|
+
|
|
505
|
+
> source 是开放字符串,宿主可自定义新标签。`validateSource()` 可检测常见 typo(基于 Levenshtein 距离)。PERSONA/RULE/SKILL/WORK_PROJECTION 四标签**仅作历史兼容与 typo 检测**保留,已不进入治理范围——圈定该范围的 `GOVERNANCE_SOURCES` 常量已随 5.0.0 事后治理链**整链退役**删除(见上文「历史留痕」注记);当前写入记忆库的主要 source 为 `round-summary`。
|
|
506
|
+
|
|
507
|
+
### 5.2 `IMemoryStorage` 接口
|
|
508
|
+
|
|
509
|
+
宿主实现此接口注入 Agent,替代内核内置的内存默认实现(内部类,不挂公共面——PUB-API-PRUNE-2 收面)。共 **15 方法**(14 必需 + 可选 `close`),所有方法同步(与 better-sqlite3 API 对齐,`await` 同步值安全)。所有查询方法自动过滤已软删除的记忆(`deletedAt != undefined`)。
|
|
510
|
+
|
|
511
|
+
```typescript
|
|
512
|
+
interface IMemoryStorage {
|
|
513
|
+
// ─── 基础 CRUD(6 方法) ───
|
|
514
|
+
upsert(memory: Memory): void;
|
|
515
|
+
getById(id: string): Memory | null;
|
|
516
|
+
getBySource(source: string): Memory[];
|
|
517
|
+
search(query: string, limit?: number): Memory[];
|
|
518
|
+
count(): number;
|
|
519
|
+
countBySource(source: string): number;
|
|
520
|
+
|
|
521
|
+
// ─── 软删除 / 回收站(6 方法,ADR-004 GAP-6 扩展) ───
|
|
522
|
+
delete(id: string): void; // 软删除(写入 deletedAt,不物理移除;对已软删除的 no-op)
|
|
523
|
+
restore(id: string): void; // 恢复软删除记忆(清除 deletedAt;对活跃记忆 no-op)
|
|
524
|
+
purge(id: string): void; // 物理删除(不可恢复,用于回收站"彻底删除")
|
|
525
|
+
listDeleted(limit?: number): Memory[]; // 列出回收站(按 deletedAt 降序;limit 缺省/≤0 = 全部,正整数 = 最近 N 条)
|
|
526
|
+
getDeletedById(id: string): Memory | null; // 按 ID 获取单条软删除记忆(restore/purge 前存在性校验)
|
|
527
|
+
purgeExpired(before: Date): number; // 清理过期回收站(物理删除 deletedAt 早于 before 的,返回清理数量)
|
|
528
|
+
|
|
529
|
+
// ─── 统计与维护(2 方法) ───
|
|
530
|
+
touch(id: string, now: string): boolean; // 刷新 accessedAt(score 退役后唯一写位;不写 score、无 clamp 语义)
|
|
531
|
+
getAllSources(): Map<string, number>; // 获取所有 source 标签及其活跃记忆数量
|
|
532
|
+
|
|
533
|
+
// ─── 可选(1 方法) ───
|
|
534
|
+
close?(): void;
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
> 宿主实现应使用 `COUNT(*)` / `UPDATE ... WHERE` 等数据库原生操作,避免全量加载数据。`getAllSources` 是性能优化方法,避免逐条遍历。详见 ADR-002 §IMemoryStorage 接口方法。
|
|
539
|
+
|
|
540
|
+
### 5.3 `ISessionStore` 接口
|
|
541
|
+
|
|
542
|
+
宿主实现此接口提供会话消息的持久化能力。共 **12 方法**(11 必需 + 可选 `setSessionTitle`),
|
|
543
|
+
按职责分三组:会话消息读写 / 元数据 / round-based 引用。**方法签名以本节为准,勿按旧版(含
|
|
544
|
+
`appendMessage` 的 3 方法版)实现**——那是 round-based 改造前的历史形态,已被删除。
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
interface ISessionStore {
|
|
548
|
+
// ─── 会话消息读写(1 方法) ───
|
|
549
|
+
/**
|
|
550
|
+
* 加载指定会话的完整消息列表(从 roundIds → RoundStore 展开),不存在返回空数组。
|
|
551
|
+
* **只返回 `user` / `assistant` 两种角色**:tool 结果属执行中间态,不落会话消息。
|
|
552
|
+
* 这不是实现自由,而是接口契约——上下文中 tool 消息的唯一来源是 Loop 的入口落盘。
|
|
553
|
+
*/
|
|
554
|
+
loadMessages(date: string, session: string): SessionMessage[];
|
|
555
|
+
|
|
556
|
+
// ─── 元数据(5 方法,1 可选) ───
|
|
557
|
+
/** 列出所有会话标识(YYYY-MM-DD-session) */
|
|
558
|
+
listSessions(): string[];
|
|
559
|
+
/** 读取会话标题元数据,不存在返回 undefined */
|
|
560
|
+
getSessionMeta(sessionId: string): SessionMeta | undefined;
|
|
561
|
+
/** 设置用户可修改的显示名(displayName);首轮自动命名走 updateSessionMeta 写 autoName */
|
|
562
|
+
setSessionTitle?(sessionId: string, title: string): void;
|
|
563
|
+
/** 更新元数据(autoName/keyTopics/summary/createdAt 等) */
|
|
564
|
+
updateSessionMeta(sessionId: string, meta: Partial<SessionMeta>): void;
|
|
565
|
+
/** 列出全部会话标题元数据,**必须按 updatedAt 降序**(最近活跃在前) */
|
|
566
|
+
listSessionMetas(): SessionMeta[];
|
|
567
|
+
|
|
568
|
+
// ─── round-based 引用(4 方法) ───
|
|
569
|
+
appendRoundId(sessionId: string, roundId: string): void;
|
|
570
|
+
appendRoundIds(sessionId: string, roundIds: string[]): void;
|
|
571
|
+
getRoundIds(sessionId: string): string[];
|
|
572
|
+
setRoundIds(sessionId: string, roundIds: string[]): void;
|
|
573
|
+
|
|
574
|
+
// ─── 会话生命周期(2 方法) ───
|
|
575
|
+
createSession(meta: SessionMeta): void;
|
|
576
|
+
/** 删除会话(同时清理 Round ID 引用) */
|
|
577
|
+
deleteSession(sessionId: string): void;
|
|
578
|
+
}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
> **`listSessionMetas` 排序方向是契约的一部分**:宿主视 `[0]` 为「最近活跃会话」的唯一真理源
|
|
582
|
+
> (打开面板时定位初始会话);升序实现会让初始定位落到最旧会话。
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## 六、项目 / 会话管理
|
|
587
|
+
|
|
588
|
+
> **方法归属**:会话相关方法在 `agent.sessionManager`(SessionManager);`forkSession` 保留在
|
|
589
|
+
> Agent 面类作为常用入口。**项目既无切换入口、也无重建入口**——多项目由宿主创建多个 Agent
|
|
590
|
+
> 实例(一个 Agent 绑定一个项目),见 §6.2。
|
|
591
|
+
|
|
592
|
+
> **switch* 返回值约定**:各 switch 操作返回与其操作语义最匹配的值 ——
|
|
593
|
+
> `switchSession` 返回新会话名(string)、`agent.switchRolePack` 返回布尔值(是否切换成功)。
|
|
594
|
+
> 这是设计性差异,非 bug。(原 `switchProject` 随 PR-SWITCH-1 删除,不再有项目切换入口。)
|
|
595
|
+
|
|
596
|
+
### 6.1 Agent 面类方法(项目/会话入口)
|
|
597
|
+
|
|
598
|
+
| 方法 | 用途 |
|
|
599
|
+
|------|------|
|
|
600
|
+
| `forkSession(targetSession?)` → `AgentForkResult` | 分叉当前会话(同步,复制完整消息历史到新分支) |
|
|
601
|
+
|
|
602
|
+
### 6.2 多项目怎么办(形态定案)
|
|
603
|
+
|
|
604
|
+
**一个 Agent 绑定一个项目**——内核不提供项目切换,也不维护跨项目名单。多项目的正确做法是
|
|
605
|
+
**宿主为每个项目各创建一个 Agent 实例**(项目数据本就隔离在项目自己的 `.memora/` 下:
|
|
606
|
+
`dataDir = <projectPath>/.memora`,记忆 / 会话 / round 三家 store 同目录)。
|
|
607
|
+
|
|
608
|
+
需要「最近项目列表」时由宿主自持(VS Code 用 `recent folders`、扫 `.memora` 等),比内核管
|
|
609
|
+
项目名单更合边界——内核不假设多项目目录的位置与形态。
|
|
610
|
+
|
|
611
|
+
> 历史留痕:5.0.0 前曾有 `agent.projects`(项目管理器)与 `switchProject` / `projectSwitched`
|
|
612
|
+
> 事件 / `registryDir` / `ProjectEntry` / `projects.json` 跨项目注册表整链,已于 PR-SWITCH-1
|
|
613
|
+
> 一并删除(形态定案后整链落空:注册表随项目级 `dataDir` 各一份、按名切换永不命中,且注入
|
|
614
|
+
> 存储不随切换重建 ⇒ 用了会错)。
|
|
615
|
+
|
|
616
|
+
### 6.3 `agent.sessionManager` — SessionManager
|
|
617
|
+
|
|
618
|
+
| 方法 | 用途 |
|
|
619
|
+
|------|------|
|
|
620
|
+
| `sessionManager.switchSession(newName)` → `string` | 切换到指定会话(chatBusy 时抛 configError) |
|
|
621
|
+
| `sessionManager.forkSession(targetSession?)` → `AgentForkResult` | 分叉当前会话 |
|
|
622
|
+
| `sessionManager.createCheckpoint()` → `SessionCheckpoint` | 创建当前会话检查点(含计划、状态机快照),首次调用返回完整检查点,后续调用合并增量。**同进程内存态**(2026-09-10 减法后不落盘)。返回值恒非空(agent 层与 sessionManager 层皆然;未 `init()` 时抛 `configError` 而非返回 `null`)。会返回 `null` 的是下一行 `getCheckpoint()`(首个检查点尚未创建时),勿混 |
|
|
623
|
+
| `sessionManager.getCheckpoint()` → `SessionCheckpoint \| null` | 获取当前检查点(只读,不修改状态) |
|
|
624
|
+
| `sessionManager.discardCheckpoint()` → `boolean` | **Phase 4 新增**:放弃当前暂停检查点(对称 pause 创建,宿主 handleStop paused 态调之;停定时器 + 清内存 + resetToRunning;无检查点返回 false) |
|
|
625
|
+
|
|
626
|
+
```typescript
|
|
627
|
+
// 会话分叉示例(Agent 面类入口,等价于 agent.sessionManager.forkSession())
|
|
628
|
+
const forkResult = agent.forkSession();
|
|
629
|
+
console.log(`分叉到 ${forkResult.newSession},含 ${forkResult.roundCount} 个 Round(roundId 指针)`);
|
|
630
|
+
|
|
631
|
+
// 自定义分支名
|
|
632
|
+
const customFork = agent.forkSession('experiment');
|
|
633
|
+
|
|
634
|
+
// listAllSessions 通过 agentHistory 访问
|
|
635
|
+
const sessions = await agent.agentHistory?.listAllSessions();
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
### `AgentForkResult` / `ForkResult` 类型
|
|
639
|
+
|
|
640
|
+
```typescript
|
|
641
|
+
// Agent.forkSession() / sessionManager.forkSession() 返回值
|
|
642
|
+
interface AgentForkResult extends ForkResult {
|
|
643
|
+
roundCount: number; // 新会话获得的 Round ID 数量(源码 = ForkResult & { roundCount })
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// MessageHistory.forkSession() 内部类型(从 memora 导出)
|
|
647
|
+
export interface ForkResult {
|
|
648
|
+
date: string;
|
|
649
|
+
newSession: string;
|
|
650
|
+
roundIds: string[]; // 已复制到新会话的 Round ID 指针列表
|
|
651
|
+
}
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
## 七、角色包管理(`agent.rolePack` · RolePackManager)
|
|
657
|
+
|
|
658
|
+
> Manager 访问路径:`agent.rolePack`(RolePackManager,`init()` 前返回 `null`)。角色包是「设定记忆唯一载体」(persona/rules/skills 归属角色包,见 memory-role-pack-boundary 纪律)。
|
|
659
|
+
|
|
660
|
+
| 成员 | 类型 | 说明 |
|
|
661
|
+
|------|------|------|
|
|
662
|
+
| `rolePack.listMeta()` | `RolePackMeta[]` | 所有角色包元数据(name / displayName / description / version / ...) |
|
|
663
|
+
| `rolePack.activeName` | `string \| null`(getter) | 当前激活的角色包名(null = 未激活) |
|
|
664
|
+
| `rolePack.getActive()` | `RolePackAssembly \| null` | 当前激活的完整角色包对象(含合并后策略) |
|
|
665
|
+
| `rolePack.getActiveRules()` | `string[]` | 当前激活角色包的规则列表 |
|
|
666
|
+
| `rolePack.getActiveTraits()` | `Record<string, number> \| undefined` | 当前激活角色包的 traits(clamp 0-1) |
|
|
667
|
+
| `rolePack.activate(name)` | 方法 → `boolean` | 手动切换到指定角色包(30s 内超 5 次切换后锁 2 分钟防抖) |
|
|
668
|
+
| `rolePack.getSwitchLockStatus()` | 方法 → `{ locked, unlockAt }` | 切换防抖锁定状态 |
|
|
669
|
+
| `rolePack.onRolePackActivated(handler)` | 方法 | 注册激活变更回调(`(from, to)`) |
|
|
670
|
+
|
|
671
|
+
```typescript
|
|
672
|
+
// 使用示例
|
|
673
|
+
const rp = agent.rolePack;
|
|
674
|
+
if (!rp) throw new Error('rolePack 未就绪');
|
|
675
|
+
const metas = rp.listMeta(); // 列出所有角色包
|
|
676
|
+
rp.activate('作家'); // 切换角色包
|
|
677
|
+
console.log(rp.activeName); // 当前角色包名
|
|
678
|
+
const lock = rp.getSwitchLockStatus(); // 切换防抖状态
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
---
|
|
682
|
+
|
|
683
|
+
## 八、工具注册(`agent.tools` · ToolExecutor)
|
|
684
|
+
|
|
685
|
+
> 工具注册/执行走 `agent.tools.xxx()`。
|
|
686
|
+
|
|
687
|
+
### 8.1 内置工具(核心摘要:默认常驻 + 条件暴露,非全集)
|
|
688
|
+
|
|
689
|
+
| 工具名 | 用途 | 参数 | 暴露条件 |
|
|
690
|
+
|--------|------|------|------|
|
|
691
|
+
| `read_file` | 读取项目内文件内容(**按行分段返回**:单次输出 token 数 ≤ `LOOP_CONSTANTS.SINGLE_TOOL_RESULT_MAX_TOKENS`=6000;未读到末尾时附「[read_file 分段]」脚注,给出已显示行号区间、总行数与续读 offset) | `path`, `offset?`, `limit?` | 默认常驻 |
|
|
692
|
+
| `write_file` | 写入/创建文件(支持 overwrite/append/insert/replace 四种模式) | `path`, `content`, `mode?`, `insert_line?`, `old_string?` | 默认常驻 |
|
|
693
|
+
| `list_dir` | 列出目录内容(递归深度 ≤ 3) | `path?`, `recursive?`, `maxDepth?` | 默认常驻 |
|
|
694
|
+
| `search_memories` | 在记忆索引中搜索(支持 match/near 两种模式) | `query`, `limit?`, `mode?` | 默认常驻 |
|
|
695
|
+
| `run_project_script` | 运行**项目内既有**脚本(内核子进程,cwd=项目根;路径白名单越界拒绝;扩展名推断 node/python/shell;超时 30s 上限 120s) | `script_path`, `args?` | 默认常驻(零注入) |
|
|
696
|
+
| `run_skill_script` | 执行技能目录下的脚本(渐进披露 L3) | `skill_name`, `script_path`, `args?` | 默认常驻(来源=技能作者) |
|
|
697
|
+
| `run_command` | 执行 shell 命令(裁决链:deny 恒拦 → 确认档位 → allow 白名单;`background: true` 转后台立即返回 taskId,结果经回流通知注入,详见 §8.7) | `command`, `cwd?`, `background?`, `timeoutMs?` | 默认常驻 |
|
|
698
|
+
| `kill_command` | 终止后台命令任务并取回截至当时的输出(仅可杀本 agent 实例起的任务,§8.7) | `taskId` | 默认常驻 |
|
|
699
|
+
| `web_search` | 搜索互联网 | `query`, `limit?` | 条件暴露(注入 `IWebSearchProvider`) |
|
|
700
|
+
| `web_fetch` | 抓取网页正文(与 `web_search` 成对闭环) | `url`, `limit?` | 条件暴露(注入 `IFetchProvider`) |
|
|
701
|
+
| `run_code` | LLM 现写代码执行(特权:`code:execute` 声明 + 宿主沙箱注入) | `language`, `code` 或 `script_path` | 条件暴露(注入 `ICodeExecutionProvider` 且角色包声明特权) |
|
|
702
|
+
|
|
703
|
+
### 8.2 `agent.tools` — ToolExecutor
|
|
704
|
+
|
|
705
|
+
| 方法 | 用途 |
|
|
706
|
+
|------|------|
|
|
707
|
+
| `tools.registerTool(definition, handler)` | 注册自定义工具(会话级) |
|
|
708
|
+
| `tools.list` | 所有工具定义(getter,`ToolDefinition[]`) |
|
|
709
|
+
| `tools.execute(name, argsJson, extensions?)` → `Promise<string>` | 执行工具调用 |
|
|
710
|
+
|
|
711
|
+
```typescript
|
|
712
|
+
// 工具定义
|
|
713
|
+
interface ToolDefinition {
|
|
714
|
+
name: string;
|
|
715
|
+
description: string;
|
|
716
|
+
parameters: {
|
|
717
|
+
type: 'object';
|
|
718
|
+
properties: Record<string, { type: string; description: string }>;
|
|
719
|
+
required: string[]; // 必填参数列表(不可省略)
|
|
720
|
+
};
|
|
721
|
+
readonly?: boolean; // 只读工具标记:true = readonly 模式下保留;缺省 false = 写操作,readonly 模式被阻止
|
|
722
|
+
diskWrite?: 'path' | 'opaque'; // 改盘声明(与 readonly 正交):'path' 按 args.path 定位目标做写串行;'opaque' 与一切写互斥;缺省 = 不改盘
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// 宿主注册领域工具示例
|
|
726
|
+
agent.tools.registerTool(
|
|
727
|
+
{
|
|
728
|
+
name: 'web_search',
|
|
729
|
+
description: '搜索互联网,返回结构化结果',
|
|
730
|
+
parameters: {
|
|
731
|
+
type: 'object',
|
|
732
|
+
properties: {
|
|
733
|
+
query: { type: 'string', description: '搜索关键词' },
|
|
734
|
+
limit: { type: 'number', description: '最大返回条数', default: 5 },
|
|
735
|
+
},
|
|
736
|
+
required: ['query'],
|
|
737
|
+
},
|
|
738
|
+
},
|
|
739
|
+
async (args) => {
|
|
740
|
+
const res = await fetch(`https://api.example.com/search?q=${encodeURIComponent(args.query)}`);
|
|
741
|
+
return await res.json();
|
|
742
|
+
},
|
|
743
|
+
);
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
### 8.3 `IWebSearchProvider` — 网络搜索注入接口
|
|
747
|
+
|
|
748
|
+
> 宿主实现此接口并注入 `AgentOptions.webSearchProvider`,即可让 Agent 拥有网络搜索能力。
|
|
749
|
+
> 未注入时,Agent 不会暴露 `web_search` 工具给 LLM,LLM 被告知搜索不可用。
|
|
750
|
+
> 内核提供 `FetchWebSearchProvider` 作为零依赖默认实现(`buildSearchEndpoints` 构建内置 Bing/DuckDuckGo 等预设降级链)。
|
|
751
|
+
> **主推宿主自建 `SearchEndpoint` 注入**(自带 URL+解析),内核预设仅作零配置保底。
|
|
752
|
+
|
|
753
|
+
```typescript
|
|
754
|
+
// 搜索结果
|
|
755
|
+
interface SearchResult {
|
|
756
|
+
title: string;
|
|
757
|
+
url: string;
|
|
758
|
+
snippet: string;
|
|
759
|
+
endpoint?: string; // 实际后端名(降级打标用,自定义实现可省略)
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// 搜索选项
|
|
763
|
+
interface WebSearchOptions {
|
|
764
|
+
limit?: number; // 返回结果数量上限(默认 5)
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// 搜索端点契约:宿主可自建(自带 URL+解析)覆盖内核预设
|
|
768
|
+
interface SearchEndpoint {
|
|
769
|
+
name: string; // 端点名(降级打标 / 结果透出)
|
|
770
|
+
buildUrl(query: string): string; // 由查询构造请求 URL
|
|
771
|
+
parse(html: string, limit: number): SearchResult[]; // 解析结果页
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// 网络搜索提供者接口
|
|
775
|
+
interface IWebSearchProvider {
|
|
776
|
+
search(query: string, options?: WebSearchOptions): Promise<SearchResult[]>;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// 注入方式
|
|
780
|
+
const agent = new Agent({
|
|
781
|
+
// ... 其他选项
|
|
782
|
+
// 方案 1(保底):内置默认实现(Bing→DuckDuckGo 零配置开箱即用)
|
|
783
|
+
webSearchProvider: new FetchWebSearchProvider(),
|
|
784
|
+
// 方案 2(主推):宿主自建端点注入,URL/解析完全由宿主掌控
|
|
785
|
+
// webSearchProvider: new FetchWebSearchProvider([
|
|
786
|
+
// { name: 'MyEngine', buildUrl: (q) => `https://my.engine/s?q=${q}`, parse: myParse },
|
|
787
|
+
// ]),
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
// buildSearchEndpoints:预设名与自定义端点混排,内核预设仅作保底
|
|
791
|
+
// buildSearchEndpoints(['bing', myEndpoint]) // 自定义端点优先,未知名忽略
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
### 8.4 `IFetchProvider` — 网页抓取注入接口(搜索→抓取闭环第二段)
|
|
795
|
+
|
|
796
|
+
> 宿主实现此接口并注入 `AgentOptions.fetchProvider`,即可让 Agent 读取 `web_search` 找到的候选链接正文。
|
|
797
|
+
> 未注入时,Agent 不会暴露 `web_fetch` 工具给 LLM。
|
|
798
|
+
> 内核提供 `FetchWebFetchProvider` 作为基于内置 `fetch` + 正则清洗 HTML 的零依赖默认实现。抓取调用由内核 `toolExecutor` 经内部超时包装执行(30s;抓取失败/超时降级返回友好提示,不中断主流程)——该包装为**内部机制,不挂公共面**(PUB-API-PRUNE-2 收面,4.x 的 `safeFetch` 导出已删)。
|
|
799
|
+
|
|
800
|
+
```typescript
|
|
801
|
+
// 抓取结果
|
|
802
|
+
interface FetchedPage {
|
|
803
|
+
url: string;
|
|
804
|
+
title: string;
|
|
805
|
+
content: string;
|
|
806
|
+
contentType?: string;
|
|
807
|
+
fetchFailed?: true; // 抓取失败降级页标记(safeFetch 专有,值恒 true);消费方据此区分「失败降级」与「成功但内容为空」
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// 抓取选项
|
|
811
|
+
interface FetchOptions {
|
|
812
|
+
maxChars?: number; // 正文截断字符数上限
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// 网页抓取提供者接口
|
|
816
|
+
interface IFetchProvider {
|
|
817
|
+
fetch(url: string, options?: FetchOptions): Promise<FetchedPage>;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// 注入方式
|
|
821
|
+
const agent = new Agent({
|
|
822
|
+
// ... 其他选项
|
|
823
|
+
fetchProvider: new FetchWebFetchProvider(), // 使用内置默认实现
|
|
824
|
+
});
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
### 8.5 `ICodeExecutionProvider` — 代码执行注入接口
|
|
828
|
+
|
|
829
|
+
> 宿主实现此接口并注入 `AgentOptions.codeExecutionProvider`,即可让 Agent 拥有通用代码执行能力(计算 / 数据处理 / 验证)。
|
|
830
|
+
> 未注入时,Agent 不会暴露 `run_code` 工具给 LLM。
|
|
831
|
+
> **内核零运行时依赖**:沙箱执行(语言白名单 / 资源限制 / 网络隔离)完全由宿主 provider 决定。执行调用由内核 `toolExecutor` 经内部超时包装执行(120s;执行失败/超时降级返回错误结果,不中断主流程)——该包装为**内部机制,不挂公共面**(PUB-API-PRUNE-2 收面,4.x 的 `safeExecuteCode` 导出已删)。
|
|
832
|
+
|
|
833
|
+
```typescript
|
|
834
|
+
// 执行结果
|
|
835
|
+
interface CodeExecutionResult {
|
|
836
|
+
stdout: string;
|
|
837
|
+
stderr: string;
|
|
838
|
+
exitCode: number;
|
|
839
|
+
timedOut: boolean;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// 执行选项
|
|
843
|
+
interface CodeExecutionOptions {
|
|
844
|
+
timeoutMs?: number; // 单次执行超时上限(毫秒,默认 30000,最大 120000)
|
|
845
|
+
cwd?: string; // 工作目录(可选,未传由执行器决定)
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// 代码执行提供者接口
|
|
849
|
+
interface ICodeExecutionProvider {
|
|
850
|
+
readonly supportedLanguages?: readonly string[]; // 支持的语言别名(如 ['javascript','js','node']);声明后 run_code 工具描述按实际生成「支持:…」,缺省则退化为去承诺文案
|
|
851
|
+
execute(code: string, language: string, options?: CodeExecutionOptions): Promise<CodeExecutionResult>;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// 注入方式(沙箱实现由宿主提供)
|
|
855
|
+
const agent = new Agent({
|
|
856
|
+
// ... 其他选项
|
|
857
|
+
codeExecutionProvider: mySandboxProvider,
|
|
858
|
+
});
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
### 8.6 `IProjectSearchProvider` — 项目内搜索注入接口
|
|
862
|
+
|
|
863
|
+
> 宿主实现此接口并注入 `AgentOptions.projectSearchProvider`,即可让 Agent 具备「在当前项目(工作区)中搜索」能力(等价 IDE 全局搜索 `Ctrl+Shift+F`)。
|
|
864
|
+
> 未注入时,Agent 不会暴露 `search_project` 工具给 LLM。
|
|
865
|
+
> **内核零依赖**:目录遍历 / 忽略规则 / 扫描与结果上限全由宿主决定。搜索调用由内核 `toolExecutor` 经内部超时包装执行(30s),并内置由分词 SSOT 产出的**放宽词表**(`buildSearchTerms`)——包装为**内部机制,不挂公共面**(PUB-API-PRUNE-2 收面,4.x 的 `safeSearchProjectFiles` / `safeSearchProjectText` 导出已删)。
|
|
866
|
+
|
|
867
|
+
```typescript
|
|
868
|
+
// 文件名命中
|
|
869
|
+
interface ProjectFileMatch {
|
|
870
|
+
path: string; // 相对项目根的 posix 路径
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// 内容命中
|
|
874
|
+
interface ProjectTextMatch {
|
|
875
|
+
path: string;
|
|
876
|
+
line?: number; // 命中行号(1 起)
|
|
877
|
+
preview?: string; // 命中行预览(去控制字符 + 限长,防上下文注入)
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// 内容搜索的**结果对象**(含本次检索的元信息)
|
|
881
|
+
interface ProjectTextSearchResult {
|
|
882
|
+
matches: ProjectTextMatch[];
|
|
883
|
+
truncated: boolean; // 检索被截断(零命中时也须如实回报)
|
|
884
|
+
truncatedBy?: 'results' | 'files'; // 截断主因:结果达上限 / 扫描达文件上限
|
|
885
|
+
scannedFiles?: number; // 实际参与匹配的文件数(宿主上报的数据)
|
|
886
|
+
partialReadFiles?: number; // 只检索了前一部分(过大)的文件数(**参与了**检索,非跳过)
|
|
887
|
+
unreadableSkipped?: number; // 读取失败(权限/被删/悬空链接)完全未参与检索的文件数
|
|
888
|
+
perFileCapped?: boolean; // 有文件的命中被单文件上限截断
|
|
889
|
+
failed?: boolean; // 检索自身失败(超时/抛错)≠ 真零命中
|
|
890
|
+
relaxed?: boolean; // 已放宽为分词匹配 → 结果**非精确**命中
|
|
891
|
+
termsUsed?: string[]; // 放宽时实际使用的词(文案的唯一取值来源)
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
interface ProjectTextSearchOptions extends ProjectFileSearchOptions {
|
|
895
|
+
pattern: string; // 内容关键词(**字面量**语义,宿主自行转义,内核不假定正则)
|
|
896
|
+
terms?: string[]; // 内核下发的放宽词表;宿主**仅在整串零命中时**才启用
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
interface IProjectSearchProvider {
|
|
900
|
+
searchFiles(options?: ProjectFileSearchOptions): Promise<ProjectFileMatch[]>;
|
|
901
|
+
searchText(options: ProjectTextSearchOptions): Promise<ProjectTextSearchResult>;
|
|
902
|
+
}
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
**实现约定(宿主侧,三条都是契约而非建议)**:
|
|
906
|
+
|
|
907
|
+
1. **精确优先 + 零命中回退**:先按 `pattern` 整串字面量匹配;整串零命中**且** `terms` 非空时,才用 `terms` 做一次 OR 放宽,并置 `relaxed` + 回填 `termsUsed`(多词无需拆开传,**任一分词命中即算**,不是"全部包含")。整串已命中时不得放宽——否则精确命中会退化成"可能不是精确命中"。
|
|
908
|
+
2. **三态必须可区分**:`failed`(没搜完/搜坏了)/ `truncated`(没搜全)/ 真零命中,三者不得再压成同一个空数组——`[]` 承载不了任何元信息,会把"没搜到"与"没搜完"变成逐字同形。失败**不要**返回工具错误("no results is not an error"),如实回报 `failed` 即可,由内核分流文案。
|
|
909
|
+
3. **预算量以数据上报,不提升为内核常量**:`scannedFiles` / `partialReadFiles` / `unreadableSkipped` / `perFileCapped` 是宿主内部预算(扫描文件数 / 单文件字节 / 单文件命中数)与**读取结果**的事实;内核从不扫描,因此不持有这些常量,只把它们写进给 LLM 的文案。同理,`truncatedBy` 由宿主判定(只有宿主知道自己是因何停下)。
|
|
910
|
+
⚠️ `partialReadFiles`(看了但没看全)与 `unreadableSkipped`(根本没看上)**必须分开上报**:两者都是「零命中 ≠ 不存在」的依据,但补救动作不同——前者换更具体的关键词或 `read_file` 精读,后者可重试。
|
|
911
|
+
|
|
912
|
+
**放宽词表(内核侧)**:`buildSearchTerms(query)` 采用「显式片段优先」——空白分隔的片段是一等公民,不含 CJK 的片段原样保留(`Next.js` 不会被切成 `next` + `js`),含 CJK 的片段交给分词 SSOT。调用方(内核 `ToolExecutor`)会剔除与整串等价的词,因此单段查询通常不会触发放宽轮。
|
|
913
|
+
|
|
914
|
+
> 参考实现:VS Code 宿主 `hosts/memora-vscode/src/extension/host/projectSearchProvider.ts`(`mode=name` 走 `workspace.findFiles`;`mode=content` 走受限 fs 递归扫描,忽略 `IGNORED_DIR_NAMES`)。
|
|
915
|
+
|
|
916
|
+
### 8.7 后台命令任务(`run_command` background 模式)
|
|
917
|
+
|
|
918
|
+
`run_command` 以 `background: true` 启动时**不阻塞本轮**:立即返回 `taskId`,进程在本轮对话之外继续跑。宿主经 Agent 门面查看 / 终止这些任务(注册表按 **Agent 实例隔离**,不跨会话互杀)。
|
|
919
|
+
|
|
920
|
+
```typescript
|
|
921
|
+
// 只读快照:供宿主 UI 渲染任务列表(只读投影,不含进程句柄)
|
|
922
|
+
agent.listBackgroundTasks(): readonly BackgroundTask[]
|
|
923
|
+
|
|
924
|
+
// 终止:先取已捕获输出快照再杀树,返回终态投影;taskId 不存在 → null
|
|
925
|
+
agent.killBackgroundTask(taskId: string): BackgroundTask | null
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
> ⚠️ 两者**未 `init()` 时抛 `configError`**(`assertInitialized` 门面统一契约),
|
|
929
|
+
> **不静默降级**——静默返回空会把「未初始化」伪装成「没有后台任务」。
|
|
930
|
+
|
|
931
|
+
```typescript
|
|
932
|
+
interface BackgroundTask {
|
|
933
|
+
taskId: string; // 寻址用(kill_command 传入它取回输出)
|
|
934
|
+
command: string;
|
|
935
|
+
startedAt: number; // 启动时间戳(ms)
|
|
936
|
+
status: 'running' | 'completed' | 'timedOut' | 'killed';
|
|
937
|
+
result?: ScriptExecutionResult; // 进入终态后才有
|
|
938
|
+
}
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
**寿命与可见性边界(务必转达用户)**:
|
|
942
|
+
|
|
943
|
+
* 结果**不会自动进入上下文**——需模型调 `kill_command` 传入该 `taskId`,取回截至当时的输出并终止;
|
|
944
|
+
* 不取则一直跑到自己结束(未传 `timeoutMs` 时**没有超时上限**);
|
|
945
|
+
* 正常退出 VS Code 时随扩展一并终止(扩展崩溃或被强制结束时不保证清理)。
|
|
946
|
+
|
|
947
|
+
> 注册表类 `BackgroundTaskRegistry` **不进公共导出面**(内核内部模块):导出它会让宿主
|
|
948
|
+
> 跨会话 kill,与「仅可杀本 agent 起的后台任务」定案冲突——故**只出方法、不出类**;
|
|
949
|
+
> 类型 `BackgroundTask` 与状态词表 `BACKGROUND_TASK_STATUS_LABELS`(宿主 UI 渲染状态
|
|
950
|
+
> 文案的唯一真源,禁自建第二套)经 `@zooique/memora` 导出。
|
|
951
|
+
|
|
952
|
+
---
|
|
953
|
+
|
|
954
|
+
## 九、作品投影(`agent.works` · WorkProjectionManager)
|
|
955
|
+
|
|
956
|
+
> 注:`WorkProjectionManager` 自 4.0.0 起为**内部类型**(不可具名 import),此处仅作 `agent.works` 的签名描述;可具名 import 的公开面以 §十六 为准。
|
|
957
|
+
|
|
958
|
+
作品投影是**项目文件的「极简指针索引」**:一张清单,记录项目关键文件的 `name`(文件名)+ `description`(一句话说明)+ `source`(源文件路径),存储在**项目级文件** `<memoraDir>/work-projections.json`(JSON 数组,不进入记忆库)。**只存指针不存内容**——AI 按 `description` 自主判断相关性,再按需 `read_file` 读取 `source` 原文(设计详述见 [architecture/work-projection.md](architecture/work-projection.md))。
|
|
959
|
+
|
|
960
|
+
> **与记忆系统的边界**:作品投影是"作品感知"而非"对话记忆"(对话记忆唯一为 round-summary,沉淀在记忆库)。它**不参与记忆召回、不参与记忆治理**(去重/冲突检测不覆盖),随项目隔离——换项目即消失。装配链已在系统提示词自动注入投影块(`contextBlock()`),宿主无需手动注入。
|
|
961
|
+
|
|
962
|
+
### 类型定义
|
|
963
|
+
|
|
964
|
+
```typescript
|
|
965
|
+
interface WorkProjectionEntry {
|
|
966
|
+
name: string; // 作品名(默认取源文件名去扩展名)
|
|
967
|
+
description: string; // 一句话说明(告诉 AI 这个文件是干什么的)
|
|
968
|
+
source: string; // 源文件路径(相对项目根,指向真实文件)
|
|
969
|
+
}
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
### `agent.works` 公开方法
|
|
973
|
+
|
|
974
|
+
| 方法 | 用途 |
|
|
975
|
+
|------|------|
|
|
976
|
+
| `agent.works.registerWork(sourcePath, description)` | 登记作品索引(`register_work` 工具数据源):同 `source` 覆盖、否则追加;写入为「读盘 refresh → 追加 → 原子写盘」。预存文件格式异常(非顶层 JSON 数组)时**拒绝写入**防覆盖原索引(fail-safe) |
|
|
977
|
+
| `agent.works.refresh()` | 从磁盘重新同步条目缓存,返回当前条目 |
|
|
978
|
+
| `agent.works.listWorks()` | 列出全部投影条目(读盘同步后返回) |
|
|
979
|
+
| `agent.works.contextBlock()` | 生成系统提示词注入块(`【项目索引】` 段;无条目返回空串) |
|
|
980
|
+
| `agent.works.loadAndGetContextBlock()` | `refresh()` + `contextBlock()` 的组合 |
|
|
981
|
+
|
|
982
|
+
> **注意**:`agent.works` 在 `init()` 前返回 `null`。内核侧**零 LLM 依赖**(纯读写、无后台任务);`description` 可由宿主生成后传入(vscode 命令即先经 LLM 生成一句话描述、失败时用文件名兜底)。并发:当前为单 Agent 单进程场景,`registerWork` 无文件锁。
|
|
983
|
+
|
|
984
|
+
### 宿主接入示例
|
|
985
|
+
|
|
986
|
+
```typescript
|
|
987
|
+
// vscode 宿主命令(memora.registerWork):把工作区文件登记为作品索引
|
|
988
|
+
const relativePath = vscode.workspace.asRelativePath(targetUri);
|
|
989
|
+
// 宿主可选:先自行生成一句话描述(LLM 或用户输入)——内核只负责落盘
|
|
990
|
+
const result = await agent.works?.registerWork(relativePath, description);
|
|
991
|
+
// result: WorkProjectionEntry | null(null = 路径越界或索引文件格式异常被拒写)
|
|
992
|
+
```
|
|
993
|
+
|
|
994
|
+
---
|
|
995
|
+
|
|
996
|
+
## 十、Provider 管理
|
|
997
|
+
|
|
998
|
+
| 方法 | 用途 |
|
|
999
|
+
|------|------|
|
|
1000
|
+
| `setProvider(provider)` | 运行时切换前台 Provider |
|
|
1001
|
+
| `setBackgroundProvider(provider)` | 运行时切换后台 Provider |
|
|
1002
|
+
|
|
1003
|
+
Agent 不再管理 Provider 映射表,宿主自行管理。
|
|
1004
|
+
|
|
1005
|
+
---
|
|
1006
|
+
|
|
1007
|
+
## 十一、内部调试
|
|
1008
|
+
|
|
1009
|
+
> v1.0 起已移除 `getBuildCtx()` 和 `inspect()` 方法。宿主项目可通过以下渠道观察内核状态:
|
|
1010
|
+
>
|
|
1011
|
+
> - **事件系统**(§2.7):订阅 `memoryAdded` / `memoryRecalled` / `sessionArchived` 等事件获取运行时动态
|
|
1012
|
+
> - **可观测性 Tracer**(§十三):注入 `ITracer` 实现获取 AgentLoop 关键 span(LLM_CALL / TOOL_EXEC / RESPONSE——`RECALL` 已随自动召回退役、内核零发射点)
|
|
1013
|
+
> - **`agent.memory.snapshot()`**(§4.1):获取 3 层记忆快照(working / bootstrap / archive)
|
|
1014
|
+
> - **`agent.agentLoop.getMessages()`**(§4.4):获取工作记忆原始消息列表
|
|
1015
|
+
|
|
1016
|
+
---
|
|
1017
|
+
|
|
1018
|
+
## 十二、完整 API 一览
|
|
1019
|
+
|
|
1020
|
+
### Agent 面类直接方法
|
|
1021
|
+
|
|
1022
|
+
| 分组 | 方法 |
|
|
1023
|
+
|------|------|
|
|
1024
|
+
| 生命周期 | `init()` / `close()` |
|
|
1025
|
+
| 对话 | `chat(input, signal?)` / `chatSync(input, signal?)` / `resumeExecution()` |
|
|
1026
|
+
| 事件 | `on()` / `off()` / `once()`(继承自 TypedEventEmitter) |
|
|
1027
|
+
| 暂停/继续 | `pause(reason, source?)` / `resume()` / `requestPause(reason, source?)` / `cancelPauseRequest()` / `isPausePending()` / `interject(content)` / `removePendingInterject(index)` / `clearPendingInterjections()` / `getPendingInterjections()` / `discardCurrentCheckpoint()` |
|
|
1028
|
+
| 会话 | `forkSession(targetSession?)` / `createCheckpoint()` / `getCheckpoint()` |
|
|
1029
|
+
| Provider | `setProvider(provider)` / `setBackgroundProvider(provider)` |
|
|
1030
|
+
| 归档模式 | `setArchiveMode(mode)` / `getArchiveMode()` |
|
|
1031
|
+
| 角色 | `switchRolePack(name)` / `getRolePackSwitchLockStatus()` / `getActiveTraits()` / `injectAffect(affectString)` |
|
|
1032
|
+
| 手动归档 | `archiveSession(...)` |
|
|
1033
|
+
| 配置热更新 | `reloadConfig(source?)` |
|
|
1034
|
+
| 后台任务 | `listBackgroundTasks()` / `killBackgroundTask(taskId)`(见 §8.7;未 `init()` 抛 `configError`,不静默降级) |
|
|
1035
|
+
| 记忆治理 | ~~经治理门面暴露~~ **该组方法已于 2026-10-18(5.0.0)整链退役**,理由为结构性恒空;`sourceHealth()` 的等价替代 = `agent.memory.stats().bySource`(见 §四 注记) |
|
|
1036
|
+
| 指标 | `getMetrics()` |
|
|
1037
|
+
|
|
1038
|
+
> **手动归档触发选项**(`archiveSession(date, session, options?)`,2026-10-19 起):
|
|
1039
|
+
> `options.autoTriggered`(系统自动触发;受 `archiveMode` 门控)+ `options.skipIfUnchanged`
|
|
1040
|
+
> (防重:距上次**实际完成归档**消息数未变则跳过 LLM。**缺省随 `autoTriggered`**——自动=防重、
|
|
1041
|
+
> 手动=无条件;显式传 `true` = 便捷手势也防重;显式 `false` = 强制重归档)。判据本体在
|
|
1042
|
+
> `SessionArchiver`(单点),协调器只转发意图。防重快照跨进程存活(内存态 + `SessionMeta.
|
|
1043
|
+
> archivedMessageCount` 落盘副本双源),宿主重启后不会重复烧 LLM;又聊过(消息数增)则一定
|
|
1044
|
+
> 重新归档。
|
|
1045
|
+
>
|
|
1046
|
+
> ⚠️ **该选项类型未具名导出**(`ArchiveTriggerOptions` 不在包导出面内):调用方传**结构字面量**
|
|
1047
|
+
> 即可(`archiveSession(d, s, { skipIfUnchanged: true })`),TS 随 `archiveSession` 签名推导类型。
|
|
1048
|
+
> 刻意不导出——公开面登记门槛守卫(`PUBLIC-API-SURFACE-1`)要求新增导出必须有真实具名消费或
|
|
1049
|
+
> 文档承诺,本类型两者皆无(宿主只按字面量用),导出即纯增面。
|
|
1050
|
+
|
|
1051
|
+
### Agent 面类只读访问器
|
|
1052
|
+
|
|
1053
|
+
`initialized` / `context` / `provider` / `isBusy` / `lastInteractionAt` / `agentLoop` / `agentHistory` / `projects` / `security` / `sessionManager` / `rolePack` / `tools` / `skills` / `memory` / `works` / `polish`
|
|
1054
|
+
|
|
1055
|
+
### 各 Manager / 组件公开成员
|
|
1056
|
+
|
|
1057
|
+
| 访问器 | 类型 | 公开成员 |
|
|
1058
|
+
|---------|---------|---------|
|
|
1059
|
+
| `agent.rolePack` | `RolePackManager` | `.listMeta()` / `.activeName` / `.getActive()` / `.getActiveRules()` / `.activate()` / `.getSwitchLockStatus()` / `.getActiveTraits()` |
|
|
1060
|
+
| `agent.tools` | `ToolExecutor` | `.list` / `.registerTool()` / `.execute()` |
|
|
1061
|
+
| `agent.skills` | `SkillManager` | `.list` / `.match()` / `.register()` / `.buildSystemPrompt()` |
|
|
1062
|
+
| ~~记忆治理门面~~ | ~~`MemoryGovernance`~~ | **已移除(2026-10-18 · 5.0.0)**:整链退役,无成员可调;健康度需求改走 `agent.memory.stats().bySource`(见 §四 注记) |
|
|
1063
|
+
| `agent.memory` | `MemoryInspector` | 读:`.snapshot()` / `.searchByKeyword()` / `.stats()` / `.list()` / `.getById()` / `.getBySource()` / `.listDeleted()`(**`.search()` 已于 4.0.0 移除**);写:`.writeUpsert()` / `.writeDelete()` / `.writeRestore()` / `.writePurge()` / `.writePurgeExpired()` |
|
|
1064
|
+
| `agent.works` | `WorkProjectionManager` | `.registerWork(sourcePath, description)` / `.refresh()` / `.listWorks()` / `.contextBlock()` / `.loadAndGetContextBlock()` |
|
|
1065
|
+
| `agent.polish` | `TextPolishManager` | `.polish(...)`(文本润色:LLM 语法修正 + 表达优化) |
|
|
1066
|
+
|
|
1067
|
+
> **说明**:记忆查询与写入**只有** `agent.memory`(`MemoryInspector`)一个入口。历史访问器 memoryMutator 与 MemoryMutator 类(4.0.0 前)已合并回 `MemoryInspector`;治理门面已于 5.0.0 整链退役(§四 注记)——三个旧名都不在源码中,读旧文档时勿按其名查找。
|
|
1068
|
+
|
|
1069
|
+
---
|
|
1070
|
+
|
|
1071
|
+
## 十三、可观测性(ITracer / ISpan)
|
|
1072
|
+
|
|
1073
|
+
Memora 内置轻量 Span/Trace 抽象,宿主注入实现后可观测 AgentLoop 行为。
|
|
1074
|
+
|
|
1075
|
+
### 13.1 ITracer 接口
|
|
1076
|
+
|
|
1077
|
+
```typescript
|
|
1078
|
+
interface ITracer {
|
|
1079
|
+
startSpan(name: string, attributes?: Record<string, string | number | boolean>): ISpan;
|
|
1080
|
+
}
|
|
1081
|
+
```
|
|
1082
|
+
|
|
1083
|
+
### 13.2 ISpan 接口
|
|
1084
|
+
|
|
1085
|
+
```typescript
|
|
1086
|
+
interface ISpan {
|
|
1087
|
+
setAttribute(key: string, value: string | number | boolean): void;
|
|
1088
|
+
end(): void;
|
|
1089
|
+
recordException(error: Error): void;
|
|
1090
|
+
}
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
### 13.3 NoopTracer(内核内部默认实现,**不挂公共面**)
|
|
1094
|
+
|
|
1095
|
+
**不注入 `tracer` 即零运行时开销**——内核自动降级为内部 Noop 实现,所有 span 方法为空操作。
|
|
1096
|
+
宿主无需、也不应引用任何 Noop 实现类;要「关闭追踪」就是不传 `tracer`。
|
|
1097
|
+
|
|
1098
|
+
### 13.4 TRACE_SPANS 常量
|
|
1099
|
+
|
|
1100
|
+
```typescript
|
|
1101
|
+
import { TRACE_SPANS } from '@zooique/memora';
|
|
1102
|
+
|
|
1103
|
+
TRACE_SPANS.LLM_CALL // 'llm.call' — LLM API 调用
|
|
1104
|
+
TRACE_SPANS.TOOL_EXEC // 'tool.execute' — 工具执行
|
|
1105
|
+
TRACE_SPANS.RESPONSE // 'response.generate' — 整轮响应
|
|
1106
|
+
TRACE_SPANS.CONTEXT_SUMMARY // 'context.summary' — 上下文摘要生成(消息超窗触发截断时)
|
|
1107
|
+
TRACE_SPANS.POST_PROCESS // 'archive.postProcess' — 每轮 chat() 后的归档处理
|
|
1108
|
+
TRACE_SPANS.DIFFICULTY // 'round.difficulty' — 难度分级(预留名)
|
|
1109
|
+
TRACE_SPANS.REPORT // 'round.report' — 汇报闭环(预留名)
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
> 共 **7** 个常量(数量由 `src/agent/__tests__/tracer.test.ts` 锁定)。
|
|
1113
|
+
>
|
|
1114
|
+
> **预留名**:`DIFFICULTY` / `REPORT` 内核当前**零 emit 点**——宿主按名建监控面板暂时收不到这两个 span 的数据,不要据此判定链路异常。
|
|
1115
|
+
>
|
|
1116
|
+
> **已删除**:`TRACE_SPANS.RECALL`(`'recall.recall'`)与 `TRACE_SPANS.RECALL_ACTUAL`(`'recall.actual'`)已于 **2026-09-11 物理删除**(自动记忆召回退役后无 emit 点,不留幽灵契约);现行记忆检索耗时看 `TOOL_EXEC`(`search_memories` 工具)。
|
|
1117
|
+
|
|
1118
|
+
---
|
|
1119
|
+
|
|
1120
|
+
## 十四、工具错误码(ToolErrorCode)
|
|
1121
|
+
|
|
1122
|
+
工具执行失败时,内核产出**结构化** `ToolOutcome`(完整契约见 §14.3)。与本表直接相关的两个字段:
|
|
1123
|
+
|
|
1124
|
+
* `errorCode` —— 失败原因分类,**Reflection 重试判定的判据面**;
|
|
1125
|
+
* `text` —— 渲染面,形如 `` `[ERR:TOOL:${code}] …` `` 给 LLM 自愈看。
|
|
1126
|
+
|
|
1127
|
+
**`text` 前缀由 `errorCode` 派生**(唯一构造出口 `failedOutcomeWithCode` 一次产出二者),
|
|
1128
|
+
故解析文案取码与读 `errorCode` 字段**恒等价**,不存在漂移。
|
|
1129
|
+
|
|
1130
|
+
### 14.1 错误码枚举
|
|
1131
|
+
|
|
1132
|
+
| 错误码 | 可重试 | 说明 |
|
|
1133
|
+
|--------|--------|------|
|
|
1134
|
+
| `PATH_NOT_ALLOWED` | ❌ | 路径不在白名单内 |
|
|
1135
|
+
| `FILE_NOT_FOUND` | ✅ | 文件不存在(LLM 可能用错路径) |
|
|
1136
|
+
| `PERMISSION_DENIED` | ❌ | 权限不足 |
|
|
1137
|
+
| `ARGUMENT_ERROR` | ✅ | 工具参数错误(LLM 可修正参数格式) |
|
|
1138
|
+
| `WRITE_REJECTED` | ❌ | 用户拒绝写入 |
|
|
1139
|
+
| `DIR_NOT_FOUND` | ✅ | 目录不存在 |
|
|
1140
|
+
| `UNKNOWN_TOOL` | ❌ | 未知工具 |
|
|
1141
|
+
| `CUSTOM_TOOL_FAILED` | ✅ | 自定义工具执行失败 |
|
|
1142
|
+
| `NOT_AVAILABLE` | ❌ | 能力未装配 / 未注入回调(provider 或技能回调缺失)——重试无意义 |
|
|
1143
|
+
| `UNKNOWN` | ❌ | 通用错误 |
|
|
1144
|
+
|
|
1145
|
+
> ⚠️ **订正(对齐 `src/utils/errors.ts` 实际枚举)**:旧版此表列有 `TOOL_TIMEOUT`(★可重试),
|
|
1146
|
+
> 该值**已从枚举删除**(删除后 retryable 由 5 → 4),属文档死条目,已移除。
|
|
1147
|
+
> 另:结果文本里会出现 `[ERR:TOOL:ABORTED]`,但 `ABORTED` **故意不入本枚举**
|
|
1148
|
+
> (中断不触发 Reflection,见 `toolRunner`),勿按本表去找它。
|
|
1149
|
+
|
|
1150
|
+
### 14.2 isRetryableErrorCode()
|
|
1151
|
+
|
|
1152
|
+
```typescript
|
|
1153
|
+
import { ToolErrorCode, isRetryableErrorCode } from '@zooique/memora';
|
|
1154
|
+
|
|
1155
|
+
isRetryableErrorCode(ToolErrorCode.FILE_NOT_FOUND); // true
|
|
1156
|
+
isRetryableErrorCode(ToolErrorCode.PATH_NOT_ALLOWED); // false
|
|
1157
|
+
```
|
|
1158
|
+
|
|
1159
|
+
### 14.3 `ToolOutcome` — 工具结果契约(status 三值 + errorCode)
|
|
1160
|
+
|
|
1161
|
+
工具结果在内核内部与可观测面共用同一形状(`agent/managers/toolCallHelpers`):
|
|
1162
|
+
|
|
1163
|
+
> **可观测性说明(勿踩空)**:`ToolOutcome` 是**内核内部**形状,
|
|
1164
|
+
> **未从 `@zooique/memora` 导出**(`src/index.ts` 无此导出),**不要尝试 import 它**。
|
|
1165
|
+
> 宿主是**间接**观察它的:`tool_result` chunk 的 `ok` / `blocked` 字段即由 `status` 派生
|
|
1166
|
+
> (`ok` ⇔ `status==='ok'`,`blocked` ⇔ `status==='blocked'`),计数经 `getMetrics()` 暴露。
|
|
1167
|
+
> 本节列出它是为了说清三值语义与计数口径,不是新增可导入类型。
|
|
1168
|
+
|
|
1169
|
+
```typescript
|
|
1170
|
+
interface ToolOutcome {
|
|
1171
|
+
readonly status: ToolStatus; // 'ok' | 'failed' | 'blocked' —— 判据面唯一真源
|
|
1172
|
+
readonly text: string; // 渲染面(原样回给 LLM 自愈)
|
|
1173
|
+
readonly blockedReason?: BlockedReason; // 仅 blocked:为什么没成功(与 status 正交)
|
|
1174
|
+
readonly hasRealFailure?: boolean; // 仅 blocked:背后是否藏真失败
|
|
1175
|
+
readonly errorCode?: ToolErrorCodeValue; // 仅 failed:失败原因分类(见 §14.1)
|
|
1176
|
+
}
|
|
1177
|
+
```
|
|
1178
|
+
|
|
1179
|
+
| `status` | 语义 | 计入 `toolFailureCount`? |
|
|
1180
|
+
|-----------|------|---------------------------|
|
|
1181
|
+
| `ok` | 工具正常执行完成(**含"成功但无输出"**:`exitCode 0` + 空输出仍是成功) | ❌ |
|
|
1182
|
+
| `failed` | 工具真的跑了但失败(非零退出 / 超时 / 抛异常 / 参数非法 / 资源不存在) | ✅ |
|
|
1183
|
+
| `blocked` | **我们主动挡下的**(护栏拦截 / 只读拒绝 / 幂等跳过 / fail-closed 拒绝) | ❌(改计 `toolBlockedCount`) |
|
|
1184
|
+
|
|
1185
|
+
**纪律(勿回改)**:
|
|
1186
|
+
|
|
1187
|
+
1. `blocked` 既非成功也非失败——「主动挡下的 ≠ 工具跑失败的」,三值穷尽,不加第四值;
|
|
1188
|
+
2. 消费者判成败**一律读 `status` 字段**,不得解析 `text`(B4/B5 后内核零文本判据,
|
|
1189
|
+
`isToolFailure` 文本判据桥已物理删除);
|
|
1190
|
+
3. `blockedReason` 与 `status` 正交——前者只回答「为什么没成功」,不新增 status 值;
|
|
1191
|
+
4. `errorCode` 与 `text` 前缀在 `failedOutcomeWithCode` **同源产出一次**,改一处即两处同步。
|
|
1192
|
+
|
|
1193
|
+
---
|
|
1194
|
+
|
|
1195
|
+
## 十五、工具错误反思(Reflection)
|
|
1196
|
+
|
|
1197
|
+
> 注:原「内容护栏(Guardrails)」章节已移除——guardrail 是「零规则、无扫描映射、无消费者」的空转链,已随内核摘除(2026-08-17,见 memory-role-pack-boundary.md §4.4)。本章仅保留原 15.3 的有效内容。
|
|
1198
|
+
|
|
1199
|
+
当工具执行失败且错误码为 retryable 时,AgentLoop 自动注入 `[REFLECTION_HINT]` 系统消息,引导 LLM 修正参数后重试。默认最多重试 2 次(`maxReflectionRetries`)。
|
|
1200
|
+
|
|
1201
|
+
> ⚠️ **执行类失败不进自动 Reflection(设计口径,非回归)**:`run_command` / `run_code` / `run_project_script` / `run_skill_script` 四条执行链路失败时返回**不带 `errorCode`** 的失败结果,不满足上述「retryable 错误码」触发条件,AgentLoop 因此不注入 `[REFLECTION_HINT]`。结局事实(超时 / 非零退出码 / 许可拒绝等)已完整呈现在返回文本里,LLM 读到后自行决定是否调整重试;自动重试机制只服务于带 retryable 错误码的工具失败(错误码全集见 §十四)。
|
|
1202
|
+
|
|
1203
|
+
---
|
|
1204
|
+
|
|
1205
|
+
## 十六、类型导出
|
|
1206
|
+
|
|
1207
|
+
> 以下**精选子集**为宿主最常用的公开导出,全部经 `@zooique/memora` 再导出(无幻影);未在清单中的其他导出(如 `SessionManager` / `ProviderRouter` 等)以 `src/index.ts` 为准。导出面已于 2026-10-06 收敛:只保留「宿主消费」或「本手册 / README 明文承诺」的符号,内部实现不再挂公共面。治理报告类型(`DedupReport` / `SourceHealthReport` 等)经方法返回推断,不列为显式导出。
|
|
1208
|
+
|
|
1209
|
+
> ⚠️ **正文表格里的类型名以本节清单为准**(不等于本节是全集——未列出的导出见上方首注,以 `src/index.ts` 为准):正文(§二 ~ §十五)表格「类型」列里的名字只用于**描述签名**,其中一部分自 4.0.0 起已降为内部类型——它们**不可具名导入**(深导入不可达),类型随 agent 对象的返回值推断即可用。
|
|
1210
|
+
|
|
1211
|
+
```typescript
|
|
1212
|
+
// Agent 与流式事件
|
|
1213
|
+
export { Agent } from '@zooique/memora';
|
|
1214
|
+
export type {
|
|
1215
|
+
AgentChunk,
|
|
1216
|
+
ThinkingPhase,
|
|
1217
|
+
UIMessages,
|
|
1218
|
+
ArchiveMode,
|
|
1219
|
+
} from '@zooique/memora';
|
|
1220
|
+
export type {
|
|
1221
|
+
AgentOptions,
|
|
1222
|
+
AgentContext,
|
|
1223
|
+
} from '@zooique/memora';
|
|
1224
|
+
export { type AgentForkResult } from '@zooique/memora';
|
|
1225
|
+
export type { SessionCheckpoint } from '@zooique/memora';
|
|
1226
|
+
|
|
1227
|
+
// 记忆快照与搜索(MemoryInspector)
|
|
1228
|
+
export type {
|
|
1229
|
+
MemorySnapshot,
|
|
1230
|
+
WorkingMemorySnapshot,
|
|
1231
|
+
BootstrapSnapshot,
|
|
1232
|
+
ArchiveSnapshot,
|
|
1233
|
+
AgentSearchHit,
|
|
1234
|
+
AgentStats,
|
|
1235
|
+
} from '@zooique/memora';
|
|
1236
|
+
// 记忆治理门面已于 5.0.0(2026-10-18)整链退役,健康度替代通道见 §四 注记
|
|
1237
|
+
// 文本润色
|
|
1238
|
+
export type { PolishResult } from '@zooique/memora';
|
|
1239
|
+
export { AGENT_CONSTANTS, LOOP_CONSTANTS } from '@zooique/memora';
|
|
1240
|
+
|
|
1241
|
+
// 工具
|
|
1242
|
+
export type { ToolDefinition, ToolHandler, ToolContext, WriteExtensions } from '@zooique/memora';
|
|
1243
|
+
// 网页抓取(搜索→抓取闭环第二段)
|
|
1244
|
+
export type { IFetchProvider, FetchedPage, FetchOptions } from '@zooique/memora';
|
|
1245
|
+
export { FetchWebFetchProvider } from '@zooique/memora';
|
|
1246
|
+
// 代码执行(通用计算底座)
|
|
1247
|
+
export type { ICodeExecutionProvider, CodeExecutionResult, CodeExecutionOptions } from '@zooique/memora';
|
|
1248
|
+
|
|
1249
|
+
// 作品投影
|
|
1250
|
+
export type { WorkProjectionEntry } from '@zooique/memora';
|
|
1251
|
+
|
|
1252
|
+
// 记忆
|
|
1253
|
+
export { SOURCE_LABELS, SUMMARY_TYPES } from '@zooique/memora';
|
|
1254
|
+
export type { Memory } from '@zooique/memora';
|
|
1255
|
+
export { validateSource } from '@zooique/memora';
|
|
1256
|
+
export type { SourceValidationSeverity } from '@zooique/memora';
|
|
1257
|
+
export type { IMemoryStorage } from '@zooique/memora';
|
|
1258
|
+
// 记忆存储落盘实现(工厂 + 只读视图)
|
|
1259
|
+
export { createNodeSqliteStorage } from '@zooique/memora';
|
|
1260
|
+
export type { ReadOnlyMemoryStorage } from '@zooique/memora';
|
|
1261
|
+
export type { ISessionStore, SessionMessage } from '@zooique/memora';
|
|
1262
|
+
export type { ForkResult } from '@zooique/memora';
|
|
1263
|
+
|
|
1264
|
+
// 事件系统
|
|
1265
|
+
export { TypedEventEmitter } from '@zooique/memora';
|
|
1266
|
+
export type { AgentEventMap, AgentEventName, AgentEventHandler } from '@zooique/memora';
|
|
1267
|
+
|
|
1268
|
+
// 可观测性
|
|
1269
|
+
export type { ITracer, ISpan, AgentMetrics } from '@zooique/memora';
|
|
1270
|
+
export { TRACE_SPANS } from '@zooique/memora';
|
|
1271
|
+
|
|
1272
|
+
// 错误码
|
|
1273
|
+
export { MemoraError, ToolErrorCode, isRetryableErrorCode } from '@zooique/memora';
|
|
1274
|
+
export type { ToolErrorCodeValue } from '@zooique/memora';
|
|
1275
|
+
|
|
1276
|
+
// 日志
|
|
1277
|
+
export type { ILogger } from '@zooique/memora';
|
|
1278
|
+
export { setLogger, logger } from '@zooique/memora';
|
|
1279
|
+
|
|
1280
|
+
// 网络搜索
|
|
1281
|
+
export type { IWebSearchProvider, SearchResult, WebSearchOptions, SearchEndpoint } from '@zooique/memora';
|
|
1282
|
+
export { FetchWebSearchProvider } from '@zooique/memora';
|
|
1283
|
+
|
|
1284
|
+
// 角色包
|
|
1285
|
+
export type { RolePackMeta } from '@zooique/memora';
|
|
1286
|
+
|
|
1287
|
+
// 技能
|
|
1288
|
+
export type { SkillEntry } from '@zooique/memora';
|
|
1289
|
+
|
|
1290
|
+
// LLM
|
|
1291
|
+
export { createProviderFromConfig } from '@zooique/memora';
|
|
1292
|
+
export type { ProviderConfig } from '@zooique/memora';
|
|
1293
|
+
export type { LlmProvider, ChatOptions } from '@zooique/memora';
|
|
1294
|
+
export type { LlmChunk } from '@zooique/memora';
|
|
1295
|
+
|
|
1296
|
+
// 配置
|
|
1297
|
+
export { loadConfig } from '@zooique/memora';
|
|
1298
|
+
export type { Config } from '@zooique/memora';
|
|
1299
|
+
|
|
1300
|
+
// 工具函数
|
|
1301
|
+
export { segmentLower } from '@zooique/memora';
|
|
1302
|
+
export { parseFrontmatter } from '@zooique/memora';
|
|
1303
|
+
export { formatDateKey, todayDate } from '@zooique/memora';
|
|
1304
|
+
|
|
1305
|
+
// 安全
|
|
1306
|
+
export type {
|
|
1307
|
+
AuditEvent,
|
|
1308
|
+
AuditListener,
|
|
1309
|
+
Permission,
|
|
1310
|
+
WriteDecision,
|
|
1311
|
+
WriteConfirmationInfo,
|
|
1312
|
+
WriteConfirmationRequest,
|
|
1313
|
+
} from '@zooique/memora';
|
|
1314
|
+
```
|
|
1315
|
+
|
|
1316
|
+
> **记忆存储落盘实现(2026-10-16 新增,内核切片)**:`createNodeSqliteStorage`(**同步工厂**,收数据库文件全长路径,
|
|
1317
|
+
> 返回 `IMemoryStorage`)与 `ReadOnlyMemoryStorage`(**只读视图类型**,即 `IMemoryStorage` 的读方法子集)。
|
|
1318
|
+
> 契约要点:① **只出工厂不出实现类**——实现类不挂公共面,须经工厂创建;② **可用性判据唯一来源 = 调用工厂的结果**
|
|
1319
|
+
> (模块不可用时抛专属错误,其错误码为 `ToolErrorCode.NOT_AVAILABLE`);宿主**不得**自行解析 Node 版本号推断;
|
|
1320
|
+
> ③ **只读视图**:工厂第二参数为只读开关,返回对象**结构上不含写方法**(供只读宿主零并列复用同一实现),
|
|
1321
|
+
> 只读连接不建库、不迁移;④ 文件路径语义留在宿主侧(内核不拼目录、不定义文件名);⑤ 实现仅依赖 Node 内建模块,
|
|
1322
|
+
> 不引入第三方运行时依赖。稳定性:随 `5.0.0` 起提供,语义受契约对拍测试(与内核内置内存实现逐位一致)约束。
|
|
1323
|
+
|
|
1324
|
+
---
|
|
1325
|
+
|
|
1326
|
+
## 十七、安全与约束
|
|
1327
|
+
|
|
1328
|
+
### 核心库零越界
|
|
1329
|
+
|
|
1330
|
+
| 检查项 | 结论 |
|
|
1331
|
+
|--------|------|
|
|
1332
|
+
| 核心库 `console.*` 调用 | 0 处 |
|
|
1333
|
+
| 核心库 `process.stdin/stdout` | 0 处 |
|
|
1334
|
+
| 核心库写配置文件 | 0 处 |
|
|
1335
|
+
| 核心库 `readFileSync/writeFileSync` 写宿主业务文件 | 0 处 |
|
|
1336
|
+
|
|
1337
|
+
### 内部数据写入(不越界)
|
|
1338
|
+
|
|
1339
|
+
Agent 内部只维护一个状态文件,路径全部由宿主传入的路径推导,内核不假设 `~/.memora/` 一类的用户级默认位置:
|
|
1340
|
+
|
|
1341
|
+
- `.lock`(项目锁)——固定落 `<projectPath>/.memora/.lock`,**不由 `dataDir` 推导**
|
|
1342
|
+
|
|
1343
|
+
`dataDir` 仅作 Agent 级资源目录(确保存在);宿主注入 `IMemoryStorage` 时内核**不**在该目录下
|
|
1344
|
+
落任何文件。(PR-SWITCH-1 前内核曾在此写 `projects.json` 跨项目注册表,随多项目形态定案删除。)
|
|
1345
|
+
|
|
1346
|
+
---
|
|
1347
|
+
|
|
1348
|
+
**版本**:v5.0.0
|
|
1349
|
+
**配套文档**:[memora-接入指南.md](./memora-接入指南.md)(步骤式教程)
|