prme 0.15.0__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 (187) hide show
  1. prme-0.15.0/PKG-INFO +329 -0
  2. prme-0.15.0/README.md +268 -0
  3. prme-0.15.0/pyproject.toml +103 -0
  4. prme-0.15.0/src/prme/__init__.py +317 -0
  5. prme-0.15.0/src/prme/_temporal.py +9 -0
  6. prme-0.15.0/src/prme/api/__init__.py +20 -0
  7. prme-0.15.0/src/prme/api/__main__.py +64 -0
  8. prme-0.15.0/src/prme/api/app.py +106 -0
  9. prme-0.15.0/src/prme/api/models.py +584 -0
  10. prme-0.15.0/src/prme/api/routes.py +1389 -0
  11. prme-0.15.0/src/prme/api/server.py +153 -0
  12. prme-0.15.0/src/prme/cli.py +1667 -0
  13. prme-0.15.0/src/prme/client.py +1135 -0
  14. prme-0.15.0/src/prme/config.py +1249 -0
  15. prme-0.15.0/src/prme/config_audit.py +318 -0
  16. prme-0.15.0/src/prme/epistemic/__init__.py +16 -0
  17. prme-0.15.0/src/prme/epistemic/inference.py +99 -0
  18. prme-0.15.0/src/prme/epistemic/matrix.py +135 -0
  19. prme-0.15.0/src/prme/epistemic/migration.py +160 -0
  20. prme-0.15.0/src/prme/ingestion/__init__.py +45 -0
  21. prme-0.15.0/src/prme/ingestion/claim_merge.py +122 -0
  22. prme-0.15.0/src/prme/ingestion/entity_merge.py +158 -0
  23. prme-0.15.0/src/prme/ingestion/entity_references.py +102 -0
  24. prme-0.15.0/src/prme/ingestion/errors.py +123 -0
  25. prme-0.15.0/src/prme/ingestion/extraction.py +1661 -0
  26. prme-0.15.0/src/prme/ingestion/graph_writer.py +224 -0
  27. prme-0.15.0/src/prme/ingestion/grounding.py +594 -0
  28. prme-0.15.0/src/prme/ingestion/novelty.py +181 -0
  29. prme-0.15.0/src/prme/ingestion/pipeline.py +1752 -0
  30. prme-0.15.0/src/prme/ingestion/planning.py +225 -0
  31. prme-0.15.0/src/prme/ingestion/resolution.py +517 -0
  32. prme-0.15.0/src/prme/ingestion/schema.py +301 -0
  33. prme-0.15.0/src/prme/ingestion/supersedence.py +316 -0
  34. prme-0.15.0/src/prme/ingestion/temporal.py +35 -0
  35. prme-0.15.0/src/prme/integrations/__init__.py +11 -0
  36. prme-0.15.0/src/prme/integrations/_chat_history.py +131 -0
  37. prme-0.15.0/src/prme/integrations/coding.py +316 -0
  38. prme-0.15.0/src/prme/integrations/coding_server.py +28 -0
  39. prme-0.15.0/src/prme/integrations/langchain.py +287 -0
  40. prme-0.15.0/src/prme/integrations/llamaindex.py +334 -0
  41. prme-0.15.0/src/prme/integrations/product_candidates.py +211 -0
  42. prme-0.15.0/src/prme/integrations/typesafe.py +579 -0
  43. prme-0.15.0/src/prme/mcp/__init__.py +22 -0
  44. prme-0.15.0/src/prme/mcp/__main__.py +5 -0
  45. prme-0.15.0/src/prme/mcp/server.py +1889 -0
  46. prme-0.15.0/src/prme/model_runtime/__init__.py +5 -0
  47. prme-0.15.0/src/prme/model_runtime/generation.py +109 -0
  48. prme-0.15.0/src/prme/models/__init__.py +84 -0
  49. prme-0.15.0/src/prme/models/aggregation.py +308 -0
  50. prme-0.15.0/src/prme/models/base.py +38 -0
  51. prme-0.15.0/src/prme/models/consolidation.py +217 -0
  52. prme-0.15.0/src/prme/models/credit.py +97 -0
  53. prme-0.15.0/src/prme/models/derivation.py +194 -0
  54. prme-0.15.0/src/prme/models/direct_store.py +54 -0
  55. prme-0.15.0/src/prme/models/edges.py +52 -0
  56. prme-0.15.0/src/prme/models/entity_identity.py +19 -0
  57. prme-0.15.0/src/prme/models/events.py +65 -0
  58. prme-0.15.0/src/prme/models/extraction.py +152 -0
  59. prme-0.15.0/src/prme/models/extraction_work.py +46 -0
  60. prme-0.15.0/src/prme/models/learning.py +547 -0
  61. prme-0.15.0/src/prme/models/nodes.py +109 -0
  62. prme-0.15.0/src/prme/models/owner_reference.py +32 -0
  63. prme-0.15.0/src/prme/models/processing.py +82 -0
  64. prme-0.15.0/src/prme/models/profile.py +166 -0
  65. prme-0.15.0/src/prme/models/provenance.py +38 -0
  66. prme-0.15.0/src/prme/models/relevance.py +730 -0
  67. prme-0.15.0/src/prme/models/speaker.py +136 -0
  68. prme-0.15.0/src/prme/models/temporal.py +193 -0
  69. prme-0.15.0/src/prme/models/value_bindings.py +368 -0
  70. prme-0.15.0/src/prme/organizer/__init__.py +50 -0
  71. prme-0.15.0/src/prme/organizer/alias_resolution.py +412 -0
  72. prme-0.15.0/src/prme/organizer/consolidation.py +589 -0
  73. prme-0.15.0/src/prme/organizer/contradiction.py +94 -0
  74. prme-0.15.0/src/prme/organizer/decay.py +178 -0
  75. prme-0.15.0/src/prme/organizer/deduplication.py +296 -0
  76. prme-0.15.0/src/prme/organizer/jobs.py +869 -0
  77. prme-0.15.0/src/prme/organizer/maintenance.py +323 -0
  78. prme-0.15.0/src/prme/organizer/merge_policy.py +36 -0
  79. prme-0.15.0/src/prme/organizer/models.py +57 -0
  80. prme-0.15.0/src/prme/organizer/oscillation.py +174 -0
  81. prme-0.15.0/src/prme/organizer/profiles.py +43 -0
  82. prme-0.15.0/src/prme/organizer/summarization.py +665 -0
  83. prme-0.15.0/src/prme/py.typed +1 -0
  84. prme-0.15.0/src/prme/quality/__init__.py +23 -0
  85. prme-0.15.0/src/prme/quality/feedback.py +116 -0
  86. prme-0.15.0/src/prme/quality/metrics.py +82 -0
  87. prme-0.15.0/src/prme/quality/tuner.py +198 -0
  88. prme-0.15.0/src/prme/retrieval/__init__.py +127 -0
  89. prme-0.15.0/src/prme/retrieval/abstention.py +140 -0
  90. prme-0.15.0/src/prme/retrieval/aggregation.py +511 -0
  91. prme-0.15.0/src/prme/retrieval/aggregation_planning.py +165 -0
  92. prme-0.15.0/src/prme/retrieval/answerability.py +547 -0
  93. prme-0.15.0/src/prme/retrieval/candidates.py +566 -0
  94. prme-0.15.0/src/prme/retrieval/claim_verification.py +1077 -0
  95. prme-0.15.0/src/prme/retrieval/config.py +787 -0
  96. prme-0.15.0/src/prme/retrieval/context_formatter.py +1014 -0
  97. prme-0.15.0/src/prme/retrieval/credit.py +151 -0
  98. prme-0.15.0/src/prme/retrieval/episode_context.py +194 -0
  99. prme-0.15.0/src/prme/retrieval/evidence_context.py +341 -0
  100. prme-0.15.0/src/prme/retrieval/execution.py +102 -0
  101. prme-0.15.0/src/prme/retrieval/filtering.py +175 -0
  102. prme-0.15.0/src/prme/retrieval/full_learning.py +275 -0
  103. prme-0.15.0/src/prme/retrieval/learning.py +265 -0
  104. prme-0.15.0/src/prme/retrieval/models.py +767 -0
  105. prme-0.15.0/src/prme/retrieval/packing.py +1026 -0
  106. prme-0.15.0/src/prme/retrieval/pipeline.py +1391 -0
  107. prme-0.15.0/src/prme/retrieval/query_analysis.py +382 -0
  108. prme-0.15.0/src/prme/retrieval/ranking_adjustments.py +19 -0
  109. prme-0.15.0/src/prme/retrieval/reformulation.py +214 -0
  110. prme-0.15.0/src/prme/retrieval/reranker.py +203 -0
  111. prme-0.15.0/src/prme/retrieval/scope.py +30 -0
  112. prme-0.15.0/src/prme/retrieval/scoring.py +984 -0
  113. prme-0.15.0/src/prme/retrieval/selection.py +151 -0
  114. prme-0.15.0/src/prme/retrieval/session_context.py +259 -0
  115. prme-0.15.0/src/prme/retrieval/snapshots.py +251 -0
  116. prme-0.15.0/src/prme/retrieval/temporal.py +293 -0
  117. prme-0.15.0/src/prme/retrieval/temporal_relation_models.py +99 -0
  118. prme-0.15.0/src/prme/retrieval/temporal_relation_providers.py +554 -0
  119. prme-0.15.0/src/prme/retrieval/temporal_relations.py +677 -0
  120. prme-0.15.0/src/prme/retrieval/time.py +12 -0
  121. prme-0.15.0/src/prme/retrieval/tokenization.py +15 -0
  122. prme-0.15.0/src/prme/storage/__init__.py +25 -0
  123. prme-0.15.0/src/prme/storage/_snapshot_json.py +117 -0
  124. prme-0.15.0/src/prme/storage/_threading.py +41 -0
  125. prme-0.15.0/src/prme/storage/alias_proposal.py +657 -0
  126. prme-0.15.0/src/prme/storage/alias_review.py +616 -0
  127. prme-0.15.0/src/prme/storage/blobs.py +90 -0
  128. prme-0.15.0/src/prme/storage/citations.py +117 -0
  129. prme-0.15.0/src/prme/storage/condition_evaluation.py +425 -0
  130. prme-0.15.0/src/prme/storage/consolidation_publication.py +762 -0
  131. prme-0.15.0/src/prme/storage/consolidation_retirement.py +163 -0
  132. prme-0.15.0/src/prme/storage/derivation.py +232 -0
  133. prme-0.15.0/src/prme/storage/derivation_registry.py +154 -0
  134. prme-0.15.0/src/prme/storage/derivation_staging.py +57 -0
  135. prme-0.15.0/src/prme/storage/duckpgq_graph.py +2020 -0
  136. prme-0.15.0/src/prme/storage/durable_queue.py +97 -0
  137. prme-0.15.0/src/prme/storage/embedding.py +512 -0
  138. prme-0.15.0/src/prme/storage/encryption.py +460 -0
  139. prme-0.15.0/src/prme/storage/engine.py +4360 -0
  140. prme-0.15.0/src/prme/storage/event_store.py +730 -0
  141. prme-0.15.0/src/prme/storage/extraction_work.py +388 -0
  142. prme-0.15.0/src/prme/storage/fast_ingest.py +165 -0
  143. prme-0.15.0/src/prme/storage/graph_store.py +573 -0
  144. prme-0.15.0/src/prme/storage/index_eviction.py +48 -0
  145. prme-0.15.0/src/prme/storage/lexical_index.py +873 -0
  146. prme-0.15.0/src/prme/storage/lifecycle.py +232 -0
  147. prme-0.15.0/src/prme/storage/metadata.py +30 -0
  148. prme-0.15.0/src/prme/storage/namespace_identity.py +33 -0
  149. prme-0.15.0/src/prme/storage/organizer_merge.py +216 -0
  150. prme-0.15.0/src/prme/storage/oscillation_penalty.py +418 -0
  151. prme-0.15.0/src/prme/storage/pack_manifest.py +118 -0
  152. prme-0.15.0/src/prme/storage/pack_tools.py +438 -0
  153. prme-0.15.0/src/prme/storage/pg/__init__.py +26 -0
  154. prme-0.15.0/src/prme/storage/pg/event_store.py +600 -0
  155. prme-0.15.0/src/prme/storage/pg/graph_store.py +1494 -0
  156. prme-0.15.0/src/prme/storage/pg/lexical_index.py +191 -0
  157. prme-0.15.0/src/prme/storage/pg/namespace.py +131 -0
  158. prme-0.15.0/src/prme/storage/pg/pool.py +35 -0
  159. prme-0.15.0/src/prme/storage/pg/schema.py +261 -0
  160. prme-0.15.0/src/prme/storage/pg/vector_index.py +240 -0
  161. prme-0.15.0/src/prme/storage/pg/vector_sql.py +44 -0
  162. prme-0.15.0/src/prme/storage/pg/workspace_catalog.py +75 -0
  163. prme-0.15.0/src/prme/storage/profile_collection.py +272 -0
  164. prme-0.15.0/src/prme/storage/profile_publication.py +270 -0
  165. prme-0.15.0/src/prme/storage/profile_registry.py +292 -0
  166. prme-0.15.0/src/prme/storage/profile_retirement.py +126 -0
  167. prme-0.15.0/src/prme/storage/profile_work.py +539 -0
  168. prme-0.15.0/src/prme/storage/provenance.py +101 -0
  169. prme-0.15.0/src/prme/storage/ranking_profiles.py +284 -0
  170. prme-0.15.0/src/prme/storage/reinforcement.py +281 -0
  171. prme-0.15.0/src/prme/storage/relevance.py +201 -0
  172. prme-0.15.0/src/prme/storage/retention.py +369 -0
  173. prme-0.15.0/src/prme/storage/schema.py +575 -0
  174. prme-0.15.0/src/prme/storage/supersedence.py +261 -0
  175. prme-0.15.0/src/prme/storage/transition_evidence.py +48 -0
  176. prme-0.15.0/src/prme/storage/vector_index.py +872 -0
  177. prme-0.15.0/src/prme/storage/write_queue.py +271 -0
  178. prme-0.15.0/src/prme/types.py +301 -0
  179. prme-0.15.0/src/prme/vision/__init__.py +44 -0
  180. prme-0.15.0/src/prme/vision/describe.py +71 -0
  181. prme-0.15.0/src/prme/vision/errors.py +33 -0
  182. prme-0.15.0/src/prme/vision/frames.py +343 -0
  183. prme-0.15.0/src/prme/vision/keyframes.py +158 -0
  184. prme-0.15.0/src/prme/vision/observe.py +375 -0
  185. prme-0.15.0/src/prme/vision/provider.py +98 -0
  186. prme-0.15.0/src/prme/vision/repeat.py +44 -0
  187. prme-0.15.0/src/prme/workspace.py +469 -0
prme-0.15.0/PKG-INFO ADDED
@@ -0,0 +1,329 @@
1
+ Metadata-Version: 2.3
2
+ Name: prme
3
+ Version: 0.15.0
4
+ Summary: Portable Relational Memory Engine - local-first memory substrate for LLM-powered systems
5
+ Keywords: memory,llm,ai,knowledge-graph,vector-search,event-sourcing,duckdb,agents,rag,long-term-memory,mcp
6
+ Author: Dwamian McLeish
7
+ Author-email: Dwamian McLeish <dwamian@journey.ly>
8
+ License: Apache-2.0
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
+ Classifier: Topic :: Database
17
+ Requires-Dist: duckdb>=1.4.0
18
+ Requires-Dist: usearch>=2.26.2
19
+ Requires-Dist: tantivy>=0.22.0
20
+ Requires-Dist: pydantic>=2.12
21
+ Requires-Dist: pydantic-settings>=2.9
22
+ Requires-Dist: fastembed>=0.7.4
23
+ Requires-Dist: structlog
24
+ Requires-Dist: pytz>=2025.2
25
+ Requires-Dist: instructor>=1.14
26
+ Requires-Dist: openai>=2.20
27
+ Requires-Dist: anthropic>=0.80
28
+ Requires-Dist: ollama>=0.6
29
+ Requires-Dist: dateparser>=1.2
30
+ Requires-Dist: cryptography>=43.0
31
+ Requires-Dist: filelock>=3.16
32
+ Requires-Dist: httpx>=0.27
33
+ Requires-Dist: tiktoken>=0.12
34
+ Requires-Dist: numpy>=1.26
35
+ Requires-Dist: pillow>=10.1
36
+ Requires-Dist: fastapi>=0.115 ; extra == 'api'
37
+ Requires-Dist: uvicorn[standard]>=0.30 ; extra == 'api'
38
+ Requires-Dist: tiktoken>=0.12 ; extra == 'evaluation'
39
+ Requires-Dist: langchain-core>=0.3 ; extra == 'langchain'
40
+ Requires-Dist: llama-index-core>=0.12 ; extra == 'llamaindex'
41
+ Requires-Dist: mcp>=1.26.0,<2 ; extra == 'mcp'
42
+ Requires-Dist: asyncpg>=0.29.0 ; extra == 'postgres'
43
+ Requires-Dist: pgvector>=0.3.0 ; extra == 'postgres'
44
+ Requires-Dist: sentence-transformers>=4.0 ; extra == 'reranker'
45
+ Requires-Dist: sentence-transformers>=4.0 ; extra == 'verification'
46
+ Requires-Python: >=3.11
47
+ Project-URL: Changelog, https://github.com/dwamianm/prism/blob/main/CHANGELOG.md
48
+ Project-URL: Documentation, https://github.com/dwamianm/prism/tree/main/docs
49
+ Project-URL: Homepage, https://github.com/dwamianm/prism
50
+ Project-URL: Issues, https://github.com/dwamianm/prism/issues
51
+ Project-URL: Repository, https://github.com/dwamianm/prism
52
+ Provides-Extra: api
53
+ Provides-Extra: evaluation
54
+ Provides-Extra: langchain
55
+ Provides-Extra: llamaindex
56
+ Provides-Extra: mcp
57
+ Provides-Extra: postgres
58
+ Provides-Extra: reranker
59
+ Provides-Extra: verification
60
+ Description-Content-Type: text/markdown
61
+
62
+ # PRME — Portable Relational Memory Engine
63
+
64
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
65
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
66
+ [![CI](https://github.com/dwamianm/prism/actions/workflows/ci.yml/badge.svg)](https://github.com/dwamianm/prism/actions/workflows/ci.yml)
67
+
68
+ **Local-first, embeddable memory for LLM-powered applications.**
69
+
70
+ PRME gives agents and chatbots persistent memory through an append-only event
71
+ log, typed relationships, and hybrid retrieval. It preserves source evidence,
72
+ tracks changing claims, and packs relevant memories into a configurable token
73
+ budget. The default backend runs locally in a portable directory; PostgreSQL is
74
+ available for server deployments.
75
+
76
+ **Current release: v0.15.0.** Python 3.11+, synchronous and async clients, HTTP,
77
+ MCP, and LangChain/LlamaIndex integrations.
78
+
79
+ ## Architecture
80
+
81
+ Four storage layers sit behind a unified memory API:
82
+
83
+ | Layer | Local implementation | Purpose |
84
+ |---|---|---|
85
+ | Event store | DuckDB | Immutable source events and durable operation records |
86
+ | Graph store | DuckDB tables and recursive CTEs | Typed memories, relationships, temporal validity, confidence, and provenance |
87
+ | Vector index | USearch | Semantic similarity search with versioned embeddings |
88
+ | Lexical index | Tantivy | BM25 full-text search |
89
+
90
+ The optional PostgreSQL backend uses PostgreSQL tables, pgvector, and full-text
91
+ search behind the same API. Both backends default to exact vector search;
92
+ approximate search is configurable.
93
+
94
+ ```text
95
+ Source text → event log → direct storage or LLM extraction → graph + indexes
96
+
97
+ Query → intent, entity, and time analysis
98
+ → graph, vector, lexical, and recent-memory candidates
99
+ → deterministic scoring and filtering
100
+ → token-bounded context with provenance
101
+ ```
102
+
103
+ - **Ingestion:** `store()` writes a memory directly without an LLM.
104
+ `ingest()` extracts entities, facts, and relationships through a configured
105
+ provider. Deferred ingestion records durable work that can resume after restart.
106
+ - **Memory state:** typed nodes carry owner, scope, lifecycle, confidence,
107
+ validity windows, and source references. Explicit corrections and contradiction
108
+ operations preserve earlier claims; automatic store-time supersedence is opt-in.
109
+ - **Retrieval:** combines multiple search paths and packs selected evidence into
110
+ context. Structured assertion-state and aggregation APIs support exact stored
111
+ claim queries and decimal totals beyond semantic top-k retrieval.
112
+ - **Default retrieval behavior:** candidates are ranked by reciprocal rank
113
+ fusion of their semantic and lexical ranks, with a recency boost on
114
+ current-state questions and an event-time tie-break. Packing uses balanced
115
+ ordering and renders each record as one plain line (the `reader` context
116
+ format), while the full records stay in the bundle's sections and the
117
+ retrieval receipt. These defaults changed after v0.12.0;
118
+ [Default retrieval settings](docs/PACKING.md#default-retrieval-settings)
119
+ lists the earlier values and the environment variables that restore them.
120
+ - **Organizer:** maintains promotion, decay, summaries, deduplication, archival,
121
+ and index compaction. It runs opportunistically or through `prme organize`;
122
+ recurring schedules use an external timer. Shared stores should pass `user_id`.
123
+ - **Workspaces:** `MemoryWorkspace` manages named local packs or PostgreSQL
124
+ schemas with identity checks and scoped leases.
125
+
126
+ A local memory pack is a directory by default, or one file when you opt in:
127
+
128
+ ```text
129
+ my_memories/ # directory pack (the default)
130
+ ├── memory.duckdb
131
+ ├── vectors.usearch
132
+ ├── lexical_index/
133
+ └── manifest.json # only when encryption is on
134
+
135
+ memories.prme # single-file pack (opt-in)
136
+ ```
137
+
138
+ Giving `MemoryClient` a path that ends in `.prme`, or setting `PRME_PACK_PATH`,
139
+ selects the single-file layout: one DuckDB file holds the event log, the graph,
140
+ the vector snapshot and a pack manifest, and the lexical index is rebuilt in
141
+ memory when the pack opens. `prme migrate` copies a directory pack into a new
142
+ `.prme` file, and [single-file packs](docs/INTEGRATION.md#single-file-packs)
143
+ covers encryption, compaction and how retrieval compares across the layouts.
144
+
145
+ Search indexes can be regenerated from the durable graph with `prme rebuild`.
146
+ Event time, ingestion time, and validity time remain distinct. The `knowledge_at`
147
+ filter applies an ingestion cutoff to current graph/index state; exact historical
148
+ state replay is not currently available.
149
+
150
+ ## Current benchmarks
151
+
152
+ | Benchmark | Correct answers | Answer accuracy |
153
+ |---|---:|---:|
154
+ | LongMemEval-S | 453 / 500 | **90.6%** |
155
+ | LoCoMo, non-adversarial questions | 1,250 / 1,540 | **81.2%** |
156
+
157
+ ### LongMemEval-S by question type
158
+
159
+ | Question type | Correct answers | Answer accuracy |
160
+ |---|---:|---:|
161
+ | Single-session user | 69 / 70 | 98.6% |
162
+ | Single-session assistant | 54 / 56 | 96.4% |
163
+ | Knowledge update | 71 / 78 | 91.0% |
164
+ | Temporal reasoning | 120 / 133 | 90.2% |
165
+ | Single-session preference | 26 / 30 | 86.7% |
166
+ | Multi-session | 113 / 133 | 85.0% |
167
+
168
+ ### LoCoMo by question type
169
+
170
+ | Question type | Correct answers | Answer accuracy |
171
+ |---|---:|---:|
172
+ | Single-hop | 756 / 841 | 89.9% |
173
+ | Temporal | 256 / 321 | 79.8% |
174
+ | Multi-hop | 182 / 282 | 64.5% |
175
+ | Open-domain | 56 / 96 | 58.3% |
176
+
177
+ Measured on September 25, 2026 with the v0.13.0 retrieval defaults and a
178
+ 3,996-token memory-context budget per question, over memory packs built with
179
+ `store()`, which never runs extraction. The defaults adopted on October 6
180
+ change what `ingest()` stores and how repeated text is packed, so they were
181
+ measured on a separate track over packs built through `ingest()`. See
182
+ [BENCHMARKS.md](BENCHMARKS.md) for both tracks, the method, earlier results
183
+ and reproducibility artifacts.
184
+
185
+ ## Installation
186
+
187
+ ```bash
188
+ pip install prme
189
+ ```
190
+
191
+ Optional integrations:
192
+
193
+ ```bash
194
+ pip install "prme[postgres]" # PostgreSQL backend
195
+ pip install "prme[api]" # HTTP API
196
+ pip install "prme[mcp]" # MCP server
197
+ pip install "prme[langchain]" # LangChain retriever and chat history
198
+ pip install "prme[llamaindex]" # LlamaIndex retriever and chat store
199
+ ```
200
+
201
+ ## Quickstart
202
+
203
+ ```python
204
+ from prme import MemoryClient
205
+
206
+ with MemoryClient("./my_memories") as memory:
207
+ memory.store("Alice prefers dark mode in her editors.", user_id="alice")
208
+ memory.store("The team decided to use PostgreSQL.", user_id="alice")
209
+
210
+ response = memory.retrieve("What are Alice's preferences?", user_id="alice")
211
+ for result in response.results:
212
+ print(f"[{result.composite_score:.3f}] {result.node.content}")
213
+ ```
214
+
215
+ `MemoryClient` is synchronous; `MemoryEngine` provides the async API. Direct
216
+ storage and retrieval use local embeddings by default and require no LLM API key.
217
+ Use `ingest()` with an OpenAI, Anthropic, or Ollama extraction provider when you
218
+ want structured memories extracted from conversation text.
219
+
220
+ Configure PRME through `PRMEConfig`, `PRME_` environment variables, or a `.env`
221
+ file. Constructor values override the environment, which overrides `.env`.
222
+ The [configuration reference](documentation/configuration.md) lists the
223
+ settings and their defaults. To return to the v0.12.0 retrieval defaults, set
224
+ `PRME_SCORING__FUSION=weighted`, `PRME_PACKING__CONTEXT_FORMAT=auditable` and
225
+ `PRME_PACKING__MULTIPATH_ORDERING=balanced` (the last is the default again and
226
+ only makes it explicit; see
227
+ [Default retrieval settings](docs/PACKING.md#default-retrieval-settings)).
228
+ See the [integration reference](docs/INTEGRATION.md) and
229
+ [examples](examples/) for configuration and application patterns.
230
+
231
+ ## Interfaces and tools
232
+
233
+ Use the CLI to initialize, inspect, search, and maintain a local pack:
234
+
235
+ ```bash
236
+ prme init ./my_memories
237
+ prme doctor ./my_memories
238
+ prme search ./my_memories/memory.duckdb "Alice's preferences" --user-id alice
239
+ prme organize ./my_memories/memory.duckdb --user-id alice
240
+ prme compact ./my_memories/memory.duckdb
241
+ prme migrate ./my_memories ./memories.prme
242
+ ```
243
+
244
+ `prme compact` rewrites a closed pack file to give back the space DuckDB never
245
+ returns, and `prme migrate` copies a directory pack into a new single-file pack,
246
+ leaving the directory in place. Every command that takes `memory.duckdb` also
247
+ takes a `.prme` file, and `prme init ./memories.prme` creates one. See the
248
+ [CLI reference](documentation/cli.md).
249
+
250
+ For a local assistant, install the MCP extra and run with a fixed owner:
251
+
252
+ ```bash
253
+ PRME_MCP_USER_ID=alice prme-mcp --db-path ./my_memories
254
+ ```
255
+
256
+ `--db-path` also accepts a single-file pack, such as `./memories.prme`.
257
+
258
+ The HTTP extra provides a FastAPI service via `python -m prme.api`, which binds to
259
+ `127.0.0.1` and refuses a network bind without API credentials (see
260
+ [Running the Server](documentation/http-api.md#running-the-server)).
261
+ Shared HTTP deployments bind owners to credentials through `PRME_API_USER_KEYS`;
262
+ MCP Streamable HTTP uses its separate `PRME_MCP_USER_KEYS` setting.
263
+ See the [HTTP guide](docs/HTTP-API.md) and
264
+ [framework integration guide](docs/FRAMEWORK-INTEGRATIONS.md) for application setup.
265
+
266
+ To browse stored entries and explore their graph connections from a source
267
+ checkout, run `uv run --extra api python -m web.server` and open
268
+ **http://127.0.0.1:8080**. The standalone [memory explorer](web/README.md) lives in
269
+ `web/` and includes filters, source evidence, and an interactive relationship map.
270
+
271
+ ## Milestones
272
+
273
+ | Milestone | Delivered |
274
+ |---|---|
275
+ | Core memory foundation, through v0.9 | Event sourcing, typed graph, hybrid retrieval, organizer jobs, encryption, CLI, evaluation harness, and index rebuilds |
276
+ | v0.10 | Deterministic vector search, batched ingestion indexing, and context-budget enforcement |
277
+ | v0.11 | Tenant-scoped maintenance, ownership and retrieval-filter fixes, and broader backend CI coverage |
278
+ | v0.12 | Durable ingestion and recovery, atomic lifecycle and correction records, scoped workspaces, structured assertion and quantity operations, retrieval receipts, and evaluated ranking profiles |
279
+ | v0.13 | Rank fusion with current-state recency, the one-line reader context format and balanced ordering as retrieval defaults; conversation participants with speaker names; refusal of unauthenticated network binds for the HTTP API; an offline evidence gate and paired answer runs for measuring retrieval changes |
280
+ | v0.14, current | A claim's own sentences as its text, a named speaker's I, me and my bound to the speaker, and each source text packed once, as `ingest()` and reader context defaults; repeated extracted claims merged into one current record; a browser memory explorer; benchmark packs built through `ingest()`, with the evidence gate and a DeepSeek answer track over them |
281
+
282
+ Experimental reranking (including the cross-encoder rank order), temporal-relation
283
+ guidance, model-assisted verification, temporal-first query intent, event-time
284
+ recency for the weighted formula, session context packing, windowed extraction,
285
+ self-contained fact text and speaker grounding remain opt-in.
286
+ Detailed changes are in the [changelog](CHANGELOG.md).
287
+
288
+ Current work follows [epic #77](https://github.com/dwamianm/prism/issues/77),
289
+ which acts on the 2026-09-23 benchmark gap audit: a reader-facing context,
290
+ better ranking, the context budget, and dated facts extracted at write time for
291
+ multi-hop and list questions. See the [roadmap](ROADMAP.md) for what has been
292
+ delivered and what is still open.
293
+
294
+ Images and video as memory sources are
295
+ [RFC-0018](docs/RFC-0018-Visual-Memory.md). Its phase 1 is implemented and
296
+ off by default: with `vision.enabled` set, `MemoryClient.observe()` and
297
+ `prme observe` turn a photo or a saved video into dated observation events
298
+ described by a local vision model, with a thumbnail of each keyframe kept in
299
+ the pack for provenance. The benchmark with real recordings is still open.
300
+
301
+ ## Documentation
302
+
303
+ - [Developer guides](documentation/README.md) and [configuration reference](documentation/configuration.md)
304
+ - [Architecture and RFC index](docs/INDEX.md)
305
+ - [Integration reference](docs/INTEGRATION.md) and [framework adapters](docs/FRAMEWORK-INTEGRATIONS.md)
306
+ - [Context packing and default retrieval settings](docs/PACKING.md) and [retrieval feedback and learning](docs/LEARNING.md)
307
+ - [Experimental retrieval policies](docs/EXPERIMENTAL-RETRIEVAL-POLICIES.md)
308
+ - [Memory corrections](docs/MEMORY-CORRECTIONS.md)
309
+ - [Entity profiles](docs/ENTITY-PROFILES.md) and [entity identity](docs/ENTITY-IDENTITY.md)
310
+ - [Workspaces](docs/WORKSPACES.md) and [local resource control](docs/LOCAL-RESOURCES.md)
311
+ - [Custom embeddings](docs/CUSTOM-EMBEDDINGS.md) and [typed value bindings](docs/VALUE-BINDINGS.md)
312
+ - [HTTP API](docs/HTTP-API.md)
313
+
314
+ ## Development
315
+
316
+ ```bash
317
+ git clone https://github.com/dwamianm/prism.git
318
+ cd prism
319
+ uv sync --dev
320
+ uv run pytest tests/ -q
321
+ ```
322
+
323
+ PostgreSQL tests require a live database configured through
324
+ `PRME_TEST_DATABASE_URL`. See [CONTRIBUTING.md](CONTRIBUTING.md) for development
325
+ setup, checks, and contribution guidelines.
326
+
327
+ ## License
328
+
329
+ Apache License 2.0 — see [LICENSE](LICENSE).
prme-0.15.0/README.md ADDED
@@ -0,0 +1,268 @@
1
+ # PRME — Portable Relational Memory Engine
2
+
3
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
4
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
5
+ [![CI](https://github.com/dwamianm/prism/actions/workflows/ci.yml/badge.svg)](https://github.com/dwamianm/prism/actions/workflows/ci.yml)
6
+
7
+ **Local-first, embeddable memory for LLM-powered applications.**
8
+
9
+ PRME gives agents and chatbots persistent memory through an append-only event
10
+ log, typed relationships, and hybrid retrieval. It preserves source evidence,
11
+ tracks changing claims, and packs relevant memories into a configurable token
12
+ budget. The default backend runs locally in a portable directory; PostgreSQL is
13
+ available for server deployments.
14
+
15
+ **Current release: v0.15.0.** Python 3.11+, synchronous and async clients, HTTP,
16
+ MCP, and LangChain/LlamaIndex integrations.
17
+
18
+ ## Architecture
19
+
20
+ Four storage layers sit behind a unified memory API:
21
+
22
+ | Layer | Local implementation | Purpose |
23
+ |---|---|---|
24
+ | Event store | DuckDB | Immutable source events and durable operation records |
25
+ | Graph store | DuckDB tables and recursive CTEs | Typed memories, relationships, temporal validity, confidence, and provenance |
26
+ | Vector index | USearch | Semantic similarity search with versioned embeddings |
27
+ | Lexical index | Tantivy | BM25 full-text search |
28
+
29
+ The optional PostgreSQL backend uses PostgreSQL tables, pgvector, and full-text
30
+ search behind the same API. Both backends default to exact vector search;
31
+ approximate search is configurable.
32
+
33
+ ```text
34
+ Source text → event log → direct storage or LLM extraction → graph + indexes
35
+
36
+ Query → intent, entity, and time analysis
37
+ → graph, vector, lexical, and recent-memory candidates
38
+ → deterministic scoring and filtering
39
+ → token-bounded context with provenance
40
+ ```
41
+
42
+ - **Ingestion:** `store()` writes a memory directly without an LLM.
43
+ `ingest()` extracts entities, facts, and relationships through a configured
44
+ provider. Deferred ingestion records durable work that can resume after restart.
45
+ - **Memory state:** typed nodes carry owner, scope, lifecycle, confidence,
46
+ validity windows, and source references. Explicit corrections and contradiction
47
+ operations preserve earlier claims; automatic store-time supersedence is opt-in.
48
+ - **Retrieval:** combines multiple search paths and packs selected evidence into
49
+ context. Structured assertion-state and aggregation APIs support exact stored
50
+ claim queries and decimal totals beyond semantic top-k retrieval.
51
+ - **Default retrieval behavior:** candidates are ranked by reciprocal rank
52
+ fusion of their semantic and lexical ranks, with a recency boost on
53
+ current-state questions and an event-time tie-break. Packing uses balanced
54
+ ordering and renders each record as one plain line (the `reader` context
55
+ format), while the full records stay in the bundle's sections and the
56
+ retrieval receipt. These defaults changed after v0.12.0;
57
+ [Default retrieval settings](docs/PACKING.md#default-retrieval-settings)
58
+ lists the earlier values and the environment variables that restore them.
59
+ - **Organizer:** maintains promotion, decay, summaries, deduplication, archival,
60
+ and index compaction. It runs opportunistically or through `prme organize`;
61
+ recurring schedules use an external timer. Shared stores should pass `user_id`.
62
+ - **Workspaces:** `MemoryWorkspace` manages named local packs or PostgreSQL
63
+ schemas with identity checks and scoped leases.
64
+
65
+ A local memory pack is a directory by default, or one file when you opt in:
66
+
67
+ ```text
68
+ my_memories/ # directory pack (the default)
69
+ ├── memory.duckdb
70
+ ├── vectors.usearch
71
+ ├── lexical_index/
72
+ └── manifest.json # only when encryption is on
73
+
74
+ memories.prme # single-file pack (opt-in)
75
+ ```
76
+
77
+ Giving `MemoryClient` a path that ends in `.prme`, or setting `PRME_PACK_PATH`,
78
+ selects the single-file layout: one DuckDB file holds the event log, the graph,
79
+ the vector snapshot and a pack manifest, and the lexical index is rebuilt in
80
+ memory when the pack opens. `prme migrate` copies a directory pack into a new
81
+ `.prme` file, and [single-file packs](docs/INTEGRATION.md#single-file-packs)
82
+ covers encryption, compaction and how retrieval compares across the layouts.
83
+
84
+ Search indexes can be regenerated from the durable graph with `prme rebuild`.
85
+ Event time, ingestion time, and validity time remain distinct. The `knowledge_at`
86
+ filter applies an ingestion cutoff to current graph/index state; exact historical
87
+ state replay is not currently available.
88
+
89
+ ## Current benchmarks
90
+
91
+ | Benchmark | Correct answers | Answer accuracy |
92
+ |---|---:|---:|
93
+ | LongMemEval-S | 453 / 500 | **90.6%** |
94
+ | LoCoMo, non-adversarial questions | 1,250 / 1,540 | **81.2%** |
95
+
96
+ ### LongMemEval-S by question type
97
+
98
+ | Question type | Correct answers | Answer accuracy |
99
+ |---|---:|---:|
100
+ | Single-session user | 69 / 70 | 98.6% |
101
+ | Single-session assistant | 54 / 56 | 96.4% |
102
+ | Knowledge update | 71 / 78 | 91.0% |
103
+ | Temporal reasoning | 120 / 133 | 90.2% |
104
+ | Single-session preference | 26 / 30 | 86.7% |
105
+ | Multi-session | 113 / 133 | 85.0% |
106
+
107
+ ### LoCoMo by question type
108
+
109
+ | Question type | Correct answers | Answer accuracy |
110
+ |---|---:|---:|
111
+ | Single-hop | 756 / 841 | 89.9% |
112
+ | Temporal | 256 / 321 | 79.8% |
113
+ | Multi-hop | 182 / 282 | 64.5% |
114
+ | Open-domain | 56 / 96 | 58.3% |
115
+
116
+ Measured on September 25, 2026 with the v0.13.0 retrieval defaults and a
117
+ 3,996-token memory-context budget per question, over memory packs built with
118
+ `store()`, which never runs extraction. The defaults adopted on October 6
119
+ change what `ingest()` stores and how repeated text is packed, so they were
120
+ measured on a separate track over packs built through `ingest()`. See
121
+ [BENCHMARKS.md](BENCHMARKS.md) for both tracks, the method, earlier results
122
+ and reproducibility artifacts.
123
+
124
+ ## Installation
125
+
126
+ ```bash
127
+ pip install prme
128
+ ```
129
+
130
+ Optional integrations:
131
+
132
+ ```bash
133
+ pip install "prme[postgres]" # PostgreSQL backend
134
+ pip install "prme[api]" # HTTP API
135
+ pip install "prme[mcp]" # MCP server
136
+ pip install "prme[langchain]" # LangChain retriever and chat history
137
+ pip install "prme[llamaindex]" # LlamaIndex retriever and chat store
138
+ ```
139
+
140
+ ## Quickstart
141
+
142
+ ```python
143
+ from prme import MemoryClient
144
+
145
+ with MemoryClient("./my_memories") as memory:
146
+ memory.store("Alice prefers dark mode in her editors.", user_id="alice")
147
+ memory.store("The team decided to use PostgreSQL.", user_id="alice")
148
+
149
+ response = memory.retrieve("What are Alice's preferences?", user_id="alice")
150
+ for result in response.results:
151
+ print(f"[{result.composite_score:.3f}] {result.node.content}")
152
+ ```
153
+
154
+ `MemoryClient` is synchronous; `MemoryEngine` provides the async API. Direct
155
+ storage and retrieval use local embeddings by default and require no LLM API key.
156
+ Use `ingest()` with an OpenAI, Anthropic, or Ollama extraction provider when you
157
+ want structured memories extracted from conversation text.
158
+
159
+ Configure PRME through `PRMEConfig`, `PRME_` environment variables, or a `.env`
160
+ file. Constructor values override the environment, which overrides `.env`.
161
+ The [configuration reference](documentation/configuration.md) lists the
162
+ settings and their defaults. To return to the v0.12.0 retrieval defaults, set
163
+ `PRME_SCORING__FUSION=weighted`, `PRME_PACKING__CONTEXT_FORMAT=auditable` and
164
+ `PRME_PACKING__MULTIPATH_ORDERING=balanced` (the last is the default again and
165
+ only makes it explicit; see
166
+ [Default retrieval settings](docs/PACKING.md#default-retrieval-settings)).
167
+ See the [integration reference](docs/INTEGRATION.md) and
168
+ [examples](examples/) for configuration and application patterns.
169
+
170
+ ## Interfaces and tools
171
+
172
+ Use the CLI to initialize, inspect, search, and maintain a local pack:
173
+
174
+ ```bash
175
+ prme init ./my_memories
176
+ prme doctor ./my_memories
177
+ prme search ./my_memories/memory.duckdb "Alice's preferences" --user-id alice
178
+ prme organize ./my_memories/memory.duckdb --user-id alice
179
+ prme compact ./my_memories/memory.duckdb
180
+ prme migrate ./my_memories ./memories.prme
181
+ ```
182
+
183
+ `prme compact` rewrites a closed pack file to give back the space DuckDB never
184
+ returns, and `prme migrate` copies a directory pack into a new single-file pack,
185
+ leaving the directory in place. Every command that takes `memory.duckdb` also
186
+ takes a `.prme` file, and `prme init ./memories.prme` creates one. See the
187
+ [CLI reference](documentation/cli.md).
188
+
189
+ For a local assistant, install the MCP extra and run with a fixed owner:
190
+
191
+ ```bash
192
+ PRME_MCP_USER_ID=alice prme-mcp --db-path ./my_memories
193
+ ```
194
+
195
+ `--db-path` also accepts a single-file pack, such as `./memories.prme`.
196
+
197
+ The HTTP extra provides a FastAPI service via `python -m prme.api`, which binds to
198
+ `127.0.0.1` and refuses a network bind without API credentials (see
199
+ [Running the Server](documentation/http-api.md#running-the-server)).
200
+ Shared HTTP deployments bind owners to credentials through `PRME_API_USER_KEYS`;
201
+ MCP Streamable HTTP uses its separate `PRME_MCP_USER_KEYS` setting.
202
+ See the [HTTP guide](docs/HTTP-API.md) and
203
+ [framework integration guide](docs/FRAMEWORK-INTEGRATIONS.md) for application setup.
204
+
205
+ To browse stored entries and explore their graph connections from a source
206
+ checkout, run `uv run --extra api python -m web.server` and open
207
+ **http://127.0.0.1:8080**. The standalone [memory explorer](web/README.md) lives in
208
+ `web/` and includes filters, source evidence, and an interactive relationship map.
209
+
210
+ ## Milestones
211
+
212
+ | Milestone | Delivered |
213
+ |---|---|
214
+ | Core memory foundation, through v0.9 | Event sourcing, typed graph, hybrid retrieval, organizer jobs, encryption, CLI, evaluation harness, and index rebuilds |
215
+ | v0.10 | Deterministic vector search, batched ingestion indexing, and context-budget enforcement |
216
+ | v0.11 | Tenant-scoped maintenance, ownership and retrieval-filter fixes, and broader backend CI coverage |
217
+ | v0.12 | Durable ingestion and recovery, atomic lifecycle and correction records, scoped workspaces, structured assertion and quantity operations, retrieval receipts, and evaluated ranking profiles |
218
+ | v0.13 | Rank fusion with current-state recency, the one-line reader context format and balanced ordering as retrieval defaults; conversation participants with speaker names; refusal of unauthenticated network binds for the HTTP API; an offline evidence gate and paired answer runs for measuring retrieval changes |
219
+ | v0.14, current | A claim's own sentences as its text, a named speaker's I, me and my bound to the speaker, and each source text packed once, as `ingest()` and reader context defaults; repeated extracted claims merged into one current record; a browser memory explorer; benchmark packs built through `ingest()`, with the evidence gate and a DeepSeek answer track over them |
220
+
221
+ Experimental reranking (including the cross-encoder rank order), temporal-relation
222
+ guidance, model-assisted verification, temporal-first query intent, event-time
223
+ recency for the weighted formula, session context packing, windowed extraction,
224
+ self-contained fact text and speaker grounding remain opt-in.
225
+ Detailed changes are in the [changelog](CHANGELOG.md).
226
+
227
+ Current work follows [epic #77](https://github.com/dwamianm/prism/issues/77),
228
+ which acts on the 2026-09-23 benchmark gap audit: a reader-facing context,
229
+ better ranking, the context budget, and dated facts extracted at write time for
230
+ multi-hop and list questions. See the [roadmap](ROADMAP.md) for what has been
231
+ delivered and what is still open.
232
+
233
+ Images and video as memory sources are
234
+ [RFC-0018](docs/RFC-0018-Visual-Memory.md). Its phase 1 is implemented and
235
+ off by default: with `vision.enabled` set, `MemoryClient.observe()` and
236
+ `prme observe` turn a photo or a saved video into dated observation events
237
+ described by a local vision model, with a thumbnail of each keyframe kept in
238
+ the pack for provenance. The benchmark with real recordings is still open.
239
+
240
+ ## Documentation
241
+
242
+ - [Developer guides](documentation/README.md) and [configuration reference](documentation/configuration.md)
243
+ - [Architecture and RFC index](docs/INDEX.md)
244
+ - [Integration reference](docs/INTEGRATION.md) and [framework adapters](docs/FRAMEWORK-INTEGRATIONS.md)
245
+ - [Context packing and default retrieval settings](docs/PACKING.md) and [retrieval feedback and learning](docs/LEARNING.md)
246
+ - [Experimental retrieval policies](docs/EXPERIMENTAL-RETRIEVAL-POLICIES.md)
247
+ - [Memory corrections](docs/MEMORY-CORRECTIONS.md)
248
+ - [Entity profiles](docs/ENTITY-PROFILES.md) and [entity identity](docs/ENTITY-IDENTITY.md)
249
+ - [Workspaces](docs/WORKSPACES.md) and [local resource control](docs/LOCAL-RESOURCES.md)
250
+ - [Custom embeddings](docs/CUSTOM-EMBEDDINGS.md) and [typed value bindings](docs/VALUE-BINDINGS.md)
251
+ - [HTTP API](docs/HTTP-API.md)
252
+
253
+ ## Development
254
+
255
+ ```bash
256
+ git clone https://github.com/dwamianm/prism.git
257
+ cd prism
258
+ uv sync --dev
259
+ uv run pytest tests/ -q
260
+ ```
261
+
262
+ PostgreSQL tests require a live database configured through
263
+ `PRME_TEST_DATABASE_URL`. See [CONTRIBUTING.md](CONTRIBUTING.md) for development
264
+ setup, checks, and contribution guidelines.
265
+
266
+ ## License
267
+
268
+ Apache License 2.0 — see [LICENSE](LICENSE).