alpha-avatar-plugins-memory 0.6.2__tar.gz → 0.6.4__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 (25) hide show
  1. {alpha_avatar_plugins_memory-0.6.2 → alpha_avatar_plugins_memory-0.6.4}/.gitignore +0 -1
  2. alpha_avatar_plugins_memory-0.6.4/PKG-INFO +242 -0
  3. alpha_avatar_plugins_memory-0.6.4/README.md +220 -0
  4. {alpha_avatar_plugins_memory-0.6.2 → alpha_avatar_plugins_memory-0.6.4}/alphaavatar/plugins/memory/__init__.py +5 -3
  5. alpha_avatar_plugins_memory-0.6.4/alphaavatar/plugins/memory/graph/__init__.py +24 -0
  6. alpha_avatar_plugins_memory-0.6.4/alphaavatar/plugins/memory/graph/graph_alias.py +144 -0
  7. alpha_avatar_plugins_memory-0.6.4/alphaavatar/plugins/memory/graph/graph_builder.py +230 -0
  8. alpha_avatar_plugins_memory-0.6.4/alphaavatar/plugins/memory/graph/graph_lookup.py +232 -0
  9. alpha_avatar_plugins_memory-0.6.4/alphaavatar/plugins/memory/graph/graph_store.py +362 -0
  10. alpha_avatar_plugins_memory-0.6.4/alphaavatar/plugins/memory/memory_delta_extractor.py +456 -0
  11. {alpha_avatar_plugins_memory-0.6.2 → alpha_avatar_plugins_memory-0.6.4}/alphaavatar/plugins/memory/memory_markdown.py +47 -17
  12. {alpha_avatar_plugins_memory-0.6.2 → alpha_avatar_plugins_memory-0.6.4}/alphaavatar/plugins/memory/memory_op.py +45 -12
  13. alpha_avatar_plugins_memory-0.6.4/alphaavatar/plugins/memory/memory_prompts.py +1003 -0
  14. alpha_avatar_plugins_memory-0.6.4/alphaavatar/plugins/memory/memory_runtime.py +886 -0
  15. alpha_avatar_plugins_memory-0.6.4/alphaavatar/plugins/memory/runner/lancedb_runner.py +663 -0
  16. {alpha_avatar_plugins_memory-0.6.2 → alpha_avatar_plugins_memory-0.6.4}/alphaavatar/plugins/memory/version.py +1 -1
  17. {alpha_avatar_plugins_memory-0.6.2 → alpha_avatar_plugins_memory-0.6.4}/pyproject.toml +0 -6
  18. alpha_avatar_plugins_memory-0.6.2/PKG-INFO +0 -176
  19. alpha_avatar_plugins_memory-0.6.2/README.md +0 -149
  20. alpha_avatar_plugins_memory-0.6.2/alphaavatar/plugins/memory/memory_prompts.py +0 -560
  21. alpha_avatar_plugins_memory-0.6.2/alphaavatar/plugins/memory/memory_runtime.py +0 -755
  22. alpha_avatar_plugins_memory-0.6.2/alphaavatar/plugins/memory/runner/lancedb_runner.py +0 -240
  23. {alpha_avatar_plugins_memory-0.6.2 → alpha_avatar_plugins_memory-0.6.4}/alphaavatar/plugins/memory/log.py +0 -0
  24. {alpha_avatar_plugins_memory-0.6.2 → alpha_avatar_plugins_memory-0.6.4}/alphaavatar/plugins/memory/runner/__init__.py +0 -0
  25. {alpha_avatar_plugins_memory-0.6.2 → alpha_avatar_plugins_memory-0.6.4}/alphaavatar/plugins/memory/runner/qdrant_runner.py +0 -0
@@ -130,7 +130,6 @@ celerybeat.pid
130
130
  .env.personal
131
131
  .env.prod
132
132
  .venv
133
- env/
134
133
  venv/
135
134
  ENV/
136
135
  env.bak/
@@ -0,0 +1,242 @@
1
+ Metadata-Version: 2.4
2
+ Name: alpha-avatar-plugins-memory
3
+ Version: 0.6.4
4
+ Summary: AlphaAvatar Framework plugin for memory service
5
+ Project-URL: Source, https://github.com/AlphaAvatar/AlphaAvatar
6
+ License-Expression: Apache-2.0
7
+ Keywords: AI,agents,langchain,llm,memory
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Multimedia :: Sound/Audio
17
+ Classifier: Topic :: Multimedia :: Video
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: <3.12,>=3.11
20
+ Requires-Dist: torchaudio>=0.10.1
21
+ Description-Content-Type: text/markdown
22
+
23
+ # 🧠 Memory Plugin for AlphaAvatar
24
+
25
+ > Give AlphaAvatar the ability to **remember you, its tools, and its environment** — across conversations, sessions, and time.
26
+
27
+ ---
28
+
29
+ ## 🤔 What is the Memory Plugin?
30
+
31
+ Imagine talking to an assistant that forgets everything the moment you close the app. Frustrating, right?
32
+
33
+ The **Memory Plugin** gives AlphaAvatar a persistent memory layer. It can:
34
+
35
+ - Remember your **preferences, goals, and important facts**
36
+ - Recall **past conversations** and previous decisions
37
+ - Learn from **tool usage**, research, and retrieved documents
38
+ - Build **environment memories** from live visual observations
39
+ - Retrieve related memories through **semantic and graph-aware search**
40
+
41
+ Think of it as AlphaAvatar's long-term notebook — important information is extracted, organized, stored, and brought back when it becomes useful.
42
+
43
+ ---
44
+
45
+ ## 💡 How Does it Work? (Simple Flow)
46
+
47
+ ```text
48
+ Conversation / Tool Result / Visual Observation
49
+
50
+ AlphaAvatar extracts useful memory updates
51
+
52
+ Runtime adds identity, session, graph, and evidence metadata
53
+
54
+ Memories are stored in local or remote vector storage
55
+
56
+ Relevant memories are retrieved in future turns
57
+
58
+ AlphaAvatar responds with better continuity and grounding
59
+ ```
60
+
61
+ Conversation and tool memory work automatically in the background.
62
+ Online ENV memory is enabled when a multimodal `env_delta_task` is configured.
63
+
64
+ ---
65
+
66
+ ## ✨ Features
67
+
68
+ ### 🌍 Persistent Memory
69
+
70
+ AlphaAvatar maintains memories beyond a single chat session.
71
+
72
+ This includes:
73
+
74
+ - Things **you** told it
75
+ - Important **conversation decisions**
76
+ - Results from **MCP, RAG, and DeepResearch**
77
+ - Useful observations from the **camera, screen, or surrounding environment**
78
+ - Links between people, objects, sessions, tools, and events
79
+
80
+ ### ⚡ Runtime Memory Updates
81
+
82
+ Memory can update while a session is active instead of waiting until the conversation ends.
83
+
84
+ Conversation, tool, and ENV memory use separate extraction paths, while the runtime controls timestamps, ownership, evidence, graph structure, and session metadata.
85
+
86
+ ### 👁️ Online ENV Memory
87
+
88
+ The Memory plugin can consume ordered observation windows from `PerceptionRuntime`.
89
+
90
+ ```text
91
+ Video / Screen Observations
92
+
93
+ PerceptionRuntime Window
94
+
95
+ Multimodal ENV Extraction Task
96
+
97
+ EnvMemoryDelta
98
+
99
+ MemoryType.ENV
100
+ ```
101
+
102
+ ENV memory prefers annotated visual evidence when available and falls back to raw frames. Heavy runtime payloads such as video frames are never written directly into memory storage.
103
+
104
+ ### 🕸️ Graph-aware Retrieval
105
+
106
+ Memories can include graph nodes and links for entities such as:
107
+
108
+ - users
109
+ - faces and speakers
110
+ - objects
111
+ - sessions
112
+ - tools
113
+ - locations
114
+ - events
115
+
116
+ Graph nodes act as retrieval anchors, while memory text remains the source of truth.
117
+
118
+ ---
119
+
120
+ ## 📦 What Kind of Things Does AlphaAvatar Remember?
121
+
122
+ | Type | Example |
123
+ |------|---------|
124
+ | 👤 Personal facts | “My name is Alex and I live in New York.” |
125
+ | ❤️ Preferences | “I prefer short, direct answers.” |
126
+ | 🗓️ Conversation memory | A decision or topic from an earlier session |
127
+ | 🔍 Research results | Findings from a DeepResearch task |
128
+ | 📄 Document knowledge | Useful information retrieved through RAG |
129
+ | 🛠️ Tool interactions | Results from MCP tools such as Gmail or Notion |
130
+ | 👁️ ENV memory | “A person placed a red cup on the desk.” |
131
+ | 🕸️ Graph associations | A user, object, tool, and event linked across memories |
132
+
133
+ ---
134
+
135
+ ## 🔧 Installation
136
+
137
+ ```bash
138
+ pip install alpha-avatar-plugins-memory
139
+ ```
140
+
141
+ The plugin is then loaded through the AlphaAvatar configuration.
142
+
143
+ To enable online ENV memory, configure a multimodal provider task such as:
144
+
145
+ ```yaml
146
+ env_delta_task: memory.env_delta
147
+ ```
148
+
149
+ If no ENV extraction task is configured, the rest of the Memory plugin continues to work normally.
150
+
151
+ ---
152
+
153
+ ## 🗄️ How Memories are Stored
154
+
155
+ AlphaAvatar stores memories as structured records with searchable embeddings and runtime-owned metadata.
156
+
157
+ Memory records can include:
158
+
159
+ - memory text
160
+ - memory type
161
+ - object ownership
162
+ - timestamps and session IDs
163
+ - evidence references
164
+ - graph nodes and links
165
+ - additional runtime metadata
166
+
167
+ ### Supported Backends
168
+
169
+ | Backend | What it Does |
170
+ |---------|--------------|
171
+ | **LanceDB** | Local vector storage and graph-aware retrieval (default) |
172
+ | **Qdrant** | Remote or self-hosted vector storage |
173
+ | **Provider Gateway** | Routes extraction tasks to configured LLM or VLM providers |
174
+
175
+ By default, AlphaAvatar can run with local LanceDB storage. Raw camera frames, audio buffers, and other heavy runtime payloads are not persisted as memory items.
176
+
177
+ ---
178
+
179
+ ## 🔗 How Memory Connects to Other Modules
180
+
181
+ ```text
182
+ PerceptionRuntime
183
+ └── → ENV Memory (visual and future audio observations)
184
+
185
+ Persona Plugin
186
+ └── → Identity Aliases (face / speaker / user relationships)
187
+
188
+ RAG / DeepResearch / MCP
189
+ └── → Tool Memory (documents, research, and actions)
190
+
191
+ Memory Plugin
192
+ ├── → Avatar Runtime (dynamic per-turn context)
193
+ ├── → Graph Retrieval (entity and relationship lookup)
194
+ ├── → Reflection* (behavior improvement)
195
+ └── → Planning* (goals and reminders)
196
+
197
+ * Planned
198
+ ```
199
+
200
+ ---
201
+
202
+ ## 🙋 Common Questions
203
+
204
+ **Q: Does memory work across sessions?**
205
+ Yes. Stored memories can be retrieved in later sessions.
206
+
207
+ **Q: Does ENV memory save my raw camera stream?**
208
+ No. Raw runtime frames are not stored as memory records. The configured multimodal model extracts useful environment memories from selected observation windows.
209
+
210
+ **Q: Is ENV memory always enabled?**
211
+ No. It is optional and only runs when `env_delta_task` is configured.
212
+
213
+ **Q: Can memory distinguish different users?**
214
+ Memory supports multi-object ownership and graph aliases. Persona can resolve temporary face or speaker identities to stable users.
215
+
216
+ **Q: Can I see or delete individual memories?**
217
+ Fine-grained inspection, correction, export, and deletion controls are still being developed.
218
+
219
+ **Q: Is my data private?**
220
+ Local LanceDB storage keeps memory data on your own machine unless you configure a remote backend or external model provider.
221
+
222
+ ---
223
+
224
+ ## 🚀 Coming Soon
225
+
226
+ | Feature | Description |
227
+ |---------|-------------|
228
+ | 🎤 Audio ENV Memory | Extract useful events and context from continuous audio streams |
229
+ | 🔍 Rich Visual-history Search | Search by objects, events, identities, and time ranges |
230
+ | 🧩 Multi-annotation Fusion | Combine face, speaker, object, action, and scene annotations |
231
+ | 🔒 Memory Privacy Controls | Inspect, edit, export, and delete memories |
232
+ | 👥 Stronger Multi-user Memory | Better separation and merging across shared sessions |
233
+ | 🧠 Reflection & Planning | Use memory for longer-term behavior improvement and goals |
234
+
235
+ ---
236
+
237
+ ## 📚 Related Links
238
+
239
+ - [AlphaAvatar ROADMAP — Memory Section](https://github.com/AlphaAvatar/AlphaAvatar/blob/main/ROADMAP.md#-memory)
240
+ - [Persona Plugin](https://github.com/AlphaAvatar/AlphaAvatar/blob/main/avatar-plugins/avatar-plugins-persona/README.md)
241
+ - [LanceDB Documentation](https://lancedb.com/docs/)
242
+ - [Qdrant Documentation](https://qdrant.tech/documentation/)
@@ -0,0 +1,220 @@
1
+ # 🧠 Memory Plugin for AlphaAvatar
2
+
3
+ > Give AlphaAvatar the ability to **remember you, its tools, and its environment** — across conversations, sessions, and time.
4
+
5
+ ---
6
+
7
+ ## 🤔 What is the Memory Plugin?
8
+
9
+ Imagine talking to an assistant that forgets everything the moment you close the app. Frustrating, right?
10
+
11
+ The **Memory Plugin** gives AlphaAvatar a persistent memory layer. It can:
12
+
13
+ - Remember your **preferences, goals, and important facts**
14
+ - Recall **past conversations** and previous decisions
15
+ - Learn from **tool usage**, research, and retrieved documents
16
+ - Build **environment memories** from live visual observations
17
+ - Retrieve related memories through **semantic and graph-aware search**
18
+
19
+ Think of it as AlphaAvatar's long-term notebook — important information is extracted, organized, stored, and brought back when it becomes useful.
20
+
21
+ ---
22
+
23
+ ## 💡 How Does it Work? (Simple Flow)
24
+
25
+ ```text
26
+ Conversation / Tool Result / Visual Observation
27
+
28
+ AlphaAvatar extracts useful memory updates
29
+
30
+ Runtime adds identity, session, graph, and evidence metadata
31
+
32
+ Memories are stored in local or remote vector storage
33
+
34
+ Relevant memories are retrieved in future turns
35
+
36
+ AlphaAvatar responds with better continuity and grounding
37
+ ```
38
+
39
+ Conversation and tool memory work automatically in the background.
40
+ Online ENV memory is enabled when a multimodal `env_delta_task` is configured.
41
+
42
+ ---
43
+
44
+ ## ✨ Features
45
+
46
+ ### 🌍 Persistent Memory
47
+
48
+ AlphaAvatar maintains memories beyond a single chat session.
49
+
50
+ This includes:
51
+
52
+ - Things **you** told it
53
+ - Important **conversation decisions**
54
+ - Results from **MCP, RAG, and DeepResearch**
55
+ - Useful observations from the **camera, screen, or surrounding environment**
56
+ - Links between people, objects, sessions, tools, and events
57
+
58
+ ### ⚡ Runtime Memory Updates
59
+
60
+ Memory can update while a session is active instead of waiting until the conversation ends.
61
+
62
+ Conversation, tool, and ENV memory use separate extraction paths, while the runtime controls timestamps, ownership, evidence, graph structure, and session metadata.
63
+
64
+ ### 👁️ Online ENV Memory
65
+
66
+ The Memory plugin can consume ordered observation windows from `PerceptionRuntime`.
67
+
68
+ ```text
69
+ Video / Screen Observations
70
+
71
+ PerceptionRuntime Window
72
+
73
+ Multimodal ENV Extraction Task
74
+
75
+ EnvMemoryDelta
76
+
77
+ MemoryType.ENV
78
+ ```
79
+
80
+ ENV memory prefers annotated visual evidence when available and falls back to raw frames. Heavy runtime payloads such as video frames are never written directly into memory storage.
81
+
82
+ ### 🕸️ Graph-aware Retrieval
83
+
84
+ Memories can include graph nodes and links for entities such as:
85
+
86
+ - users
87
+ - faces and speakers
88
+ - objects
89
+ - sessions
90
+ - tools
91
+ - locations
92
+ - events
93
+
94
+ Graph nodes act as retrieval anchors, while memory text remains the source of truth.
95
+
96
+ ---
97
+
98
+ ## 📦 What Kind of Things Does AlphaAvatar Remember?
99
+
100
+ | Type | Example |
101
+ |------|---------|
102
+ | 👤 Personal facts | “My name is Alex and I live in New York.” |
103
+ | ❤️ Preferences | “I prefer short, direct answers.” |
104
+ | 🗓️ Conversation memory | A decision or topic from an earlier session |
105
+ | 🔍 Research results | Findings from a DeepResearch task |
106
+ | 📄 Document knowledge | Useful information retrieved through RAG |
107
+ | 🛠️ Tool interactions | Results from MCP tools such as Gmail or Notion |
108
+ | 👁️ ENV memory | “A person placed a red cup on the desk.” |
109
+ | 🕸️ Graph associations | A user, object, tool, and event linked across memories |
110
+
111
+ ---
112
+
113
+ ## 🔧 Installation
114
+
115
+ ```bash
116
+ pip install alpha-avatar-plugins-memory
117
+ ```
118
+
119
+ The plugin is then loaded through the AlphaAvatar configuration.
120
+
121
+ To enable online ENV memory, configure a multimodal provider task such as:
122
+
123
+ ```yaml
124
+ env_delta_task: memory.env_delta
125
+ ```
126
+
127
+ If no ENV extraction task is configured, the rest of the Memory plugin continues to work normally.
128
+
129
+ ---
130
+
131
+ ## 🗄️ How Memories are Stored
132
+
133
+ AlphaAvatar stores memories as structured records with searchable embeddings and runtime-owned metadata.
134
+
135
+ Memory records can include:
136
+
137
+ - memory text
138
+ - memory type
139
+ - object ownership
140
+ - timestamps and session IDs
141
+ - evidence references
142
+ - graph nodes and links
143
+ - additional runtime metadata
144
+
145
+ ### Supported Backends
146
+
147
+ | Backend | What it Does |
148
+ |---------|--------------|
149
+ | **LanceDB** | Local vector storage and graph-aware retrieval (default) |
150
+ | **Qdrant** | Remote or self-hosted vector storage |
151
+ | **Provider Gateway** | Routes extraction tasks to configured LLM or VLM providers |
152
+
153
+ By default, AlphaAvatar can run with local LanceDB storage. Raw camera frames, audio buffers, and other heavy runtime payloads are not persisted as memory items.
154
+
155
+ ---
156
+
157
+ ## 🔗 How Memory Connects to Other Modules
158
+
159
+ ```text
160
+ PerceptionRuntime
161
+ └── → ENV Memory (visual and future audio observations)
162
+
163
+ Persona Plugin
164
+ └── → Identity Aliases (face / speaker / user relationships)
165
+
166
+ RAG / DeepResearch / MCP
167
+ └── → Tool Memory (documents, research, and actions)
168
+
169
+ Memory Plugin
170
+ ├── → Avatar Runtime (dynamic per-turn context)
171
+ ├── → Graph Retrieval (entity and relationship lookup)
172
+ ├── → Reflection* (behavior improvement)
173
+ └── → Planning* (goals and reminders)
174
+
175
+ * Planned
176
+ ```
177
+
178
+ ---
179
+
180
+ ## 🙋 Common Questions
181
+
182
+ **Q: Does memory work across sessions?**
183
+ Yes. Stored memories can be retrieved in later sessions.
184
+
185
+ **Q: Does ENV memory save my raw camera stream?**
186
+ No. Raw runtime frames are not stored as memory records. The configured multimodal model extracts useful environment memories from selected observation windows.
187
+
188
+ **Q: Is ENV memory always enabled?**
189
+ No. It is optional and only runs when `env_delta_task` is configured.
190
+
191
+ **Q: Can memory distinguish different users?**
192
+ Memory supports multi-object ownership and graph aliases. Persona can resolve temporary face or speaker identities to stable users.
193
+
194
+ **Q: Can I see or delete individual memories?**
195
+ Fine-grained inspection, correction, export, and deletion controls are still being developed.
196
+
197
+ **Q: Is my data private?**
198
+ Local LanceDB storage keeps memory data on your own machine unless you configure a remote backend or external model provider.
199
+
200
+ ---
201
+
202
+ ## 🚀 Coming Soon
203
+
204
+ | Feature | Description |
205
+ |---------|-------------|
206
+ | 🎤 Audio ENV Memory | Extract useful events and context from continuous audio streams |
207
+ | 🔍 Rich Visual-history Search | Search by objects, events, identities, and time ranges |
208
+ | 🧩 Multi-annotation Fusion | Combine face, speaker, object, action, and scene annotations |
209
+ | 🔒 Memory Privacy Controls | Inspect, edit, export, and delete memories |
210
+ | 👥 Stronger Multi-user Memory | Better separation and merging across shared sessions |
211
+ | 🧠 Reflection & Planning | Use memory for longer-term behavior improvement and goals |
212
+
213
+ ---
214
+
215
+ ## 📚 Related Links
216
+
217
+ - [AlphaAvatar ROADMAP — Memory Section](https://github.com/AlphaAvatar/AlphaAvatar/blob/main/ROADMAP.md#-memory)
218
+ - [Persona Plugin](https://github.com/AlphaAvatar/AlphaAvatar/blob/main/avatar-plugins/avatar-plugins-persona/README.md)
219
+ - [LanceDB Documentation](https://lancedb.com/docs/)
220
+ - [Qdrant Documentation](https://qdrant.tech/documentation/)
@@ -14,7 +14,7 @@
14
14
  import os
15
15
 
16
16
  from alphaavatar.agents import AvatarModule, AvatarPlugin
17
- from alphaavatar.agents.runtime import SessionRuntime
17
+ from alphaavatar.agents.runtime import AvatarRuntime
18
18
 
19
19
  from .log import logger
20
20
  from .memory_runtime import MemoryRuntime
@@ -33,7 +33,8 @@ class MemoryPlugin(AvatarPlugin):
33
33
 
34
34
  def get_plugin(
35
35
  self,
36
- session_runtime: SessionRuntime,
36
+ runtime: AvatarRuntime,
37
+ avatar_id: str,
37
38
  memory_search_context: int,
38
39
  memory_recall_num: int,
39
40
  maximum_memory_num: int,
@@ -43,7 +44,8 @@ class MemoryPlugin(AvatarPlugin):
43
44
  ) -> MemoryRuntime:
44
45
  try:
45
46
  return MemoryRuntime(
46
- session_runtime=session_runtime,
47
+ runtime=runtime,
48
+ avatar_id=avatar_id,
47
49
  memory_search_context=memory_search_context,
48
50
  memory_recall_num=memory_recall_num,
49
51
  maximum_memory_num=maximum_memory_num,
@@ -0,0 +1,24 @@
1
+ # Copyright 2026 AlphaAvatar project
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ from .graph_alias import save_graph_aliases
15
+ from .graph_builder import build_graph_from_mentions
16
+ from .graph_lookup import GraphLookup
17
+ from .graph_store import save_memory_graph_stubs
18
+
19
+ __all__ = [
20
+ "save_graph_aliases",
21
+ "build_graph_from_mentions",
22
+ "GraphLookup",
23
+ "save_memory_graph_stubs",
24
+ ]
@@ -0,0 +1,144 @@
1
+ # Copyright 2026 AlphaAvatar project
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ import json
15
+ import pathlib
16
+ from typing import Any
17
+
18
+
19
+ def _json_dumps(value: Any) -> str:
20
+ return json.dumps(value, ensure_ascii=False, default=str)
21
+
22
+
23
+ def _json_loads(line: str) -> dict[str, Any] | None:
24
+ try:
25
+ data = json.loads(line)
26
+ return data if isinstance(data, dict) else None
27
+ except Exception:
28
+ return None
29
+
30
+
31
+ def _read_alias_map(path: pathlib.Path) -> dict[str, dict[str, Any]]:
32
+ if not path.exists():
33
+ return {}
34
+
35
+ out: dict[str, dict[str, Any]] = {}
36
+
37
+ for line in path.read_text(encoding="utf-8").splitlines():
38
+ line = line.strip()
39
+ if not line:
40
+ continue
41
+
42
+ row = _json_loads(line)
43
+ if not row:
44
+ continue
45
+
46
+ alias_key = str(row.get("alias_key", "")).strip()
47
+ canonical_key = str(row.get("canonical_key", "")).strip()
48
+
49
+ if not alias_key or not canonical_key:
50
+ continue
51
+
52
+ out[alias_key] = row
53
+
54
+ return out
55
+
56
+
57
+ def _write_aliases(path: pathlib.Path, aliases: dict[str, dict[str, Any]]) -> None:
58
+ path.parent.mkdir(parents=True, exist_ok=True)
59
+
60
+ rows = sorted(
61
+ aliases.values(),
62
+ key=lambda x: (
63
+ str(x.get("canonical_key", "")),
64
+ str(x.get("alias_key", "")),
65
+ ),
66
+ )
67
+
68
+ text = "\n".join(_json_dumps(row) for row in rows)
69
+ path.write_text(text + ("\n" if text else ""), encoding="utf-8")
70
+
71
+
72
+ def save_graph_aliases(
73
+ *,
74
+ graph_path: str | pathlib.Path,
75
+ aliases: list[dict[str, Any]],
76
+ ) -> dict[str, Any]:
77
+ graph_path = pathlib.Path(graph_path)
78
+ aliases_path = graph_path / "aliases.jsonl"
79
+
80
+ alias_map = _read_alias_map(aliases_path)
81
+
82
+ updated = 0
83
+ skipped = 0
84
+ conflicts: list[dict[str, Any]] = []
85
+
86
+ for alias in aliases:
87
+ alias_key = str(alias.get("alias_key", "")).strip()
88
+ canonical_key = str(alias.get("canonical_key", "")).strip()
89
+
90
+ if not alias_key or not canonical_key or alias_key == canonical_key:
91
+ skipped += 1
92
+ continue
93
+
94
+ # local detector keys must already be scoped before aliasing
95
+ if alias_key.startswith(("face:", "voice:", "object:")) and ":local:" not in alias_key:
96
+ skipped += 1
97
+ conflicts.append(
98
+ {
99
+ "alias_key": alias_key,
100
+ "canonical_key": canonical_key,
101
+ "reason": "unscoped_local_key",
102
+ }
103
+ )
104
+ continue
105
+
106
+ old = alias_map.get(alias_key)
107
+
108
+ if old:
109
+ old_canonical = str(old.get("canonical_key", "")).strip()
110
+ old_weight = float(old.get("weight", 0.0))
111
+ new_weight = float(alias.get("weight", 0.0))
112
+
113
+ # If conflict, only replace when new confidence is higher.
114
+ if old_canonical and old_canonical != canonical_key and new_weight < old_weight:
115
+ conflicts.append(
116
+ {
117
+ "alias_key": alias_key,
118
+ "old_canonical_key": old_canonical,
119
+ "new_canonical_key": canonical_key,
120
+ "old_weight": old_weight,
121
+ "new_weight": new_weight,
122
+ "reason": "lower_confidence_conflict",
123
+ }
124
+ )
125
+ skipped += 1
126
+ continue
127
+
128
+ merged = dict(old)
129
+ merged.update(alias)
130
+ alias_map[alias_key] = merged
131
+ else:
132
+ alias_map[alias_key] = alias
133
+
134
+ updated += 1
135
+
136
+ _write_aliases(aliases_path, alias_map)
137
+
138
+ return {
139
+ "aliases_file": str(aliases_path),
140
+ "aliases": len(alias_map),
141
+ "updated": updated,
142
+ "skipped": skipped,
143
+ "conflicts": conflicts,
144
+ }