cuemap 0.7.0__tar.gz → 0.7.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.
- {cuemap-0.7.0/cuemap.egg-info → cuemap-0.7.2}/PKG-INFO +34 -25
- {cuemap-0.7.0 → cuemap-0.7.2}/README.md +33 -24
- {cuemap-0.7.0 → cuemap-0.7.2}/cuemap/__init__.py +4 -1
- {cuemap-0.7.0 → cuemap-0.7.2}/cuemap/client.py +121 -21
- cuemap-0.7.2/cuemap/embedded.py +186 -0
- {cuemap-0.7.0 → cuemap-0.7.2/cuemap.egg-info}/PKG-INFO +34 -25
- {cuemap-0.7.0 → cuemap-0.7.2}/cuemap.egg-info/SOURCES.txt +1 -0
- {cuemap-0.7.0 → cuemap-0.7.2}/pyproject.toml +1 -1
- {cuemap-0.7.0 → cuemap-0.7.2}/LICENSE +0 -0
- {cuemap-0.7.0 → cuemap-0.7.2}/MANIFEST.in +0 -0
- {cuemap-0.7.0 → cuemap-0.7.2}/cuemap/exceptions.py +0 -0
- {cuemap-0.7.0 → cuemap-0.7.2}/cuemap/grounding.py +0 -0
- {cuemap-0.7.0 → cuemap-0.7.2}/cuemap/models.py +0 -0
- {cuemap-0.7.0 → cuemap-0.7.2}/cuemap.egg-info/dependency_links.txt +0 -0
- {cuemap-0.7.0 → cuemap-0.7.2}/cuemap.egg-info/requires.txt +0 -0
- {cuemap-0.7.0 → cuemap-0.7.2}/cuemap.egg-info/top_level.txt +0 -0
- {cuemap-0.7.0 → cuemap-0.7.2}/examples/pure_usage.py +0 -0
- {cuemap-0.7.0 → cuemap-0.7.2}/examples/with_local_llm.py +0 -0
- {cuemap-0.7.0 → cuemap-0.7.2}/examples/with_openai.py +0 -0
- {cuemap-0.7.0 → cuemap-0.7.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cuemap
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: CueMap Python SDK - High-performance temporal-associative memory
|
|
5
5
|
Author-email: Kaan Demirel <hello@cuemap.dev>
|
|
6
6
|
License: MIT
|
|
@@ -42,14 +42,14 @@ Dynamic: license-file
|
|
|
42
42
|
CueMap implements a **Continuous Gradient Algorithm** optimized for associative data structures:
|
|
43
43
|
|
|
44
44
|
1. **Intersection (Context Filter)**: Triangulates relevant memories by overlapping cues
|
|
45
|
-
2. **
|
|
45
|
+
2. **Local semantic reranking**: Uses bundled qint8 MiniLM-L3 by default, or q4 MiniLM-L3 with the edge profile, for bounded semantic ranking inside the engine.
|
|
46
46
|
3. **Recency & Salience (Signal Dynamics)**: Balances fresh data with salient, high-signal events prioritized by an adaptive impact scoring module.
|
|
47
47
|
4. **Reinforcement (Access-based Learning)**: Frequently accessed memories gain signal strength, remaining highly accessible even as they age.
|
|
48
48
|
5. **Deterministic Facets & Intent Routing**: Extracts synchronous source, evidence, temporal, type, and entity facets, then uses sparse intent cues and reranking during recall.
|
|
49
49
|
|
|
50
|
-
As of v0.7.
|
|
50
|
+
As of v0.7.2, CueMap keeps deterministic lexical candidate discovery and adds bundled qint8 `all-MiniLM-L3-v2` for bounded hybrid semantic and intent reranking. The `edge` engine profile uses a q4 build of the same model. No runtime model download is required, and callers can disable the encoder or provide their own vectors.
|
|
51
51
|
|
|
52
|
-
v0.7.
|
|
52
|
+
v0.7.2 also preserves numeric per-project memory IDs everywhere. If callers need deterministic upsert/dedupe identity, pass `source_key`; memory IDs remain compact runtime addresses.
|
|
53
53
|
|
|
54
54
|
Use this SDK to talk to the Rust engine from Python applications.
|
|
55
55
|
|
|
@@ -134,9 +134,9 @@ print(response["proof"])
|
|
|
134
134
|
# Cryptographic proof of context retrieval
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
-
### v0.7 Recall Controls
|
|
137
|
+
### v0.7.2 Recall Controls
|
|
138
138
|
|
|
139
|
-
CueMap v0.7 adds
|
|
139
|
+
CueMap v0.7.2 adds local semantic query signals alongside temporal query intent and optional reconstruction passes for longer conversational/codebase context.
|
|
140
140
|
|
|
141
141
|
```python
|
|
142
142
|
results = client.recall(
|
|
@@ -145,11 +145,23 @@ results = client.recall(
|
|
|
145
145
|
ordered_reconstruction="auto",
|
|
146
146
|
evidence_coverage="auto",
|
|
147
147
|
parent_fusion="auto",
|
|
148
|
-
|
|
148
|
+
semantic_mode="hybrid",
|
|
149
149
|
explain=True,
|
|
150
150
|
)
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
+
Use `semantic_mode="lexical"` for a semantic-reranker-disabled comparison, `"semantic"` for vector candidate discovery, or `"hybrid"` (the engine default) to rerank lexical candidates. `query_embedding` supplies a precomputed vector when the application owns the embedding provider.
|
|
154
|
+
|
|
155
|
+
Classify query or memory intent with the same local engine model. Returned scores are ranking signals, not calibrated probabilities:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
classification = client.classify_intent(
|
|
159
|
+
"What did we decide about auth retries?",
|
|
160
|
+
target="query",
|
|
161
|
+
)
|
|
162
|
+
print(classification["primary_intent"], classification["recall_eligible"])
|
|
163
|
+
```
|
|
164
|
+
|
|
153
165
|
### Cloud Backup (v0.6.1)
|
|
154
166
|
|
|
155
167
|
Manage project snapshots in the cloud (S3, GCS, Azure).
|
|
@@ -186,6 +198,20 @@ client.ingest_content(
|
|
|
186
198
|
)
|
|
187
199
|
```
|
|
188
200
|
|
|
201
|
+
When an application chunks content itself, pass exactly one vector per produced chunk with `embeddings=[[...], [...]]`.
|
|
202
|
+
|
|
203
|
+
Preview and persist a repository ingestion scope:
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
preview = client.preview_directory("/work/my-app", included_paths=["src"])
|
|
207
|
+
client.set_project_watch_dir(
|
|
208
|
+
"repo-my-app",
|
|
209
|
+
"/work/my-app",
|
|
210
|
+
included_paths=["src", "README.md"],
|
|
211
|
+
)
|
|
212
|
+
scope = client.get_project_watch_dir("repo-my-app")
|
|
213
|
+
```
|
|
214
|
+
|
|
189
215
|
### Lexicon Management (v0.6+)
|
|
190
216
|
|
|
191
217
|
Inspect and wire the brain's associations manually.
|
|
@@ -208,19 +234,7 @@ Check the progress of background ingestion tasks.
|
|
|
208
234
|
```python
|
|
209
235
|
status = client.jobs_status()
|
|
210
236
|
print(f"Ingested: {status['writes_completed']} / {status['writes_total']}")
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
### Advanced Brain Control
|
|
214
|
-
|
|
215
|
-
Disable specific brain modules for deterministic debugging.
|
|
216
|
-
|
|
217
|
-
```python
|
|
218
|
-
results = client.recall(
|
|
219
|
-
"urgent issue",
|
|
220
|
-
disable_salience_bias=True,
|
|
221
|
-
disable_alias_expansion=True,
|
|
222
|
-
disable_cuebridge_artifacts=True,
|
|
223
|
-
)
|
|
237
|
+
print(f"Intent ready: {status.get('intent_ready', False)}")
|
|
224
238
|
```
|
|
225
239
|
|
|
226
240
|
## Async Support
|
|
@@ -233,11 +247,6 @@ async with AsyncCueMap() as client:
|
|
|
233
247
|
await client.recall(cues=["note"])
|
|
234
248
|
```
|
|
235
249
|
|
|
236
|
-
## Performance
|
|
237
|
-
|
|
238
|
-
- **Write Latency**: ~2ms (O(1) complexity)
|
|
239
|
-
- **Read Latency**: ~3ms (P99, 1M memories)
|
|
240
|
-
|
|
241
250
|
## License
|
|
242
251
|
|
|
243
252
|
MIT
|
|
@@ -7,14 +7,14 @@
|
|
|
7
7
|
CueMap implements a **Continuous Gradient Algorithm** optimized for associative data structures:
|
|
8
8
|
|
|
9
9
|
1. **Intersection (Context Filter)**: Triangulates relevant memories by overlapping cues
|
|
10
|
-
2. **
|
|
10
|
+
2. **Local semantic reranking**: Uses bundled qint8 MiniLM-L3 by default, or q4 MiniLM-L3 with the edge profile, for bounded semantic ranking inside the engine.
|
|
11
11
|
3. **Recency & Salience (Signal Dynamics)**: Balances fresh data with salient, high-signal events prioritized by an adaptive impact scoring module.
|
|
12
12
|
4. **Reinforcement (Access-based Learning)**: Frequently accessed memories gain signal strength, remaining highly accessible even as they age.
|
|
13
13
|
5. **Deterministic Facets & Intent Routing**: Extracts synchronous source, evidence, temporal, type, and entity facets, then uses sparse intent cues and reranking during recall.
|
|
14
14
|
|
|
15
|
-
As of v0.7.
|
|
15
|
+
As of v0.7.2, CueMap keeps deterministic lexical candidate discovery and adds bundled qint8 `all-MiniLM-L3-v2` for bounded hybrid semantic and intent reranking. The `edge` engine profile uses a q4 build of the same model. No runtime model download is required, and callers can disable the encoder or provide their own vectors.
|
|
16
16
|
|
|
17
|
-
v0.7.
|
|
17
|
+
v0.7.2 also preserves numeric per-project memory IDs everywhere. If callers need deterministic upsert/dedupe identity, pass `source_key`; memory IDs remain compact runtime addresses.
|
|
18
18
|
|
|
19
19
|
Use this SDK to talk to the Rust engine from Python applications.
|
|
20
20
|
|
|
@@ -99,9 +99,9 @@ print(response["proof"])
|
|
|
99
99
|
# Cryptographic proof of context retrieval
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
### v0.7 Recall Controls
|
|
102
|
+
### v0.7.2 Recall Controls
|
|
103
103
|
|
|
104
|
-
CueMap v0.7 adds
|
|
104
|
+
CueMap v0.7.2 adds local semantic query signals alongside temporal query intent and optional reconstruction passes for longer conversational/codebase context.
|
|
105
105
|
|
|
106
106
|
```python
|
|
107
107
|
results = client.recall(
|
|
@@ -110,11 +110,23 @@ results = client.recall(
|
|
|
110
110
|
ordered_reconstruction="auto",
|
|
111
111
|
evidence_coverage="auto",
|
|
112
112
|
parent_fusion="auto",
|
|
113
|
-
|
|
113
|
+
semantic_mode="hybrid",
|
|
114
114
|
explain=True,
|
|
115
115
|
)
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
+
Use `semantic_mode="lexical"` for a semantic-reranker-disabled comparison, `"semantic"` for vector candidate discovery, or `"hybrid"` (the engine default) to rerank lexical candidates. `query_embedding` supplies a precomputed vector when the application owns the embedding provider.
|
|
119
|
+
|
|
120
|
+
Classify query or memory intent with the same local engine model. Returned scores are ranking signals, not calibrated probabilities:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
classification = client.classify_intent(
|
|
124
|
+
"What did we decide about auth retries?",
|
|
125
|
+
target="query",
|
|
126
|
+
)
|
|
127
|
+
print(classification["primary_intent"], classification["recall_eligible"])
|
|
128
|
+
```
|
|
129
|
+
|
|
118
130
|
### Cloud Backup (v0.6.1)
|
|
119
131
|
|
|
120
132
|
Manage project snapshots in the cloud (S3, GCS, Azure).
|
|
@@ -151,6 +163,20 @@ client.ingest_content(
|
|
|
151
163
|
)
|
|
152
164
|
```
|
|
153
165
|
|
|
166
|
+
When an application chunks content itself, pass exactly one vector per produced chunk with `embeddings=[[...], [...]]`.
|
|
167
|
+
|
|
168
|
+
Preview and persist a repository ingestion scope:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
preview = client.preview_directory("/work/my-app", included_paths=["src"])
|
|
172
|
+
client.set_project_watch_dir(
|
|
173
|
+
"repo-my-app",
|
|
174
|
+
"/work/my-app",
|
|
175
|
+
included_paths=["src", "README.md"],
|
|
176
|
+
)
|
|
177
|
+
scope = client.get_project_watch_dir("repo-my-app")
|
|
178
|
+
```
|
|
179
|
+
|
|
154
180
|
### Lexicon Management (v0.6+)
|
|
155
181
|
|
|
156
182
|
Inspect and wire the brain's associations manually.
|
|
@@ -173,19 +199,7 @@ Check the progress of background ingestion tasks.
|
|
|
173
199
|
```python
|
|
174
200
|
status = client.jobs_status()
|
|
175
201
|
print(f"Ingested: {status['writes_completed']} / {status['writes_total']}")
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
### Advanced Brain Control
|
|
179
|
-
|
|
180
|
-
Disable specific brain modules for deterministic debugging.
|
|
181
|
-
|
|
182
|
-
```python
|
|
183
|
-
results = client.recall(
|
|
184
|
-
"urgent issue",
|
|
185
|
-
disable_salience_bias=True,
|
|
186
|
-
disable_alias_expansion=True,
|
|
187
|
-
disable_cuebridge_artifacts=True,
|
|
188
|
-
)
|
|
202
|
+
print(f"Intent ready: {status.get('intent_ready', False)}")
|
|
189
203
|
```
|
|
190
204
|
|
|
191
205
|
## Async Support
|
|
@@ -198,11 +212,6 @@ async with AsyncCueMap() as client:
|
|
|
198
212
|
await client.recall(cues=["note"])
|
|
199
213
|
```
|
|
200
214
|
|
|
201
|
-
## Performance
|
|
202
|
-
|
|
203
|
-
- **Write Latency**: ~2ms (O(1) complexity)
|
|
204
|
-
- **Read Latency**: ~3ms (P99, 1M memories)
|
|
205
|
-
|
|
206
215
|
## License
|
|
207
216
|
|
|
208
217
|
MIT
|
|
@@ -18,14 +18,17 @@ Example:
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
from .client import CueMap, AsyncCueMap
|
|
21
|
+
from .embedded import EmbeddedCueMap, resolve_cuemap_binary
|
|
21
22
|
from .models import Memory, RecallResult
|
|
22
23
|
from .exceptions import CueMapError, ConnectionError, AuthenticationError
|
|
23
24
|
from .grounding import CueMapGroundingRetriever, AsyncCueMapGroundingRetriever
|
|
24
25
|
|
|
25
|
-
__version__ = "0.7.
|
|
26
|
+
__version__ = "0.7.2"
|
|
26
27
|
__all__ = [
|
|
27
28
|
"CueMap",
|
|
28
29
|
"AsyncCueMap",
|
|
30
|
+
"EmbeddedCueMap",
|
|
31
|
+
"resolve_cuemap_binary",
|
|
29
32
|
"Memory",
|
|
30
33
|
"RecallResult",
|
|
31
34
|
"CueMapError",
|
|
@@ -16,7 +16,8 @@ class CueMap:
|
|
|
16
16
|
"""
|
|
17
17
|
Pure CueMap client.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
The engine performs deterministic cue extraction and can use its bundled
|
|
20
|
+
local MiniLM encoder for semantic retrieval when configured.
|
|
20
21
|
|
|
21
22
|
Example:
|
|
22
23
|
>>> client = CueMap()
|
|
@@ -65,7 +66,8 @@ class CueMap:
|
|
|
65
66
|
metadata: Optional[Dict[str, Any]] = None,
|
|
66
67
|
disable_temporal_chunking: bool = False,
|
|
67
68
|
source_key: Optional[str] = None,
|
|
68
|
-
|
|
69
|
+
event_time: Optional[float] = None,
|
|
70
|
+
embedding: Optional[List[float]] = None,
|
|
69
71
|
async_ingest: bool = False,
|
|
70
72
|
minimal_response: bool = False,
|
|
71
73
|
trace_timing: bool = False,
|
|
@@ -77,6 +79,7 @@ class CueMap:
|
|
|
77
79
|
content: Memory content
|
|
78
80
|
cues: Optional list of cues (tags) for retrieval
|
|
79
81
|
metadata: Optional metadata
|
|
82
|
+
event_time: Original event timestamp as Unix seconds. Defaults to ingestion time.
|
|
80
83
|
|
|
81
84
|
Returns:
|
|
82
85
|
Memory ID
|
|
@@ -95,7 +98,8 @@ class CueMap:
|
|
|
95
98
|
"metadata": metadata,
|
|
96
99
|
"disable_temporal_chunking": disable_temporal_chunking,
|
|
97
100
|
"source_key": source_key,
|
|
98
|
-
"
|
|
101
|
+
"event_time": event_time,
|
|
102
|
+
"embedding": embedding,
|
|
99
103
|
"async_ingest": async_ingest,
|
|
100
104
|
"minimal_response": minimal_response,
|
|
101
105
|
"trace_timing": trace_timing,
|
|
@@ -133,6 +137,21 @@ class CueMap:
|
|
|
133
137
|
raise CueMapError(f"Failed to add memories: {response.text}")
|
|
134
138
|
|
|
135
139
|
return response.json()
|
|
140
|
+
|
|
141
|
+
def classify_intent(
|
|
142
|
+
self,
|
|
143
|
+
text: str,
|
|
144
|
+
target: str = "query",
|
|
145
|
+
) -> Dict[str, Any]:
|
|
146
|
+
"""Classify query or memory intent with the engine's local model."""
|
|
147
|
+
response = self.client.post(
|
|
148
|
+
"/intent/classify",
|
|
149
|
+
json={"text": text, "target": target},
|
|
150
|
+
headers=self._headers(),
|
|
151
|
+
)
|
|
152
|
+
if response.status_code != 200:
|
|
153
|
+
raise CueMapError(f"Failed to classify intent: {response.text}")
|
|
154
|
+
return response.json()
|
|
136
155
|
|
|
137
156
|
def recall(
|
|
138
157
|
self,
|
|
@@ -149,7 +168,6 @@ class CueMap:
|
|
|
149
168
|
disable_alias_expansion: bool = True,
|
|
150
169
|
trace_timing: bool = False,
|
|
151
170
|
expansion_depth: int = 1,
|
|
152
|
-
cuepacks: Optional[List[str]] = None,
|
|
153
171
|
parent_fusion: str = "off",
|
|
154
172
|
parent_fusion_limit: int = 80,
|
|
155
173
|
parent_fusion_min_chunks: int = 2,
|
|
@@ -165,6 +183,8 @@ class CueMap:
|
|
|
165
183
|
cuebridge_gap_limit: int = 6,
|
|
166
184
|
disable_pattern_completion: Optional[bool] = None,
|
|
167
185
|
disable_systems_consolidation: Optional[bool] = None,
|
|
186
|
+
semantic_mode: str = "hybrid",
|
|
187
|
+
query_embedding: Optional[List[float]] = None,
|
|
168
188
|
) -> List[RecallResult]:
|
|
169
189
|
"""
|
|
170
190
|
Recall memories by cues or natural language.
|
|
@@ -209,6 +229,8 @@ class CueMap:
|
|
|
209
229
|
"evidence_coverage_max_sessions": evidence_coverage_max_sessions,
|
|
210
230
|
"disable_cuebridge_artifacts": disable_cuebridge_artifacts,
|
|
211
231
|
"cuebridge_gap_limit": cuebridge_gap_limit,
|
|
232
|
+
"semantic_mode": semantic_mode,
|
|
233
|
+
"query_embedding": query_embedding,
|
|
212
234
|
}
|
|
213
235
|
if cues:
|
|
214
236
|
payload["cues"] = cues
|
|
@@ -220,9 +242,6 @@ class CueMap:
|
|
|
220
242
|
payload["min_intersection"] = min_intersection
|
|
221
243
|
if projects:
|
|
222
244
|
payload["projects"] = projects
|
|
223
|
-
if cuepacks:
|
|
224
|
-
payload["cuepacks"] = cuepacks
|
|
225
|
-
|
|
226
245
|
response = self.client.post(
|
|
227
246
|
"/recall",
|
|
228
247
|
json=_clean_payload(payload),
|
|
@@ -251,7 +270,6 @@ class CueMap:
|
|
|
251
270
|
disable_salience_bias: bool = False,
|
|
252
271
|
disable_alias_expansion: bool = True,
|
|
253
272
|
expansion_depth: int = 1,
|
|
254
|
-
cuepacks: Optional[List[str]] = None,
|
|
255
273
|
disable_pattern_completion: Optional[bool] = None,
|
|
256
274
|
disable_systems_consolidation: Optional[bool] = None,
|
|
257
275
|
) -> Dict[str, Any]:
|
|
@@ -275,7 +293,6 @@ class CueMap:
|
|
|
275
293
|
"disable_salience_bias": disable_salience_bias,
|
|
276
294
|
"disable_alias_expansion": disable_alias_expansion,
|
|
277
295
|
"expansion_depth": expansion_depth,
|
|
278
|
-
"cuepacks": cuepacks,
|
|
279
296
|
}),
|
|
280
297
|
headers=self._headers()
|
|
281
298
|
)
|
|
@@ -365,12 +382,14 @@ class CueMap:
|
|
|
365
382
|
watch_dir: str,
|
|
366
383
|
ignored_patterns: Optional[List[str]] = None,
|
|
367
384
|
ignored_extensions: Optional[List[str]] = None,
|
|
385
|
+
included_paths: Optional[List[str]] = None,
|
|
368
386
|
) -> Dict[str, Any]:
|
|
369
387
|
"""Set the self-learning agent watch directory for a project."""
|
|
370
388
|
response = self.client.post(
|
|
371
389
|
f"/projects/{project_id}/watch-dir",
|
|
372
390
|
json=_clean_payload({
|
|
373
391
|
"watch_dir": watch_dir,
|
|
392
|
+
"included_paths": included_paths,
|
|
374
393
|
"ignored_patterns": ignored_patterns,
|
|
375
394
|
"ignored_extensions": ignored_extensions,
|
|
376
395
|
}),
|
|
@@ -380,6 +399,38 @@ class CueMap:
|
|
|
380
399
|
raise CueMapError(f"Failed to set project watch directory: {response.text}")
|
|
381
400
|
return response.json()
|
|
382
401
|
|
|
402
|
+
def get_project_watch_dir(self, project_id: str) -> Dict[str, Any]:
|
|
403
|
+
"""Read a project's persisted repository ingestion scope."""
|
|
404
|
+
response = self.client.get(
|
|
405
|
+
f"/projects/{project_id}/watch-dir",
|
|
406
|
+
headers=self._headers(),
|
|
407
|
+
)
|
|
408
|
+
if response.status_code != 200:
|
|
409
|
+
raise CueMapError(f"Failed to get project watch directory: {response.text}")
|
|
410
|
+
return response.json()
|
|
411
|
+
|
|
412
|
+
def preview_directory(
|
|
413
|
+
self,
|
|
414
|
+
watch_dir: str,
|
|
415
|
+
included_paths: Optional[List[str]] = None,
|
|
416
|
+
ignored_patterns: Optional[List[str]] = None,
|
|
417
|
+
ignored_extensions: Optional[List[str]] = None,
|
|
418
|
+
) -> Dict[str, Any]:
|
|
419
|
+
"""Preview supported repository files without ingesting content."""
|
|
420
|
+
response = self.client.post(
|
|
421
|
+
"/ingest/directory/preview",
|
|
422
|
+
json=_clean_payload({
|
|
423
|
+
"watch_dir": watch_dir,
|
|
424
|
+
"included_paths": included_paths,
|
|
425
|
+
"ignored_patterns": ignored_patterns,
|
|
426
|
+
"ignored_extensions": ignored_extensions,
|
|
427
|
+
}),
|
|
428
|
+
headers=self._headers(),
|
|
429
|
+
)
|
|
430
|
+
if response.status_code != 200:
|
|
431
|
+
raise CueMapError(f"Failed to preview directory: {response.text}")
|
|
432
|
+
return response.json()
|
|
433
|
+
|
|
383
434
|
def add_alias(self, from_cue: str, to_cue: str, weight: float = 1.0) -> bool:
|
|
384
435
|
"""Add an alias (manual cue mapping)."""
|
|
385
436
|
response = self.client.post(
|
|
@@ -574,6 +625,7 @@ class CueMap:
|
|
|
574
625
|
source_key: Optional[str] = None,
|
|
575
626
|
metadata: Optional[Dict[str, Any]] = None,
|
|
576
627
|
structural_cues: Optional[List[str]] = None,
|
|
628
|
+
embeddings: Optional[List[List[float]]] = None,
|
|
577
629
|
segmenter: str = "sentence_window",
|
|
578
630
|
segment_window_size: Optional[int] = None,
|
|
579
631
|
segment_overlap: Optional[int] = None,
|
|
@@ -589,6 +641,7 @@ class CueMap:
|
|
|
589
641
|
"source_key": source_key,
|
|
590
642
|
"metadata": metadata,
|
|
591
643
|
"structural_cues": structural_cues,
|
|
644
|
+
"embeddings": embeddings,
|
|
592
645
|
"segmenter": segmenter,
|
|
593
646
|
"segment_window_size": segment_window_size,
|
|
594
647
|
"segment_overlap": segment_overlap,
|
|
@@ -624,7 +677,6 @@ class CueMap:
|
|
|
624
677
|
metadata: Optional[Dict[str, Any]] = None,
|
|
625
678
|
existing_cues: Optional[List[str]] = None,
|
|
626
679
|
available_cues: Optional[List[str]] = None,
|
|
627
|
-
cuepacks: Optional[List[str]] = None,
|
|
628
680
|
filename: Optional[str] = None,
|
|
629
681
|
segmenter: str = "sentence_window",
|
|
630
682
|
segment_window_size: Optional[int] = None,
|
|
@@ -641,7 +693,6 @@ class CueMap:
|
|
|
641
693
|
"metadata": metadata,
|
|
642
694
|
"existing_cues": existing_cues,
|
|
643
695
|
"available_cues": available_cues,
|
|
644
|
-
"cuepacks": cuepacks,
|
|
645
696
|
"filename": filename,
|
|
646
697
|
"segmenter": segmenter,
|
|
647
698
|
"segment_window_size": segment_window_size,
|
|
@@ -736,7 +787,8 @@ class AsyncCueMap:
|
|
|
736
787
|
metadata: Optional[Dict[str, Any]] = None,
|
|
737
788
|
disable_temporal_chunking: bool = False,
|
|
738
789
|
source_key: Optional[str] = None,
|
|
739
|
-
|
|
790
|
+
event_time: Optional[float] = None,
|
|
791
|
+
embedding: Optional[List[float]] = None,
|
|
740
792
|
async_ingest: bool = False,
|
|
741
793
|
minimal_response: bool = False,
|
|
742
794
|
trace_timing: bool = False,
|
|
@@ -750,7 +802,8 @@ class AsyncCueMap:
|
|
|
750
802
|
"metadata": metadata,
|
|
751
803
|
"disable_temporal_chunking": disable_temporal_chunking,
|
|
752
804
|
"source_key": source_key,
|
|
753
|
-
"
|
|
805
|
+
"event_time": event_time,
|
|
806
|
+
"embedding": embedding,
|
|
754
807
|
"async_ingest": async_ingest,
|
|
755
808
|
"minimal_response": minimal_response,
|
|
756
809
|
"trace_timing": trace_timing,
|
|
@@ -788,6 +841,21 @@ class AsyncCueMap:
|
|
|
788
841
|
raise CueMapError(f"Failed to add memories: {response.text}")
|
|
789
842
|
|
|
790
843
|
return response.json()
|
|
844
|
+
|
|
845
|
+
async def classify_intent(
|
|
846
|
+
self,
|
|
847
|
+
text: str,
|
|
848
|
+
target: str = "query",
|
|
849
|
+
) -> Dict[str, Any]:
|
|
850
|
+
"""Classify query or memory intent with the engine's local model (async)."""
|
|
851
|
+
response = await self.client.post(
|
|
852
|
+
"/intent/classify",
|
|
853
|
+
json={"text": text, "target": target},
|
|
854
|
+
headers=self._headers(),
|
|
855
|
+
)
|
|
856
|
+
if response.status_code != 200:
|
|
857
|
+
raise CueMapError(f"Failed to classify intent: {response.text}")
|
|
858
|
+
return response.json()
|
|
791
859
|
|
|
792
860
|
async def recall(
|
|
793
861
|
self,
|
|
@@ -804,7 +872,6 @@ class AsyncCueMap:
|
|
|
804
872
|
disable_alias_expansion: bool = True,
|
|
805
873
|
trace_timing: bool = False,
|
|
806
874
|
expansion_depth: int = 1,
|
|
807
|
-
cuepacks: Optional[List[str]] = None,
|
|
808
875
|
parent_fusion: str = "off",
|
|
809
876
|
parent_fusion_limit: int = 80,
|
|
810
877
|
parent_fusion_min_chunks: int = 2,
|
|
@@ -820,6 +887,8 @@ class AsyncCueMap:
|
|
|
820
887
|
cuebridge_gap_limit: int = 6,
|
|
821
888
|
disable_pattern_completion: Optional[bool] = None,
|
|
822
889
|
disable_systems_consolidation: Optional[bool] = None,
|
|
890
|
+
semantic_mode: str = "hybrid",
|
|
891
|
+
query_embedding: Optional[List[float]] = None,
|
|
823
892
|
) -> List[RecallResult]:
|
|
824
893
|
"""Recall memories (async)."""
|
|
825
894
|
payload = {
|
|
@@ -844,6 +913,8 @@ class AsyncCueMap:
|
|
|
844
913
|
"evidence_coverage_max_sessions": evidence_coverage_max_sessions,
|
|
845
914
|
"disable_cuebridge_artifacts": disable_cuebridge_artifacts,
|
|
846
915
|
"cuebridge_gap_limit": cuebridge_gap_limit,
|
|
916
|
+
"semantic_mode": semantic_mode,
|
|
917
|
+
"query_embedding": query_embedding,
|
|
847
918
|
}
|
|
848
919
|
if cues:
|
|
849
920
|
payload["cues"] = cues
|
|
@@ -855,9 +926,6 @@ class AsyncCueMap:
|
|
|
855
926
|
payload["min_intersection"] = min_intersection
|
|
856
927
|
if projects:
|
|
857
928
|
payload["projects"] = projects
|
|
858
|
-
if cuepacks:
|
|
859
|
-
payload["cuepacks"] = cuepacks
|
|
860
|
-
|
|
861
929
|
response = await self.client.post(
|
|
862
930
|
"/recall",
|
|
863
931
|
json=_clean_payload(payload),
|
|
@@ -886,7 +954,6 @@ class AsyncCueMap:
|
|
|
886
954
|
disable_salience_bias: bool = False,
|
|
887
955
|
disable_alias_expansion: bool = True,
|
|
888
956
|
expansion_depth: int = 1,
|
|
889
|
-
cuepacks: Optional[List[str]] = None,
|
|
890
957
|
disable_pattern_completion: Optional[bool] = None,
|
|
891
958
|
disable_systems_consolidation: Optional[bool] = None,
|
|
892
959
|
) -> Dict[str, Any]:
|
|
@@ -903,7 +970,6 @@ class AsyncCueMap:
|
|
|
903
970
|
"disable_salience_bias": disable_salience_bias,
|
|
904
971
|
"disable_alias_expansion": disable_alias_expansion,
|
|
905
972
|
"expansion_depth": expansion_depth,
|
|
906
|
-
"cuepacks": cuepacks,
|
|
907
973
|
}),
|
|
908
974
|
headers=self._headers()
|
|
909
975
|
)
|
|
@@ -993,12 +1059,14 @@ class AsyncCueMap:
|
|
|
993
1059
|
watch_dir: str,
|
|
994
1060
|
ignored_patterns: Optional[List[str]] = None,
|
|
995
1061
|
ignored_extensions: Optional[List[str]] = None,
|
|
1062
|
+
included_paths: Optional[List[str]] = None,
|
|
996
1063
|
) -> Dict[str, Any]:
|
|
997
1064
|
"""Set the self-learning agent watch directory for a project (async)."""
|
|
998
1065
|
response = await self.client.post(
|
|
999
1066
|
f"/projects/{project_id}/watch-dir",
|
|
1000
1067
|
json=_clean_payload({
|
|
1001
1068
|
"watch_dir": watch_dir,
|
|
1069
|
+
"included_paths": included_paths,
|
|
1002
1070
|
"ignored_patterns": ignored_patterns,
|
|
1003
1071
|
"ignored_extensions": ignored_extensions,
|
|
1004
1072
|
}),
|
|
@@ -1008,6 +1076,38 @@ class AsyncCueMap:
|
|
|
1008
1076
|
raise CueMapError(f"Failed to set project watch directory: {response.text}")
|
|
1009
1077
|
return response.json()
|
|
1010
1078
|
|
|
1079
|
+
async def get_project_watch_dir(self, project_id: str) -> Dict[str, Any]:
|
|
1080
|
+
"""Read a project's persisted repository ingestion scope (async)."""
|
|
1081
|
+
response = await self.client.get(
|
|
1082
|
+
f"/projects/{project_id}/watch-dir",
|
|
1083
|
+
headers=self._headers(),
|
|
1084
|
+
)
|
|
1085
|
+
if response.status_code != 200:
|
|
1086
|
+
raise CueMapError(f"Failed to get project watch directory: {response.text}")
|
|
1087
|
+
return response.json()
|
|
1088
|
+
|
|
1089
|
+
async def preview_directory(
|
|
1090
|
+
self,
|
|
1091
|
+
watch_dir: str,
|
|
1092
|
+
included_paths: Optional[List[str]] = None,
|
|
1093
|
+
ignored_patterns: Optional[List[str]] = None,
|
|
1094
|
+
ignored_extensions: Optional[List[str]] = None,
|
|
1095
|
+
) -> Dict[str, Any]:
|
|
1096
|
+
"""Preview supported repository files without ingesting content (async)."""
|
|
1097
|
+
response = await self.client.post(
|
|
1098
|
+
"/ingest/directory/preview",
|
|
1099
|
+
json=_clean_payload({
|
|
1100
|
+
"watch_dir": watch_dir,
|
|
1101
|
+
"included_paths": included_paths,
|
|
1102
|
+
"ignored_patterns": ignored_patterns,
|
|
1103
|
+
"ignored_extensions": ignored_extensions,
|
|
1104
|
+
}),
|
|
1105
|
+
headers=self._headers(),
|
|
1106
|
+
)
|
|
1107
|
+
if response.status_code != 200:
|
|
1108
|
+
raise CueMapError(f"Failed to preview directory: {response.text}")
|
|
1109
|
+
return response.json()
|
|
1110
|
+
|
|
1011
1111
|
async def add_alias(self, from_cue: str, to_cue: str, weight: float = 1.0) -> bool:
|
|
1012
1112
|
"""Add an alias (async)."""
|
|
1013
1113
|
response = await self.client.post(
|
|
@@ -1187,6 +1287,7 @@ class AsyncCueMap:
|
|
|
1187
1287
|
source_key: Optional[str] = None,
|
|
1188
1288
|
metadata: Optional[Dict[str, Any]] = None,
|
|
1189
1289
|
structural_cues: Optional[List[str]] = None,
|
|
1290
|
+
embeddings: Optional[List[List[float]]] = None,
|
|
1190
1291
|
segmenter: str = "sentence_window",
|
|
1191
1292
|
segment_window_size: Optional[int] = None,
|
|
1192
1293
|
segment_overlap: Optional[int] = None,
|
|
@@ -1202,6 +1303,7 @@ class AsyncCueMap:
|
|
|
1202
1303
|
"source_key": source_key,
|
|
1203
1304
|
"metadata": metadata,
|
|
1204
1305
|
"structural_cues": structural_cues,
|
|
1306
|
+
"embeddings": embeddings,
|
|
1205
1307
|
"segmenter": segmenter,
|
|
1206
1308
|
"segment_window_size": segment_window_size,
|
|
1207
1309
|
"segment_overlap": segment_overlap,
|
|
@@ -1237,7 +1339,6 @@ class AsyncCueMap:
|
|
|
1237
1339
|
metadata: Optional[Dict[str, Any]] = None,
|
|
1238
1340
|
existing_cues: Optional[List[str]] = None,
|
|
1239
1341
|
available_cues: Optional[List[str]] = None,
|
|
1240
|
-
cuepacks: Optional[List[str]] = None,
|
|
1241
1342
|
filename: Optional[str] = None,
|
|
1242
1343
|
segmenter: str = "sentence_window",
|
|
1243
1344
|
segment_window_size: Optional[int] = None,
|
|
@@ -1254,7 +1355,6 @@ class AsyncCueMap:
|
|
|
1254
1355
|
"metadata": metadata,
|
|
1255
1356
|
"existing_cues": existing_cues,
|
|
1256
1357
|
"available_cues": available_cues,
|
|
1257
|
-
"cuepacks": cuepacks,
|
|
1258
1358
|
"filename": filename,
|
|
1259
1359
|
"segmenter": segmenter,
|
|
1260
1360
|
"segment_window_size": segment_window_size,
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""Lifecycle management for a local CueMap engine process."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import platform
|
|
8
|
+
import shutil
|
|
9
|
+
import socket
|
|
10
|
+
import subprocess
|
|
11
|
+
import time
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Callable, Mapping, Optional
|
|
15
|
+
from urllib.error import HTTPError, URLError
|
|
16
|
+
from urllib.request import Request, urlopen
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _normalize_url(url: str) -> str:
|
|
20
|
+
return url.rstrip("/")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _inspect_engine(url: str, api_key: Optional[str] = None) -> str:
|
|
24
|
+
headers = {"X-API-Key": api_key} if api_key else {}
|
|
25
|
+
try:
|
|
26
|
+
with urlopen(Request(f"{_normalize_url(url)}/", headers=headers), timeout=0.75) as response:
|
|
27
|
+
payload = json.loads(response.read(16_384))
|
|
28
|
+
return "cuemap" if payload.get("name") == "CueMap Rust Engine" else "occupied"
|
|
29
|
+
except HTTPError:
|
|
30
|
+
return "occupied"
|
|
31
|
+
except (URLError, TimeoutError, OSError, ValueError, json.JSONDecodeError):
|
|
32
|
+
return "closed"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _free_port() -> int:
|
|
36
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as listener:
|
|
37
|
+
listener.bind(("127.0.0.1", 0))
|
|
38
|
+
return int(listener.getsockname()[1])
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _platform_package() -> str:
|
|
42
|
+
operating_system = platform.system().lower()
|
|
43
|
+
machine = platform.machine().lower()
|
|
44
|
+
architecture = "arm64" if machine in {"arm64", "aarch64"} else "x64"
|
|
45
|
+
return f"@cuemap-dev/engine-{operating_system}-{architecture}"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _npm_global_binary() -> Optional[str]:
|
|
49
|
+
npm = shutil.which("npm")
|
|
50
|
+
if not npm:
|
|
51
|
+
return None
|
|
52
|
+
try:
|
|
53
|
+
root = subprocess.run(
|
|
54
|
+
[npm, "root", "--global"],
|
|
55
|
+
check=True,
|
|
56
|
+
capture_output=True,
|
|
57
|
+
text=True,
|
|
58
|
+
timeout=5,
|
|
59
|
+
).stdout.strip()
|
|
60
|
+
except (OSError, subprocess.SubprocessError):
|
|
61
|
+
return None
|
|
62
|
+
binary_name = "cuemap.exe" if os.name == "nt" else "cuemap"
|
|
63
|
+
candidate = Path(root) / _platform_package() / "bin" / binary_name
|
|
64
|
+
return str(candidate) if candidate.is_file() else None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def resolve_cuemap_binary(explicit_path: Optional[str] = None) -> str:
|
|
68
|
+
"""Resolve an engine binary without downloading or mutating the machine."""
|
|
69
|
+
|
|
70
|
+
configured = explicit_path or os.environ.get("CUEMAP_BIN")
|
|
71
|
+
if configured:
|
|
72
|
+
path = Path(configured).expanduser()
|
|
73
|
+
if not path.is_file():
|
|
74
|
+
raise FileNotFoundError(f"CueMap executable does not exist: {path}")
|
|
75
|
+
return str(path)
|
|
76
|
+
|
|
77
|
+
installed = shutil.which("cuemap")
|
|
78
|
+
if installed:
|
|
79
|
+
return installed
|
|
80
|
+
|
|
81
|
+
global_binary = _npm_global_binary()
|
|
82
|
+
if global_binary:
|
|
83
|
+
return global_binary
|
|
84
|
+
|
|
85
|
+
workspace = Path(__file__).resolve().parents[2] / "rust_engine" / "target"
|
|
86
|
+
binary_name = "cuemap.exe" if os.name == "nt" else "cuemap"
|
|
87
|
+
source_binaries = [
|
|
88
|
+
workspace / profile / binary_name
|
|
89
|
+
for profile in ("release", "debug")
|
|
90
|
+
if (workspace / profile / binary_name).is_file()
|
|
91
|
+
]
|
|
92
|
+
if source_binaries:
|
|
93
|
+
return str(max(source_binaries, key=lambda candidate: candidate.stat().st_mtime))
|
|
94
|
+
|
|
95
|
+
raise FileNotFoundError(
|
|
96
|
+
"Could not find the CueMap engine. Set CUEMAP_BIN, install `cuemap` on PATH, "
|
|
97
|
+
f"or install the native npm package {_platform_package()}."
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@dataclass
|
|
102
|
+
class EmbeddedCueMap:
|
|
103
|
+
"""A verified engine connection and, when applicable, its owned process."""
|
|
104
|
+
|
|
105
|
+
url: str
|
|
106
|
+
owned: bool
|
|
107
|
+
_process: Optional[subprocess.Popen] = None
|
|
108
|
+
_shutdown_timeout: float = 5.0
|
|
109
|
+
|
|
110
|
+
@classmethod
|
|
111
|
+
def start(
|
|
112
|
+
cls,
|
|
113
|
+
*,
|
|
114
|
+
url: Optional[str] = None,
|
|
115
|
+
bin_path: Optional[str] = None,
|
|
116
|
+
port: int = 8080,
|
|
117
|
+
config_path: Optional[str] = None,
|
|
118
|
+
api_key: Optional[str] = None,
|
|
119
|
+
startup_timeout: float = 15.0,
|
|
120
|
+
shutdown_timeout: float = 5.0,
|
|
121
|
+
env: Optional[Mapping[str, str]] = None,
|
|
122
|
+
logger: Optional[Callable[[str], None]] = None,
|
|
123
|
+
) -> "EmbeddedCueMap":
|
|
124
|
+
log = logger or (lambda _message: None)
|
|
125
|
+
if url:
|
|
126
|
+
normalized = _normalize_url(url)
|
|
127
|
+
if _inspect_engine(normalized, api_key) != "cuemap":
|
|
128
|
+
raise ConnectionError(f"No CueMap engine is reachable at {normalized}")
|
|
129
|
+
log(f"Attached to CueMap at {normalized}")
|
|
130
|
+
return cls(normalized, False, _shutdown_timeout=shutdown_timeout)
|
|
131
|
+
|
|
132
|
+
preferred_url = f"http://127.0.0.1:{port}"
|
|
133
|
+
status = _inspect_engine(preferred_url, api_key)
|
|
134
|
+
if status == "cuemap":
|
|
135
|
+
log(f"Attached to CueMap at {preferred_url}")
|
|
136
|
+
return cls(preferred_url, False, _shutdown_timeout=shutdown_timeout)
|
|
137
|
+
|
|
138
|
+
selected_port = _free_port() if status == "occupied" else port
|
|
139
|
+
selected_url = f"http://127.0.0.1:{selected_port}"
|
|
140
|
+
executable = resolve_cuemap_binary(bin_path)
|
|
141
|
+
arguments = [executable, "start", "--port", str(selected_port)]
|
|
142
|
+
if config_path:
|
|
143
|
+
arguments.extend(["--config", str(Path(config_path).expanduser())])
|
|
144
|
+
process_env = dict(os.environ)
|
|
145
|
+
if env:
|
|
146
|
+
process_env.update(env)
|
|
147
|
+
process_env["CUEMAP_PORT"] = str(selected_port)
|
|
148
|
+
|
|
149
|
+
log(f"Starting CueMap at {selected_url}")
|
|
150
|
+
process = subprocess.Popen(
|
|
151
|
+
arguments,
|
|
152
|
+
stdin=subprocess.DEVNULL,
|
|
153
|
+
stdout=subprocess.DEVNULL,
|
|
154
|
+
stderr=subprocess.DEVNULL,
|
|
155
|
+
env=process_env,
|
|
156
|
+
)
|
|
157
|
+
deadline = time.monotonic() + startup_timeout
|
|
158
|
+
while time.monotonic() < deadline:
|
|
159
|
+
return_code = process.poll()
|
|
160
|
+
if return_code is not None:
|
|
161
|
+
raise RuntimeError(f"CueMap exited before becoming ready (code={return_code})")
|
|
162
|
+
if _inspect_engine(selected_url, api_key) == "cuemap":
|
|
163
|
+
log(f"CueMap is ready at {selected_url}")
|
|
164
|
+
return cls(selected_url, True, process, shutdown_timeout)
|
|
165
|
+
time.sleep(0.1)
|
|
166
|
+
|
|
167
|
+
process.terminate()
|
|
168
|
+
raise TimeoutError(f"CueMap did not become ready within {startup_timeout:g}s")
|
|
169
|
+
|
|
170
|
+
def stop(self) -> None:
|
|
171
|
+
process = self._process
|
|
172
|
+
self._process = None
|
|
173
|
+
if not self.owned or process is None or process.poll() is not None:
|
|
174
|
+
return
|
|
175
|
+
process.terminate()
|
|
176
|
+
try:
|
|
177
|
+
process.wait(timeout=self._shutdown_timeout)
|
|
178
|
+
except subprocess.TimeoutExpired:
|
|
179
|
+
process.kill()
|
|
180
|
+
process.wait(timeout=self._shutdown_timeout)
|
|
181
|
+
|
|
182
|
+
def __enter__(self) -> "EmbeddedCueMap":
|
|
183
|
+
return self
|
|
184
|
+
|
|
185
|
+
def __exit__(self, _exc_type, _exc_value, _traceback) -> None:
|
|
186
|
+
self.stop()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cuemap
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: CueMap Python SDK - High-performance temporal-associative memory
|
|
5
5
|
Author-email: Kaan Demirel <hello@cuemap.dev>
|
|
6
6
|
License: MIT
|
|
@@ -42,14 +42,14 @@ Dynamic: license-file
|
|
|
42
42
|
CueMap implements a **Continuous Gradient Algorithm** optimized for associative data structures:
|
|
43
43
|
|
|
44
44
|
1. **Intersection (Context Filter)**: Triangulates relevant memories by overlapping cues
|
|
45
|
-
2. **
|
|
45
|
+
2. **Local semantic reranking**: Uses bundled qint8 MiniLM-L3 by default, or q4 MiniLM-L3 with the edge profile, for bounded semantic ranking inside the engine.
|
|
46
46
|
3. **Recency & Salience (Signal Dynamics)**: Balances fresh data with salient, high-signal events prioritized by an adaptive impact scoring module.
|
|
47
47
|
4. **Reinforcement (Access-based Learning)**: Frequently accessed memories gain signal strength, remaining highly accessible even as they age.
|
|
48
48
|
5. **Deterministic Facets & Intent Routing**: Extracts synchronous source, evidence, temporal, type, and entity facets, then uses sparse intent cues and reranking during recall.
|
|
49
49
|
|
|
50
|
-
As of v0.7.
|
|
50
|
+
As of v0.7.2, CueMap keeps deterministic lexical candidate discovery and adds bundled qint8 `all-MiniLM-L3-v2` for bounded hybrid semantic and intent reranking. The `edge` engine profile uses a q4 build of the same model. No runtime model download is required, and callers can disable the encoder or provide their own vectors.
|
|
51
51
|
|
|
52
|
-
v0.7.
|
|
52
|
+
v0.7.2 also preserves numeric per-project memory IDs everywhere. If callers need deterministic upsert/dedupe identity, pass `source_key`; memory IDs remain compact runtime addresses.
|
|
53
53
|
|
|
54
54
|
Use this SDK to talk to the Rust engine from Python applications.
|
|
55
55
|
|
|
@@ -134,9 +134,9 @@ print(response["proof"])
|
|
|
134
134
|
# Cryptographic proof of context retrieval
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
-
### v0.7 Recall Controls
|
|
137
|
+
### v0.7.2 Recall Controls
|
|
138
138
|
|
|
139
|
-
CueMap v0.7 adds
|
|
139
|
+
CueMap v0.7.2 adds local semantic query signals alongside temporal query intent and optional reconstruction passes for longer conversational/codebase context.
|
|
140
140
|
|
|
141
141
|
```python
|
|
142
142
|
results = client.recall(
|
|
@@ -145,11 +145,23 @@ results = client.recall(
|
|
|
145
145
|
ordered_reconstruction="auto",
|
|
146
146
|
evidence_coverage="auto",
|
|
147
147
|
parent_fusion="auto",
|
|
148
|
-
|
|
148
|
+
semantic_mode="hybrid",
|
|
149
149
|
explain=True,
|
|
150
150
|
)
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
+
Use `semantic_mode="lexical"` for a semantic-reranker-disabled comparison, `"semantic"` for vector candidate discovery, or `"hybrid"` (the engine default) to rerank lexical candidates. `query_embedding` supplies a precomputed vector when the application owns the embedding provider.
|
|
154
|
+
|
|
155
|
+
Classify query or memory intent with the same local engine model. Returned scores are ranking signals, not calibrated probabilities:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
classification = client.classify_intent(
|
|
159
|
+
"What did we decide about auth retries?",
|
|
160
|
+
target="query",
|
|
161
|
+
)
|
|
162
|
+
print(classification["primary_intent"], classification["recall_eligible"])
|
|
163
|
+
```
|
|
164
|
+
|
|
153
165
|
### Cloud Backup (v0.6.1)
|
|
154
166
|
|
|
155
167
|
Manage project snapshots in the cloud (S3, GCS, Azure).
|
|
@@ -186,6 +198,20 @@ client.ingest_content(
|
|
|
186
198
|
)
|
|
187
199
|
```
|
|
188
200
|
|
|
201
|
+
When an application chunks content itself, pass exactly one vector per produced chunk with `embeddings=[[...], [...]]`.
|
|
202
|
+
|
|
203
|
+
Preview and persist a repository ingestion scope:
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
preview = client.preview_directory("/work/my-app", included_paths=["src"])
|
|
207
|
+
client.set_project_watch_dir(
|
|
208
|
+
"repo-my-app",
|
|
209
|
+
"/work/my-app",
|
|
210
|
+
included_paths=["src", "README.md"],
|
|
211
|
+
)
|
|
212
|
+
scope = client.get_project_watch_dir("repo-my-app")
|
|
213
|
+
```
|
|
214
|
+
|
|
189
215
|
### Lexicon Management (v0.6+)
|
|
190
216
|
|
|
191
217
|
Inspect and wire the brain's associations manually.
|
|
@@ -208,19 +234,7 @@ Check the progress of background ingestion tasks.
|
|
|
208
234
|
```python
|
|
209
235
|
status = client.jobs_status()
|
|
210
236
|
print(f"Ingested: {status['writes_completed']} / {status['writes_total']}")
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
### Advanced Brain Control
|
|
214
|
-
|
|
215
|
-
Disable specific brain modules for deterministic debugging.
|
|
216
|
-
|
|
217
|
-
```python
|
|
218
|
-
results = client.recall(
|
|
219
|
-
"urgent issue",
|
|
220
|
-
disable_salience_bias=True,
|
|
221
|
-
disable_alias_expansion=True,
|
|
222
|
-
disable_cuebridge_artifacts=True,
|
|
223
|
-
)
|
|
237
|
+
print(f"Intent ready: {status.get('intent_ready', False)}")
|
|
224
238
|
```
|
|
225
239
|
|
|
226
240
|
## Async Support
|
|
@@ -233,11 +247,6 @@ async with AsyncCueMap() as client:
|
|
|
233
247
|
await client.recall(cues=["note"])
|
|
234
248
|
```
|
|
235
249
|
|
|
236
|
-
## Performance
|
|
237
|
-
|
|
238
|
-
- **Write Latency**: ~2ms (O(1) complexity)
|
|
239
|
-
- **Read Latency**: ~3ms (P99, 1M memories)
|
|
240
|
-
|
|
241
250
|
## License
|
|
242
251
|
|
|
243
252
|
MIT
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|