amrita_plugin_memory 0.1.6__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. amrita_plugin_memory-0.2.1/PKG-INFO +221 -0
  2. amrita_plugin_memory-0.2.1/README.md +205 -0
  3. amrita_plugin_memory-0.2.1/amrita_plugin_memory/__init__.py +9 -0
  4. {amrita_plugin_memory-0.1.6 → amrita_plugin_memory-0.2.1}/amrita_plugin_memory/config.py +61 -0
  5. {amrita_plugin_memory-0.1.6 → amrita_plugin_memory-0.2.1}/amrita_plugin_memory/tools.py +2 -2
  6. amrita_plugin_memory-0.2.1/amrita_plugin_memory.egg-info/PKG-INFO +221 -0
  7. {amrita_plugin_memory-0.1.6 → amrita_plugin_memory-0.2.1}/amrita_plugin_memory.egg-info/requires.txt +1 -0
  8. {amrita_plugin_memory-0.1.6 → amrita_plugin_memory-0.2.1}/pyproject.toml +3 -1
  9. amrita_plugin_memory-0.1.6/PKG-INFO +0 -187
  10. amrita_plugin_memory-0.1.6/README.md +0 -172
  11. amrita_plugin_memory-0.1.6/amrita_plugin_memory/__init__.py +0 -8
  12. amrita_plugin_memory-0.1.6/amrita_plugin_memory.egg-info/PKG-INFO +0 -187
  13. {amrita_plugin_memory-0.1.6 → amrita_plugin_memory-0.2.1}/LICENSE +0 -0
  14. {amrita_plugin_memory-0.1.6 → amrita_plugin_memory-0.2.1}/amrita_plugin_memory/embed.py +0 -0
  15. {amrita_plugin_memory-0.1.6 → amrita_plugin_memory-0.2.1}/amrita_plugin_memory/matchers.py +0 -0
  16. {amrita_plugin_memory-0.1.6 → amrita_plugin_memory-0.2.1}/amrita_plugin_memory/vector.py +0 -0
  17. {amrita_plugin_memory-0.1.6 → amrita_plugin_memory-0.2.1}/amrita_plugin_memory.egg-info/SOURCES.txt +0 -0
  18. {amrita_plugin_memory-0.1.6 → amrita_plugin_memory-0.2.1}/amrita_plugin_memory.egg-info/dependency_links.txt +0 -0
  19. {amrita_plugin_memory-0.1.6 → amrita_plugin_memory-0.2.1}/amrita_plugin_memory.egg-info/top_level.txt +0 -0
  20. {amrita_plugin_memory-0.1.6 → amrita_plugin_memory-0.2.1}/setup.cfg +0 -0
@@ -0,0 +1,221 @@
1
+ Metadata-Version: 2.4
2
+ Name: amrita_plugin_memory
3
+ Version: 0.2.1
4
+ Summary: Amrita长期记忆插件
5
+ Requires-Python: <3.14,>=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: aiohttp>=3.13.3
9
+ Requires-Dist: aiologic>=0.16.0
10
+ Requires-Dist: amrita-core>=0.8.5
11
+ Requires-Dist: amrita>=1.3
12
+ Requires-Dist: chromadb>=1.5.8
13
+ Requires-Dist: nonebot-plugin-apscheduler>=0.5.0
14
+ Requires-Dist: nonebot-plugin-localstore>=0.7.4
15
+ Dynamic: license-file
16
+
17
+ # amrita_plugin_memory
18
+
19
+ Amrita Harness 记忆增强插件 — 双层架构:表层 Function Calling 记忆工具 + 底层常驻推理循环 Agent。
20
+
21
+ **表层** — LLM 对话中按需调用 5 个记忆工具(读写删改列),基于 ChromaDB 语义检索。
22
+ **底层** — 后台 Agent 定时自动扫描、去重、合并、压缩记忆库,基于 Core Agent 框架 + Harness 模式复用 ChatObject。
23
+
24
+ ## 双层架构
25
+
26
+ ```mermaid
27
+ flowchart TB
28
+ subgraph Surface["表层:Long-Term Memory Tools"]
29
+ S_LLM["对话 LLM"] -->|"write_memory"| S_Write["写入记忆"]
30
+ S_LLM -->|"read_memory"| S_Read["语义检索"]
31
+ S_LLM -->|"update/delete/list"| S_Mut["更新 / 删除 / 列表"]
32
+ S_Write --> ChromaDB[("ChromaDB<br/>向量数据库")]
33
+ S_Read --> ChromaDB
34
+ S_Mut --> ChromaDB
35
+ end
36
+
37
+ subgraph Subconscious["底层:Subconscious Reasoning Loop"]
38
+ APScheduler["APScheduler<br/>定时触发"] --> Runner["SubconsciousRunner"]
39
+ Runner --> ChatObject["ChatObject<br/>(Harness 容器)"]
40
+ ChatObject --> WF["Workflow 管线"]
41
+ WF --> LM["LIMITING_MEMORY<br/>Core MemoryLimiter"]
42
+ LM --> Build["BUILD_MESSAGE"]
43
+ Build --> Init["STRATEGY_INIT"]
44
+ Init --> AgentLoop["ReAct Agent Loop<br/>WHILE(SINGLE_STRATEGY_CALL)"]
45
+ AgentLoop -->|"工具调用"| STools["subconscious_* 工具"]
46
+ STools --> ChromaDB
47
+ AgentLoop -->|"subconscious_iter_stop"| APScheduler
48
+ end
49
+
50
+ Surface -.->|"共享 ChromaDB"| Subconscious
51
+ Runner -->|"持久化状态"| CachedRepo["CachedUserDataRepository<br/>uid=amritabot_inner_thinker"]
52
+ Runner -->|"usage 统计"| Insights["InsightsModel<br/>全局 Token 统计"]
53
+ ```
54
+
55
+ ## Harness 模式
56
+
57
+ `SubconsciousRunner` 不自己管理推理循环,而是将 **ChatObject 作为数据容器**,注入自定义 `SubconsciousBackend` + Core `ReActAgentStrategy`,通过替换 `_workflow` / `_interpreter` 复用完整的 Core Agent 管线:
58
+
59
+ ```
60
+ LOAD_STATE → JINJA2_RENDER → LIMITING_MEMORY → BUILD_MESSAGE → STRATEGY_INIT
61
+ → AGENT_ENTRY → WHILE(SINGLE_STRATEGY_CALL).ACTION(REACT_COUNTER)
62
+ ```
63
+
64
+ `LIMITING_MEMORY` **在 Agent Loop 之前**运行 Core `MemoryLimiter`:消息截断 → token 限制 → 自动生成摘要。摘要通过 Core Jinja2 模板 `<SUMMARY>` 标签注入 prompt。
65
+
66
+ 暂停时 `dump_interpreter()`,恢复时 `rebase_context()`,毫秒级断点续推理。
67
+
68
+ ## 技术栈
69
+
70
+ | 组件 | 技术 |
71
+ | ---------- | --------------------------------------------------------- |
72
+ | 后端框架 | Python 3.11+ / NoneBot2 / AmritaCore / AmritaSense |
73
+ | 向量数据库 | ChromaDB(PersistentClient / HttpClient) |
74
+ | 嵌入模型 | OpenAI Embedding / Ollama Embedding |
75
+ | 调度引擎 | nonebot_plugin_apscheduler |
76
+ | 持久化 | CachedUserDataRepository(uid=`amritabot_inner_thinker`) |
77
+ | Token 统计 | InsightsModel(复用 Bot 全局 usage 统计) |
78
+ | 配置管理 | Pydantic + TOML |
79
+ | 代码质量 | Ruff + Pyright |
80
+
81
+ ## 功能
82
+
83
+ ### 表层:长期记忆
84
+
85
+ | 功能 | 说明 |
86
+ | -------- | ------------------------------------------------ |
87
+ | 语义检索 | ChromaDB 嵌入向量相似度搜索,中日英多语言 |
88
+ | 分区隔离 | `scope="user"` 个人记忆 / `scope="group"` 群共享 |
89
+ | 重要性 | low / medium / high 三级,支持过滤 |
90
+ | 标签分类 | 自定义标签(preference、project、personal 等) |
91
+ | 过期清理 | 短/长/永久三级过期天数可配置 |
92
+ | 并发安全 | 用户 ID 粒度 `aiologic.Lock` |
93
+
94
+ ### 底层:常驻推理循环
95
+
96
+ | 功能 | 说明 |
97
+ | ---------- | ---------------------------------------------------------------- |
98
+ | 自动整理 | LLM 后台去重、合并、标签补全、低质清理 |
99
+ | 自调度 | `subconscious_iter_stop` 返回下次运行时间 |
100
+ | 记忆压缩 | Core `MemoryLimiter` 截断超限消息 + 自动生成摘要 |
101
+ | 去重辅助 | `subconscious_duplicate_helper` 返回待整理记忆 + 合并指导 prompt |
102
+ | 统计概览 | `subconscious_get_memory_stats` 总量/重要性分布/标签分布 |
103
+ | 膨胀感知 | ChromaDB 超 `memory_warn_threshold` 时自动注入压缩提示 |
104
+ | 滑动窗口 | `max_abstracts` 轮摘要保留,跨轮传递进度 |
105
+ | 暂停协调 | 目标用户聊天时自动暂停+随机延迟恢复 |
106
+ | 主动消息 | LLM 向用户发起主动问候(需 `allow_send_to_user`) |
107
+ | Token 统计 | 复用 Bot `InsightsModel` 全局统计,无需额外维护 |
108
+
109
+ ## 工具
110
+
111
+ ### 表层工具(`tools.py`)
112
+
113
+ LLM 在对话中按需调用,受 `scope` 分区隔离:
114
+
115
+ | 工具 | 参数 |
116
+ | --------------- | -------------------------------------------- |
117
+ | `write_memory` | content, tags, importance(enum), scope(enum) |
118
+ | `read_memory` | query, top_k(5), importance?, scope(enum) |
119
+ | `update_memory` | id, scope, content?, tags?, importance? |
120
+ | `delete_memory` | id, scope |
121
+ | `list_memory` | limit, scope |
122
+
123
+ ### 潜意识工具(`rethinking/tools.py`)
124
+
125
+ 仅供 Subconscious Agent 使用,不暴露给对话 LLM:
126
+
127
+ | 工具 | 用途 |
128
+ | -------------------------------- | ------------------------------------------- |
129
+ | `subconscious_read_memory` | 语义检索(硬编码 user scope) |
130
+ | `subconscious_write_memory` | 写入新记忆 |
131
+ | `subconscious_update_memory` | 更新指定 ID 记忆 |
132
+ | `subconscious_delete_memory` | 删除指定 ID 记忆 |
133
+ | `subconscious_list_memory` | 列出全部记忆 |
134
+ | `subconscious_iter_stop` | 结束本轮,设置下次运行时间 |
135
+ | `subconscious_send_to_user` | 主动向用户发消息(需 allow_send_to_user) |
136
+ | `subconscious_read_chat_context` | 读取用户最近聊天记录 |
137
+ | `subconscious_duplicate_helper` | 返回全部记忆 + LLM 合并指导 prompt(去重) |
138
+ | `subconscious_get_memory_stats` | 统计概览:总数/重要性分布/标签分布/时间范围 |
139
+
140
+ ## 配置
141
+
142
+ ### `config/amrita_plugin_memory/config.toml`
143
+
144
+ ```toml
145
+ # 记忆过期
146
+ short_term_expiry_days = 3
147
+ long_term_expiry_days = 30
148
+ permanent_expiry_days = 365
149
+ per_session_memory_limit = 50
150
+
151
+ # 常驻推理循环
152
+ [subconscious]
153
+ enabled = false # 是否启用
154
+ experimental = true # 实验性标注
155
+ target_user_id = "" # 目标用户 ID(为空则不启用)
156
+ allowed_tools = [] # 额外可用工具
157
+ max_iterations = 10 # 单轮 ReAct 最大步数
158
+ loop_detect_threshold = 3 # 连续同工具触发警告阈值
159
+ initial_delay_seconds = 60 # 启动后首轮延迟
160
+ default_interval_seconds = 600# LLM 未指定时默认间隔
161
+ pause_on_user_chat = true # 用户聊天时自动暂停
162
+ pause_wakeup_min_seconds = 180# 暂停后最小唤醒延迟
163
+ pause_wakeup_max_seconds = 480# 暂停后最大唤醒延迟
164
+ prompt_file = "subconscious_prompt.txt"
165
+ enable_memory_compress = true # 启用 MemoryLimiter 上下文压缩
166
+ allow_send_to_user = false # 允许 Agent 主动发消息
167
+ memory_warn_threshold = 100 # ChromaDB 超此数量注入压缩提示
168
+ max_abstracts = 5 # 摘要滑动窗口大小
169
+ ```
170
+
171
+ ### 提示词模板
172
+
173
+ 两个 Jinja2 模板文件位于 `config/amrita_plugin_memory/`:
174
+
175
+ **`subconscious_prompt.txt`** — Agent 系统提示词(由 `prompt_file` 配置指定)
176
+
177
+ | 模板变量 | 说明 |
178
+ | ------------------------ | ------------------------------------ |
179
+ | `{{ character_prompt }}` | Bot 当前角色设定(从 `config/chat/private_prompts/` 读取) |
180
+ | `{{ last_run }}` | 上一轮 MemoryLimiter 产出的摘要 |
181
+ | `{{ last_abstracts }}` | 最近 N 轮摘要列表(max_abstracts 控制) |
182
+ | `{{ current_time }}` | 当前 UTC 时间 |
183
+ | `{{ target_user_id }}` | 目标用户 ID |
184
+ | `{{ total_runs }}` | 累计运行轮数 |
185
+
186
+ **`subconscious_send_prompt.txt`** — 主动消息生成模板
187
+
188
+ | 模板变量 | 说明 |
189
+ | ------------------------ | ------------------------------------ |
190
+ | `{{ character_prompt }}` | Bot 当前角色设定 |
191
+ | `{{ intent }}` | LLM 指定的消息意图 |
192
+ | `{{ memory_context }}` | 关联的记忆上下文 |
193
+ | `{{ current_time }}` | 当前 UTC 时间 |
194
+
195
+ ### 环境变量(`.env`)
196
+
197
+ | 变量 | 类型 | 默认值 | 说明 |
198
+ | ------------------------- | ------------------- | ---------------------- | ------------- |
199
+ | `VECTOR_DB_TYPE` | local/remote | local | ChromaDB 类型 |
200
+ | `VECTOR_DB_SERVER` | string | 127.0.0.1 | 远程地址 |
201
+ | `VECTOR_DB_PORT` | int | 8000 | 远程端口 |
202
+ | `EMBEDDING_MODEL_URL` | string | http://127.0.0.1:11434 | 嵌入模型地址 |
203
+ | `EMBEDDING_MODEL_NAME` | string | auto | 模型名 |
204
+ | `EMBEDDING_PROCTOL` | openai/ollama-embed | ollama-embed | 协议 |
205
+ | `EMBEDDING_MODEL_API_KEY` | string | (空) | API Key |
206
+
207
+ ## 安装
208
+
209
+ ```bash
210
+ ambot plugin install amrita_plugin_memory
211
+ ```
212
+
213
+ 前置:Python 3.11+ / AmritaBot 实例 / Ollama 或 OpenAI 嵌入服务 / ChromaDB。
214
+
215
+ ## 开发
216
+
217
+ ```bash
218
+ uv sync # 安装依赖
219
+ ruff format . && ruff check . # 格式化 + 检查
220
+ pyright # 类型检查
221
+ ```
@@ -0,0 +1,205 @@
1
+ # amrita_plugin_memory
2
+
3
+ Amrita Harness 记忆增强插件 — 双层架构:表层 Function Calling 记忆工具 + 底层常驻推理循环 Agent。
4
+
5
+ **表层** — LLM 对话中按需调用 5 个记忆工具(读写删改列),基于 ChromaDB 语义检索。
6
+ **底层** — 后台 Agent 定时自动扫描、去重、合并、压缩记忆库,基于 Core Agent 框架 + Harness 模式复用 ChatObject。
7
+
8
+ ## 双层架构
9
+
10
+ ```mermaid
11
+ flowchart TB
12
+ subgraph Surface["表层:Long-Term Memory Tools"]
13
+ S_LLM["对话 LLM"] -->|"write_memory"| S_Write["写入记忆"]
14
+ S_LLM -->|"read_memory"| S_Read["语义检索"]
15
+ S_LLM -->|"update/delete/list"| S_Mut["更新 / 删除 / 列表"]
16
+ S_Write --> ChromaDB[("ChromaDB<br/>向量数据库")]
17
+ S_Read --> ChromaDB
18
+ S_Mut --> ChromaDB
19
+ end
20
+
21
+ subgraph Subconscious["底层:Subconscious Reasoning Loop"]
22
+ APScheduler["APScheduler<br/>定时触发"] --> Runner["SubconsciousRunner"]
23
+ Runner --> ChatObject["ChatObject<br/>(Harness 容器)"]
24
+ ChatObject --> WF["Workflow 管线"]
25
+ WF --> LM["LIMITING_MEMORY<br/>Core MemoryLimiter"]
26
+ LM --> Build["BUILD_MESSAGE"]
27
+ Build --> Init["STRATEGY_INIT"]
28
+ Init --> AgentLoop["ReAct Agent Loop<br/>WHILE(SINGLE_STRATEGY_CALL)"]
29
+ AgentLoop -->|"工具调用"| STools["subconscious_* 工具"]
30
+ STools --> ChromaDB
31
+ AgentLoop -->|"subconscious_iter_stop"| APScheduler
32
+ end
33
+
34
+ Surface -.->|"共享 ChromaDB"| Subconscious
35
+ Runner -->|"持久化状态"| CachedRepo["CachedUserDataRepository<br/>uid=amritabot_inner_thinker"]
36
+ Runner -->|"usage 统计"| Insights["InsightsModel<br/>全局 Token 统计"]
37
+ ```
38
+
39
+ ## Harness 模式
40
+
41
+ `SubconsciousRunner` 不自己管理推理循环,而是将 **ChatObject 作为数据容器**,注入自定义 `SubconsciousBackend` + Core `ReActAgentStrategy`,通过替换 `_workflow` / `_interpreter` 复用完整的 Core Agent 管线:
42
+
43
+ ```
44
+ LOAD_STATE → JINJA2_RENDER → LIMITING_MEMORY → BUILD_MESSAGE → STRATEGY_INIT
45
+ → AGENT_ENTRY → WHILE(SINGLE_STRATEGY_CALL).ACTION(REACT_COUNTER)
46
+ ```
47
+
48
+ `LIMITING_MEMORY` **在 Agent Loop 之前**运行 Core `MemoryLimiter`:消息截断 → token 限制 → 自动生成摘要。摘要通过 Core Jinja2 模板 `<SUMMARY>` 标签注入 prompt。
49
+
50
+ 暂停时 `dump_interpreter()`,恢复时 `rebase_context()`,毫秒级断点续推理。
51
+
52
+ ## 技术栈
53
+
54
+ | 组件 | 技术 |
55
+ | ---------- | --------------------------------------------------------- |
56
+ | 后端框架 | Python 3.11+ / NoneBot2 / AmritaCore / AmritaSense |
57
+ | 向量数据库 | ChromaDB(PersistentClient / HttpClient) |
58
+ | 嵌入模型 | OpenAI Embedding / Ollama Embedding |
59
+ | 调度引擎 | nonebot_plugin_apscheduler |
60
+ | 持久化 | CachedUserDataRepository(uid=`amritabot_inner_thinker`) |
61
+ | Token 统计 | InsightsModel(复用 Bot 全局 usage 统计) |
62
+ | 配置管理 | Pydantic + TOML |
63
+ | 代码质量 | Ruff + Pyright |
64
+
65
+ ## 功能
66
+
67
+ ### 表层:长期记忆
68
+
69
+ | 功能 | 说明 |
70
+ | -------- | ------------------------------------------------ |
71
+ | 语义检索 | ChromaDB 嵌入向量相似度搜索,中日英多语言 |
72
+ | 分区隔离 | `scope="user"` 个人记忆 / `scope="group"` 群共享 |
73
+ | 重要性 | low / medium / high 三级,支持过滤 |
74
+ | 标签分类 | 自定义标签(preference、project、personal 等) |
75
+ | 过期清理 | 短/长/永久三级过期天数可配置 |
76
+ | 并发安全 | 用户 ID 粒度 `aiologic.Lock` |
77
+
78
+ ### 底层:常驻推理循环
79
+
80
+ | 功能 | 说明 |
81
+ | ---------- | ---------------------------------------------------------------- |
82
+ | 自动整理 | LLM 后台去重、合并、标签补全、低质清理 |
83
+ | 自调度 | `subconscious_iter_stop` 返回下次运行时间 |
84
+ | 记忆压缩 | Core `MemoryLimiter` 截断超限消息 + 自动生成摘要 |
85
+ | 去重辅助 | `subconscious_duplicate_helper` 返回待整理记忆 + 合并指导 prompt |
86
+ | 统计概览 | `subconscious_get_memory_stats` 总量/重要性分布/标签分布 |
87
+ | 膨胀感知 | ChromaDB 超 `memory_warn_threshold` 时自动注入压缩提示 |
88
+ | 滑动窗口 | `max_abstracts` 轮摘要保留,跨轮传递进度 |
89
+ | 暂停协调 | 目标用户聊天时自动暂停+随机延迟恢复 |
90
+ | 主动消息 | LLM 向用户发起主动问候(需 `allow_send_to_user`) |
91
+ | Token 统计 | 复用 Bot `InsightsModel` 全局统计,无需额外维护 |
92
+
93
+ ## 工具
94
+
95
+ ### 表层工具(`tools.py`)
96
+
97
+ LLM 在对话中按需调用,受 `scope` 分区隔离:
98
+
99
+ | 工具 | 参数 |
100
+ | --------------- | -------------------------------------------- |
101
+ | `write_memory` | content, tags, importance(enum), scope(enum) |
102
+ | `read_memory` | query, top_k(5), importance?, scope(enum) |
103
+ | `update_memory` | id, scope, content?, tags?, importance? |
104
+ | `delete_memory` | id, scope |
105
+ | `list_memory` | limit, scope |
106
+
107
+ ### 潜意识工具(`rethinking/tools.py`)
108
+
109
+ 仅供 Subconscious Agent 使用,不暴露给对话 LLM:
110
+
111
+ | 工具 | 用途 |
112
+ | -------------------------------- | ------------------------------------------- |
113
+ | `subconscious_read_memory` | 语义检索(硬编码 user scope) |
114
+ | `subconscious_write_memory` | 写入新记忆 |
115
+ | `subconscious_update_memory` | 更新指定 ID 记忆 |
116
+ | `subconscious_delete_memory` | 删除指定 ID 记忆 |
117
+ | `subconscious_list_memory` | 列出全部记忆 |
118
+ | `subconscious_iter_stop` | 结束本轮,设置下次运行时间 |
119
+ | `subconscious_send_to_user` | 主动向用户发消息(需 allow_send_to_user) |
120
+ | `subconscious_read_chat_context` | 读取用户最近聊天记录 |
121
+ | `subconscious_duplicate_helper` | 返回全部记忆 + LLM 合并指导 prompt(去重) |
122
+ | `subconscious_get_memory_stats` | 统计概览:总数/重要性分布/标签分布/时间范围 |
123
+
124
+ ## 配置
125
+
126
+ ### `config/amrita_plugin_memory/config.toml`
127
+
128
+ ```toml
129
+ # 记忆过期
130
+ short_term_expiry_days = 3
131
+ long_term_expiry_days = 30
132
+ permanent_expiry_days = 365
133
+ per_session_memory_limit = 50
134
+
135
+ # 常驻推理循环
136
+ [subconscious]
137
+ enabled = false # 是否启用
138
+ experimental = true # 实验性标注
139
+ target_user_id = "" # 目标用户 ID(为空则不启用)
140
+ allowed_tools = [] # 额外可用工具
141
+ max_iterations = 10 # 单轮 ReAct 最大步数
142
+ loop_detect_threshold = 3 # 连续同工具触发警告阈值
143
+ initial_delay_seconds = 60 # 启动后首轮延迟
144
+ default_interval_seconds = 600# LLM 未指定时默认间隔
145
+ pause_on_user_chat = true # 用户聊天时自动暂停
146
+ pause_wakeup_min_seconds = 180# 暂停后最小唤醒延迟
147
+ pause_wakeup_max_seconds = 480# 暂停后最大唤醒延迟
148
+ prompt_file = "subconscious_prompt.txt"
149
+ enable_memory_compress = true # 启用 MemoryLimiter 上下文压缩
150
+ allow_send_to_user = false # 允许 Agent 主动发消息
151
+ memory_warn_threshold = 100 # ChromaDB 超此数量注入压缩提示
152
+ max_abstracts = 5 # 摘要滑动窗口大小
153
+ ```
154
+
155
+ ### 提示词模板
156
+
157
+ 两个 Jinja2 模板文件位于 `config/amrita_plugin_memory/`:
158
+
159
+ **`subconscious_prompt.txt`** — Agent 系统提示词(由 `prompt_file` 配置指定)
160
+
161
+ | 模板变量 | 说明 |
162
+ | ------------------------ | ------------------------------------ |
163
+ | `{{ character_prompt }}` | Bot 当前角色设定(从 `config/chat/private_prompts/` 读取) |
164
+ | `{{ last_run }}` | 上一轮 MemoryLimiter 产出的摘要 |
165
+ | `{{ last_abstracts }}` | 最近 N 轮摘要列表(max_abstracts 控制) |
166
+ | `{{ current_time }}` | 当前 UTC 时间 |
167
+ | `{{ target_user_id }}` | 目标用户 ID |
168
+ | `{{ total_runs }}` | 累计运行轮数 |
169
+
170
+ **`subconscious_send_prompt.txt`** — 主动消息生成模板
171
+
172
+ | 模板变量 | 说明 |
173
+ | ------------------------ | ------------------------------------ |
174
+ | `{{ character_prompt }}` | Bot 当前角色设定 |
175
+ | `{{ intent }}` | LLM 指定的消息意图 |
176
+ | `{{ memory_context }}` | 关联的记忆上下文 |
177
+ | `{{ current_time }}` | 当前 UTC 时间 |
178
+
179
+ ### 环境变量(`.env`)
180
+
181
+ | 变量 | 类型 | 默认值 | 说明 |
182
+ | ------------------------- | ------------------- | ---------------------- | ------------- |
183
+ | `VECTOR_DB_TYPE` | local/remote | local | ChromaDB 类型 |
184
+ | `VECTOR_DB_SERVER` | string | 127.0.0.1 | 远程地址 |
185
+ | `VECTOR_DB_PORT` | int | 8000 | 远程端口 |
186
+ | `EMBEDDING_MODEL_URL` | string | http://127.0.0.1:11434 | 嵌入模型地址 |
187
+ | `EMBEDDING_MODEL_NAME` | string | auto | 模型名 |
188
+ | `EMBEDDING_PROCTOL` | openai/ollama-embed | ollama-embed | 协议 |
189
+ | `EMBEDDING_MODEL_API_KEY` | string | (空) | API Key |
190
+
191
+ ## 安装
192
+
193
+ ```bash
194
+ ambot plugin install amrita_plugin_memory
195
+ ```
196
+
197
+ 前置:Python 3.11+ / AmritaBot 实例 / Ollama 或 OpenAI 嵌入服务 / ChromaDB。
198
+
199
+ ## 开发
200
+
201
+ ```bash
202
+ uv sync # 安装依赖
203
+ ruff format . && ruff check . # 格式化 + 检查
204
+ pyright # 类型检查
205
+ ```
@@ -0,0 +1,9 @@
1
+ from nonebot import require
2
+
3
+ require("nonebot_plugin_localstore")
4
+ require("nonebot_plugin_apscheduler")
5
+ require("amrita.plugins.chat")
6
+ require("amrita.plugins.menu")
7
+ from . import config, embed, matchers, rethinking, tools, vector
8
+
9
+ __all__ = ["config", "embed", "matchers", "rethinking", "tools", "vector"]
@@ -13,6 +13,64 @@ VECTOR_DB_PATH = DATA_PATH / "vector_db.chroma"
13
13
  PLUGIN_IM = "amrita_plugin_memory"
14
14
 
15
15
 
16
+ class SubconsciousConfig(BaseModel):
17
+ """常驻推理循环(潜意识层)配置 — 实验性功能"""
18
+
19
+ enabled: bool = Field(default=False, description="是否启用常驻推理循环")
20
+ experimental: bool = Field(
21
+ default=True, description="实验性标注,启用时日志输出 [EXPERIMENTAL]"
22
+ )
23
+ target_user_id: str = Field(
24
+ default="", description="目标用户ID(MVP仅支持单用户),为空则不启动"
25
+ )
26
+ allowed_tools: list[str] = Field(
27
+ default_factory=list,
28
+ description="额外可用工具名列表,从全局 ToolsManager 查找,不存在仅告警",
29
+ )
30
+ max_iterations: int = Field(
31
+ default=10, ge=1, le=50, description="单次推理最大 ReAct 循环步数"
32
+ )
33
+ loop_detect_threshold: int = Field(
34
+ default=3, ge=2, le=10, description="连续相同工具调用次数阈值,触发后注入提示"
35
+ )
36
+ initial_delay_seconds: int = Field(
37
+ default=60, ge=1, description="启动后首次触发延迟(秒)"
38
+ )
39
+ default_interval_seconds: int = Field(
40
+ default=600, ge=10, description="LLM 未返回时间时的默认间隔(秒)"
41
+ )
42
+ pause_on_user_chat: bool = Field(
43
+ default=True, description="目标用户聊天时是否暂停推理循环"
44
+ )
45
+ pause_wakeup_min_seconds: int = Field(
46
+ default=180, ge=10, description="用户聊天后唤醒的最小延迟(秒)"
47
+ )
48
+ pause_wakeup_max_seconds: int = Field(
49
+ default=480, ge=60, description="用户聊天后唤醒的最大延迟(秒)"
50
+ )
51
+ prompt_file: str = Field(
52
+ default="subconscious_prompt.txt",
53
+ description="系统提示词文件名,相对于 config/amrita_plugin_memory/",
54
+ )
55
+ enable_memory_compress: bool = Field(
56
+ default=True, description="是否在每次运行后压缩持久化摘要"
57
+ )
58
+ allow_send_to_user: bool = Field(
59
+ default=False, description="是否允许潜意识主动向用户发送消息"
60
+ )
61
+ memory_warn_threshold: int = Field(
62
+ default=100,
63
+ ge=10,
64
+ description="ChromaDB 记忆总量超过此值时,在 prompt 中注入压缩提示",
65
+ )
66
+ max_abstracts: int = Field(
67
+ default=5,
68
+ ge=1,
69
+ le=20,
70
+ description="保留最近 N 轮摘要的滑动窗口大小",
71
+ )
72
+
73
+
16
74
  class ConfigFile(BaseModel):
17
75
  """配置文件"""
18
76
 
@@ -28,6 +86,9 @@ class ConfigFile(BaseModel):
28
86
  per_session_memory_limit: int = Field(
29
87
  default=50, description="每个会话的记忆数量限制,默认为50条"
30
88
  )
89
+ subconscious: SubconsciousConfig = Field(
90
+ default_factory=SubconsciousConfig, description="常驻推理循环配置"
91
+ )
31
92
 
32
93
 
33
94
  class EnvConfig(BaseModel):
@@ -79,7 +79,7 @@ _SCOPE_PROP = FunctionPropertySchema(
79
79
  enum=["group", "user"],
80
80
  )
81
81
 
82
- # Function Schema 定义 ─
82
+ # Function Schema 定义
83
83
 
84
84
  WRITE_MEMORY_FUN = FunctionDefinitionSchema(
85
85
  name="write_memory",
@@ -186,7 +186,7 @@ LIST_MEMORY_FUN = FunctionDefinitionSchema(
186
186
  )
187
187
 
188
188
 
189
- # Handler 实现 ─
189
+ # Handler 实现
190
190
 
191
191
 
192
192
  @on_tools(WRITE_MEMORY_FUN, custom_run=True, strict=True)