pdm-memory 0.1.2__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 (48) hide show
  1. pdm_memory-0.1.2/LICENSE +50 -0
  2. pdm_memory-0.1.2/PKG-INFO +485 -0
  3. pdm_memory-0.1.2/README.md +382 -0
  4. pdm_memory-0.1.2/pdm_memory/__init__.py +22 -0
  5. pdm_memory-0.1.2/pdm_memory/auth/__init__.py +4 -0
  6. pdm_memory-0.1.2/pdm_memory/auth/jwt_handler.py +119 -0
  7. pdm_memory-0.1.2/pdm_memory/bench.py +5 -0
  8. pdm_memory-0.1.2/pdm_memory/core/__init__.py +1 -0
  9. pdm_memory-0.1.2/pdm_memory/core/math.py +329 -0
  10. pdm_memory-0.1.2/pdm_memory/core/retrieval.py +362 -0
  11. pdm_memory-0.1.2/pdm_memory/core/signature.py +257 -0
  12. pdm_memory-0.1.2/pdm_memory/ingest/__init__.py +6 -0
  13. pdm_memory-0.1.2/pdm_memory/ingest/auto_signature.py +202 -0
  14. pdm_memory-0.1.2/pdm_memory/ingest/batch.py +164 -0
  15. pdm_memory-0.1.2/pdm_memory/ingest/ingester.py +272 -0
  16. pdm_memory-0.1.2/pdm_memory/integrations/__init__.py +21 -0
  17. pdm_memory-0.1.2/pdm_memory/integrations/anthropic_adapter.py +179 -0
  18. pdm_memory-0.1.2/pdm_memory/integrations/context_manager.py +134 -0
  19. pdm_memory-0.1.2/pdm_memory/integrations/gemini_adapter.py +215 -0
  20. pdm_memory-0.1.2/pdm_memory/integrations/groq_adapter.py +171 -0
  21. pdm_memory-0.1.2/pdm_memory/integrations/ollama_adapter.py +184 -0
  22. pdm_memory-0.1.2/pdm_memory/integrations/openai_adapter.py +191 -0
  23. pdm_memory-0.1.2/pdm_memory/memory.py +552 -0
  24. pdm_memory-0.1.2/pdm_memory/storage/__init__.py +5 -0
  25. pdm_memory-0.1.2/pdm_memory/storage/base.py +123 -0
  26. pdm_memory-0.1.2/pdm_memory/storage/cloud_driver.py +271 -0
  27. pdm_memory-0.1.2/pdm_memory/storage/sqlite_driver.py +331 -0
  28. pdm_memory-0.1.2/pdm_memory/sync.py +145 -0
  29. pdm_memory-0.1.2/pdm_memory/tools/__init__.py +1 -0
  30. pdm_memory-0.1.2/pdm_memory/tools/bench.py +294 -0
  31. pdm_memory-0.1.2/pdm_memory/tools/cli.py +207 -0
  32. pdm_memory-0.1.2/pdm_memory.egg-info/PKG-INFO +485 -0
  33. pdm_memory-0.1.2/pdm_memory.egg-info/SOURCES.txt +46 -0
  34. pdm_memory-0.1.2/pdm_memory.egg-info/dependency_links.txt +1 -0
  35. pdm_memory-0.1.2/pdm_memory.egg-info/entry_points.txt +2 -0
  36. pdm_memory-0.1.2/pdm_memory.egg-info/requires.txt +37 -0
  37. pdm_memory-0.1.2/pdm_memory.egg-info/top_level.txt +1 -0
  38. pdm_memory-0.1.2/pyproject.toml +66 -0
  39. pdm_memory-0.1.2/setup.cfg +4 -0
  40. pdm_memory-0.1.2/tests/test_bench.py +24 -0
  41. pdm_memory-0.1.2/tests/test_cli.py +110 -0
  42. pdm_memory-0.1.2/tests/test_gemini_adapter.py +102 -0
  43. pdm_memory-0.1.2/tests/test_groq_adapter.py +66 -0
  44. pdm_memory-0.1.2/tests/test_jwt_auth.py +187 -0
  45. pdm_memory-0.1.2/tests/test_math.py +201 -0
  46. pdm_memory-0.1.2/tests/test_memory.py +152 -0
  47. pdm_memory-0.1.2/tests/test_ollama_adapter.py +67 -0
  48. pdm_memory-0.1.2/tests/test_sqlite_driver.py +141 -0
@@ -0,0 +1,50 @@
1
+ MIT License with Patent Scope Clause
2
+
3
+ Copyright (c) 2026 Westfield Innovations LLC
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.
22
+
23
+ ─────────────────────────────────────────────
24
+ PATENT SCOPE CLAUSE (Additional Terms)
25
+ ─────────────────────────────────────────────
26
+
27
+ The above MIT license grant covers the software source code in this repository.
28
+ It does not grant any license to patents held or applied for by Westfield
29
+ Innovations LLC, including but not limited to patents covering the following
30
+ methods and systems embodied in the Pressure-Driven Memory (PDM) system:
31
+
32
+ 1. Pressure-based memory retrieval and ranking (threshold-driven recall).
33
+ 2. Resonance retrieval via threshold-adjustment search (TAS).
34
+ 3. Temporal deformation geometry for deadline-aware memory pressure.
35
+ 4. Validation coefficient computation for memory signal quality.
36
+ 5. Incremental decay without a scheduler (time-delta-based decay on read).
37
+
38
+ The license granted by this file permits you to:
39
+ ✓ Use this SDK (pdm-memory) in your applications.
40
+ ✓ Distribute applications that incorporate this SDK.
41
+ ✓ Modify this SDK for your own use or contribution back to this repository.
42
+
43
+ This license does NOT permit you to:
44
+ ✗ Reimplement the patented PDM algorithms independently (outside this SDK).
45
+ ✗ Use the patent claims of PDM to build a competing product.
46
+ ✗ Sub-license the patent rights granted herein to third parties.
47
+
48
+ Use of the SDK constitutes acceptance of these additional terms.
49
+ For commercial licensing inquiries beyond the scope described above,
50
+ contact: legal@westfieldinnovations.com
@@ -0,0 +1,485 @@
1
+ Metadata-Version: 2.4
2
+ Name: pdm-memory
3
+ Version: 0.1.2
4
+ Summary: Pressure-Driven Memory (PDM) — persistent, resonance-based memory for AI apps.
5
+ Author: Westfield Innovations LLC
6
+ License: MIT License with Patent Scope Clause
7
+
8
+ Copyright (c) 2026 Westfield Innovations LLC
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ ─────────────────────────────────────────────
29
+ PATENT SCOPE CLAUSE (Additional Terms)
30
+ ─────────────────────────────────────────────
31
+
32
+ The above MIT license grant covers the software source code in this repository.
33
+ It does not grant any license to patents held or applied for by Westfield
34
+ Innovations LLC, including but not limited to patents covering the following
35
+ methods and systems embodied in the Pressure-Driven Memory (PDM) system:
36
+
37
+ 1. Pressure-based memory retrieval and ranking (threshold-driven recall).
38
+ 2. Resonance retrieval via threshold-adjustment search (TAS).
39
+ 3. Temporal deformation geometry for deadline-aware memory pressure.
40
+ 4. Validation coefficient computation for memory signal quality.
41
+ 5. Incremental decay without a scheduler (time-delta-based decay on read).
42
+
43
+ The license granted by this file permits you to:
44
+ ✓ Use this SDK (pdm-memory) in your applications.
45
+ ✓ Distribute applications that incorporate this SDK.
46
+ ✓ Modify this SDK for your own use or contribution back to this repository.
47
+
48
+ This license does NOT permit you to:
49
+ ✗ Reimplement the patented PDM algorithms independently (outside this SDK).
50
+ ✗ Use the patent claims of PDM to build a competing product.
51
+ ✗ Sub-license the patent rights granted herein to third parties.
52
+
53
+ Use of the SDK constitutes acceptance of these additional terms.
54
+ For commercial licensing inquiries beyond the scope described above,
55
+ contact: legal@westfieldinnovations.com
56
+
57
+ Project-URL: Homepage, https://github.com/westfield-innovations/pdm-memory
58
+ Project-URL: Bug Tracker, https://github.com/westfield-innovations/pdm-memory/issues
59
+ Keywords: ai,memory,llm,rag,pressure-driven,persistent-memory
60
+ Classifier: Development Status :: 4 - Beta
61
+ Classifier: Intended Audience :: Developers
62
+ Classifier: License :: OSI Approved :: MIT License
63
+ Classifier: Programming Language :: Python :: 3
64
+ Classifier: Programming Language :: Python :: 3.10
65
+ Classifier: Programming Language :: Python :: 3.11
66
+ Classifier: Programming Language :: Python :: 3.12
67
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
68
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
69
+ Requires-Python: >=3.10
70
+ Description-Content-Type: text/markdown
71
+ License-File: LICENSE
72
+ Requires-Dist: httpx>=0.27
73
+ Provides-Extra: openai
74
+ Requires-Dist: openai>=1.0; extra == "openai"
75
+ Requires-Dist: tiktoken>=0.7; extra == "openai"
76
+ Provides-Extra: anthropic
77
+ Requires-Dist: anthropic>=0.25; extra == "anthropic"
78
+ Provides-Extra: gemini
79
+ Requires-Dist: google-genai>=0.1.0; extra == "gemini"
80
+ Provides-Extra: ollama
81
+ Requires-Dist: ollama>=0.2.0; extra == "ollama"
82
+ Provides-Extra: groq
83
+ Requires-Dist: groq>=0.9.0; extra == "groq"
84
+ Provides-Extra: all
85
+ Requires-Dist: openai>=1.0; extra == "all"
86
+ Requires-Dist: tiktoken>=0.7; extra == "all"
87
+ Requires-Dist: anthropic>=0.25; extra == "all"
88
+ Requires-Dist: google-genai>=0.1.0; extra == "all"
89
+ Requires-Dist: ollama>=0.2.0; extra == "all"
90
+ Requires-Dist: groq>=0.9.0; extra == "all"
91
+ Provides-Extra: dev
92
+ Requires-Dist: pytest>=8.0; extra == "dev"
93
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
94
+ Requires-Dist: respx>=0.21; extra == "dev"
95
+ Requires-Dist: openai>=1.0; extra == "dev"
96
+ Requires-Dist: anthropic>=0.25; extra == "dev"
97
+ Requires-Dist: tiktoken>=0.7; extra == "dev"
98
+ Requires-Dist: google-genai>=0.1.0; extra == "dev"
99
+ Requires-Dist: ollama>=0.2.0; extra == "dev"
100
+ Requires-Dist: groq>=0.9.0; extra == "dev"
101
+ Requires-Dist: ruff>=0.4; extra == "dev"
102
+ Dynamic: license-file
103
+
104
+ # PDM — Memory for AI Apps That Works Like Memory
105
+
106
+ [![PyPI](https://img.shields.io/pypi/v/pdm-memory)](https://pypi.org/project/pdm-memory/)
107
+ [![Python](https://img.shields.io/pypi/pyversions/pdm-memory)](https://pypi.org/project/pdm-memory/)
108
+ [![CI](https://github.com/westfield-innovations/pdm-memory/actions/workflows/ci.yml/badge.svg)](https://github.com/westfield-innovations/pdm-memory/actions)
109
+ [![License: MIT](https://img.shields.io/badge/License-MIT%2BPatent-blue)](LICENSE)
110
+
111
+ Your LLM forgets everything between conversations. The standard fix — stuff a vector database into the context window — is expensive, slow, and retrieves **what matches words, not what matters**.
112
+
113
+ **PDM stores meaning signatures instead of raw text.** Memories that get used grow stronger. Memories that don't, fade. Retrieval works by resonance: the question itself surfaces what's relevant, instead of a keyword search digging for it.
114
+
115
+ - 🔑 **Your API key.** Works with your existing Anthropic/OpenAI account.
116
+ - 🗄️ **Your storage.** One local file. Your data never leaves your machine. Check the source — there's no phone-home in it.
117
+ - ⚡ **Ten minutes.** `pip install pdm-memory` → three lines → persistent memory.
118
+
119
+ **Benchmarks vs standard RAG:** [link] · Run yourself: `python -m pdm_memory.bench`
120
+
121
+ ---
122
+
123
+ ## Table of Contents
124
+
125
+ 1. [Privacy Mode](#-privacy-mode-local-sqlite)
126
+ 2. [Ecosystem Mode](#-ecosystem-mode-azus-cloud)
127
+ 3. [LLM Adapters](#-llm-adapters)
128
+ 4. [Data Ingestion](#-data-ingestion)
129
+ 5. [Developer Tools](#-developer-tools)
130
+ 6. [API Reference](#-api-reference)
131
+ 7. [License](#-license)
132
+
133
+ ---
134
+
135
+ ## 🔒 Privacy Mode (Local SQLite)
136
+
137
+ Zero setup. No network calls. Your data stays in a single file on your machine.
138
+
139
+ ### Install
140
+
141
+ ```bash
142
+ pip install pdm-memory
143
+ # With OpenAI support:
144
+ pip install "pdm-memory[openai]"
145
+ # With Anthropic support:
146
+ pip install "pdm-memory[anthropic]"
147
+ # Everything:
148
+ pip install "pdm-memory[all]"
149
+ ```
150
+
151
+ ### Quick Start
152
+
153
+ ```python
154
+ from pdm_memory import Memory
155
+
156
+ # One line to start. The .db file is created automatically.
157
+ mem = Memory(store="./my_app_memory.db")
158
+
159
+ # Write: PDM assigns pressure and stores a signature.
160
+ mem.save("User prefers metric units and short answers", source="chat",
161
+ tags=["units", "formatting", "preferences"])
162
+
163
+ # Read: resonance retrieval — surfaces what's relevant, not just what matches.
164
+ hits = mem.recall("how should I format the answer?", k=5)
165
+
166
+ for h in hits:
167
+ print(h.text, h.pressure, h.last_reinforced)
168
+
169
+ # Reinforce a memory manually (recall() does this automatically).
170
+ mem.reinforce(hits[0].id)
171
+
172
+ # Inspect why a memory surfaced.
173
+ report = mem.explain(hits[0].id, query="how should I format the answer?")
174
+ print(report.render())
175
+
176
+ # Decay runs automatically on each recall(). Manual trigger:
177
+ counts = mem.decay()
178
+ print(f"Decayed: {counts['decayed']}, Deleted: {counts['deleted']}")
179
+ ```
180
+
181
+ ### Privacy-First Mode
182
+
183
+ Store only SHA-256 hashes of memory text — the content never touches disk:
184
+
185
+ ```python
186
+ mem = Memory(store="./private.db", store_raw=False)
187
+ ```
188
+
189
+ ---
190
+
191
+ ## ☁️ Ecosystem Mode (AZUS Cloud)
192
+
193
+ Connect to the AZUS Companion API to sync memories across devices and share them with the AI companion.
194
+
195
+ ### Connect to the Cloud
196
+
197
+ ```python
198
+ from pdm_memory import Memory
199
+
200
+ mem = Memory(
201
+ store="cloud",
202
+ token="eyJ...", # Your AZUS JWT access token
203
+ cloud_url="https://api.azus.ai",
204
+ )
205
+
206
+ # All save/recall operations go to the cloud.
207
+ mem.save("User's team is in Kyiv (UTC+3)", tags=["location", "team", "timezone"])
208
+ hits = mem.recall("what timezone are they in?")
209
+ ```
210
+
211
+ ### Sync Local ↔ Cloud
212
+
213
+ ```python
214
+ # Start with a local store
215
+ local_mem = Memory(store="./local.db")
216
+ local_mem.save("Local preference", tags=["pref", "local", "test"])
217
+
218
+ # Push local memories to cloud
219
+ report = local_mem.sync(
220
+ direction="push",
221
+ token="eyJ...",
222
+ cloud_url="https://api.azus.ai",
223
+ )
224
+ print(report) # SyncReport(pushed=1, pulled=0, conflicts=0, errors=0)
225
+
226
+ # Pull cloud memories to local
227
+ report = local_mem.sync(direction="pull", token="eyJ...")
228
+
229
+ # Two-way sync (higher pressure wins on conflict)
230
+ report = local_mem.sync(direction="bidirectional", token="eyJ...")
231
+ ```
232
+
233
+ ### JWT Token Handling
234
+
235
+ ```python
236
+ from pdm_memory.auth import JWTAuth
237
+
238
+ # Tokens are refreshed automatically when they expire
239
+ auth = JWTAuth(
240
+ token="eyJ...",
241
+ refresh_token="eyJ...",
242
+ refresh_url="https://api.azus.ai/api/v1/accounts/auth/refresh/",
243
+ )
244
+ ```
245
+
246
+ ---
247
+
248
+ ## 🤖 LLM Adapters
249
+
250
+ The wrapper is the demo; the primitives are the product. Most developers start here.
251
+
252
+ ### OpenAI
253
+
254
+ ```python
255
+ from pdm_memory import Memory
256
+ from pdm_memory.integrations import wrap_openai
257
+
258
+ mem = Memory(store="./my_app.db")
259
+ client = wrap_openai(api_key="sk-...", memory=mem)
260
+
261
+ # Memory is handled completely invisibly:
262
+ # - Before the call: relevant memories are injected into the system prompt
263
+ # - After the call: user message + AI reply are saved to memory
264
+ reply = client.chat("What units should I use?")
265
+ print(reply)
266
+ ```
267
+
268
+ ### Anthropic
269
+
270
+ ```python
271
+ from pdm_memory.integrations import wrap_anthropic
272
+
273
+ client = wrap_anthropic(api_key="sk-ant-...", memory=mem)
274
+ reply = client.chat("What units should I use?")
275
+ ```
276
+
277
+ ### Manual Control
278
+
279
+ ```python
280
+ from pdm_memory.integrations import ContextWindowManager
281
+
282
+ # Control exactly what goes into context
283
+ manager = ContextWindowManager(max_tokens=1500, model="gpt-4o")
284
+ hits = mem.recall("user's formatting preferences", k=10)
285
+ trimmed = manager.fit(hits) # Drop lowest-pressure memories first
286
+ system_block = manager.format_for_prompt(trimmed)
287
+ print(system_block)
288
+ ```
289
+
290
+ ---
291
+
292
+ ## 📥 Data Ingestion
293
+
294
+ ### Import Legacy Data
295
+
296
+ ```python
297
+ # From a list of dicts
298
+ mem.ingest(
299
+ data_source=[
300
+ {"text": "User hates Comic Sans", "importance": 85},
301
+ {"content": "Team deploys on Fridays — bad idea", "labels": "devops,process,risk"},
302
+ ],
303
+ mapping={"text": "compressed_fact", "importance": "p_magnitude"},
304
+ )
305
+
306
+ # From a CSV file (auto-detects common column names)
307
+ mem.ingest("./old_chat_logs.csv")
308
+
309
+ # With progress tracking
310
+ def on_progress(processed, total):
311
+ print(f"{processed}/{total} records processed")
312
+
313
+ mem.ingest("./large_dataset.csv", on_progress=on_progress)
314
+ ```
315
+
316
+ ### Auto-Generate Signatures with an LLM
317
+
318
+ ```python
319
+ import openai
320
+ client = openai.OpenAI(api_key="sk-...")
321
+
322
+ # LLM will compress raw text → compressed_fact + 3 tags + p_magnitude
323
+ mem.ingest(
324
+ data_source=["User complains about slow API responses every Monday morning"],
325
+ llm_client=client,
326
+ )
327
+ ```
328
+
329
+ ### Batch Processing (Large Datasets)
330
+
331
+ ```python
332
+ # 10,000 records processed in batches of 50, with rate limiting
333
+ mem.ingest(
334
+ data_source="./10k_records.csv",
335
+ batch_size=50,
336
+ )
337
+ ```
338
+
339
+ ---
340
+
341
+ ## 🛠️ Developer Tools
342
+
343
+ ### The explain Method
344
+
345
+ ```python
346
+ report = mem.explain(memory_id, query="how should I format this?")
347
+ print(report.render())
348
+ ```
349
+
350
+ ```
351
+ ╔══════════════════════════════════════════════════════
352
+ ║ PDM Memory Explain Report
353
+ ╠══════════════════════════════════════════════════════
354
+ ║ ID: abc12345-...
355
+ ║ Fact: User prefers metric units and short answers
356
+ ║ Tags: units, formatting, preferences
357
+ ╠──────────────────────────────────────────────────────
358
+ ║ Pressure Components:
359
+ ║ p_magnitude: 80.00
360
+ ║ V coefficient: 0.8333 (4 retrievals)
361
+ ║ Decay factor: 0.0231 (1.0d since retrieved, T½=30d)
362
+ ║ Intent weight: 1.0000
363
+ ║ Quality: 0.80
364
+ ║ ─────────────────────────────
365
+ ║ P_effective: 55.28
366
+ ╠──────────────────────────────────────────────────────
367
+ ║ Resonance (TAS coupling):
368
+ ║ coupling_score: 0.8750
369
+ ║ tag_overlap: 1.0000
370
+ ║ domain_match: 1.0000
371
+ ╚══════════════════════════════════════════════════════
372
+ ```
373
+
374
+ ### Benchmark Harness
375
+
376
+ ```bash
377
+ # Run full benchmark (PDM vs keyword+recency baseline)
378
+ python -m pdm_memory.bench
379
+
380
+ # Quick smoke test (5 scenarios)
381
+ python -m pdm_memory.bench --quick
382
+
383
+ # Save results as JSON
384
+ python -m pdm_memory.bench --output results.json
385
+ ```
386
+
387
+ ### CLI Tool
388
+
389
+ ```bash
390
+ # List all memories
391
+ pdm-cli list-memories --store ./my_app.db
392
+
393
+ # Filter by pressure
394
+ pdm-cli list-memories --store ./my_app.db --min-pressure 60
395
+
396
+ # Explain a specific memory
397
+ pdm-cli explain abc12345 --store ./my_app.db --query "formatting"
398
+
399
+ # Trigger a decay pass (dry run first)
400
+ pdm-cli decay --store ./my_app.db --dry-run
401
+ pdm-cli decay --store ./my_app.db
402
+
403
+ # Show stats
404
+ pdm-cli stats --store ./my_app.db
405
+
406
+ # List drawers (categories)
407
+ pdm-cli drawers --store ./my_app.db
408
+
409
+ # Sync to cloud
410
+ pdm-cli sync --store ./my_app.db --token eyJ... --direction push
411
+ ```
412
+
413
+ ---
414
+
415
+ ## 📖 API Reference
416
+
417
+ ### `Memory(store, user, token, cloud_url, store_raw)`
418
+
419
+ | Method | Description |
420
+ |--------|-------------|
421
+ | `save(text, source, tags, p_magnitude, t_persistence, drawer, regime, deadline)` | Store a new memory |
422
+ | `recall(query, k, min_pressure, search_cost, drawer, reinforce)` → `List[MemoryHit]` | Retrieve top-k relevant memories |
423
+ | `reinforce(memory_id, coupling_score)` | Manually raise a memory's pressure |
424
+ | `decay(dry_run)` → `dict` | Trigger decay pass (runs automatically on recall) |
425
+ | `explain(memory_id, query)` → `ExplainReport` | Show why a memory has its current pressure |
426
+ | `sync(direction, token, cloud_url)` → `SyncReport` | Sync local ↔ cloud |
427
+ | `ingest(data_source, mapping, llm_client, batch_size)` → `dict` | Import legacy data |
428
+ | `list_drawers()` → `List[DrawerInfo]` | List memory categories |
429
+ | `count()` → `int` | Total memory count |
430
+ | `close()` | Release storage connections |
431
+
432
+ ### `MemoryHit`
433
+
434
+ | Field | Description |
435
+ |-------|-------------|
436
+ | `id` | UUID |
437
+ | `text` | Memory content |
438
+ | `pressure` | Live P_effective at retrieval time |
439
+ | `p_raw` | Stored p_magnitude |
440
+ | `intent_tags` | Classification tags |
441
+ | `coupling_score` | TAS resonance score (0–1) |
442
+ | `last_reinforced` | Last retrieval datetime |
443
+
444
+ ---
445
+
446
+ ## 🔬 How PDM Works
447
+
448
+ **Pressure** — every memory has a p_magnitude (0–100). Important, frequently-used memories stay strong. Unused ones decay. You control the baseline; the system adjusts dynamically.
449
+
450
+ **Decay** — computed at recall time based on elapsed days vs. domain-specific half-lives. No scheduler required (Celery-free). Market signals decay in 1 day; core facts persist for a year.
451
+
452
+ **Retrieval (TAS)** — Threshold-Adjustment Search lowers the pressure threshold based on query uncertainty (search_cost). Then coupling scores rank memories by tag overlap, domain, regime, and pressure proximity. The most resonant memories surface first.
453
+
454
+ **Validation Coefficient (V)** — Laplace-smoothed accuracy tracker. Memories that prove predictively useful grow stronger; ones that mislead decay faster.
455
+
456
+ ---
457
+
458
+ ## 🏗️ Custom Storage Backend
459
+
460
+ Implement `BaseStorage` to add your own backend (Postgres, Redis, DynamoDB…):
461
+
462
+ ```python
463
+ from pdm_memory.storage.base import BaseStorage
464
+
465
+ class MyPostgresStorage(BaseStorage):
466
+ def save(self, sig): ...
467
+ def get(self, memory_id, user): ...
468
+ def update(self, memory_id, **fields): ...
469
+ def delete(self, memory_id, user): ...
470
+ def list(self, user, limit, min_pressure, drawer): ...
471
+ def list_drawers(self, user): ...
472
+
473
+ mem = Memory.__new__(Memory)
474
+ mem._storage = MyPostgresStorage(...)
475
+ mem._user = "alice"
476
+ mem._engine = RetrievalEngine()
477
+ ```
478
+
479
+ ---
480
+
481
+ ## 📄 License
482
+
483
+ [MIT + Patent Scope Clause](LICENSE) — use the SDK freely; the PDM algorithm patents stay with Westfield Innovations LLC.
484
+
485
+ Built by **Westfield Innovations LLC** · [westfieldinnovations.com](https://westfieldinnovations.com)