ltcai 12.1.0 → 12.2.1
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.
- package/README.md +86 -88
- package/docs/CHANGELOG.md +48 -4
- package/docs/CI_AND_RELEASE_GATES.md +7 -4
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +11 -11
- package/docs/ONBOARDING.md +1 -1
- package/docs/OPERATIONS.md +1 -1
- package/docs/ROADMAP.md +8 -8
- package/docs/TRUST_MODEL.md +2 -2
- package/docs/WHY_LATTICE.md +1 -1
- package/docs/kg-schema.md +1 -1
- package/lattice_brain/__init__.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/core/vector_index/hnsw.py +49 -10
- package/latticeai/core/vector_index/sidecar.py +120 -31
- package/latticeai/services/architecture_readiness.py +1 -1
- package/latticeai/services/product_readiness.py +2 -2
- package/package.json +1 -1
- package/scripts/check_current_release_docs.mjs +1 -1
- package/scripts/release_screen_claims.json +34 -0
- package/src-tauri/Cargo.lock +10 -10
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +45 -45
- package/static/app/assets/{Act-DCRUH46a.js → Act-DC676bqE.js} +2 -2
- package/static/app/assets/{AdminConsole-BFBj6OvN.js → AdminConsole-aCxQgD2L.js} +1 -1
- package/static/app/assets/{Brain-BXcoxIvb.js → Brain-Dbd0xvsc.js} +2 -2
- package/static/app/assets/BrainHome-N00B-MAJ.js +2 -0
- package/static/app/assets/{BrainSignals-DrfYSNjR.js → BrainSignals-CNA0d6xS.js} +1 -1
- package/static/app/assets/{Capture-BsO_OAeh.js → Capture-BB19fo7P.js} +1 -1
- package/static/app/assets/{Chronicle-BUj_UH3D.js → Chronicle-D8p3dqxZ.js} +1 -1
- package/static/app/assets/{CommandPalette-B4SWOaR-.js → CommandPalette-uVFYAa-6.js} +1 -1
- package/static/app/assets/{DigitalBrainExplorer-S1GSsyIT.js → DigitalBrainExplorer-mH6ZSuvK.js} +1 -1
- package/static/app/assets/{Library-CKUR2eVb.js → Library-0q8Sdke7.js} +1 -1
- package/static/app/assets/{LivingBrain--2UoV3Ki.js → LivingBrain-wess-qJZ.js} +1 -1
- package/static/app/assets/ProductFlow-DeBGF6qz.js +1 -0
- package/static/app/assets/{ReviewCard-UzQZ1ULT.js → ReviewCard-DyTrDpy0.js} +1 -1
- package/static/app/assets/{RunsListPanel-CDGFQYMo.js → RunsListPanel-CHJv2Qyw.js} +1 -1
- package/static/app/assets/System-CyKGHQrW.js +1 -0
- package/static/app/assets/{WorkflowGraph-BIcWZTUQ.js → WorkflowGraph-B5nKCCGa.js} +1 -1
- package/static/app/assets/{WorkflowsPanel-BeT5fmbk.js → WorkflowsPanel-C7RZNRGo.js} +2 -2
- package/static/app/assets/{actHelpers-DhutJObL.js → actHelpers-6MYDH2kW.js} +1 -1
- package/static/app/assets/arrow-left-DOnpwsVV.js +1 -0
- package/static/app/assets/{bot-D8tZzKMD.js → bot-Dm3fmXAE.js} +1 -1
- package/static/app/assets/brain-C2XwdQL1.js +1 -0
- package/static/app/assets/{button-Tzf5D7L1.js → button-xXPeemQr.js} +1 -1
- package/static/app/assets/circle-check-D44VI2ZE.js +1 -0
- package/static/app/assets/{circle-pause-Druue_tZ.js → circle-pause-B_lmNicW.js} +1 -1
- package/static/app/assets/{circle-play-BAht4SSW.js → circle-play-DSYCP0RD.js} +1 -1
- package/static/app/assets/{cpu-BPbmZRPp.js → cpu-D7x-dtxi.js} +1 -1
- package/static/app/assets/{download-BmxPZEwU.js → download-BHuJr-5V.js} +1 -1
- package/static/app/assets/{folder-open-DokOmFQJ.js → folder-open-BiO31EwS.js} +1 -1
- package/static/app/assets/{hard-drive-Cw6aEA2h.js → hard-drive-CFEaZ-wP.js} +1 -1
- package/static/app/assets/{index-CB93CZWW.css → index-C8gwOf0C.css} +1 -1
- package/static/app/assets/{index-DhszK7A3.js → index-DCT79wzR.js} +3 -3
- package/static/app/assets/{input-BCdHoZXA.js → input-D3YrgxvO.js} +1 -1
- package/static/app/assets/{link-2-CCModn4z.js → link-2-3O-By3qc.js} +1 -1
- package/static/app/assets/{permissionCopy-BSp1jYG7.js → permissionCopy-CNK2tfkz.js} +1 -1
- package/static/app/assets/{primitives-D01WcJn7.js → primitives-B6DzQC3H.js} +1 -1
- package/static/app/assets/search-BwMK0hjs.js +1 -0
- package/static/app/assets/{share-2-DMMkM8Iu.js → share-2-BljIPAku.js} +1 -1
- package/static/app/assets/{shield-alert--mrCWQko.js → shield-alert-WDP2DSTM.js} +1 -1
- package/static/app/assets/{sourceMeta-nvd3Cdz3.js → sourceMeta-By2WIjlN.js} +1 -1
- package/static/app/assets/{textarea-DfayhQiX.js → textarea-5v8vtDlK.js} +1 -1
- package/static/app/assets/{useFocusTrap-C5NsTvsI.js → useFocusTrap-ssiDeh6P.js} +1 -1
- package/static/app/assets/{useMutation-D7IMQTeI.js → useMutation-Bi0PXQMC.js} +1 -1
- package/static/app/assets/workspace-BsxrRYQI.js +1 -0
- package/static/app/index.html +2 -2
- package/static/sw.js +1 -1
- package/static/app/assets/BrainHome-IhcEPC3v.js +0 -2
- package/static/app/assets/ProductFlow-D7rB6Xsu.js +0 -1
- package/static/app/assets/System-0OSxZrTp.js +0 -1
- package/static/app/assets/arrow-left-BwJfcH8J.js +0 -1
- package/static/app/assets/brain-DP2JPXSV.js +0 -1
- package/static/app/assets/circle-check-D68nHcgS.js +0 -1
- package/static/app/assets/search-C_zAGfvO.js +0 -1
- package/static/app/assets/workspace-C7xidB7c.js +0 -1
|
@@ -118,6 +118,11 @@ class HnswIndex:
|
|
|
118
118
|
def model_id(self) -> str:
|
|
119
119
|
return self._model_id
|
|
120
120
|
|
|
121
|
+
@property
|
|
122
|
+
def labels(self) -> List[str]:
|
|
123
|
+
"""Live label order — the sidecar's identity, loaded or rebuilt."""
|
|
124
|
+
return list(self._labels)
|
|
125
|
+
|
|
121
126
|
def _identity_matches(self, dim: int, space: str, model_id: str) -> bool:
|
|
122
127
|
return (
|
|
123
128
|
int(dim) == self._dim
|
|
@@ -177,10 +182,12 @@ class HnswIndex:
|
|
|
177
182
|
doors without guessing.
|
|
178
183
|
|
|
179
184
|
Full rebuild when the embedder identity changed, when any currently
|
|
180
|
-
indexed id is missing from
|
|
181
|
-
deletes would exceed :data:`DELETE_REBUILD_RATIO
|
|
182
|
-
|
|
183
|
-
|
|
185
|
+
indexed id is missing from a *full* incoming snapshot (a deletion),
|
|
186
|
+
or when deletes would exceed :data:`DELETE_REBUILD_RATIO`. A sidecar
|
|
187
|
+
that was loaded without source vectors still **appends**: the
|
|
188
|
+
caller passes only the new ids (COUNT+delta) and ``_append_live``
|
|
189
|
+
extends the graph. A disjoint incoming set is that delta, not a
|
|
190
|
+
wipe.
|
|
184
191
|
"""
|
|
185
192
|
incoming: Dict[str, IndexItem] = {}
|
|
186
193
|
for item_id, vector, metadata in items:
|
|
@@ -197,13 +204,36 @@ class HnswIndex:
|
|
|
197
204
|
return "rebuild"
|
|
198
205
|
|
|
199
206
|
if self._loaded:
|
|
207
|
+
current = set(self._labels)
|
|
208
|
+
incoming_ids = set(incoming)
|
|
209
|
+
overlap = current & incoming_ids
|
|
210
|
+
deleted = current - incoming_ids
|
|
211
|
+
# Delta-only: the caller passed new ids, none of the live labels.
|
|
212
|
+
# A full snapshot that dropped ids is a deletion and must rebuild.
|
|
213
|
+
delta_only = bool(incoming_ids) and not overlap
|
|
214
|
+
if deleted and not delta_only:
|
|
215
|
+
self.rebuild(incoming.values())
|
|
216
|
+
return "rebuild"
|
|
217
|
+
new_ids = [item_id for item_id in incoming if item_id not in current]
|
|
218
|
+
if not new_ids:
|
|
219
|
+
return "append"
|
|
220
|
+
for item_id in new_ids:
|
|
221
|
+
_, vector, metadata = incoming[item_id]
|
|
222
|
+
self._vectors[item_id] = [float(value) for value in vector]
|
|
223
|
+
self._metadata[item_id] = dict(metadata or {})
|
|
224
|
+
if self._ann is not None and self._module is not None:
|
|
225
|
+
self._append_live(new_ids)
|
|
226
|
+
return "append"
|
|
200
227
|
self.rebuild(incoming.values())
|
|
201
228
|
return "rebuild"
|
|
202
229
|
|
|
203
230
|
current = set(self._vectors)
|
|
204
231
|
incoming_ids = set(incoming)
|
|
205
232
|
deleted = current - incoming_ids
|
|
206
|
-
|
|
233
|
+
overlap = current & incoming_ids
|
|
234
|
+
# Same discriminant as the loaded path: a disjoint incoming set is
|
|
235
|
+
# COUNT+delta, not a snapshot that deleted every live id.
|
|
236
|
+
if deleted and not (bool(incoming_ids) and not overlap):
|
|
207
237
|
ratio = len(deleted) / max(1, len(current))
|
|
208
238
|
if ratio >= DELETE_REBUILD_RATIO or not current:
|
|
209
239
|
self.rebuild(incoming.values())
|
|
@@ -339,18 +369,25 @@ class HnswIndex:
|
|
|
339
369
|
return False
|
|
340
370
|
return True
|
|
341
371
|
|
|
342
|
-
def load(self, db_path: Any, *, fingerprint: str) -> bool:
|
|
343
|
-
"""Adopt a sidecar graph when it
|
|
372
|
+
def load(self, db_path: Any, *, fingerprint: str, strict: bool = True) -> bool:
|
|
373
|
+
"""Adopt a sidecar graph when it matches this embedder identity.
|
|
374
|
+
|
|
375
|
+
``strict`` (the default) also requires the stored fingerprint — size
|
|
376
|
+
included — so a grown store does not search a stale graph. Relaxed
|
|
377
|
+
load keeps dim/model and leaves COUNT+delta to append the missing
|
|
378
|
+
ids rather than dumping the whole table.
|
|
379
|
+
"""
|
|
344
380
|
module = self._module
|
|
345
381
|
if module is None:
|
|
346
382
|
return False
|
|
347
383
|
index_path, meta_path = sidecar_paths(db_path)
|
|
348
384
|
try:
|
|
349
385
|
meta = json.loads(meta_path.read_text(encoding="utf-8"))
|
|
350
|
-
matches =
|
|
351
|
-
matches = matches and int(meta["dim"]) == self._dim
|
|
386
|
+
matches = int(meta["dim"]) == self._dim
|
|
352
387
|
if meta.get("model_id") not in (None, "", self._model_id):
|
|
353
388
|
matches = False
|
|
389
|
+
if strict:
|
|
390
|
+
matches = matches and str(meta["fingerprint"]) == str(fingerprint)
|
|
354
391
|
labels = [str(label) for label in meta["labels"]]
|
|
355
392
|
except Exception: # noqa: BLE001 — absent/corrupt sidecar = rebuild
|
|
356
393
|
return False
|
|
@@ -358,7 +395,9 @@ class HnswIndex:
|
|
|
358
395
|
return False
|
|
359
396
|
try:
|
|
360
397
|
graph = module.Index(space=self._space, dim=self._dim)
|
|
361
|
-
|
|
398
|
+
# Headroom so an in-process append does not have to rebuild
|
|
399
|
+
# just because load_index pinned max_elements to the old size.
|
|
400
|
+
graph.load_index(str(index_path), max_elements=max(len(labels) + 64, 1))
|
|
362
401
|
except Exception: # noqa: BLE001 — corrupt binary = rebuild
|
|
363
402
|
return False
|
|
364
403
|
self._ann = graph
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
The live graph is cached per ``(db_path, model_id, dim)``. A missing sidecar
|
|
4
4
|
is ``index: "none"``. When the store has vectors the cache (or a rebuild from
|
|
5
|
-
``vector_embeddings``) can serve, the reply is ``index: "hnsw"``.
|
|
6
|
-
sidecar size vs ``COUNT(*)`` for that identity
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
``vector_embeddings``) can serve, the reply is ``index: "hnsw"``. Freshness is
|
|
6
|
+
sidecar size vs ``COUNT(*)`` for that identity. A warm COUNT match never
|
|
7
|
+
opens embedding blobs. Growth loads **missing ids only** and appends; a
|
|
8
|
+
shrink still rebuilds from the remaining rows.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
from __future__ import annotations
|
|
@@ -81,6 +81,83 @@ def load_store_items(
|
|
|
81
81
|
return items
|
|
82
82
|
|
|
83
83
|
|
|
84
|
+
def load_store_ids(conn: sqlite3.Connection, model_id: str, dim: int) -> List[str]:
|
|
85
|
+
"""Item ids only — the COUNT+delta path must not pull embedding blobs."""
|
|
86
|
+
rows = conn.execute(
|
|
87
|
+
"SELECT item_id FROM vector_embeddings "
|
|
88
|
+
"WHERE embedding_model=? AND embedding_dim=? ORDER BY indexed_at ASC, item_id ASC",
|
|
89
|
+
(model_id, int(dim)),
|
|
90
|
+
)
|
|
91
|
+
return [str(item_id) for (item_id,) in rows]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def load_store_items_for(
|
|
95
|
+
conn: sqlite3.Connection,
|
|
96
|
+
model_id: str,
|
|
97
|
+
dim: int,
|
|
98
|
+
item_ids: Sequence[str],
|
|
99
|
+
) -> List[Tuple[str, List[float], Dict[str, Any]]]:
|
|
100
|
+
"""Blobs for ``item_ids`` only, preserving the caller's order."""
|
|
101
|
+
if not item_ids:
|
|
102
|
+
return []
|
|
103
|
+
by_id: Dict[str, List[float]] = {}
|
|
104
|
+
wanted = [str(item_id) for item_id in item_ids]
|
|
105
|
+
# SQLite caps bound parameters; 400 leaves room for the identity pair.
|
|
106
|
+
for start in range(0, len(wanted), 400):
|
|
107
|
+
chunk = wanted[start : start + 400]
|
|
108
|
+
qmarks = ",".join("?" * len(chunk))
|
|
109
|
+
query = "SELECT item_id, embedding FROM vector_embeddings WHERE embedding_model=? AND embedding_dim=? AND item_id IN (%s)" % qmarks # noqa: S608
|
|
110
|
+
for item_id, blob in conn.execute(query, (model_id, int(dim), *chunk)):
|
|
111
|
+
vector = decode_f32le(bytes(blob or b""), int(dim))
|
|
112
|
+
if len(vector) != int(dim):
|
|
113
|
+
continue
|
|
114
|
+
by_id[str(item_id)] = vector
|
|
115
|
+
return [
|
|
116
|
+
(item_id, by_id[item_id], {})
|
|
117
|
+
for item_id in wanted
|
|
118
|
+
if item_id in by_id
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _open_and_count(path: Path, model_id: str, dim: int) -> int:
|
|
123
|
+
conn = _open_readonly(path)
|
|
124
|
+
if conn is None:
|
|
125
|
+
return 0
|
|
126
|
+
try:
|
|
127
|
+
return store_vector_count(conn, model_id, dim)
|
|
128
|
+
finally:
|
|
129
|
+
conn.close()
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _load_all_items(
|
|
133
|
+
path: Path, model_id: str, dim: int
|
|
134
|
+
) -> List[Tuple[str, List[float], Dict[str, Any]]]:
|
|
135
|
+
conn = _open_readonly(path)
|
|
136
|
+
if conn is None:
|
|
137
|
+
return []
|
|
138
|
+
try:
|
|
139
|
+
return load_store_items(conn, model_id, dim)
|
|
140
|
+
finally:
|
|
141
|
+
conn.close()
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _load_missing_items(
|
|
145
|
+
path: Path,
|
|
146
|
+
model_id: str,
|
|
147
|
+
dim: int,
|
|
148
|
+
have: Sequence[str],
|
|
149
|
+
) -> List[Tuple[str, List[float], Dict[str, Any]]]:
|
|
150
|
+
conn = _open_readonly(path)
|
|
151
|
+
if conn is None:
|
|
152
|
+
return []
|
|
153
|
+
try:
|
|
154
|
+
have_set = set(have)
|
|
155
|
+
missing = [item_id for item_id in load_store_ids(conn, model_id, dim) if item_id not in have_set]
|
|
156
|
+
return load_store_items_for(conn, model_id, dim, missing)
|
|
157
|
+
finally:
|
|
158
|
+
conn.close()
|
|
159
|
+
|
|
160
|
+
|
|
84
161
|
def sidecar_meta_size(db_path: Path) -> Optional[int]:
|
|
85
162
|
"""Label count from the sidecar meta file, or ``None`` when it is absent."""
|
|
86
163
|
_, meta_path = sidecar_paths(db_path)
|
|
@@ -185,17 +262,8 @@ def query_sidecar(
|
|
|
185
262
|
if not model_id:
|
|
186
263
|
return _none_reply(detail="embedding_model is required")
|
|
187
264
|
|
|
188
|
-
|
|
189
|
-
store_size =
|
|
190
|
-
items: List[Tuple[str, List[float], Dict[str, Any]]] = []
|
|
191
|
-
if conn is not None:
|
|
192
|
-
try:
|
|
193
|
-
store_size = store_vector_count(conn, model_id, dim)
|
|
194
|
-
if store_size > 0:
|
|
195
|
-
items = load_store_items(conn, model_id, dim)
|
|
196
|
-
store_size = len(items)
|
|
197
|
-
finally:
|
|
198
|
-
conn.close()
|
|
265
|
+
# COUNT first. Warm queries that already match never open embedding blobs.
|
|
266
|
+
store_size = _open_and_count(path, model_id, dim)
|
|
199
267
|
|
|
200
268
|
key = (str(path), model_id, dim)
|
|
201
269
|
with _LOCK:
|
|
@@ -203,8 +271,20 @@ def query_sidecar(
|
|
|
203
271
|
refreshed: Optional[str] = None
|
|
204
272
|
if index is None:
|
|
205
273
|
index = HnswIndex(dim=dim, model_id=model_id)
|
|
206
|
-
loaded = index.load(
|
|
274
|
+
loaded = index.load(
|
|
275
|
+
path, fingerprint=sidecar_fingerprint(model_id, dim, store_size)
|
|
276
|
+
)
|
|
277
|
+
if not loaded and store_size > 0:
|
|
278
|
+
# Sidecar exists for this identity but the COUNT moved —
|
|
279
|
+
# load the graph and append the missing ids below.
|
|
280
|
+
loaded = index.load(
|
|
281
|
+
path,
|
|
282
|
+
fingerprint=sidecar_fingerprint(model_id, dim, store_size),
|
|
283
|
+
strict=False,
|
|
284
|
+
)
|
|
207
285
|
if not loaded:
|
|
286
|
+
items = _load_all_items(path, model_id, dim)
|
|
287
|
+
store_size = len(items)
|
|
208
288
|
if not items:
|
|
209
289
|
return _none_reply(
|
|
210
290
|
store_size=store_size,
|
|
@@ -216,25 +296,31 @@ def query_sidecar(
|
|
|
216
296
|
|
|
217
297
|
cached_size = int(index.stats().get("size") or 0)
|
|
218
298
|
stale = cached_size != store_size
|
|
219
|
-
if stale:
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
299
|
+
if stale and store_size == 0:
|
|
300
|
+
_CACHE.pop(key, None)
|
|
301
|
+
return _none_reply(
|
|
302
|
+
store_size=0,
|
|
303
|
+
detail="vector store is empty for this embedding identity",
|
|
304
|
+
)
|
|
305
|
+
if stale and store_size > cached_size:
|
|
306
|
+
delta = _load_missing_items(path, model_id, dim, index.labels)
|
|
307
|
+
if delta:
|
|
308
|
+
refreshed = _refresh_index(index, delta, model_id, dim)
|
|
309
|
+
cached_size = int(index.stats().get("size") or 0)
|
|
310
|
+
index.save(
|
|
311
|
+
path, fingerprint=sidecar_fingerprint(model_id, dim, cached_size)
|
|
312
|
+
)
|
|
313
|
+
stale = cached_size != store_size
|
|
314
|
+
elif stale:
|
|
315
|
+
items = _load_all_items(path, model_id, dim)
|
|
316
|
+
store_size = len(items)
|
|
227
317
|
if items:
|
|
228
318
|
refreshed = _refresh_index(index, items, model_id, dim)
|
|
229
|
-
index.save(path, fingerprint=sidecar_fingerprint(model_id, dim, len(items)))
|
|
230
319
|
cached_size = int(index.stats().get("size") or 0)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
_CACHE.pop(key, None)
|
|
234
|
-
return _none_reply(
|
|
235
|
-
store_size=0,
|
|
236
|
-
detail="vector store is empty for this embedding identity",
|
|
320
|
+
index.save(
|
|
321
|
+
path, fingerprint=sidecar_fingerprint(model_id, dim, cached_size)
|
|
237
322
|
)
|
|
323
|
+
stale = cached_size != store_size
|
|
238
324
|
|
|
239
325
|
if cached_size <= 0:
|
|
240
326
|
return _none_reply(
|
|
@@ -326,4 +412,7 @@ __all__ = [
|
|
|
326
412
|
"sidecar_freshness",
|
|
327
413
|
"sidecar_meta_size",
|
|
328
414
|
"store_vector_count",
|
|
415
|
+
"load_store_ids",
|
|
416
|
+
"load_store_items",
|
|
417
|
+
"load_store_items_for",
|
|
329
418
|
]
|
|
@@ -28,7 +28,7 @@ from typing import Any, Dict, List
|
|
|
28
28
|
|
|
29
29
|
from latticeai.services.architecture_readiness import architecture_readiness
|
|
30
30
|
|
|
31
|
-
PRODUCT_VERSION_TARGET = "12.1
|
|
31
|
+
PRODUCT_VERSION_TARGET = "12.2.1"
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
@dataclass(frozen=True)
|
|
@@ -123,7 +123,7 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
123
123
|
f"vscode-extension/README.md::**{PRODUCT_VERSION_TARGET}",
|
|
124
124
|
f"docs/CHANGELOG.md::## [{PRODUCT_VERSION_TARGET}]",
|
|
125
125
|
"FEATURE_STATUS.md",
|
|
126
|
-
f"RELEASE_NOTES_v{PRODUCT_VERSION_TARGET}.md",
|
|
126
|
+
f"docs/releases/RELEASE_NOTES_v{PRODUCT_VERSION_TARGET}.md",
|
|
127
127
|
"rust/lattice-agent/src/kernel/permission.rs::pub fn block_reason_for_tool",
|
|
128
128
|
"rust/lattice-agent/src/kernel/mod.rs::pub mod agentloop",
|
|
129
129
|
"latticeai/api/agent_worker_seam.py::create_agent_worker_seam_router",
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@ const root = process.cwd();
|
|
|
6
6
|
const pkg = JSON.parse(readFileSync(path.join(root, "package.json"), "utf8"));
|
|
7
7
|
const version = pkg.version;
|
|
8
8
|
const releaseDir = `output/release/v${version}`;
|
|
9
|
-
const releaseTheme = "
|
|
9
|
+
const releaseTheme = "True Count";
|
|
10
10
|
const title = `${version} — ${releaseTheme}`;
|
|
11
11
|
const escapedVersion = version.replaceAll(".", "\\.");
|
|
12
12
|
|
|
@@ -20,6 +20,40 @@
|
|
|
20
20
|
"whole-image delta: naming where the change is makes the claim more",
|
|
21
21
|
"specific, not less."
|
|
22
22
|
],
|
|
23
|
+
"12.2.1": {
|
|
24
|
+
"_why": [
|
|
25
|
+
"True Count is a backend honesty release: HNSW COUNT+delta, SkipByHash",
|
|
26
|
+
"restamp, watch graph prune, summary salvage, MCP CORE, api_key /models",
|
|
27
|
+
"probe, and hash-search copy. The library embedding panel and first-run",
|
|
28
|
+
"hint changed wording; that is below a redesign floor.",
|
|
29
|
+
"",
|
|
30
|
+
"No screen was redesigned. Empty claim set on purpose. Unclaimed screens",
|
|
31
|
+
"are still measured and printed; they are not gated."
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"12.2.0": {
|
|
35
|
+
"_why": [
|
|
36
|
+
"Small Voice is a 2B tool-calling release with two visible surfaces.",
|
|
37
|
+
"",
|
|
38
|
+
"1. Brain home composer: four plain-language chips (folder search, read",
|
|
39
|
+
" and summarize, memory, skill review) sit under the textarea. The",
|
|
40
|
+
" Living Brain still dominates the shot, so the whole-image delta sits",
|
|
41
|
+
" under the 8% live floor; the claim uses the measured 3.96% as the",
|
|
42
|
+
" floor, not a redesign of the shell.",
|
|
43
|
+
"",
|
|
44
|
+
"2. Settings: a new 'small models can use tools' card with four badges.",
|
|
45
|
+
" That card is why 08 grew 168px.",
|
|
46
|
+
"",
|
|
47
|
+
"No other screen was redesigned. Unclaimed screens are measured and",
|
|
48
|
+
"printed; they are not gated."
|
|
49
|
+
],
|
|
50
|
+
"04-brain-chat-home.png": {
|
|
51
|
+
"min_pct": 3.0
|
|
52
|
+
},
|
|
53
|
+
"08-system.png": {
|
|
54
|
+
"min_pct": 1.5
|
|
55
|
+
}
|
|
56
|
+
},
|
|
23
57
|
"12.1.0": {
|
|
24
58
|
"_why": [
|
|
25
59
|
"Fast Path is a backend ingest/search release. Folder ingest overlaps",
|
package/src-tauri/Cargo.lock
CHANGED
|
@@ -1863,7 +1863,7 @@ dependencies = [
|
|
|
1863
1863
|
|
|
1864
1864
|
[[package]]
|
|
1865
1865
|
name = "lattice-agent"
|
|
1866
|
-
version = "12.1
|
|
1866
|
+
version = "12.2.1"
|
|
1867
1867
|
dependencies = [
|
|
1868
1868
|
"axum",
|
|
1869
1869
|
"base64 0.22.1",
|
|
@@ -1880,7 +1880,7 @@ dependencies = [
|
|
|
1880
1880
|
|
|
1881
1881
|
[[package]]
|
|
1882
1882
|
name = "lattice-ai-desktop"
|
|
1883
|
-
version = "12.1
|
|
1883
|
+
version = "12.2.1"
|
|
1884
1884
|
dependencies = [
|
|
1885
1885
|
"lattice-host",
|
|
1886
1886
|
"lattice-jobs",
|
|
@@ -1895,7 +1895,7 @@ dependencies = [
|
|
|
1895
1895
|
|
|
1896
1896
|
[[package]]
|
|
1897
1897
|
name = "lattice-auth"
|
|
1898
|
-
version = "12.1
|
|
1898
|
+
version = "12.2.1"
|
|
1899
1899
|
dependencies = [
|
|
1900
1900
|
"axum",
|
|
1901
1901
|
"base64 0.22.1",
|
|
@@ -1912,7 +1912,7 @@ dependencies = [
|
|
|
1912
1912
|
|
|
1913
1913
|
[[package]]
|
|
1914
1914
|
name = "lattice-chat"
|
|
1915
|
-
version = "12.1
|
|
1915
|
+
version = "12.2.1"
|
|
1916
1916
|
dependencies = [
|
|
1917
1917
|
"axum",
|
|
1918
1918
|
"bytes",
|
|
@@ -1934,7 +1934,7 @@ dependencies = [
|
|
|
1934
1934
|
|
|
1935
1935
|
[[package]]
|
|
1936
1936
|
name = "lattice-core"
|
|
1937
|
-
version = "12.1
|
|
1937
|
+
version = "12.2.1"
|
|
1938
1938
|
dependencies = [
|
|
1939
1939
|
"blake2",
|
|
1940
1940
|
"bytes",
|
|
@@ -1950,7 +1950,7 @@ dependencies = [
|
|
|
1950
1950
|
|
|
1951
1951
|
[[package]]
|
|
1952
1952
|
name = "lattice-host"
|
|
1953
|
-
version = "12.1
|
|
1953
|
+
version = "12.2.1"
|
|
1954
1954
|
dependencies = [
|
|
1955
1955
|
"axum",
|
|
1956
1956
|
"lattice-agent",
|
|
@@ -1971,7 +1971,7 @@ dependencies = [
|
|
|
1971
1971
|
|
|
1972
1972
|
[[package]]
|
|
1973
1973
|
name = "lattice-ingest"
|
|
1974
|
-
version = "12.1
|
|
1974
|
+
version = "12.2.1"
|
|
1975
1975
|
dependencies = [
|
|
1976
1976
|
"axum",
|
|
1977
1977
|
"lattice-auth",
|
|
@@ -1986,7 +1986,7 @@ dependencies = [
|
|
|
1986
1986
|
|
|
1987
1987
|
[[package]]
|
|
1988
1988
|
name = "lattice-jobs"
|
|
1989
|
-
version = "12.1
|
|
1989
|
+
version = "12.2.1"
|
|
1990
1990
|
dependencies = [
|
|
1991
1991
|
"axum",
|
|
1992
1992
|
"lattice-auth",
|
|
@@ -2001,7 +2001,7 @@ dependencies = [
|
|
|
2001
2001
|
|
|
2002
2002
|
[[package]]
|
|
2003
2003
|
name = "lattice-platform"
|
|
2004
|
-
version = "12.1
|
|
2004
|
+
version = "12.2.1"
|
|
2005
2005
|
dependencies = [
|
|
2006
2006
|
"axum",
|
|
2007
2007
|
"base64 0.22.1",
|
|
@@ -2024,7 +2024,7 @@ dependencies = [
|
|
|
2024
2024
|
|
|
2025
2025
|
[[package]]
|
|
2026
2026
|
name = "lattice-retrieval"
|
|
2027
|
-
version = "12.1
|
|
2027
|
+
version = "12.2.1"
|
|
2028
2028
|
dependencies = [
|
|
2029
2029
|
"axum",
|
|
2030
2030
|
"fancy-regex",
|
package/src-tauri/Cargo.toml
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "12.1
|
|
2
|
+
"version": "12.2.1",
|
|
3
3
|
"generated_at": "vite",
|
|
4
4
|
"entrypoints": {
|
|
5
|
-
"app": "/static/app/assets/index-
|
|
5
|
+
"app": "/static/app/assets/index-DCT79wzR.js"
|
|
6
6
|
},
|
|
7
7
|
"assets": {
|
|
8
8
|
"../node_modules/@tauri-apps/api/core.js": "/static/app/assets/core-CwxXejkd.js",
|
|
9
|
-
"_BrainSignals-
|
|
10
|
-
"_LivingBrain
|
|
9
|
+
"_BrainSignals-CNA0d6xS.js": "/static/app/assets/BrainSignals-CNA0d6xS.js",
|
|
10
|
+
"_LivingBrain-wess-qJZ.js": "/static/app/assets/LivingBrain-wess-qJZ.js",
|
|
11
11
|
"_QueryClientProvider-B3OjqSyJ.js": "/static/app/assets/QueryClientProvider-B3OjqSyJ.js",
|
|
12
|
-
"_ReviewCard-
|
|
13
|
-
"_actHelpers-
|
|
14
|
-
"_arrow-left-
|
|
15
|
-
"_bot-
|
|
16
|
-
"_brain-
|
|
17
|
-
"_button-
|
|
18
|
-
"_circle-check-
|
|
19
|
-
"_circle-pause-
|
|
20
|
-
"_circle-play-
|
|
21
|
-
"_cpu-
|
|
22
|
-
"_download-
|
|
23
|
-
"_folder-open-
|
|
24
|
-
"_hard-drive-
|
|
25
|
-
"_input-
|
|
12
|
+
"_ReviewCard-DyTrDpy0.js": "/static/app/assets/ReviewCard-DyTrDpy0.js",
|
|
13
|
+
"_actHelpers-6MYDH2kW.js": "/static/app/assets/actHelpers-6MYDH2kW.js",
|
|
14
|
+
"_arrow-left-DOnpwsVV.js": "/static/app/assets/arrow-left-DOnpwsVV.js",
|
|
15
|
+
"_bot-Dm3fmXAE.js": "/static/app/assets/bot-Dm3fmXAE.js",
|
|
16
|
+
"_brain-C2XwdQL1.js": "/static/app/assets/brain-C2XwdQL1.js",
|
|
17
|
+
"_button-xXPeemQr.js": "/static/app/assets/button-xXPeemQr.js",
|
|
18
|
+
"_circle-check-D44VI2ZE.js": "/static/app/assets/circle-check-D44VI2ZE.js",
|
|
19
|
+
"_circle-pause-B_lmNicW.js": "/static/app/assets/circle-pause-B_lmNicW.js",
|
|
20
|
+
"_circle-play-DSYCP0RD.js": "/static/app/assets/circle-play-DSYCP0RD.js",
|
|
21
|
+
"_cpu-D7x-dtxi.js": "/static/app/assets/cpu-D7x-dtxi.js",
|
|
22
|
+
"_download-BHuJr-5V.js": "/static/app/assets/download-BHuJr-5V.js",
|
|
23
|
+
"_folder-open-BiO31EwS.js": "/static/app/assets/folder-open-BiO31EwS.js",
|
|
24
|
+
"_hard-drive-CFEaZ-wP.js": "/static/app/assets/hard-drive-CFEaZ-wP.js",
|
|
25
|
+
"_input-D3YrgxvO.js": "/static/app/assets/input-D3YrgxvO.js",
|
|
26
26
|
"_jsx-runtime-bzQ4Vb5N.js": "/static/app/assets/jsx-runtime-bzQ4Vb5N.js",
|
|
27
|
-
"_link-2-
|
|
28
|
-
"_permissionCopy-
|
|
29
|
-
"_primitives-
|
|
30
|
-
"_search-
|
|
31
|
-
"_share-2-
|
|
32
|
-
"_shield-alert
|
|
33
|
-
"_sourceMeta-
|
|
34
|
-
"_textarea-
|
|
35
|
-
"_useFocusTrap-
|
|
36
|
-
"_useMutation-
|
|
37
|
-
"_workspace-
|
|
38
|
-
"index.html": "/static/app/assets/index-
|
|
39
|
-
"assets/index-
|
|
40
|
-
"src/components/ProductFlow.tsx": "/static/app/assets/ProductFlow-
|
|
41
|
-
"src/features/act/RunsListPanel.tsx": "/static/app/assets/RunsListPanel-
|
|
42
|
-
"src/features/act/WorkflowGraph.tsx": "/static/app/assets/WorkflowGraph-
|
|
43
|
-
"src/features/act/WorkflowsPanel.tsx": "/static/app/assets/WorkflowsPanel-
|
|
44
|
-
"src/features/admin/AdminConsole.tsx": "/static/app/assets/AdminConsole-
|
|
45
|
-
"src/features/brain/BrainHome.tsx": "/static/app/assets/BrainHome-
|
|
46
|
-
"src/features/command/CommandPalette.tsx": "/static/app/assets/CommandPalette-
|
|
47
|
-
"src/pages/Act.tsx": "/static/app/assets/Act-
|
|
48
|
-
"src/pages/Brain.tsx": "/static/app/assets/Brain-
|
|
49
|
-
"src/pages/Capture.tsx": "/static/app/assets/Capture-
|
|
50
|
-
"src/pages/Chronicle.tsx": "/static/app/assets/Chronicle-
|
|
51
|
-
"src/pages/Library.tsx": "/static/app/assets/Library-
|
|
52
|
-
"src/pages/System.tsx": "/static/app/assets/System-
|
|
53
|
-
"src/pages/brain/DigitalBrainExplorer.tsx": "/static/app/assets/DigitalBrainExplorer-
|
|
27
|
+
"_link-2-3O-By3qc.js": "/static/app/assets/link-2-3O-By3qc.js",
|
|
28
|
+
"_permissionCopy-CNK2tfkz.js": "/static/app/assets/permissionCopy-CNK2tfkz.js",
|
|
29
|
+
"_primitives-B6DzQC3H.js": "/static/app/assets/primitives-B6DzQC3H.js",
|
|
30
|
+
"_search-BwMK0hjs.js": "/static/app/assets/search-BwMK0hjs.js",
|
|
31
|
+
"_share-2-BljIPAku.js": "/static/app/assets/share-2-BljIPAku.js",
|
|
32
|
+
"_shield-alert-WDP2DSTM.js": "/static/app/assets/shield-alert-WDP2DSTM.js",
|
|
33
|
+
"_sourceMeta-By2WIjlN.js": "/static/app/assets/sourceMeta-By2WIjlN.js",
|
|
34
|
+
"_textarea-5v8vtDlK.js": "/static/app/assets/textarea-5v8vtDlK.js",
|
|
35
|
+
"_useFocusTrap-ssiDeh6P.js": "/static/app/assets/useFocusTrap-ssiDeh6P.js",
|
|
36
|
+
"_useMutation-Bi0PXQMC.js": "/static/app/assets/useMutation-Bi0PXQMC.js",
|
|
37
|
+
"_workspace-BsxrRYQI.js": "/static/app/assets/workspace-BsxrRYQI.js",
|
|
38
|
+
"index.html": "/static/app/assets/index-DCT79wzR.js",
|
|
39
|
+
"assets/index-C8gwOf0C.css": "/static/app/assets/index-C8gwOf0C.css",
|
|
40
|
+
"src/components/ProductFlow.tsx": "/static/app/assets/ProductFlow-DeBGF6qz.js",
|
|
41
|
+
"src/features/act/RunsListPanel.tsx": "/static/app/assets/RunsListPanel-CHJv2Qyw.js",
|
|
42
|
+
"src/features/act/WorkflowGraph.tsx": "/static/app/assets/WorkflowGraph-B5nKCCGa.js",
|
|
43
|
+
"src/features/act/WorkflowsPanel.tsx": "/static/app/assets/WorkflowsPanel-C7RZNRGo.js",
|
|
44
|
+
"src/features/admin/AdminConsole.tsx": "/static/app/assets/AdminConsole-aCxQgD2L.js",
|
|
45
|
+
"src/features/brain/BrainHome.tsx": "/static/app/assets/BrainHome-N00B-MAJ.js",
|
|
46
|
+
"src/features/command/CommandPalette.tsx": "/static/app/assets/CommandPalette-uVFYAa-6.js",
|
|
47
|
+
"src/pages/Act.tsx": "/static/app/assets/Act-DC676bqE.js",
|
|
48
|
+
"src/pages/Brain.tsx": "/static/app/assets/Brain-Dbd0xvsc.js",
|
|
49
|
+
"src/pages/Capture.tsx": "/static/app/assets/Capture-BB19fo7P.js",
|
|
50
|
+
"src/pages/Chronicle.tsx": "/static/app/assets/Chronicle-D8p3dqxZ.js",
|
|
51
|
+
"src/pages/Library.tsx": "/static/app/assets/Library-0q8Sdke7.js",
|
|
52
|
+
"src/pages/System.tsx": "/static/app/assets/System-CyKGHQrW.js",
|
|
53
|
+
"src/pages/brain/DigitalBrainExplorer.tsx": "/static/app/assets/DigitalBrainExplorer-mH6ZSuvK.js"
|
|
54
54
|
}
|
|
55
55
|
}
|