3tears-agent-memory 0.14.0__py3-none-any.whl
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.
- 3tears_agent_memory-0.14.0.dist-info/METADATA +231 -0
- 3tears_agent_memory-0.14.0.dist-info/RECORD +44 -0
- 3tears_agent_memory-0.14.0.dist-info/WHEEL +4 -0
- 3tears_agent_memory-0.14.0.dist-info/licenses/LICENSE +21 -0
- threetears/agent/memory/__init__.py +229 -0
- threetears/agent/memory/access.py +205 -0
- threetears/agent/memory/authorize.py +505 -0
- threetears/agent/memory/collections.py +3197 -0
- threetears/agent/memory/embedding_utils.py +138 -0
- threetears/agent/memory/entities.py +1134 -0
- threetears/agent/memory/events.py +229 -0
- threetears/agent/memory/extraction.py +758 -0
- threetears/agent/memory/integration.py +361 -0
- threetears/agent/memory/merge.py +192 -0
- threetears/agent/memory/middleware.py +297 -0
- threetears/agent/memory/migrations/__init__.py +222 -0
- threetears/agent/memory/migrations/v001_create_memories_table.py +73 -0
- threetears/agent/memory/migrations/v002_create_conversation_memory_refs.py +50 -0
- threetears/agent/memory/migrations/v003_memory_column_reconciliation.py +110 -0
- threetears/agent/memory/migrations/v004_memory_lifecycle_columns.py +75 -0
- threetears/agent/memory/migrations/v005_memory_fts.py +78 -0
- threetears/agent/memory/migrations/v006_memory_media_content.py +123 -0
- threetears/agent/memory/migrations/v007_memory_chunks.py +96 -0
- threetears/agent/memory/migrations/v008_restore_memories_agent_customer_not_null.py +73 -0
- threetears/agent/memory/migrations/v009_media_composite_fk.py +132 -0
- threetears/agent/memory/migrations/v010_media_content_composite_fk.py +94 -0
- threetears/agent/memory/migrations/v011_memory_chunks_composite_fk.py +93 -0
- threetears/agent/memory/migrations/v012_memories_media_composite_fk.py +133 -0
- threetears/agent/memory/migrations/v013_datetime_to_datetimetz.py +256 -0
- threetears/agent/memory/migrations/v014_memory_refs_date_columns.py +131 -0
- threetears/agent/memory/migrations/v015_unified_memory_columns.py +123 -0
- threetears/agent/memory/migrations/v016_backfill_memory_ids.py +276 -0
- threetears/agent/memory/migrations/v017_memory_fk_flip.py +168 -0
- threetears/agent/memory/migrations/v018_drop_legacy_memory_columns.py +171 -0
- threetears/agent/memory/migrations/v019_conversation_id_not_null.py +82 -0
- threetears/agent/memory/migrations/v020_memories_alias.py +64 -0
- threetears/agent/memory/migrations/v021_memory_chunks_index_and_token.py +304 -0
- threetears/agent/memory/migrations/v022_add_hnsw_gin_indexes.py +241 -0
- threetears/agent/memory/migrations/v023_fix_idx_chunks_message_id_start.py +79 -0
- threetears/agent/memory/prompts.py +112 -0
- threetears/agent/memory/py.typed +0 -0
- threetears/agent/memory/retrieval.py +633 -0
- threetears/agent/memory/tools.py +1584 -0
- threetears/agent/memory/types.py +75 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: 3tears-agent-memory
|
|
3
|
+
Version: 0.14.0
|
|
4
|
+
Summary: Memory system for LLM agents -- extraction, retrieval, hybrid search, and MMR reranking
|
|
5
|
+
Project-URL: Repository, https://github.com/pacepace/3tears
|
|
6
|
+
Author: pace
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Framework :: AsyncIO
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Python: >=3.14
|
|
18
|
+
Requires-Dist: 3tears
|
|
19
|
+
Requires-Dist: 3tears-agent-acl
|
|
20
|
+
Requires-Dist: 3tears-langgraph
|
|
21
|
+
Requires-Dist: 3tears-observe
|
|
22
|
+
Requires-Dist: langchain-core
|
|
23
|
+
Requires-Dist: pgvector
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# 3tears Agent Memory
|
|
27
|
+
|
|
28
|
+
Memory system for LLM agents. Handles extraction of memorable facts from conversations, hybrid retrieval (semantic + full-text + recency), and memory lifecycle management.
|
|
29
|
+
|
|
30
|
+
Part of the [3tears](https://github.com/pacepace/3tears) framework.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install 3tears-agent-memory
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Components
|
|
39
|
+
|
|
40
|
+
### Collections are the single entry point for memory-table SQL
|
|
41
|
+
|
|
42
|
+
Every memory-table write, single-row read, batch read, and hybrid-search query goes through one of four `BaseCollection` subclasses; no consumer of this package holds an `asyncpg.Pool` reference directly.
|
|
43
|
+
|
|
44
|
+
- `MemoriesCollection` -- `memories` table. CRUD through `get` / `save_entity` / `delete`; complex queries through `hybrid_search`, `search_by_ids`, `search_by_semantic`, `search_by_fts`, `find_similar_for_dedup`, `count_by_user`, `fetch_content_for_recall`.
|
|
45
|
+
- `MediaCollection` -- `media` parent table. CRUD only.
|
|
46
|
+
- `MediaContentCollection` -- `media_content` child table. CRUD + `hybrid_search`, `search_by_ids`, `search_by_semantic`, `search_by_fts`, `fetch_content_for_recall`.
|
|
47
|
+
- `MemoryChunkCollection` -- `memory_chunks` child table. CRUD + `hybrid_search`, `search_by_ids`, `search_by_semantic`, `fetch_content_for_recall`.
|
|
48
|
+
|
|
49
|
+
All four resolve their L3 pool through `CollectionRegistry` (same pattern `ConversationCollection` uses); an L1 `SQLiteBackend` attached to the registry populates on `save_entity` and serves subsequent by-id `get` calls without an L3 round-trip. The `media` / `media_content` / `memory_chunks` tables are introduced by migrations v006 / v007.
|
|
50
|
+
|
|
51
|
+
Hybrid-search methods carry documented `# cache-bypass: <reason>` inline comments because the query shape (vector distance, FTS rank, multi-table joins) is not primary-key-addressable and the L1 row cache cannot serve the lookup. Keeping the SQL on the Collection preserves the single entry point. The cache-primitive enforcement walker recognises in-Collection bypass sites as legitimate and reports any bypass that leaks back into `retrieval.py` / `extraction.py` / `tools.py` as a violation.
|
|
52
|
+
|
|
53
|
+
### MemoryExtractor
|
|
54
|
+
|
|
55
|
+
Extracts memorable facts from conversation turns. Uses a multi-stage pipeline: candidate extraction via LLM, deduplication against existing memories via embedding similarity, and action resolution (ADD / UPDATE / DELETE).
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from threetears.agent.memory import (
|
|
59
|
+
MemoriesCollection,
|
|
60
|
+
MemoryConfig,
|
|
61
|
+
MemoryExtractor,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
extractor = MemoryExtractor(
|
|
65
|
+
config=MemoryConfig(),
|
|
66
|
+
embedding_provider=my_embedding_provider,
|
|
67
|
+
chat_model_factory=my_chat_model_factory,
|
|
68
|
+
authorizer=authorizer_bundle,
|
|
69
|
+
memories_collection=memories_collection,
|
|
70
|
+
summary_callback=on_new_memory,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
await extractor.extract(
|
|
74
|
+
user_id=user_id,
|
|
75
|
+
conversation_id=conv_id,
|
|
76
|
+
message_id_source=msg_id,
|
|
77
|
+
user_message="I just moved to Portland",
|
|
78
|
+
assistant_response="That's exciting! Portland has great food...",
|
|
79
|
+
turn_count=5,
|
|
80
|
+
agent_id=agent_id,
|
|
81
|
+
customer_id=customer_id,
|
|
82
|
+
)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### MemoryRetriever
|
|
86
|
+
|
|
87
|
+
Retrieves relevant memories using hybrid search: pgvector semantic similarity, PostgreSQL full-text search, recency decay, and MMR reranking for diversity. Takes the three search-bearing Collections at construction; no pool.
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from threetears.agent.memory import MemoryRetriever, MemoryConfig
|
|
91
|
+
|
|
92
|
+
retriever = MemoryRetriever(
|
|
93
|
+
config=MemoryConfig(),
|
|
94
|
+
embedding_provider=my_embedding_provider,
|
|
95
|
+
authorizer=authorizer_bundle,
|
|
96
|
+
memories_collection=memories_collection,
|
|
97
|
+
media_content_collection=media_content_collection,
|
|
98
|
+
memory_chunk_collection=memory_chunk_collection,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
result = await retriever.retrieve_with_candidates(
|
|
102
|
+
user_id,
|
|
103
|
+
"Tell me about Portland",
|
|
104
|
+
agent_id=agent_id,
|
|
105
|
+
customer_id=customer_id,
|
|
106
|
+
caller_user_id=user_id,
|
|
107
|
+
caller_agent_id=agent_id,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# result.context -- formatted string for injection into system prompt
|
|
111
|
+
# result.memories -- raw memory dicts with similarity scores
|
|
112
|
+
# result.media_content -- matched media content
|
|
113
|
+
# result.memory_chunks -- matched document chunks
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Protocols
|
|
117
|
+
|
|
118
|
+
Implement these to integrate with your infrastructure:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from threetears.agent.memory import EmbeddingProvider, ChatModelFactory
|
|
122
|
+
|
|
123
|
+
class MyEmbeddingProvider(EmbeddingProvider):
|
|
124
|
+
async def embed(self, text: str) -> tuple[list[float], int, UUID]:
|
|
125
|
+
# Returns (embedding_vector, token_count, model_id)
|
|
126
|
+
...
|
|
127
|
+
|
|
128
|
+
class MyChatModelFactory(ChatModelFactory):
|
|
129
|
+
async def create_chat_model(self, purpose: str = "extraction"):
|
|
130
|
+
# Returns a langchain BaseChatModel
|
|
131
|
+
...
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Tools
|
|
135
|
+
|
|
136
|
+
LangChain tools for agent use: memory search, recall, and explicit add. Factories take Collection references; no pool:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from threetears.agent.memory import (
|
|
140
|
+
load_memory_add_tool,
|
|
141
|
+
load_memory_search_tool,
|
|
142
|
+
load_memory_recall_tool,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
search_tool = await load_memory_search_tool(
|
|
146
|
+
user_id=user_id,
|
|
147
|
+
embedding_provider=embedding_provider,
|
|
148
|
+
agent_id=agent_id,
|
|
149
|
+
customer_id=customer_id,
|
|
150
|
+
authorizer=authorizer_bundle,
|
|
151
|
+
memories_collection=memories_collection,
|
|
152
|
+
media_content_collection=media_content_collection,
|
|
153
|
+
memory_chunk_collection=memory_chunk_collection,
|
|
154
|
+
)
|
|
155
|
+
recall_tool = await load_memory_recall_tool(
|
|
156
|
+
user_id=user_id,
|
|
157
|
+
agent_id=agent_id,
|
|
158
|
+
customer_id=customer_id,
|
|
159
|
+
authorizer=authorizer_bundle,
|
|
160
|
+
memories_collection=memories_collection,
|
|
161
|
+
media_content_collection=media_content_collection,
|
|
162
|
+
memory_chunk_collection=memory_chunk_collection,
|
|
163
|
+
)
|
|
164
|
+
add_tool = await load_memory_add_tool(
|
|
165
|
+
user_id=user_id,
|
|
166
|
+
conversation_id=conv_id,
|
|
167
|
+
message_id=msg_id,
|
|
168
|
+
embedding_provider=embedding_provider,
|
|
169
|
+
agent_id=agent_id,
|
|
170
|
+
customer_id=customer_id,
|
|
171
|
+
authorizer=authorizer_bundle,
|
|
172
|
+
memories_collection=memories_collection,
|
|
173
|
+
)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Configuration
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from threetears.agent.memory import MemoryConfig
|
|
180
|
+
|
|
181
|
+
config = MemoryConfig(
|
|
182
|
+
similarity_threshold=0.4, # minimum cosine similarity for retrieval
|
|
183
|
+
detail_threshold=0.85, # threshold for including full memory detail
|
|
184
|
+
context_budget=15, # max memories in context
|
|
185
|
+
dedup_threshold=0.85, # similarity threshold for deduplication
|
|
186
|
+
max_candidates=10, # max candidates per extraction
|
|
187
|
+
)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Database Schema
|
|
191
|
+
|
|
192
|
+
Requires PostgreSQL with the `pgvector` extension. The package's own migration runner (`threetears.agent.memory.migrations.register`) produces the full schema per agent schema. Registered versions:
|
|
193
|
+
|
|
194
|
+
- **v001** -- `memories` (PK `memory_id`, pgvector `embedding`, scoping ids, content, summary, lifecycle timestamps).
|
|
195
|
+
- **v002** -- `conversation_memory_refs` (ledger of per-conversation surfaced items).
|
|
196
|
+
- **v003** -- column reconciliation: renames PK and discriminator to match the package code (`id` to `memory_id`, `memory_type` to `type_memory`), drops columns the code does not read (`embedding_model`, `importance`, `metadata`, `date_accessed`), loosens `agent_id`/`customer_id` to NULL.
|
|
197
|
+
- **v004** -- lifecycle + conversation-link columns on `memories` (`conversation_id`, `message_id_source`, `is_deleted`, `media_id`, `date_deleted`, `summary`) with indexes.
|
|
198
|
+
- **v005** -- FTS: `search_vector TSVECTOR` + GIN index + maintenance trigger on `memories`.
|
|
199
|
+
- **v006** -- `media` (parent) + `media_content` (chunked extracted text with embedding + FTS).
|
|
200
|
+
- **v007** -- `memory_chunks` (document-style chunks with heading / page metadata + embedding + FTS).
|
|
201
|
+
|
|
202
|
+
Every FTS column is trigger-maintained from `content` + `summary` (weighted A/B); callers do not have to populate `search_vector` manually. Integration tests under `tests/integration/` exercise the full chain + every public API surface against `pgvector/pgvector:pg16` via testcontainers.
|
|
203
|
+
|
|
204
|
+
## RBAC Enforcement
|
|
205
|
+
|
|
206
|
+
Memory reads, writes, and extractions flow through the unified rbac evaluator in `threetears.agent.acl`. Every (agent, customer) pair is a `memory`-type namespace in the `namespaces` table; each access resolves the namespace and evaluates one of three canonical actions against the caller's `(user_id, agent_id)` pair:
|
|
207
|
+
|
|
208
|
+
- `memory.read` -- retrieval / search / recall. Guarded on `MemoryRetriever.retrieve*`, `MemoriesCollection.find_by_user`, `MemoriesCollection.find_by_scope`, the `memory_search` + `memory_recall` LangChain tools.
|
|
209
|
+
- `memory.write` -- user-initiated writes. Guarded on `MemoriesCollection.save_memory` and the `memory_add` LangChain tool.
|
|
210
|
+
- `memory.extract` -- agent-internal extraction path. Guarded on `MemoryExtractor.extract`; the owner short-circuit keeps the common case (agent emitting memories on its own namespace) grant-free.
|
|
211
|
+
|
|
212
|
+
Owner short-circuit: the evaluator allows any action when the calling agent owns the memory namespace. Agent-internal retrieval and extraction therefore work without explicit grants; user-initiated reads and writes require evaluator assignments.
|
|
213
|
+
|
|
214
|
+
Auto-assignment on first user-write: `memory_add` ensures a `MemoryOwner` assignment for the calling user on their first write (idempotent-by-state; the ensurer only fires when the user has zero memory rows in the target schema). Subsequent writes authorize against the materialized grant; admin-revoked grants stay revoked (the ensurer does not resurrect them).
|
|
215
|
+
|
|
216
|
+
Wiring shape: every consumer of the memory surface REQUIRES a `MemoryAuthorizerDependencies` bundle exposing:
|
|
217
|
+
|
|
218
|
+
- `acl_cache` -- shared `threetears.agent.acl.AclCache` instance;
|
|
219
|
+
- `membership_loader` + `grant_loader` -- the evaluator's loaders (`threetears.agent.acl.MembershipLoader` / `GrantLoader`);
|
|
220
|
+
- `namespace_collection` -- three-tier `NamespaceCollection` used to resolve the memory namespace via `get_by_owner_and_customer(namespace_type="memory", owner_agent_id, customer_id)` (create-if-absent flows through `save_entity`);
|
|
221
|
+
- `group_collection` + `group_member_collection` + `role_collection` + `role_assignment_collection` -- the rbac Collections the first-write owner-assignment path uses via `ensure_memory_owner_assignment(...)`.
|
|
222
|
+
|
|
223
|
+
There is no bypass. Every `MemoriesCollection`, `MemoryRetriever`, `MemoryExtractor`, and LangChain tool factory (`load_memory_search_tool`, `load_memory_add_tool`, `load_memory_recall_tool`) takes the bundle as a required constructor/factory argument; every code path that touches a memory row runs `authorize_memory_access` first. Callers that omit the bundle fail at the type checker and the Python signature boundary.
|
|
224
|
+
|
|
225
|
+
- Production wiring builds the bundle directly from the agent-side three-tier stack's Collections (`NatsProxyL3Backend`-backed `NamespaceCollection` / `GroupCollection` / ...).
|
|
226
|
+
- Test wiring injects a permissive fixture `permissive_memory_authorizer` (see `tests/conftest.py`) that carries in-memory Collection stand-ins and a permissive evaluator. Fixture usage is explicit in every test file that constructs a memory surface.
|
|
227
|
+
- Back-office / admin tooling that genuinely needs to read or write memories without an identity must construct its own bundle with Collections bound directly to an asyncpg pool; there is no global escape hatch.
|
|
228
|
+
|
|
229
|
+
See `threetears.agent.memory.authorize` for the full public surface.
|
|
230
|
+
|
|
231
|
+
The three platform roles (`MemoryOwner` / `MemoryReader` / `MemoryWriter`) carry the canonical action vocabulary. Platform-side migrations seed these roles and backfill the rbac rows required for evaluator resolution.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
threetears/agent/memory/__init__.py,sha256=jGo_9QlPJ8eFMX6e6VBAlH5WJYt4Q5zSPMYAjgQJ7do,10678
|
|
2
|
+
threetears/agent/memory/access.py,sha256=Hk9WQda_ssC-kcR2PfiTDx5uUCfh5uPgihQEqfFZu_w,8309
|
|
3
|
+
threetears/agent/memory/authorize.py,sha256=07mPdKHSjFgilmdOgBXxVFLKklDcCc5Dwk7deJfSfLY,19705
|
|
4
|
+
threetears/agent/memory/collections.py,sha256=QCojKCUVKAdsRdXnP1gRiyumvaNV3oHJSrM5Gp2S3Vk,128370
|
|
5
|
+
threetears/agent/memory/embedding_utils.py,sha256=cFZ4pHxzAShLCFfytDA8fwwRtCUExku8ILj0HE-5YzU,5323
|
|
6
|
+
threetears/agent/memory/entities.py,sha256=0PocHbBQUtOY_WNw8RgvnyJzxvXnmdxfTetxAhIvg6U,34495
|
|
7
|
+
threetears/agent/memory/events.py,sha256=8yhFcprivqFgLiZyJfs-UdMWifGodGJQtxp5gNd-X30,9355
|
|
8
|
+
threetears/agent/memory/extraction.py,sha256=LamsymOrCwwsRLaqchtSdB-0goNjR0gg0ZZ7K3oGSi4,31173
|
|
9
|
+
threetears/agent/memory/integration.py,sha256=aKJXO5rOdwTPpY_JpWW-edpd8FNG9XeBrrzH029Wd_o,13406
|
|
10
|
+
threetears/agent/memory/merge.py,sha256=mjNja4X94OR9un3gKCG9B_mw4fGV3gCEnmmQAVR8jXY,7400
|
|
11
|
+
threetears/agent/memory/middleware.py,sha256=YGDfLBpnuj1ZEeM4iZvKiVjgLjHl0U01vF_C5sqWgQM,15072
|
|
12
|
+
threetears/agent/memory/prompts.py,sha256=ms1OEM295Zd-2eJvpCjFTIcK4oh6S6wzMzgQ-PIIn80,6217
|
|
13
|
+
threetears/agent/memory/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
threetears/agent/memory/retrieval.py,sha256=lAVW648E6Fi893eXlsnD8szAOISdBK6QoIgoIy8yNw0,24338
|
|
15
|
+
threetears/agent/memory/tools.py,sha256=2h-XNpefK79Lr1IhjZBriOADLPKLa8AJe30CvZVOcN0,64570
|
|
16
|
+
threetears/agent/memory/types.py,sha256=MesgOsGGgjbdgWUh7g84ADCxzcdgfa9H_8NQAR8S5RE,1980
|
|
17
|
+
threetears/agent/memory/migrations/__init__.py,sha256=H5olHd_veZC9dVvaUSg1Nx2dNM5ZVKxjSnFJOJGoja4,8808
|
|
18
|
+
threetears/agent/memory/migrations/v001_create_memories_table.py,sha256=Ls_rkYDdVSMO5ioVG-_J2GGhVx3kWXlxIt0BjYoata8,2602
|
|
19
|
+
threetears/agent/memory/migrations/v002_create_conversation_memory_refs.py,sha256=pXV_yBm44NswVIGYvCIEoxdAExAw-0yFehe96LjuVx4,1544
|
|
20
|
+
threetears/agent/memory/migrations/v003_memory_column_reconciliation.py,sha256=LU7q2KIAFbvMy86yp9WjAw94RHjC2TJD_nvD6LUSE50,4055
|
|
21
|
+
threetears/agent/memory/migrations/v004_memory_lifecycle_columns.py,sha256=jhb4uLZqe9SZJtgBezyZAMl9Au7JagmEGKBTZwxL1bA,2952
|
|
22
|
+
threetears/agent/memory/migrations/v005_memory_fts.py,sha256=lTerrZ9_i4oWbkttN6rZDDEBstcO0YIzeYWwJktTaLc,2519
|
|
23
|
+
threetears/agent/memory/migrations/v006_memory_media_content.py,sha256=FmB8og7DCKjG2pBDLu8-NMfGbnWg23T92eTuLQQQabk,4076
|
|
24
|
+
threetears/agent/memory/migrations/v007_memory_chunks.py,sha256=muGDAttKEn411MBX3kI45TT_bObzA39u8qXJIKLLd0g,3341
|
|
25
|
+
threetears/agent/memory/migrations/v008_restore_memories_agent_customer_not_null.py,sha256=UhyDYOTEsoeP3Oj_fZuiK57eceTpRps_WoOe0MqoqV8,2842
|
|
26
|
+
threetears/agent/memory/migrations/v009_media_composite_fk.py,sha256=wlM19dxcz836wQCunOQkFWgh1lJ3xNhrvBozEJEyuis,4937
|
|
27
|
+
threetears/agent/memory/migrations/v010_media_content_composite_fk.py,sha256=IU0RfAWqY2Ukwu-YclyRtDKqOxqFvPKefkCy3oqe_wc,3188
|
|
28
|
+
threetears/agent/memory/migrations/v011_memory_chunks_composite_fk.py,sha256=_hwAkREFlIcwrDcok5EqOFiB1JVcsydXjD1MK3utw9c,3105
|
|
29
|
+
threetears/agent/memory/migrations/v012_memories_media_composite_fk.py,sha256=vRhn97Vz6Sqmz_kkl1VpQtDfzTeTQWLewrZOA1jXlqQ,5069
|
|
30
|
+
threetears/agent/memory/migrations/v013_datetime_to_datetimetz.py,sha256=mjSDeZiES7PtPYzzw9tcJddm7xHg63h5ww-siK1F1lA,8081
|
|
31
|
+
threetears/agent/memory/migrations/v014_memory_refs_date_columns.py,sha256=KDSCeWXz9obpOPFdn6B_zzS1snBrzmC00PdE2GLBhV0,4546
|
|
32
|
+
threetears/agent/memory/migrations/v015_unified_memory_columns.py,sha256=aifypnMEji3y3GW0uqsNwM-BTyHNZ7sJiDHJHolsVTw,5112
|
|
33
|
+
threetears/agent/memory/migrations/v016_backfill_memory_ids.py,sha256=Lng6Hih_FShYtLOjvnKWjA5zN26xgDTyLSiWfHD9dK0,9594
|
|
34
|
+
threetears/agent/memory/migrations/v017_memory_fk_flip.py,sha256=COGO7QrgLTULE4-5MO4DnNoy5a35xtpiaGIFRd4GXMM,5423
|
|
35
|
+
threetears/agent/memory/migrations/v018_drop_legacy_memory_columns.py,sha256=S65m9ujHQgp89Ti03x_dRnu2zO_YXWBy9C8rbD7Z5E8,5936
|
|
36
|
+
threetears/agent/memory/migrations/v019_conversation_id_not_null.py,sha256=8GHKou_JBqWA1BT8gGuPxG5H2Hel0xnZK_mtP4FSEe8,2390
|
|
37
|
+
threetears/agent/memory/migrations/v020_memories_alias.py,sha256=yyl6GYnl5gzA5glfXuubSO47kun_ixzWVgo-BYvZCZ8,1763
|
|
38
|
+
threetears/agent/memory/migrations/v021_memory_chunks_index_and_token.py,sha256=QY5mysFEnnTsePLo0C4t2gkXyewjQNa9WzV3ZN5SbW4,14088
|
|
39
|
+
threetears/agent/memory/migrations/v022_add_hnsw_gin_indexes.py,sha256=55zu4kDqTsWmiH3JR34lfeEpkgM9wjzKOB9NkSbI8Pc,9652
|
|
40
|
+
threetears/agent/memory/migrations/v023_fix_idx_chunks_message_id_start.py,sha256=4nZZVR_94XapT0PSBMYExBVbMVNuQhzstrNtXnPtcok,2995
|
|
41
|
+
3tears_agent_memory-0.14.0.dist-info/METADATA,sha256=MUXbhpydR3YibUXsj5ujV-Q9D3yqI_R8H_QmZKQdF9E,12216
|
|
42
|
+
3tears_agent_memory-0.14.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
43
|
+
3tears_agent_memory-0.14.0.dist-info/licenses/LICENSE,sha256=7GWEoEOcFJenZLt4LDzqH2K7QLxo_2m8rzG7Vv8VGXo,1066
|
|
44
|
+
3tears_agent_memory-0.14.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mark Pace
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"""Agent memory package -- memory entities, collections, and embedding protocol."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
# Version derived from pyproject.toml so the metadata is the single
|
|
6
|
+
# source of truth -- a future release that bumps pyproject without
|
|
7
|
+
# updating ``__init__.py`` can't drift the runtime ``__version__``.
|
|
8
|
+
# The except guard handles the rare case where the package isn't
|
|
9
|
+
# installed via importlib.metadata (e.g. running directly from a
|
|
10
|
+
# checked-out source tree without ``uv sync``); the fallback keeps
|
|
11
|
+
# imports working but reports ``unknown`` rather than crashing.
|
|
12
|
+
from importlib.metadata import PackageNotFoundError as _PackageNotFoundError
|
|
13
|
+
from importlib.metadata import version as _version
|
|
14
|
+
from typing import TYPE_CHECKING
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
__version__ = _version("3tears-agent-memory")
|
|
18
|
+
except _PackageNotFoundError: # pragma: no cover - dev fallback
|
|
19
|
+
__version__ = "unknown"
|
|
20
|
+
|
|
21
|
+
# lazy public API (PEP 562). the package namespace no longer imports its
|
|
22
|
+
# implementation modules eagerly: importing this package (or any of its
|
|
23
|
+
# submodules) costs only this file, and each public attribute resolves
|
|
24
|
+
# its defining module on first access. the TYPE_CHECKING block carries
|
|
25
|
+
# the real imports so mypy and IDEs see the full statically-typed API;
|
|
26
|
+
# the _LAZY map is the runtime equivalent. the three-way agreement
|
|
27
|
+
# between __all__, _LAZY, and the TYPE_CHECKING block is pinned by the
|
|
28
|
+
# package's lazy-surface consistency test.
|
|
29
|
+
# decision record: docs/separate-concerns-decisions.md (hand-rolled
|
|
30
|
+
# PEP 562 over lazy_loader -- zero added runtime deps, no stub drift).
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
from threetears.agent.memory.access import MemoryAccessService
|
|
33
|
+
from threetears.agent.memory.authorize import (
|
|
34
|
+
ACTION_MEMORY_EXTRACT,
|
|
35
|
+
ACTION_MEMORY_READ,
|
|
36
|
+
ACTION_MEMORY_WRITE,
|
|
37
|
+
MEMORY_NAMESPACE_TYPE,
|
|
38
|
+
MEMORY_OWNER_GROUP_PREFIX,
|
|
39
|
+
MEMORY_OWNER_ROLE_NAME,
|
|
40
|
+
MemoryAccessDenied,
|
|
41
|
+
MemoryAuthorizerDependencies,
|
|
42
|
+
authorize_memory_access,
|
|
43
|
+
ensure_memory_owner_assignment,
|
|
44
|
+
memory_namespace_name,
|
|
45
|
+
)
|
|
46
|
+
from threetears.agent.memory.collections import (
|
|
47
|
+
MediaCollection,
|
|
48
|
+
MediaContentCollection,
|
|
49
|
+
MemoriesCollection,
|
|
50
|
+
MemoryChunkCollection,
|
|
51
|
+
MemoryRefsCollection,
|
|
52
|
+
conversation_memory_refs_table,
|
|
53
|
+
)
|
|
54
|
+
from threetears.agent.memory.embedding_utils import embedding_attribution_scope
|
|
55
|
+
from threetears.agent.memory.entities import (
|
|
56
|
+
MediaContentEntity,
|
|
57
|
+
MediaEntity,
|
|
58
|
+
MemoryChunkEntity,
|
|
59
|
+
MemoryEntity,
|
|
60
|
+
MemoryRefEntity,
|
|
61
|
+
)
|
|
62
|
+
from threetears.agent.memory.events import (
|
|
63
|
+
MemoryCreatedEvent,
|
|
64
|
+
MemoryRetrievedEvent,
|
|
65
|
+
default_memory_created_dispatcher,
|
|
66
|
+
)
|
|
67
|
+
from threetears.agent.memory.extraction import ChatModelFactory, MemoryExtractor
|
|
68
|
+
from threetears.agent.memory.integration import (
|
|
69
|
+
MemoryIntegration,
|
|
70
|
+
NatsEmbeddingAdapter,
|
|
71
|
+
extract_memories,
|
|
72
|
+
retrieve_memories,
|
|
73
|
+
)
|
|
74
|
+
from threetears.agent.memory.merge import MemoryRepointResult, repoint_user
|
|
75
|
+
from threetears.agent.memory.middleware import MemoryInjectionMiddleware
|
|
76
|
+
from threetears.agent.memory.prompts import ExtractionPrompts
|
|
77
|
+
from threetears.agent.memory.retrieval import MemoryRetriever, RetrievalResult
|
|
78
|
+
from threetears.agent.memory.tools import (
|
|
79
|
+
ChunkRecallInput,
|
|
80
|
+
ChunkSearchInput,
|
|
81
|
+
MemoryAddInput,
|
|
82
|
+
MemoryRecallInput,
|
|
83
|
+
MemorySearchInput,
|
|
84
|
+
load_chunk_recall_tool,
|
|
85
|
+
load_chunk_search_tool,
|
|
86
|
+
load_memory_add_tool,
|
|
87
|
+
load_memory_recall_tool,
|
|
88
|
+
load_memory_search_tool,
|
|
89
|
+
)
|
|
90
|
+
from threetears.agent.memory.types import MemoryConfig, MemoryType
|
|
91
|
+
|
|
92
|
+
# public attribute -> (defining module, attribute name in that module)
|
|
93
|
+
_LAZY: dict[str, tuple[str, str]] = {
|
|
94
|
+
"ACTION_MEMORY_EXTRACT": ("threetears.agent.memory.authorize", "ACTION_MEMORY_EXTRACT"),
|
|
95
|
+
"ACTION_MEMORY_READ": ("threetears.agent.memory.authorize", "ACTION_MEMORY_READ"),
|
|
96
|
+
"ACTION_MEMORY_WRITE": ("threetears.agent.memory.authorize", "ACTION_MEMORY_WRITE"),
|
|
97
|
+
"ChatModelFactory": ("threetears.agent.memory.extraction", "ChatModelFactory"),
|
|
98
|
+
"ChunkRecallInput": ("threetears.agent.memory.tools", "ChunkRecallInput"),
|
|
99
|
+
"ChunkSearchInput": ("threetears.agent.memory.tools", "ChunkSearchInput"),
|
|
100
|
+
"ExtractionPrompts": ("threetears.agent.memory.prompts", "ExtractionPrompts"),
|
|
101
|
+
"MEMORY_NAMESPACE_TYPE": ("threetears.agent.memory.authorize", "MEMORY_NAMESPACE_TYPE"),
|
|
102
|
+
"MEMORY_OWNER_GROUP_PREFIX": ("threetears.agent.memory.authorize", "MEMORY_OWNER_GROUP_PREFIX"),
|
|
103
|
+
"MEMORY_OWNER_ROLE_NAME": ("threetears.agent.memory.authorize", "MEMORY_OWNER_ROLE_NAME"),
|
|
104
|
+
"MediaCollection": ("threetears.agent.memory.collections", "MediaCollection"),
|
|
105
|
+
"MediaContentCollection": ("threetears.agent.memory.collections", "MediaContentCollection"),
|
|
106
|
+
"MediaContentEntity": ("threetears.agent.memory.entities", "MediaContentEntity"),
|
|
107
|
+
"MediaEntity": ("threetears.agent.memory.entities", "MediaEntity"),
|
|
108
|
+
"MemoriesCollection": ("threetears.agent.memory.collections", "MemoriesCollection"),
|
|
109
|
+
"MemoryAccessDenied": ("threetears.agent.memory.authorize", "MemoryAccessDenied"),
|
|
110
|
+
"MemoryAccessService": ("threetears.agent.memory.access", "MemoryAccessService"),
|
|
111
|
+
"MemoryAddInput": ("threetears.agent.memory.tools", "MemoryAddInput"),
|
|
112
|
+
"MemoryAuthorizerDependencies": ("threetears.agent.memory.authorize", "MemoryAuthorizerDependencies"),
|
|
113
|
+
"MemoryChunkCollection": ("threetears.agent.memory.collections", "MemoryChunkCollection"),
|
|
114
|
+
"MemoryChunkEntity": ("threetears.agent.memory.entities", "MemoryChunkEntity"),
|
|
115
|
+
"MemoryConfig": ("threetears.agent.memory.types", "MemoryConfig"),
|
|
116
|
+
"MemoryCreatedEvent": ("threetears.agent.memory.events", "MemoryCreatedEvent"),
|
|
117
|
+
"MemoryEntity": ("threetears.agent.memory.entities", "MemoryEntity"),
|
|
118
|
+
"MemoryExtractor": ("threetears.agent.memory.extraction", "MemoryExtractor"),
|
|
119
|
+
"MemoryInjectionMiddleware": ("threetears.agent.memory.middleware", "MemoryInjectionMiddleware"),
|
|
120
|
+
"MemoryIntegration": ("threetears.agent.memory.integration", "MemoryIntegration"),
|
|
121
|
+
"MemoryRecallInput": ("threetears.agent.memory.tools", "MemoryRecallInput"),
|
|
122
|
+
"MemoryRefEntity": ("threetears.agent.memory.entities", "MemoryRefEntity"),
|
|
123
|
+
"MemoryRefsCollection": ("threetears.agent.memory.collections", "MemoryRefsCollection"),
|
|
124
|
+
"MemoryRetrievedEvent": ("threetears.agent.memory.events", "MemoryRetrievedEvent"),
|
|
125
|
+
"MemoryRepointResult": ("threetears.agent.memory.merge", "MemoryRepointResult"),
|
|
126
|
+
"MemoryRetriever": ("threetears.agent.memory.retrieval", "MemoryRetriever"),
|
|
127
|
+
"MemorySearchInput": ("threetears.agent.memory.tools", "MemorySearchInput"),
|
|
128
|
+
"MemoryType": ("threetears.agent.memory.types", "MemoryType"),
|
|
129
|
+
"NatsEmbeddingAdapter": ("threetears.agent.memory.integration", "NatsEmbeddingAdapter"),
|
|
130
|
+
"RetrievalResult": ("threetears.agent.memory.retrieval", "RetrievalResult"),
|
|
131
|
+
"authorize_memory_access": ("threetears.agent.memory.authorize", "authorize_memory_access"),
|
|
132
|
+
"conversation_memory_refs_table": ("threetears.agent.memory.collections", "conversation_memory_refs_table"),
|
|
133
|
+
"default_memory_created_dispatcher": ("threetears.agent.memory.events", "default_memory_created_dispatcher"),
|
|
134
|
+
"embedding_attribution_scope": ("threetears.agent.memory.embedding_utils", "embedding_attribution_scope"),
|
|
135
|
+
"ensure_memory_owner_assignment": ("threetears.agent.memory.authorize", "ensure_memory_owner_assignment"),
|
|
136
|
+
"extract_memories": ("threetears.agent.memory.integration", "extract_memories"),
|
|
137
|
+
"load_chunk_recall_tool": ("threetears.agent.memory.tools", "load_chunk_recall_tool"),
|
|
138
|
+
"load_chunk_search_tool": ("threetears.agent.memory.tools", "load_chunk_search_tool"),
|
|
139
|
+
"load_memory_add_tool": ("threetears.agent.memory.tools", "load_memory_add_tool"),
|
|
140
|
+
"load_memory_recall_tool": ("threetears.agent.memory.tools", "load_memory_recall_tool"),
|
|
141
|
+
"load_memory_search_tool": ("threetears.agent.memory.tools", "load_memory_search_tool"),
|
|
142
|
+
"memory_namespace_name": ("threetears.agent.memory.authorize", "memory_namespace_name"),
|
|
143
|
+
"repoint_user": ("threetears.agent.memory.merge", "repoint_user"),
|
|
144
|
+
"retrieve_memories": ("threetears.agent.memory.integration", "retrieve_memories"),
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
__all__ = [
|
|
148
|
+
"ACTION_MEMORY_EXTRACT",
|
|
149
|
+
"ACTION_MEMORY_READ",
|
|
150
|
+
"ACTION_MEMORY_WRITE",
|
|
151
|
+
"ChatModelFactory",
|
|
152
|
+
"ChunkRecallInput",
|
|
153
|
+
"ChunkSearchInput",
|
|
154
|
+
"ExtractionPrompts",
|
|
155
|
+
"MEMORY_NAMESPACE_TYPE",
|
|
156
|
+
"MEMORY_OWNER_GROUP_PREFIX",
|
|
157
|
+
"MEMORY_OWNER_ROLE_NAME",
|
|
158
|
+
"MediaCollection",
|
|
159
|
+
"MediaContentCollection",
|
|
160
|
+
"MediaContentEntity",
|
|
161
|
+
"MediaEntity",
|
|
162
|
+
"MemoriesCollection",
|
|
163
|
+
"MemoryAccessDenied",
|
|
164
|
+
"MemoryAccessService",
|
|
165
|
+
"MemoryAddInput",
|
|
166
|
+
"MemoryAuthorizerDependencies",
|
|
167
|
+
"MemoryChunkCollection",
|
|
168
|
+
"MemoryChunkEntity",
|
|
169
|
+
"MemoryConfig",
|
|
170
|
+
"MemoryCreatedEvent",
|
|
171
|
+
"MemoryEntity",
|
|
172
|
+
"MemoryExtractor",
|
|
173
|
+
"MemoryInjectionMiddleware",
|
|
174
|
+
"MemoryIntegration",
|
|
175
|
+
"MemoryRecallInput",
|
|
176
|
+
"MemoryRefEntity",
|
|
177
|
+
"MemoryRefsCollection",
|
|
178
|
+
"MemoryRepointResult",
|
|
179
|
+
"MemoryRetrievedEvent",
|
|
180
|
+
"MemoryRetriever",
|
|
181
|
+
"MemorySearchInput",
|
|
182
|
+
"MemoryType",
|
|
183
|
+
"NatsEmbeddingAdapter",
|
|
184
|
+
"RetrievalResult",
|
|
185
|
+
"authorize_memory_access",
|
|
186
|
+
"conversation_memory_refs_table",
|
|
187
|
+
"default_memory_created_dispatcher",
|
|
188
|
+
"embedding_attribution_scope",
|
|
189
|
+
"ensure_memory_owner_assignment",
|
|
190
|
+
"extract_memories",
|
|
191
|
+
"load_chunk_recall_tool",
|
|
192
|
+
"load_chunk_search_tool",
|
|
193
|
+
"load_memory_add_tool",
|
|
194
|
+
"load_memory_recall_tool",
|
|
195
|
+
"load_memory_search_tool",
|
|
196
|
+
"memory_namespace_name",
|
|
197
|
+
"repoint_user",
|
|
198
|
+
"retrieve_memories",
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def __getattr__(name: str) -> object:
|
|
203
|
+
"""resolve a public attribute from its defining module on first access.
|
|
204
|
+
|
|
205
|
+
:param name: attribute name being resolved
|
|
206
|
+
:ptype name: str
|
|
207
|
+
:return: the resolved attribute (also cached in module globals so
|
|
208
|
+
``__getattr__`` fires at most once per name)
|
|
209
|
+
:rtype: object
|
|
210
|
+
:raises AttributeError: when ``name`` is not part of the public API
|
|
211
|
+
"""
|
|
212
|
+
entry = _LAZY.get(name)
|
|
213
|
+
if entry is None:
|
|
214
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
215
|
+
from importlib import import_module
|
|
216
|
+
|
|
217
|
+
module_name, attr = entry
|
|
218
|
+
value: object = getattr(import_module(module_name), attr)
|
|
219
|
+
globals()[name] = value
|
|
220
|
+
return value
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def __dir__() -> list[str]:
|
|
224
|
+
"""include lazy attributes in ``dir()`` output.
|
|
225
|
+
|
|
226
|
+
:return: sorted union of materialized globals and lazy names
|
|
227
|
+
:rtype: list[str]
|
|
228
|
+
"""
|
|
229
|
+
return sorted(set(globals()) | set(_LAZY))
|