prismcortex 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. prismcortex-0.2.1/LICENSE +21 -0
  2. prismcortex-0.2.1/PKG-INFO +175 -0
  3. prismcortex-0.2.1/README.md +106 -0
  4. prismcortex-0.2.1/prismcortex/__init__.py +40 -0
  5. prismcortex-0.2.1/prismcortex/adapters/__init__.py +20 -0
  6. prismcortex-0.2.1/prismcortex/adapters/ann.py +104 -0
  7. prismcortex-0.2.1/prismcortex/adapters/prism.py +174 -0
  8. prismcortex-0.2.1/prismcortex/adapters/reference.py +381 -0
  9. prismcortex-0.2.1/prismcortex/auth.py +81 -0
  10. prismcortex-0.2.1/prismcortex/determinism.py +75 -0
  11. prismcortex-0.2.1/prismcortex/engine.py +524 -0
  12. prismcortex-0.2.1/prismcortex/factory.py +48 -0
  13. prismcortex-0.2.1/prismcortex/labels.py +114 -0
  14. prismcortex-0.2.1/prismcortex/licensing.py +94 -0
  15. prismcortex-0.2.1/prismcortex/llm/__init__.py +1 -0
  16. prismcortex-0.2.1/prismcortex/llm/gemini.py +176 -0
  17. prismcortex-0.2.1/prismcortex/models.py +207 -0
  18. prismcortex-0.2.1/prismcortex/policy.py +64 -0
  19. prismcortex-0.2.1/prismcortex/ports.py +121 -0
  20. prismcortex-0.2.1/prismcortex/salience.py +44 -0
  21. prismcortex-0.2.1/prismcortex/server.py +520 -0
  22. prismcortex-0.2.1/prismcortex/server_helpers.py +74 -0
  23. prismcortex-0.2.1/prismcortex/static/index.html +94 -0
  24. prismcortex-0.2.1/prismcortex/tenant.py +103 -0
  25. prismcortex-0.2.1/prismcortex/tracing.py +85 -0
  26. prismcortex-0.2.1/prismcortex.egg-info/PKG-INFO +175 -0
  27. prismcortex-0.2.1/prismcortex.egg-info/SOURCES.txt +37 -0
  28. prismcortex-0.2.1/prismcortex.egg-info/dependency_links.txt +1 -0
  29. prismcortex-0.2.1/prismcortex.egg-info/requires.txt +27 -0
  30. prismcortex-0.2.1/prismcortex.egg-info/top_level.txt +1 -0
  31. prismcortex-0.2.1/pyproject.toml +61 -0
  32. prismcortex-0.2.1/setup.cfg +4 -0
  33. prismcortex-0.2.1/tests/test_enterprise.py +96 -0
  34. prismcortex-0.2.1/tests/test_gemini_e2e.py +61 -0
  35. prismcortex-0.2.1/tests/test_graph_engine.py +405 -0
  36. prismcortex-0.2.1/tests/test_licensing.py +45 -0
  37. prismcortex-0.2.1/tests/test_prism_adapters.py +54 -0
  38. prismcortex-0.2.1/tests/test_scale_bench.py +9 -0
  39. prismcortex-0.2.1/tests/test_server_security.py +32 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Amin Parva / Insight IT Solutions 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.
@@ -0,0 +1,175 @@
1
+ Metadata-Version: 2.4
2
+ Name: prismcortex
3
+ Version: 0.2.1
4
+ Summary: Deterministic, auditable, self-consolidating memory for AI agents
5
+ Author-email: Amin Parva <info@insightits.com>
6
+ Maintainer-email: Insight IT Solutions LLC <info@insightits.com>
7
+ License: MIT License
8
+
9
+ Copyright (c) 2026 Amin Parva / Insight IT Solutions LLC
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+
29
+ Project-URL: Homepage, https://www.insightits.com/products/prismcortex.html
30
+ Project-URL: Documentation, https://github.com/insightitsGit/PrismCortex#readme
31
+ Project-URL: Repository, https://github.com/insightitsGit/PrismCortex
32
+ Project-URL: Bug Tracker, https://github.com/insightitsGit/PrismCortex/issues
33
+ Keywords: llm,memory,agents,knowledge-graph,deterministic,rag,bitemporal,audit,agent-memory,compliance
34
+ Classifier: Development Status :: 4 - Beta
35
+ Classifier: Intended Audience :: Developers
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Programming Language :: Python :: 3
38
+ Classifier: Programming Language :: Python :: 3.10
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
42
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
43
+ Requires-Python: >=3.10
44
+ Description-Content-Type: text/markdown
45
+ License-File: LICENSE
46
+ Requires-Dist: pydantic>=2.5
47
+ Requires-Dist: numpy>=1.24
48
+ Requires-Dist: cryptography>=42
49
+ Provides-Extra: prism
50
+ Requires-Dist: prismlang>=0.1.1; extra == "prism"
51
+ Requires-Dist: prismlib>=0.4.0; extra == "prism"
52
+ Requires-Dist: prismrag-patch>=0.2.1; extra == "prism"
53
+ Requires-Dist: prismresonance>=0.3.0; extra == "prism"
54
+ Provides-Extra: gemini
55
+ Requires-Dist: google-genai>=0.3.0; extra == "gemini"
56
+ Provides-Extra: server
57
+ Requires-Dist: fastapi>=0.110; extra == "server"
58
+ Requires-Dist: uvicorn[standard]>=0.27; extra == "server"
59
+ Provides-Extra: dev
60
+ Requires-Dist: pytest>=7; extra == "dev"
61
+ Requires-Dist: google-genai>=0.3.0; extra == "dev"
62
+ Requires-Dist: fastapi>=0.110; extra == "dev"
63
+ Requires-Dist: uvicorn[standard]>=0.27; extra == "dev"
64
+ Requires-Dist: httpx>=0.27; extra == "dev"
65
+ Provides-Extra: bench
66
+ Requires-Dist: mem0ai>=2.0; extra == "bench"
67
+ Requires-Dist: zep-cloud>=2.0; extra == "bench"
68
+ Dynamic: license-file
69
+
70
+ # PrismCortex
71
+
72
+ **Deterministic, auditable, self-consolidating memory for AI agents.**
73
+
74
+ Most agent "memory" is an append-only chat log that you stuff back into the context
75
+ window until it overflows. PrismCortex does what a brain does instead: it **digests**
76
+ each turn into a knowledge graph, **consolidates** uncertain facts in the background
77
+ (like sleep), and demotes the LLM from *thinker* to *renderer* — it only paints the
78
+ facts you hand it. Change the memory and only the affected answers change; everything
79
+ is traceable to the exact facts and source events behind it.
80
+
81
+ It's the orchestration layer over five shipped Insight ITS packages — PrismLang,
82
+ PrismRAG, PrismResonance, PrismLib, and Chorus Fabric — behind one tiny API.
83
+
84
+ ```python
85
+ from prismcortex import reference_memory
86
+
87
+ mem = reference_memory(cache_path=".prismcortex_cache/demo.json")
88
+
89
+ mem.digest("My production deploy budget is $40,000.")
90
+ print(mem.recall("What's my deploy budget?").answer) # → "$40,000"
91
+
92
+ mem.digest("Correction: my deploy budget is now $55,000.") # fast-tracked (ALERT)
93
+ print(mem.recall("What's my deploy budget?").answer) # → "$55,000"
94
+ # …and the $40,000 fact is still on record, time-stamped, for audit/time-travel.
95
+ ```
96
+
97
+ ## Why it's different
98
+
99
+ | | Append-only RAG | PrismCortex |
100
+ |---|---|---|
101
+ | Storage | every chat turn | graph topology (the *gist*) |
102
+ | Updates | append + hope retrieval ranks it | bitemporal: invalidate old, add new, keep history |
103
+ | Determinism | none (logs + LLM both drift) | content-addressed render cache, replay-identical |
104
+ | Cost | re-extract context every call | salience-gated writes, cached reads |
105
+ | Audit | grep the logs | every answer → exact facts + source events |
106
+
107
+ ## What you get that a vector store can't
108
+
109
+ | Capability | What it does |
110
+ |---|---|
111
+ | **Explainability** (`/explain`) | Every answer returns its **evidence trail** — the exact facts, their source events, and confidence. A vector store returns memories; only a provenance graph returns *evidence*. |
112
+ | **Confidence + freshness** | Each recall reports how reinforced its facts are (0–1) and when they were last confirmed. |
113
+ | **Time-travel / audit** | Corrections invalidate but **retain** the old fact as a queryable bitemporal record (a paid feature in Mem0 OSS). |
114
+ | **Bounded memory** | `sleep()` prunes the coldest facts to a cap — the active set **plateaus** instead of growing forever; pruned facts are kept for audit. |
115
+ | **~12× smaller index** | 128-dim vectors vs the 1536–3072-dim default elsewhere; plus entity-dedup. |
116
+ | **Sovereign** | Self-hosted, your data, offline-keyed — no third-party SaaS. |
117
+
118
+ These are validated in `benchmarks/` (incl. a fair head-to-head vs Mem0 in `vs_mem0.py`).
119
+
120
+ ## Determinism, honestly
121
+
122
+ We do **not** claim "temperature 0 → identical output" — that's false for any shared
123
+ API model (batching + floating-point non-associativity flip near-tied tokens). Instead:
124
+
125
+ - **Content-addressed rendering.** The cache key is a hash of the exact retrieved
126
+ subgraph + query + template + **pinned model snapshot**. The model is invoked at most
127
+ once per unique (query, memory-version); its answer is frozen and replayed
128
+ byte-for-byte. A changed fact changes the key, so a stale answer is *unreachable* —
129
+ invalidation and determinism are the same mechanism.
130
+ - **Extractive facts.** Numbers, names, ids, and dates are substituted from the graph,
131
+ not generated, and a verification pass rejects fabricated values — so the *facts* are
132
+ deterministic even on the first render; only prose phrasing can vary (then it's frozen).
133
+
134
+ Scope: replay-determinism, pinned model snapshot, snapshot sources (not live feeds).
135
+ First-render *token* determinism requires the self-hosted sovereign tier. See
136
+ [`DESIGN.md`](DESIGN.md) §2.
137
+
138
+ ## Architecture (one engine, five swappable ports)
139
+
140
+ ```
141
+ digest(text) ─▶ salience gate ─▶ extract gist ─▶ delta in RAM
142
+ ├─ certain / urgent ─▶ commit (version++)
143
+ └─ uncertain ───────▶ staging buffer
144
+ │ sleep()
145
+ consolidate ─▶ commit (version++)
146
+
147
+ recall(query) ─▶ retrieve subgraph @version ─▶ content-address ─▶ cache hit? replay
148
+ miss? render once → freeze
149
+ ```
150
+
151
+ | Port | Reference adapter | Production (`pip install prismcortex[prism]`) |
152
+ |---|---|---|
153
+ | Gist projection | hashing-trick embeddings | `prismlang` |
154
+ | Graph store (bitemporal) | in-memory | `prismrag-patch` |
155
+ | Weight / salience / sleep | in-process | `prismresonance` |
156
+ | Render cache (durable) | JSON file | `prismlib` (cache-as-failover) |
157
+ | Mesh broadcast | in-process | `prismlib` cluster / Chorus |
158
+ | Extraction + rendering | — | **real Gemini** (`prismcortex[gemini]`) |
159
+
160
+ ## Install & test
161
+
162
+ ```bash
163
+ pip install -e . # core
164
+ pip install -e ".[gemini]" # + real Gemini extraction/rendering
165
+
166
+ pytest tests/test_graph_engine.py # deterministic substrate — no API key
167
+ GEMINI_API_KEY=... pytest # full end-to-end with real Gemini
168
+ ```
169
+
170
+ ## Licensing
171
+
172
+ Open-core (MIT). The core (`digest`/`recall`, bitemporal graph, determinism cache) is
173
+ free. Commercial modules (audit console, consolidation-at-scale, multi-agent mesh, the
174
+ sovereign determinism tier) are gated by an **offline signed license key** — no
175
+ phone-home, works air-gapped. See [`DESIGN.md`](DESIGN.md) §7.
@@ -0,0 +1,106 @@
1
+ # PrismCortex
2
+
3
+ **Deterministic, auditable, self-consolidating memory for AI agents.**
4
+
5
+ Most agent "memory" is an append-only chat log that you stuff back into the context
6
+ window until it overflows. PrismCortex does what a brain does instead: it **digests**
7
+ each turn into a knowledge graph, **consolidates** uncertain facts in the background
8
+ (like sleep), and demotes the LLM from *thinker* to *renderer* — it only paints the
9
+ facts you hand it. Change the memory and only the affected answers change; everything
10
+ is traceable to the exact facts and source events behind it.
11
+
12
+ It's the orchestration layer over five shipped Insight ITS packages — PrismLang,
13
+ PrismRAG, PrismResonance, PrismLib, and Chorus Fabric — behind one tiny API.
14
+
15
+ ```python
16
+ from prismcortex import reference_memory
17
+
18
+ mem = reference_memory(cache_path=".prismcortex_cache/demo.json")
19
+
20
+ mem.digest("My production deploy budget is $40,000.")
21
+ print(mem.recall("What's my deploy budget?").answer) # → "$40,000"
22
+
23
+ mem.digest("Correction: my deploy budget is now $55,000.") # fast-tracked (ALERT)
24
+ print(mem.recall("What's my deploy budget?").answer) # → "$55,000"
25
+ # …and the $40,000 fact is still on record, time-stamped, for audit/time-travel.
26
+ ```
27
+
28
+ ## Why it's different
29
+
30
+ | | Append-only RAG | PrismCortex |
31
+ |---|---|---|
32
+ | Storage | every chat turn | graph topology (the *gist*) |
33
+ | Updates | append + hope retrieval ranks it | bitemporal: invalidate old, add new, keep history |
34
+ | Determinism | none (logs + LLM both drift) | content-addressed render cache, replay-identical |
35
+ | Cost | re-extract context every call | salience-gated writes, cached reads |
36
+ | Audit | grep the logs | every answer → exact facts + source events |
37
+
38
+ ## What you get that a vector store can't
39
+
40
+ | Capability | What it does |
41
+ |---|---|
42
+ | **Explainability** (`/explain`) | Every answer returns its **evidence trail** — the exact facts, their source events, and confidence. A vector store returns memories; only a provenance graph returns *evidence*. |
43
+ | **Confidence + freshness** | Each recall reports how reinforced its facts are (0–1) and when they were last confirmed. |
44
+ | **Time-travel / audit** | Corrections invalidate but **retain** the old fact as a queryable bitemporal record (a paid feature in Mem0 OSS). |
45
+ | **Bounded memory** | `sleep()` prunes the coldest facts to a cap — the active set **plateaus** instead of growing forever; pruned facts are kept for audit. |
46
+ | **~12× smaller index** | 128-dim vectors vs the 1536–3072-dim default elsewhere; plus entity-dedup. |
47
+ | **Sovereign** | Self-hosted, your data, offline-keyed — no third-party SaaS. |
48
+
49
+ These are validated in `benchmarks/` (incl. a fair head-to-head vs Mem0 in `vs_mem0.py`).
50
+
51
+ ## Determinism, honestly
52
+
53
+ We do **not** claim "temperature 0 → identical output" — that's false for any shared
54
+ API model (batching + floating-point non-associativity flip near-tied tokens). Instead:
55
+
56
+ - **Content-addressed rendering.** The cache key is a hash of the exact retrieved
57
+ subgraph + query + template + **pinned model snapshot**. The model is invoked at most
58
+ once per unique (query, memory-version); its answer is frozen and replayed
59
+ byte-for-byte. A changed fact changes the key, so a stale answer is *unreachable* —
60
+ invalidation and determinism are the same mechanism.
61
+ - **Extractive facts.** Numbers, names, ids, and dates are substituted from the graph,
62
+ not generated, and a verification pass rejects fabricated values — so the *facts* are
63
+ deterministic even on the first render; only prose phrasing can vary (then it's frozen).
64
+
65
+ Scope: replay-determinism, pinned model snapshot, snapshot sources (not live feeds).
66
+ First-render *token* determinism requires the self-hosted sovereign tier. See
67
+ [`DESIGN.md`](DESIGN.md) §2.
68
+
69
+ ## Architecture (one engine, five swappable ports)
70
+
71
+ ```
72
+ digest(text) ─▶ salience gate ─▶ extract gist ─▶ delta in RAM
73
+ ├─ certain / urgent ─▶ commit (version++)
74
+ └─ uncertain ───────▶ staging buffer
75
+ │ sleep()
76
+ consolidate ─▶ commit (version++)
77
+
78
+ recall(query) ─▶ retrieve subgraph @version ─▶ content-address ─▶ cache hit? replay
79
+ miss? render once → freeze
80
+ ```
81
+
82
+ | Port | Reference adapter | Production (`pip install prismcortex[prism]`) |
83
+ |---|---|---|
84
+ | Gist projection | hashing-trick embeddings | `prismlang` |
85
+ | Graph store (bitemporal) | in-memory | `prismrag-patch` |
86
+ | Weight / salience / sleep | in-process | `prismresonance` |
87
+ | Render cache (durable) | JSON file | `prismlib` (cache-as-failover) |
88
+ | Mesh broadcast | in-process | `prismlib` cluster / Chorus |
89
+ | Extraction + rendering | — | **real Gemini** (`prismcortex[gemini]`) |
90
+
91
+ ## Install & test
92
+
93
+ ```bash
94
+ pip install -e . # core
95
+ pip install -e ".[gemini]" # + real Gemini extraction/rendering
96
+
97
+ pytest tests/test_graph_engine.py # deterministic substrate — no API key
98
+ GEMINI_API_KEY=... pytest # full end-to-end with real Gemini
99
+ ```
100
+
101
+ ## Licensing
102
+
103
+ Open-core (MIT). The core (`digest`/`recall`, bitemporal graph, determinism cache) is
104
+ free. Commercial modules (audit console, consolidation-at-scale, multi-agent mesh, the
105
+ sovereign determinism tier) are gated by an **offline signed license key** — no
106
+ phone-home, works air-gapped. See [`DESIGN.md`](DESIGN.md) §7.
@@ -0,0 +1,40 @@
1
+ """PrismCortex — deterministic, auditable, self-consolidating memory for AI agents.
2
+
3
+ from prismcortex import reference_memory
4
+ mem = reference_memory() # reference adapters + real Gemini
5
+ mem.digest("My deploy budget is $40k.")
6
+ mem.recall("What's my deploy budget?").answer
7
+
8
+ Swap the reference adapters for the real Insight ITS packages (prismlang, prismrag,
9
+ prismresonance, prismlib, Chorus) one port at a time — the engine never changes.
10
+ """
11
+ from .engine import Memory
12
+ from .factory import reference_memory
13
+ from .models import (
14
+ Band,
15
+ DigestOutcome,
16
+ DigestResult,
17
+ Edge,
18
+ GraphVersion,
19
+ Node,
20
+ RecallResult,
21
+ StateDelta,
22
+ Subgraph,
23
+ )
24
+
25
+ __version__ = "0.2.1"
26
+
27
+ __all__ = [
28
+ "Memory",
29
+ "reference_memory",
30
+ "Band",
31
+ "DigestOutcome",
32
+ "DigestResult",
33
+ "RecallResult",
34
+ "Node",
35
+ "Edge",
36
+ "Subgraph",
37
+ "StateDelta",
38
+ "GraphVersion",
39
+ "__version__",
40
+ ]
@@ -0,0 +1,20 @@
1
+ """Adapters that satisfy the PrismCortex ports."""
2
+ from .reference import (
3
+ DurableCache,
4
+ HashingProjector,
5
+ InMemoryGraphStore,
6
+ InProcessMesh,
7
+ InProcessResonance,
8
+ ListStaging,
9
+ LocalBlobStore,
10
+ )
11
+
12
+ __all__ = [
13
+ "DurableCache",
14
+ "HashingProjector",
15
+ "InMemoryGraphStore",
16
+ "InProcessMesh",
17
+ "InProcessResonance",
18
+ "ListStaging",
19
+ "LocalBlobStore",
20
+ ]
@@ -0,0 +1,104 @@
1
+ """IVF-style ANN retrieval for graphs beyond ~10k nodes (numpy-only, no extra deps)."""
2
+ from __future__ import annotations
3
+
4
+ import os
5
+ from typing import Optional
6
+
7
+ import numpy as np
8
+
9
+ from .reference import InMemoryGraphStore
10
+
11
+
12
+ class AnnGraphStore(InMemoryGraphStore):
13
+ """In-memory bitemporal store with inverted-file ANN when node count exceeds threshold."""
14
+
15
+ def __init__(self, *, tenant_id: str = "default", ivf_threshold: Optional[int] = None, nlist: int = 256, nprobe: int = 16) -> None:
16
+ super().__init__()
17
+ self.tenant_id = tenant_id
18
+ self._ivf_threshold = ivf_threshold or int(os.environ.get("PRISMCORTEX_ANN_THRESHOLD", "5000"))
19
+ self._nlist = nlist
20
+ self._nprobe = nprobe
21
+ self._centroids: Optional[np.ndarray] = None
22
+ self._inverted: list[list[str]] = []
23
+ self._ivf_dirty = True
24
+
25
+ def _rebuild_ivf(self) -> None:
26
+ self._ensure_matrix()
27
+ if self._emb_unit is None or len(self._emb_ids) < self._ivf_threshold:
28
+ self._centroids = None
29
+ self._inverted = []
30
+ self._ivf_dirty = False
31
+ return
32
+ n, d = self._emb_unit.shape
33
+ k = min(self._nlist, max(8, n // 40))
34
+ rng = np.random.default_rng(42)
35
+ idx = rng.choice(n, size=k, replace=False)
36
+ self._centroids = self._emb_unit[idx].copy()
37
+ # Lloyd-lite: 3 iterations
38
+ for _ in range(3):
39
+ sims = self._emb_unit @ self._centroids.T
40
+ assign = np.argmax(sims, axis=1)
41
+ for c in range(k):
42
+ mask = assign == c
43
+ if mask.any():
44
+ self._centroids[c] = self._emb_unit[mask].mean(axis=0)
45
+ cn = np.linalg.norm(self._centroids[c]) or 1.0
46
+ self._centroids[c] /= cn
47
+ self._inverted = [[] for _ in range(k)]
48
+ sims = self._emb_unit @ self._centroids.T
49
+ assign = np.argmax(sims, axis=1)
50
+ for i, c in enumerate(assign):
51
+ self._inverted[int(c)].append(self._emb_ids[i])
52
+ self._ivf_dirty = False
53
+
54
+ def _ensure_matrix(self) -> None:
55
+ super()._ensure_matrix()
56
+ if self._matrix_dirty:
57
+ self._ivf_dirty = True
58
+
59
+ def apply(self, delta):
60
+ v = super().apply(delta)
61
+ self._ivf_dirty = True
62
+ return v
63
+
64
+ def retrieve(self, embedding: list[float], k: int = 8):
65
+ if not self._nodes:
66
+ return super().retrieve(embedding, k)
67
+ self._ensure_matrix()
68
+ if self._emb_unit is None:
69
+ return super().retrieve(embedding, k)
70
+ if len(self._emb_ids) < self._ivf_threshold:
71
+ return super().retrieve(embedding, k)
72
+ if self._ivf_dirty:
73
+ self._rebuild_ivf()
74
+ if self._centroids is None:
75
+ return super().retrieve(embedding, k)
76
+
77
+ q = np.asarray(embedding, dtype=np.float32)
78
+ qn = float(np.linalg.norm(q)) or 1.0
79
+ q = q / qn
80
+ csim = self._centroids @ q
81
+ n = len(self._emb_ids)
82
+ # Scale probe depth with graph size (more clusters searched at 50k+ nodes).
83
+ nprobe = min(len(csim), max(self._nprobe, n // 2000))
84
+ probe = np.argsort(-csim, kind="stable")[:nprobe]
85
+ candidates: set[str] = set()
86
+ id_to_row = {nid: i for i, nid in enumerate(self._emb_ids)}
87
+ for c in probe:
88
+ for nid in self._inverted[int(c)]:
89
+ candidates.add(nid)
90
+ if not candidates:
91
+ return super().retrieve(embedding, k)
92
+
93
+ rows = [id_to_row[nid] for nid in candidates if nid in id_to_row]
94
+ sims = self._emb_unit[rows] @ q
95
+ order = np.argsort(-sims, kind="stable")[: min(k, len(rows))]
96
+ chosen = {self._emb_ids[rows[int(i)]] for i in order}
97
+
98
+ edges = [e for e in self._edges.values() if e.is_current and (e.src in chosen or e.dst in chosen)]
99
+ for e in edges:
100
+ chosen.add(e.src)
101
+ chosen.add(e.dst)
102
+ nodes = [self._nodes[n] for n in chosen if n in self._nodes]
103
+ from ..models import Subgraph
104
+ return Subgraph(nodes=nodes, edges=edges)
@@ -0,0 +1,174 @@
1
+ """Production adapters — the real Insight ITS packages behind the ports.
2
+
3
+ Import-guarded so the OSS core stays installable without them (`pip install
4
+ prismcortex[prism]`). Each class wraps exactly one package:
5
+
6
+ - PrismLangProjector → prismlang.PrismProjector (deterministic, CPU-stable vectors)
7
+ - PrismResonanceAdapter → prismresonance.PrismResonance (wavepacket weight + sleep)
8
+ - PrismLibCache → prismlib SQLiteStore (durable cache-as-failover)
9
+
10
+ The bitemporal GraphStore stays PrismCortex-owned (the reference store *is* the design
11
+ — prismrag-patch is a retrieval governor, not a bitemporal database, so it slots in as
12
+ a recall-time filter rather than the store itself). The Chorus/prismlib cluster mesh is
13
+ the remaining seam; InProcessMesh stands in until it's wired.
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import os
18
+ import time
19
+ from typing import Optional
20
+
21
+ import numpy as np
22
+
23
+
24
+ class PrismLangProjector:
25
+ """GistProjector via prismlang.PrismProjector.
26
+
27
+ project() returns (category_slug, vector, trace). The vector is all-MiniLM-L6-v2
28
+ JL-reduced with a seed derived from tenant_id — deterministic given a fixed tenant,
29
+ which is exactly the CPU-stable projection the read-path determinism contract needs.
30
+ """
31
+
32
+ def __init__(self, taxonomy=None, tenant_id: str = "prismcortex", k: int = 128) -> None:
33
+ # k = projection dimension. PrismLang defaults to 64, which crowds at scale
34
+ # (retrieval recall drops to ~0.86 at 3k facts); 128 restores it to ~0.97 with no
35
+ # latency cost. See benchmarks/scale_bench.py.
36
+ from prismlang import Category, PrismProjector, TaxonomyConfig
37
+
38
+ if taxonomy is None:
39
+ taxonomy = TaxonomyConfig(categories=[
40
+ Category("general", "General", ["the", "a", "is", "of", "to"]),
41
+ Category("preference", "Preference", ["like", "prefer", "favorite", "want", "hate"]),
42
+ Category("fact", "Fact", ["is", "are", "has", "budget", "name", "id", "number"]),
43
+ Category("tech", "Tech", ["deploy", "database", "server", "region", "api", "model"]),
44
+ ])
45
+ self._p = PrismProjector(taxonomy, tenant_id=tenant_id, k=k)
46
+ _, probe, _ = self._p.project("dimension probe")
47
+ self.dim = len(probe)
48
+
49
+ def embed(self, text: str) -> list[float]:
50
+ _, vec, _ = self._p.project(text)
51
+ return [float(x) for x in vec]
52
+
53
+ def classify(self, text: str) -> str:
54
+ cat, _, _ = self._p.project(text)
55
+ return cat
56
+
57
+
58
+ class PrismResonanceAdapter:
59
+ """ResonanceEngine via prismresonance.PrismResonance (compiles an ONNX graph on
60
+ first construction; writes a small state db)."""
61
+
62
+ def __init__(self, embedding_dim: int, state_path: str = "resonance_state.db", onnx_path: str = "resonance_engine.onnx") -> None:
63
+ from prismresonance import PrismResonance
64
+ from prismresonance.frequency import FrequencyFamily
65
+
66
+ self._FF = FrequencyFamily
67
+ self._r = PrismResonance.create(embedding_dim=embedding_dim, state_path=state_path, onnx_path=onnx_path)
68
+ self._amps: dict[str, np.ndarray] = {} # kept so reinforce can re-ingest
69
+
70
+ def _freq(self, band: str):
71
+ return getattr(self._FF, band, self._FF.NEUTRAL)
72
+
73
+ def ingest(self, chunk_id: str, amplitude: list[float], band: str) -> None:
74
+ amp = np.asarray(amplitude, dtype=np.float32)
75
+ if amp.size == 0:
76
+ return
77
+ self._amps[chunk_id] = amp
78
+ self._r.ingest(chunk_id, amp, self._freq(band))
79
+
80
+ def reinforce(self, chunk_id: str) -> None:
81
+ amp = self._amps.get(chunk_id)
82
+ if amp is not None: # re-ingest at higher salience ≈ LTP
83
+ self._r.ingest(chunk_id, amp, self._FF.ALERT)
84
+
85
+ def rank(self, candidate_ids: list[str]) -> list[str]:
86
+ return list(candidate_ids) # resonance ordering is not on the determinism path
87
+
88
+ def consolidate(self) -> None:
89
+ self._r.sleep()
90
+
91
+ def shutdown(self) -> None:
92
+ try:
93
+ self._r.shutdown()
94
+ except Exception:
95
+ pass
96
+
97
+
98
+ class PrismLibCache:
99
+ """ResponseCache via prismlib SQLiteStore — exact-key, durable (cache-as-failover).
100
+
101
+ packet_id carries our content-address; response carries the frozen answer. Durable
102
+ by file path so a frozen answer survives restart and cache eviction.
103
+ """
104
+
105
+ _TEN_YEARS = 10 * 365 * 24 * 3600
106
+
107
+ def __init__(self, db_path: str = ".prismcortex_cache/prismlib.db") -> None:
108
+ from prism.cache import CacheEntry, SQLiteStore
109
+
110
+ os.makedirs(os.path.dirname(db_path) or ".", exist_ok=True)
111
+ self._CacheEntry = CacheEntry
112
+ self._db_path = db_path
113
+ self._store = SQLiteStore(db_path=db_path)
114
+
115
+ def get(self, key: str) -> Optional[str]:
116
+ entry = self._store.load(key)
117
+ return entry.response if entry else None
118
+
119
+ def has(self, key: str) -> bool:
120
+ return self._store.load(key) is not None
121
+
122
+ def put(self, key: str, value: str) -> None:
123
+ now = time.time()
124
+ self._store.save(self._CacheEntry(
125
+ packet_id=key, query_text="", response=value,
126
+ created_at=now, expires_at=now + self._TEN_YEARS,
127
+ ))
128
+
129
+ def clear(self) -> None:
130
+ """Drop all cached answers (recreate the store) — used on erasure."""
131
+ from prism.cache import SQLiteStore
132
+
133
+ try:
134
+ self._store.close()
135
+ except Exception: # noqa: BLE001
136
+ pass
137
+ if self._db_path != ":memory:" and os.path.exists(self._db_path):
138
+ os.remove(self._db_path)
139
+ self._store = SQLiteStore(db_path=self._db_path)
140
+
141
+
142
+ def prism_memory(
143
+ *,
144
+ model: Optional[str] = None,
145
+ cache_db: str = ".prismcortex_cache/prismlib.db",
146
+ tenant_id: str = "prismcortex",
147
+ resonance_state: str = ".prismcortex_cache/resonance_state.db",
148
+ resonance_onnx: str = ".prismcortex_cache/resonance_engine.onnx",
149
+ k: int = 8,
150
+ ):
151
+ """Production-wired Memory: real PrismLang + PrismResonance + PrismLib + Gemini.
152
+
153
+ GraphStore + Mesh remain the reference (PrismCortex-owned bitemporal store; mesh is
154
+ the open Chorus seam). Needs prismcortex[prism], prismcortex[gemini], and a key.
155
+ """
156
+ from ..engine import Memory
157
+ from ..llm.gemini import GeminiClient
158
+ from .reference import InMemoryGraphStore, InProcessMesh, ListStaging
159
+
160
+ projector = PrismLangProjector(tenant_id=tenant_id)
161
+ resonance = PrismResonanceAdapter(embedding_dim=projector.dim, state_path=resonance_state, onnx_path=resonance_onnx)
162
+ cache = PrismLibCache(db_path=cache_db)
163
+ gemini = GeminiClient(model=model)
164
+ return Memory(
165
+ projector=projector,
166
+ extractor=gemini,
167
+ renderer=gemini,
168
+ store=InMemoryGraphStore(),
169
+ resonance=resonance,
170
+ cache=cache,
171
+ mesh=InProcessMesh(),
172
+ staging=ListStaging(),
173
+ k=k,
174
+ )