ltcai 11.6.0 → 11.9.0
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 +80 -75
- package/docs/BENCHMARKS.md +9 -2
- package/docs/CHANGELOG.md +201 -0
- package/docs/CI_AND_RELEASE_GATES.md +126 -41
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +34 -14
- package/docs/LEGACY_COMPATIBILITY.md +10 -6
- package/docs/ONBOARDING.md +5 -3
- package/docs/OPERATIONS.md +5 -1
- package/docs/PERMISSION_MODE.md +14 -9
- package/docs/TRUST_MODEL.md +13 -6
- package/docs/USABILITY_AUDIT.md +5 -0
- package/docs/WHY_LATTICE.md +6 -4
- package/docs/kg-schema.md +7 -3
- package/docs/mcp-tools.md +73 -79
- package/docs/security-model.md +6 -3
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/graph/_kg_common/__init__.py +1 -54
- package/lattice_brain/graph/_kg_common/text.py +14 -450
- package/lattice_brain/ingestion/__init__.py +6 -3
- package/lattice_brain/multimodal/__init__.py +9 -3
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/agent_worker_seam.py +12 -1
- package/latticeai/api/models.py +18 -110
- package/latticeai/api/search.py +7 -30
- package/latticeai/api/worker_compute.py +53 -107
- package/latticeai/api/worker_seams.py +17 -2
- package/latticeai/core/http_origin.py +3 -3
- package/latticeai/core/messages.py +0 -5
- package/latticeai/core/policy.py +1 -6
- package/latticeai/core/quiet.py +1 -20
- package/latticeai/core/security.py +29 -83
- package/latticeai/core/sessions.py +95 -4
- package/latticeai/core/users.py +0 -38
- package/latticeai/models/router/catalog.py +2 -2
- package/latticeai/models/router/generation.py +81 -14
- package/latticeai/models/router/loading.py +41 -5
- package/latticeai/runtime/access_runtime.py +7 -4
- package/latticeai/runtime/build_phases/features.py +8 -31
- package/latticeai/runtime/build_phases/foundation.py +7 -16
- package/latticeai/runtime/build_phases/web.py +3 -3
- package/latticeai/runtime/build_phases/worker_profile.py +21 -28
- package/latticeai/runtime/runtime_context.py +0 -2
- package/latticeai/services/architecture_readiness.py +18 -19
- package/latticeai/services/process_audit.py +1 -22
- package/latticeai/services/product_readiness.py +33 -11
- package/latticeai/services/voice_capture.py +8 -28
- package/latticeai/tools/__init__.py +6 -46
- package/latticeai/tools/commands.py +9 -15
- package/latticeai/tools/knowledge.py +0 -6
- package/package.json +3 -5
- package/requirements.txt +0 -1
- package/scripts/check_current_release_docs.mjs +1 -1
- package/scripts/check_openapi_drift.mjs +3 -2
- package/scripts/check_server_i18n.mjs +5 -4
- package/scripts/compose_openapi.py +2 -1
- package/scripts/export_openapi.py +5 -4
- package/scripts/gen_worker_allowlist_fixture.py +2 -2
- package/scripts/openapi_route_families.json +14 -73
- package/scripts/release_screen_claims.json +151 -14
- package/src-tauri/Cargo.lock +11 -10
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +41 -41
- package/static/app/assets/{Act-CToZnOHz.js → Act-B4WT81kh.js} +1 -1
- package/static/app/assets/AdminConsole--Wf71m-o.js +1 -0
- package/static/app/assets/{Brain-C6zCdv4S.js → Brain-CtYaa26c.js} +2 -2
- package/static/app/assets/BrainHome-Be2VPJEc.js +2 -0
- package/static/app/assets/BrainSignals-C0__xgpG.js +1 -0
- package/static/app/assets/Capture-DdNi5Peb.js +1 -0
- package/static/app/assets/Chronicle-B3hNveeI.js +1 -0
- package/static/app/assets/CommandPalette-CIsnSsFL.js +1 -0
- package/static/app/assets/Library-Bl5XClFV.js +1 -0
- package/static/app/assets/LivingBrain-DjkTB_gh.js +1 -0
- package/static/app/assets/{ProductFlow-CBLdmesT.js → ProductFlow-DCUNRNHs.js} +1 -1
- package/static/app/assets/ReviewCard-CD3yWvUB.js +3 -0
- package/static/app/assets/System-BJ6jQ_SL.js +1 -0
- package/static/app/assets/arrow-left-6_28Z0qH.js +1 -0
- package/static/app/assets/{bot-C5-XIww2.js → bot-Bc3Q27YR.js} +1 -1
- package/static/app/assets/brain-B9BDrMTe.js +1 -0
- package/static/app/assets/{button-DI1KcQP-.js → button-D6JcpYcf.js} +1 -1
- package/static/app/assets/circle-check-BFu9lD-3.js +1 -0
- package/static/app/assets/{circle-pause-C8HHyood.js → circle-pause-BGMiV8UU.js} +1 -1
- package/static/app/assets/{circle-play-Cufc235E.js → circle-play-DoanLHnd.js} +1 -1
- package/static/app/assets/{cpu-DW2_JVsv.js → cpu-DwzNf82m.js} +1 -1
- package/static/app/assets/{download-gbdKTBb8.js → download-Ddw49yCV.js} +1 -1
- package/static/app/assets/{folder-open-C9ydyX33.js → folder-open-Brd6Kvto.js} +1 -1
- package/static/app/assets/{hard-drive-BxNMzBM3.js → hard-drive-Bu-DTJdB.js} +1 -1
- package/static/app/assets/index-CGdg_aq9.css +2 -0
- package/static/app/assets/{index-q9XyDY7A.js → index-CWKRRsLW.js} +4 -4
- package/static/app/assets/input-CEqsxtil.js +1 -0
- package/static/app/assets/{link-2-B4Y0gz1S.js → link-2-DZ4OA5tJ.js} +1 -1
- package/static/app/assets/{permissionCopy-CxrV0fvU.js → permissionCopy-D9TR0F8b.js} +1 -1
- package/static/app/assets/primitives-DORg7Z_7.js +1 -0
- package/static/app/assets/search-0NQ21wXe.js +1 -0
- package/static/app/assets/{share-2-DxArfiuI.js → share-2-BC5FirFv.js} +1 -1
- package/static/app/assets/{shield-alert-CgftuFFs.js → shield-alert-DUbR2W2s.js} +1 -1
- package/static/app/assets/textarea-jtQcRSXo.js +1 -0
- package/static/app/assets/{useFocusTrap-Dzq2j_OG.js → useFocusTrap-HRemcWId.js} +1 -1
- package/static/app/assets/{useMutation-BcqfMLNq.js → useMutation-DqlFE-Bw.js} +1 -1
- package/static/app/assets/{useQuery-DBzLKCOv.js → useQuery-BizqBNGw.js} +1 -1
- package/static/app/assets/utils-WgW4V69R.js +4 -0
- package/static/app/assets/workspace-DSek3jCY.js +1 -0
- package/static/app/index.html +4 -4
- package/static/sw.js +1 -1
- package/lattice_brain/ingestion/pipeline.py +0 -108
- package/latticeai/api/local_files.py +0 -44
- package/latticeai/api/tools.py +0 -126
- package/latticeai/api/voice_capture.py +0 -32
- package/latticeai/core/agent_permission.py +0 -85
- package/scripts/agent_eval.py +0 -34
- package/scripts/brain_quality_eval.py +0 -37
- package/scripts/check_legacy_debt.mjs +0 -91
- package/scripts/check_python.py +0 -100
- package/scripts/chunking_parity_corpus.py +0 -449
- package/scripts/generate_agent_parity_fixtures.py +0 -771
- package/scripts/generate_chunking_parity_fixtures.py +0 -259
- package/static/app/assets/AdminConsole-D5kbrBu8.js +0 -1
- package/static/app/assets/BrainHome-D4n3EDUt.js +0 -2
- package/static/app/assets/BrainSignals-CzeZ-vQ9.js +0 -1
- package/static/app/assets/Capture-DPcyTczq.js +0 -1
- package/static/app/assets/Chronicle-D3Nx-oWS.js +0 -1
- package/static/app/assets/CommandPalette-DPPvpp28.js +0 -1
- package/static/app/assets/Library-Co2qTu3I.js +0 -1
- package/static/app/assets/LivingBrain-Bsmzwy8_.js +0 -1
- package/static/app/assets/ReviewCard-CfR6DLs7.js +0 -3
- package/static/app/assets/System-Ce-P2YL6.js +0 -1
- package/static/app/assets/arrow-left-DD5jFGHV.js +0 -1
- package/static/app/assets/brain-CFRJUvdX.js +0 -1
- package/static/app/assets/circle-check-CY20XMCh.js +0 -1
- package/static/app/assets/index-BovSWRmQ.css +0 -2
- package/static/app/assets/input-GLD94Y_K.js +0 -1
- package/static/app/assets/primitives-2ANdAsu2.js +0 -1
- package/static/app/assets/search-DTxtjQ07.js +0 -1
- package/static/app/assets/textarea-BHVBAoCr.js +0 -1
- package/static/app/assets/utils-B-Aah1bO.js +0 -4
- package/static/app/assets/workspace-B6fFhoko.js +0 -1
|
@@ -3,16 +3,18 @@
|
|
|
3
3
|
The tail of the build order — everything that mounts a router on the finished
|
|
4
4
|
application. WP-P1 replaced two phases (``platform_features`` and
|
|
5
5
|
``interaction``, ~34 product routers between them) with this one, because the
|
|
6
|
-
worker mounts
|
|
6
|
+
worker mounts four things:
|
|
7
7
|
|
|
8
8
|
* ``/health`` — the posture the supervisor gates on;
|
|
9
|
-
* the MLX model lifecycle (``/models*``, ``/engines
|
|
10
|
-
* the embedder report (
|
|
11
|
-
* the document parser (``POST /tools/read_document``, ``GET /tools/pdf_pages``);
|
|
12
|
-
* the two capability probes (``/api/ingestion/multimodal``,
|
|
13
|
-
``/api/capture/voice/status``);
|
|
9
|
+
* the MLX model lifecycle (``/models*``, ``/engines/prepare-model*``);
|
|
10
|
+
* the embedder report (``GET /api/embeddings/status``);
|
|
14
11
|
* the Rust loop's seam (``POST /agent/llm``, ``POST /agent/tool``).
|
|
15
12
|
|
|
13
|
+
It mounted three more until v11.8.0 — the ``/tools/*`` document parser, the
|
|
14
|
+
multi-modal capability probe and the voice capability probe. Every one of them
|
|
15
|
+
had no caller in the tree, so the routers, their modules and the construction
|
|
16
|
+
that fed them are gone rather than kept "in case".
|
|
17
|
+
|
|
16
18
|
The ``/worker/*`` seams are not here: they are mounted by
|
|
17
19
|
:func:`~latticeai.runtime.build_phases.worker_profile.phase_worker_routes`,
|
|
18
20
|
which runs after this phase and is the module that owns the worker contract.
|
|
@@ -33,22 +35,15 @@ def phase_features(ctx: RuntimeContext) -> None:
|
|
|
33
35
|
|
|
34
36
|
from latticeai.api.agent_worker_seam import create_agent_worker_seam_router
|
|
35
37
|
from latticeai.api.health import create_health_router
|
|
36
|
-
from latticeai.api.local_files import create_local_files_router
|
|
37
38
|
from latticeai.api.models import create_models_router
|
|
38
39
|
from latticeai.api.search import create_search_router
|
|
39
|
-
from latticeai.api.tools import create_tools_router
|
|
40
|
-
from latticeai.api.voice_capture import create_voice_capture_router
|
|
41
40
|
from latticeai.core.model_compat import list_cached_profiles
|
|
42
41
|
from latticeai.runtime.access_runtime import is_externally_reachable
|
|
43
42
|
from latticeai.runtime.platform_services_runtime import build_model_service
|
|
44
43
|
from latticeai.services.model_runtime import (
|
|
45
44
|
ENGINE_MODEL_CATALOG,
|
|
46
45
|
MODEL_ENGINE_ALIASES,
|
|
47
|
-
download_hf_model,
|
|
48
|
-
ensure_ollama_server,
|
|
49
46
|
filter_lower_family_versions,
|
|
50
|
-
local_binary,
|
|
51
|
-
normalize_local_model_request,
|
|
52
47
|
sse_event,
|
|
53
48
|
)
|
|
54
49
|
from latticeai.services.search_service import SearchService
|
|
@@ -81,13 +76,9 @@ def phase_features(ctx: RuntimeContext) -> None:
|
|
|
81
76
|
model_router=ctx.model_router,
|
|
82
77
|
require_user=ctx.require_user,
|
|
83
78
|
require_admin=ctx.require_admin,
|
|
84
|
-
normalize_local_model_request=normalize_local_model_request,
|
|
85
|
-
download_hf_model=download_hf_model,
|
|
86
79
|
prepare_and_load_model=service.prepare_and_load_model,
|
|
87
80
|
prepare_and_load_model_stream=service.prepare_and_load_model_stream,
|
|
88
81
|
sse_event=sse_event,
|
|
89
|
-
ensure_ollama_server=ensure_ollama_server,
|
|
90
|
-
local_binary=local_binary,
|
|
91
82
|
engine_status=service.engine_status,
|
|
92
83
|
filter_lower_family_versions=filter_lower_family_versions,
|
|
93
84
|
list_compat_profiles=list_cached_profiles,
|
|
@@ -120,20 +111,6 @@ def phase_features(ctx: RuntimeContext) -> None:
|
|
|
120
111
|
)
|
|
121
112
|
)
|
|
122
113
|
|
|
123
|
-
app.include_router(
|
|
124
|
-
create_tools_router(require_user=ctx.require_user)
|
|
125
|
-
)
|
|
126
|
-
app.include_router(
|
|
127
|
-
create_local_files_router(
|
|
128
|
-
require_user=ctx.require_user, ingestion_pipeline=ctx.INGESTION_PIPELINE
|
|
129
|
-
)
|
|
130
|
-
)
|
|
131
|
-
app.include_router(
|
|
132
|
-
create_voice_capture_router(
|
|
133
|
-
service=ctx.VOICE_CAPTURE, require_user=ctx.require_user
|
|
134
|
-
)
|
|
135
|
-
)
|
|
136
|
-
|
|
137
114
|
# AI-Worker seam (v11.5.1, plan §Y1): the calls the Rust agent loop makes
|
|
138
115
|
# back into Python once orchestration lives in ``lattice-agent``. The tool
|
|
139
116
|
# route stays behind ``LATTICEAI_AGENT_TOOL_SEAM=1``, which only
|
|
@@ -189,16 +189,12 @@ def phase_brain(ctx: RuntimeContext) -> None:
|
|
|
189
189
|
"""
|
|
190
190
|
ctx.enter("brain")
|
|
191
191
|
|
|
192
|
-
from lattice_brain.ingestion import IngestionPipeline
|
|
193
192
|
from latticeai.core.embedding_providers import (
|
|
194
193
|
resolve_embedder,
|
|
195
194
|
resolve_embedding_profile,
|
|
196
195
|
)
|
|
197
196
|
from latticeai.runtime.brain_runtime import build_embedder_runtime
|
|
198
|
-
from latticeai.services.multimodal_ports import
|
|
199
|
-
build_multimodal_ports,
|
|
200
|
-
multimodal_enabled,
|
|
201
|
-
)
|
|
197
|
+
from latticeai.services.multimodal_ports import build_multimodal_ports
|
|
202
198
|
from latticeai.services.voice_capture import VoiceCaptureService
|
|
203
199
|
|
|
204
200
|
# Resolve the configured embedding provider once. Degrades to the offline
|
|
@@ -228,18 +224,13 @@ def phase_brain(ctx: RuntimeContext) -> None:
|
|
|
228
224
|
# The transcriber is resolved through the voice service so a voice memo and
|
|
229
225
|
# a scanned ``.m4a`` are transcribed by the same thing — or, far more often,
|
|
230
226
|
# by the same nothing.
|
|
227
|
+
#
|
|
228
|
+
# The service itself is not published on the context: v11.8.0 deleted its
|
|
229
|
+
# one route (``GET /api/capture/voice/status``, which nothing called), so
|
|
230
|
+
# what the rest of the build needs from it is the port it resolves, and
|
|
231
|
+
# that travels in ``MULTIMODAL_PORTS``.
|
|
231
232
|
voice_capture = VoiceCaptureService(transcriber=None)
|
|
232
233
|
multimodal_ports = build_multimodal_ports(
|
|
233
234
|
transcriber=voice_capture.multimodal_ports().transcriber
|
|
234
235
|
)
|
|
235
|
-
|
|
236
|
-
# what this machine *could* do with a picture, a recording or a video; the
|
|
237
|
-
# ingest door itself is native (§W3b), which is why nothing is passed here
|
|
238
|
-
# for it to write through.
|
|
239
|
-
ctx.set(
|
|
240
|
-
VOICE_CAPTURE=voice_capture,
|
|
241
|
-
MULTIMODAL_PORTS=multimodal_ports,
|
|
242
|
-
INGESTION_PIPELINE=IngestionPipeline(
|
|
243
|
-
allow_multimodal=multimodal_enabled(), multimodal=multimodal_ports
|
|
244
|
-
),
|
|
245
|
-
)
|
|
236
|
+
ctx.set(MULTIMODAL_PORTS=multimodal_ports)
|
|
@@ -110,9 +110,9 @@ def build_worker_app_shell(ctx: RuntimeContext):
|
|
|
110
110
|
opaque network error.
|
|
111
111
|
* **The CSRF origin guard** is what makes ``LATTICEAI_CSRF_TRUSTED_ORIGINS``
|
|
112
112
|
load-bearing for the gateway (v11.6.0 gateway integration §3): a proxied
|
|
113
|
-
browser write — ``POST /models/load``, ``POST /engines/
|
|
114
|
-
``
|
|
115
|
-
cookie *and* ``Origin: …:{gateway port}``, and without the host's
|
|
113
|
+
browser write — ``POST /models/load``, ``POST /engines/prepare-model``,
|
|
114
|
+
``DELETE /models/unload/{model_id}`` — arrives carrying the browser's
|
|
115
|
+
session cookie *and* ``Origin: …:{gateway port}``, and without the host's
|
|
116
116
|
injected trust list this guard would answer 403.
|
|
117
117
|
"""
|
|
118
118
|
from fastapi import FastAPI
|
|
@@ -29,12 +29,16 @@ from __future__ import annotations
|
|
|
29
29
|
|
|
30
30
|
from typing import Any, List, Set, Tuple
|
|
31
31
|
|
|
32
|
-
#: ``(method, path)`` for each product route
|
|
32
|
+
#: ``(method, path)`` for each product route the worker still serves —
|
|
33
33
|
#: docs/v11.6.0_ONE_DOOR_PLAN.md §최종 Python 워커 표면, cross-checked against
|
|
34
34
|
#: the KEEP_WORKER table of the route scout, then narrowed by §W3b (ingest,
|
|
35
|
-
#: drain/rebuild, voice capture and the four document creators went native)
|
|
36
|
-
#: widened by §4a (the model pull came back)
|
|
37
|
-
#:
|
|
35
|
+
#: drain/rebuild, voice capture and the four document creators went native),
|
|
36
|
+
#: widened by §4a (the model pull came back) and narrowed again by v11.8.0,
|
|
37
|
+
#: which deleted the eight product routes with no caller anywhere in the tree:
|
|
38
|
+
#: the embedding-provider catalogue, both ``/tools/*`` document reads, the
|
|
39
|
+
#: multi-modal and voice capability probes, and three model-lifecycle doors
|
|
40
|
+
#: (see below). Paths are FastAPI's, converters included, so this compares to
|
|
41
|
+
#: ``APIRoute.path`` without normalisation.
|
|
38
42
|
#:
|
|
39
43
|
#: This tuple, through :func:`worker_route_keys`, is the **one** source of the
|
|
40
44
|
#: gateway's proxy allowlist. ``rust/fixtures/worker_allowlist.json`` is its
|
|
@@ -53,27 +57,16 @@ WORKER_ROUTES: Tuple[Tuple[str, str], ...] = (
|
|
|
53
57
|
("GET", "/health"),
|
|
54
58
|
# embedding production (drain/rebuild are native — W3b)
|
|
55
59
|
("GET", "/api/embeddings/status"),
|
|
56
|
-
(
|
|
57
|
-
#
|
|
60
|
+
# MLX model + engine lifecycle (in-process only). v11.8.0 dropped
|
|
61
|
+
# ``/models/switch``, ``/models/unload-all`` and ``/engines/pull-model``:
|
|
62
|
+
# nothing in the tree called them, and the surfaces that do this work send
|
|
63
|
+
# ``/models/load`` and ``/engines/prepare-model``, which switch and
|
|
64
|
+
# download as part of what they already do.
|
|
58
65
|
("GET", "/models"),
|
|
59
66
|
("POST", "/models/load"),
|
|
60
|
-
("POST", "/models/switch/{model_id:path}"),
|
|
61
67
|
("DELETE", "/models/unload/{model_id:path}"),
|
|
62
|
-
("DELETE", "/models/unload-all"),
|
|
63
68
|
("POST", "/engines/prepare-model"),
|
|
64
69
|
("POST", "/engines/prepare-model/stream"),
|
|
65
|
-
# The download itself is huggingface_hub / ollama running in *this*
|
|
66
|
-
# interpreter, which is the same reason the six lines above stay: model
|
|
67
|
-
# management is the worker's box. The gateway proxies it rather than
|
|
68
|
-
# shipping a native consent check in front of a 501 (v11.6.0 gateway
|
|
69
|
-
# integration §4a).
|
|
70
|
-
("POST", "/engines/pull-model"),
|
|
71
|
-
# document parser (create_* + upload are native — W3b)
|
|
72
|
-
("POST", "/tools/read_document"),
|
|
73
|
-
("GET", "/tools/pdf_pages"),
|
|
74
|
-
("GET", "/api/ingestion/multimodal"),
|
|
75
|
-
# local ASR status (POST /api/capture/voice is native — W3b)
|
|
76
|
-
("GET", "/api/capture/voice/status"),
|
|
77
70
|
)
|
|
78
71
|
|
|
79
72
|
#: Retired by W3b — ingest is native. Kept as an empty tuple so imports
|
|
@@ -93,8 +86,10 @@ WORKER_SEAM_ROUTES: Tuple[Tuple[str, str], ...] = (
|
|
|
93
86
|
#: The pure-compute seams of Wave 2.5 §W2 (``latticeai/api/worker_compute.py``).
|
|
94
87
|
#: Kept apart from :data:`WORKER_SEAM_ROUTES` because they age in the opposite
|
|
95
88
|
#: direction: the state seams above are retired once §W3 lands the native write
|
|
96
|
-
#: engine, while these
|
|
97
|
-
#: write. Mounted here and nowhere else.
|
|
89
|
+
#: engine, while these eight are what the worker is *for* once Rust owns every
|
|
90
|
+
#: write. Mounted here and nowhere else. ``/worker/multimodal/describe`` was the
|
|
91
|
+
#: ninth until v11.8.0 — it described an image for a native image ingest that
|
|
92
|
+
#: was never built, and no caller ever appeared.
|
|
98
93
|
WORKER_COMPUTE_ROUTES: Tuple[Tuple[str, str], ...] = (
|
|
99
94
|
("POST", "/worker/embed"),
|
|
100
95
|
("POST", "/worker/parse"),
|
|
@@ -103,7 +98,6 @@ WORKER_COMPUTE_ROUTES: Tuple[Tuple[str, str], ...] = (
|
|
|
103
98
|
("POST", "/worker/render/pptx"),
|
|
104
99
|
("POST", "/worker/render/pdf"),
|
|
105
100
|
("POST", "/worker/asr"),
|
|
106
|
-
("POST", "/worker/multimodal/describe"),
|
|
107
101
|
("POST", "/worker/extract"),
|
|
108
102
|
)
|
|
109
103
|
|
|
@@ -148,16 +142,15 @@ def phase_worker_routes(ctx: Any) -> None:
|
|
|
148
142
|
)
|
|
149
143
|
)
|
|
150
144
|
# The compute seams take the *resolved* embedder and the same injected
|
|
151
|
-
#
|
|
152
|
-
#
|
|
153
|
-
#
|
|
154
|
-
#
|
|
145
|
+
# transcriber the voice path holds, so a vector or a transcript produced
|
|
146
|
+
# through HTTP is the one this process would have produced in-process.
|
|
147
|
+
# ``getattr`` because a worker built without a Brain still boots — each seam
|
|
148
|
+
# reports the absence rather than failing construction.
|
|
155
149
|
ports = getattr(ctx, "MULTIMODAL_PORTS", None)
|
|
156
150
|
app.include_router(
|
|
157
151
|
create_worker_compute_router(
|
|
158
152
|
embedder=getattr(ctx, "EMBEDDER", None),
|
|
159
153
|
transcriber=getattr(ports, "transcriber", None),
|
|
160
|
-
multimodal_ports=ports,
|
|
161
154
|
require_user=ctx.require_user,
|
|
162
155
|
enforce_rate_limit=ctx.enforce_rate_limit,
|
|
163
156
|
)
|
|
@@ -81,9 +81,7 @@ class RuntimeContext:
|
|
|
81
81
|
# ── phase 4: the compute ports ───────────────────────────────────────
|
|
82
82
|
EMBEDDING_PROFILE: Any
|
|
83
83
|
EMBEDDER: Any
|
|
84
|
-
VOICE_CAPTURE: Any
|
|
85
84
|
MULTIMODAL_PORTS: Any
|
|
86
|
-
INGESTION_PIPELINE: Any
|
|
87
85
|
|
|
88
86
|
# ── phase 5: domain singletons ───────────────────────────────────────
|
|
89
87
|
model_router: Any
|
|
@@ -19,7 +19,7 @@ from dataclasses import dataclass
|
|
|
19
19
|
from pathlib import Path
|
|
20
20
|
from typing import Any, Dict, List
|
|
21
21
|
|
|
22
|
-
ARCHITECTURE_VERSION_TARGET = "11.
|
|
22
|
+
ARCHITECTURE_VERSION_TARGET = "11.9.0"
|
|
23
23
|
|
|
24
24
|
PREFERRED_REFACTORING_ORDER = [
|
|
25
25
|
"agent-runtime",
|
|
@@ -156,31 +156,28 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
156
156
|
["from fastapi import HTTPException", "raise HTTPException"],
|
|
157
157
|
)
|
|
158
158
|
)
|
|
159
|
-
# The Python agent loop package is gone.
|
|
160
|
-
#
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
root,
|
|
169
|
-
relative_path,
|
|
170
|
-
["AgentRuntime = SingleAgentRuntime"],
|
|
171
|
-
)
|
|
172
|
-
]
|
|
159
|
+
# The Python agent loop package is gone, and 11.8.0 removed the last of its
|
|
160
|
+
# gate tables (``core/agent_permission.py``) once the Rust goldens froze.
|
|
161
|
+
# The compatibility alias is scanned on the one Python file that still
|
|
162
|
+
# talks about permission mode: the worker seam the native loop calls.
|
|
163
|
+
agent_alias_forbidden = _forbidden_patterns(
|
|
164
|
+
root,
|
|
165
|
+
"latticeai/api/agent_worker_seam.py",
|
|
166
|
+
["AgentRuntime = SingleAgentRuntime"],
|
|
167
|
+
)
|
|
173
168
|
|
|
174
169
|
gates = [
|
|
175
170
|
ArchitectureGate(
|
|
176
171
|
id="agent-runtime",
|
|
177
172
|
title="AgentRuntime boundary",
|
|
178
173
|
status="complete" if (
|
|
179
|
-
_symbol_exists(
|
|
174
|
+
_symbol_exists(
|
|
175
|
+
"latticeai.api.agent_worker_seam.create_agent_worker_seam_router"
|
|
176
|
+
)
|
|
180
177
|
and not agent_alias_forbidden
|
|
181
178
|
) else "incomplete",
|
|
182
179
|
evidence=[
|
|
183
|
-
"
|
|
180
|
+
"rust/lattice-agent/src/permission.rs block_reason_for_tool (native owner)",
|
|
184
181
|
"latticeai.api.agent_worker_seam.create_agent_worker_seam_router",
|
|
185
182
|
"tests/unit/test_agent_worker_seam.py",
|
|
186
183
|
],
|
|
@@ -256,8 +253,10 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
256
253
|
title="Legacy shim sunset plan",
|
|
257
254
|
status="complete" if shim_report["status"] == "managed" else "incomplete",
|
|
258
255
|
evidence=[
|
|
256
|
+
# The standalone `check_legacy_debt.mjs` scanner retired once
|
|
257
|
+
# the shim layer hit zero; `legacy_shim_report` *is* the check
|
|
258
|
+
# now, and its status is what this gate reads.
|
|
259
259
|
"latticeai.services.architecture_readiness.legacy_shim_report",
|
|
260
|
-
"scripts/check_legacy_debt.mjs",
|
|
261
260
|
"tests/unit/test_legacy_root_shims.py",
|
|
262
261
|
],
|
|
263
262
|
),
|
|
@@ -291,7 +290,7 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
291
290
|
"refactoring_order": list(PREFERRED_REFACTORING_ORDER),
|
|
292
291
|
"boundaries": {
|
|
293
292
|
"agent-runtime": {
|
|
294
|
-
"owner": "
|
|
293
|
+
"owner": "lattice-agent::permission::block_reason_for_tool",
|
|
295
294
|
"surface": "/agent/llm + /agent/tool",
|
|
296
295
|
"status": "worker-seam",
|
|
297
296
|
},
|
|
@@ -8,7 +8,7 @@ import os
|
|
|
8
8
|
import re
|
|
9
9
|
import time
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Any,
|
|
11
|
+
from typing import Any, Mapping, Optional, Sequence
|
|
12
12
|
|
|
13
13
|
_SECRET_RE = re.compile(
|
|
14
14
|
r"(api[_-]?key|access[_-]?token|auth[_-]?token|bearer|client[_-]?secret|password|secret|token)",
|
|
@@ -104,27 +104,6 @@ def command_plan(
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
|
|
107
|
-
def command_plan_for_commands(
|
|
108
|
-
commands: Iterable[Sequence[Any]],
|
|
109
|
-
*,
|
|
110
|
-
name: str,
|
|
111
|
-
purpose: str = "installer",
|
|
112
|
-
cwd: Optional[str] = None,
|
|
113
|
-
metadata: Optional[Mapping[str, Any]] = None,
|
|
114
|
-
) -> dict[str, Any]:
|
|
115
|
-
normalized = [_normalize_command(command) for command in commands]
|
|
116
|
-
digest = _digest_payload({"purpose": purpose, "commands": normalized, "cwd": cwd or ""})
|
|
117
|
-
return {
|
|
118
|
-
"name": name,
|
|
119
|
-
"purpose": purpose,
|
|
120
|
-
"command_count": len(normalized),
|
|
121
|
-
"command_hash": digest,
|
|
122
|
-
"confirmation_token": digest[:16],
|
|
123
|
-
"cwd": cwd,
|
|
124
|
-
"metadata": dict(metadata or {}),
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
107
|
def verify_command_confirmation(
|
|
129
108
|
command: Sequence[Any],
|
|
130
109
|
provided_token: Optional[str],
|
|
@@ -7,8 +7,12 @@ evidence that is probed on disk, so a gate only reports ``complete`` when its
|
|
|
7
7
|
evidence actually resolves.
|
|
8
8
|
|
|
9
9
|
v11.6.0 retargeted every needle that named a deleted Python product module
|
|
10
|
-
onto the worker-only tree, the native owner, or the surviving test.
|
|
11
|
-
|
|
10
|
+
onto the worker-only tree, the native owner, or the surviving test. 11.8.0 did
|
|
11
|
+
the same for the five needles that named a Python evaluation harness or parity
|
|
12
|
+
generator whose subject is now native: they point at the cargo test or the
|
|
13
|
+
committed golden that actually guards the behaviour. The assertions themselves
|
|
14
|
+
were not deleted — an evidence path is repointed at the owner or it is a gate
|
|
15
|
+
that has stopped meaning anything.
|
|
12
16
|
"""
|
|
13
17
|
|
|
14
18
|
from __future__ import annotations
|
|
@@ -19,7 +23,7 @@ from typing import Any, Dict, List
|
|
|
19
23
|
|
|
20
24
|
from latticeai.services.architecture_readiness import architecture_readiness
|
|
21
25
|
|
|
22
|
-
PRODUCT_VERSION_TARGET = "11.
|
|
26
|
+
PRODUCT_VERSION_TARGET = "11.9.0"
|
|
23
27
|
|
|
24
28
|
|
|
25
29
|
@dataclass(frozen=True)
|
|
@@ -55,7 +59,11 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
55
59
|
title="Answers carry memory proof and citations",
|
|
56
60
|
evidence=[
|
|
57
61
|
"latticeai/api/search.py::embeddings_status",
|
|
58
|
-
|
|
62
|
+
# 11.8.0: the Python answer-quality harness was deleted with the
|
|
63
|
+
# loop it drove. The committed agent/retrieval goldens are what a
|
|
64
|
+
# proof is checked against now, and they are regenerated by no
|
|
65
|
+
# Python — the manifest is the frozen grid itself.
|
|
66
|
+
"rust/fixtures/golden/manifest.json",
|
|
59
67
|
],
|
|
60
68
|
),
|
|
61
69
|
ProductGate(
|
|
@@ -66,7 +74,7 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
66
74
|
"latticeai/tools/documents.py::read_document",
|
|
67
75
|
"latticeai/tools/filesystem.py::read_file",
|
|
68
76
|
"latticeai/core/tool_governor.py::classify_tool_call",
|
|
69
|
-
"
|
|
77
|
+
"rust/lattice-agent/src/permission.rs::pub fn block_reason_for_tool",
|
|
70
78
|
"tests/unit/test_worker_compute.py::test_the_docx_bytes_open_as_a_document_with_the_blocks_that_were_sent",
|
|
71
79
|
"tests/unit/test_tool_registry.py::test_execute_tool_uses_registry",
|
|
72
80
|
],
|
|
@@ -111,10 +119,10 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
111
119
|
f"docs/CHANGELOG.md::## [{PRODUCT_VERSION_TARGET}]",
|
|
112
120
|
"FEATURE_STATUS.md",
|
|
113
121
|
f"RELEASE_NOTES_v{PRODUCT_VERSION_TARGET}.md",
|
|
114
|
-
"
|
|
122
|
+
"rust/lattice-agent/src/permission.rs::pub fn block_reason_for_tool",
|
|
115
123
|
"rust/lattice-agent/src/lib.rs::pub mod agentloop",
|
|
116
124
|
"latticeai/api/agent_worker_seam.py::create_agent_worker_seam_router",
|
|
117
|
-
"
|
|
125
|
+
"rust/lattice-agent/src/permission.rs::pub fn non_auto_plan_steps",
|
|
118
126
|
"latticeai/worker_app.py::create_worker_app",
|
|
119
127
|
"latticeai/worker_app.py::def create_worker_app",
|
|
120
128
|
"latticeai/services/architecture_readiness.py::lattice-architecture-contract/v1",
|
|
@@ -136,22 +144,36 @@ PRODUCT_GATES: List[ProductGate] = [
|
|
|
136
144
|
title="Graph and ingestion integration coverage guards the Brain",
|
|
137
145
|
evidence=[
|
|
138
146
|
"tests/unit/test_worker_compute.py::test_extract_returns_the_structures_ingestion_consumes",
|
|
139
|
-
|
|
147
|
+
# 11.8.0: `POST /worker/multimodal/describe` was deleted with the
|
|
148
|
+
# rest of the caller-less surface, so its seam test went too. The
|
|
149
|
+
# guarantee this gate needs — that an image becomes the exact facts
|
|
150
|
+
# and metadata an ingest writes — is asserted directly against
|
|
151
|
+
# Brain Core's `extract_image_facts`, which is where the seam only
|
|
152
|
+
# ever forwarded to. Repointed to the surviving equivalent rather
|
|
153
|
+
# than dropped: the gate still has to bite on image ingestion.
|
|
154
|
+
"tests/unit/test_cov_p1b_multimodal.py::test_extract_image_facts_unreadable_skipped_and_full_ports",
|
|
140
155
|
"tests/unit/test_t3_vision_embedding.py",
|
|
141
156
|
"tests/unit/test_lattice_brain_isolation.py",
|
|
142
|
-
|
|
157
|
+
# Chunking is native; the parity gate is the cargo test over the
|
|
158
|
+
# committed rust/fixtures/chunking goldens.
|
|
159
|
+
"rust/lattice-ingest/tests/chunking_parity.rs",
|
|
143
160
|
],
|
|
144
161
|
),
|
|
145
162
|
ProductGate(
|
|
146
163
|
id="quality-gates",
|
|
147
164
|
title="Quality is guarded by repeatable gates",
|
|
148
165
|
evidence=[
|
|
149
|
-
"
|
|
166
|
+
"rust/lattice-retrieval/tests/parity.rs",
|
|
150
167
|
"scripts/product_readiness.py",
|
|
151
168
|
"tests/unit/test_product_readiness.py",
|
|
152
169
|
"tests/visual/v3.surfaces.spec.js::Brain Chat Home",
|
|
153
170
|
".github/workflows/ci.yml::scripts/product_readiness.py",
|
|
154
|
-
|
|
171
|
+
# 11.8.0: the release workflow's lint step folded into the CI leg
|
|
172
|
+
# that already runs it. What this gate has to prove about a release
|
|
173
|
+
# is that a release *runs the readiness gate*, which is the needle
|
|
174
|
+
# below — naming a step by its shell text made the assertion track
|
|
175
|
+
# the workflow's wording rather than its guarantee.
|
|
176
|
+
".github/workflows/release.yml::scripts/product_readiness.py",
|
|
155
177
|
],
|
|
156
178
|
),
|
|
157
179
|
]
|
|
@@ -28,15 +28,18 @@ either, and both say so the same way.
|
|
|
28
28
|
|
|
29
29
|
v11.6.0 took the *ingest* half away: ``POST /api/capture/voice`` is a native
|
|
30
30
|
route that stores the memo itself and asks ``POST /worker/asr`` for the words.
|
|
31
|
-
|
|
32
|
-
answer
|
|
31
|
+
v11.8.0 took the report away too — ``GET /api/capture/voice/status`` had no
|
|
32
|
+
caller, and a capability answer nobody asks for is a second copy of the same
|
|
33
|
+
facts ``/worker/asr`` already returns per call. What is left is the port
|
|
34
|
+
itself: the transcriber, the two module constants ``/worker/asr`` enforces
|
|
35
|
+
against, and the conversion into the shape Brain Core accepts.
|
|
33
36
|
"""
|
|
34
37
|
|
|
35
38
|
from __future__ import annotations
|
|
36
39
|
|
|
37
40
|
import logging
|
|
38
41
|
from pathlib import Path
|
|
39
|
-
from typing import TYPE_CHECKING,
|
|
42
|
+
from typing import TYPE_CHECKING, Callable, Optional
|
|
40
43
|
|
|
41
44
|
if TYPE_CHECKING: # import-time isolation: the port is a callable, not a class
|
|
42
45
|
from lattice_brain.multimodal import MultimodalPorts
|
|
@@ -62,35 +65,12 @@ class TranscriptionUnavailable(RuntimeError):
|
|
|
62
65
|
|
|
63
66
|
|
|
64
67
|
class VoiceCaptureService:
|
|
65
|
-
"""The local transcriber, and the honest
|
|
68
|
+
"""The local transcriber port, and the honest refusal when there is none."""
|
|
66
69
|
|
|
67
70
|
def __init__(
|
|
68
|
-
self,
|
|
69
|
-
*,
|
|
70
|
-
transcriber: Optional[Callable[[str], str]] = None,
|
|
71
|
-
max_bytes: int = MAX_AUDIO_BYTES,
|
|
71
|
+
self, *, transcriber: Optional[Callable[[str], str]] = None
|
|
72
72
|
) -> None:
|
|
73
73
|
self._transcriber = transcriber
|
|
74
|
-
self._max_bytes = max(1, int(max_bytes))
|
|
75
|
-
|
|
76
|
-
# ── capability ───────────────────────────────────────────────────────
|
|
77
|
-
def status(self) -> Dict[str, Any]:
|
|
78
|
-
"""What this install can actually do with a voice memo, honestly."""
|
|
79
|
-
return {
|
|
80
|
-
# Storing the memo is native (``POST /api/capture/voice`` in
|
|
81
|
-
# lattice-platform), so capture is always available to a caller
|
|
82
|
-
# that reached this answer through the gateway. Only the
|
|
83
|
-
# transcriber is a fact about this process.
|
|
84
|
-
"capture": True,
|
|
85
|
-
"transcription": self._transcriber is not None,
|
|
86
|
-
"supported_extensions": sorted(SUPPORTED_AUDIO_EXTENSIONS),
|
|
87
|
-
"max_bytes": self._max_bytes,
|
|
88
|
-
"detail": (
|
|
89
|
-
"음성 메모를 글로 바꿔 Brain에 저장합니다."
|
|
90
|
-
if self._transcriber is not None
|
|
91
|
-
else "이 컴퓨터에는 음성 인식기가 없어서, 메모는 저장되지만 글로 바뀌지는 않습니다."
|
|
92
|
-
),
|
|
93
|
-
}
|
|
94
74
|
|
|
95
75
|
def multimodal_ports(self) -> "MultimodalPorts":
|
|
96
76
|
"""This service's transcriber, shaped for the ingestion pipeline.
|
|
@@ -41,54 +41,14 @@ _PLATFORM = platform.system() # "Darwin" | "Windows" | "Linux"
|
|
|
41
41
|
AGENT_ROOT = Path(os.getenv("LATTICEAI_AGENT_ROOT") or "agent_workspace").resolve()
|
|
42
42
|
MAX_FILE_BYTES = 512_000
|
|
43
43
|
MAX_COMMAND_SECONDS = 30
|
|
44
|
-
MAX_BUILD_SECONDS = 180
|
|
45
|
-
MAX_DEPLOY_SECONDS = 300
|
|
46
44
|
MAX_COMMAND_OUTPUT = 12_000
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"chown",
|
|
55
|
-
"curl",
|
|
56
|
-
"wget",
|
|
57
|
-
"ssh",
|
|
58
|
-
"scp",
|
|
59
|
-
"rsync",
|
|
60
|
-
"dd",
|
|
61
|
-
"mkfs",
|
|
62
|
-
"diskutil",
|
|
63
|
-
"launchctl",
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
ALLOWED_COMMANDS = {
|
|
67
|
-
"pwd",
|
|
68
|
-
"ls",
|
|
69
|
-
"find",
|
|
70
|
-
"cat",
|
|
71
|
-
"head",
|
|
72
|
-
"tail",
|
|
73
|
-
"wc",
|
|
74
|
-
"rg",
|
|
75
|
-
"git",
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
BUILD_SCRIPT_NAMES = {"build", "compile", "typecheck", "test"}
|
|
79
|
-
DEPLOY_SCRIPT_NAMES = {
|
|
80
|
-
"deploy",
|
|
81
|
-
"preview",
|
|
82
|
-
"release",
|
|
83
|
-
"package",
|
|
84
|
-
"dist",
|
|
85
|
-
"make",
|
|
86
|
-
"build:installer",
|
|
87
|
-
"build:pkg",
|
|
88
|
-
"build:exe",
|
|
89
|
-
"package:mac",
|
|
90
|
-
"package:win",
|
|
91
|
-
}
|
|
46
|
+
# The build/deploy script allow-lists and their longer timeouts used to live
|
|
47
|
+
# here too. `run_build` / `run_deploy` are native (`lattice-agent`'s
|
|
48
|
+
# `tools::shell`, which carries its own `BUILD_SCRIPT_NAMES`,
|
|
49
|
+
# `DEPLOY_SCRIPT_NAMES`, `MAX_BUILD_SECONDS` and `MAX_DEPLOY_SECONDS`), so the
|
|
50
|
+
# copies here had no reader in this interpreter — a second, unenforced
|
|
51
|
+
# allow-list that could drift from the one that actually gates a subprocess.
|
|
92
52
|
|
|
93
53
|
ALLOWED_GIT_SUBCOMMANDS = {"status", "diff", "log", "show"}
|
|
94
54
|
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Read-only git tools (no shell, allow-listed subcommands).
|
|
2
|
+
|
|
3
|
+
``run_command`` and its sandbox left the worker in v11.6.0 §W4 — execution is
|
|
4
|
+
``lattice-agent``'s. The flag/binary allowlists that only that validator read
|
|
5
|
+
went with it in 11.8.0; what is left here is the four git readers ``POST
|
|
6
|
+
/agent/tool`` still dispatches, and the two argument guards they apply:
|
|
7
|
+
remote targets are refused outright, and a revision may not carry ``..``,
|
|
8
|
+
``:``, ``/``, ``\\`` or a leading ``-``.
|
|
9
|
+
"""
|
|
2
10
|
|
|
3
11
|
from __future__ import annotations
|
|
4
12
|
|
|
@@ -15,20 +23,6 @@ from latticeai.tools import (
|
|
|
15
23
|
_resolve_path,
|
|
16
24
|
)
|
|
17
25
|
|
|
18
|
-
# find(1) flags that execute or delete; checked in run_command.
|
|
19
|
-
_BLOCKED_FIND_FLAGS = {
|
|
20
|
-
"-delete",
|
|
21
|
-
"-exec",
|
|
22
|
-
"-execdir",
|
|
23
|
-
"-fls",
|
|
24
|
-
"-fprint",
|
|
25
|
-
"-fprintf",
|
|
26
|
-
"-ok",
|
|
27
|
-
"-okdir",
|
|
28
|
-
}
|
|
29
|
-
_BLOCKED_RG_FLAGS = {"--pre", "--pre-glob"}
|
|
30
|
-
_SAFE_EXECUTABLE_PATH = "/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin:/usr/local/bin"
|
|
31
|
-
|
|
32
26
|
|
|
33
27
|
def _run_git(args: List[str], cwd: Optional[str] = None) -> Dict[str, Any]:
|
|
34
28
|
if not args:
|
|
@@ -11,12 +11,6 @@ from latticeai.services.p_reinforce import BRAIN_DIR, STRUCTURE
|
|
|
11
11
|
from latticeai.tools import ToolError
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def _safe_brain_folder(folder: str) -> str:
|
|
15
|
-
if folder not in STRUCTURE:
|
|
16
|
-
raise ToolError(f"Unknown knowledge folder: {folder}")
|
|
17
|
-
return folder
|
|
18
|
-
|
|
19
|
-
|
|
20
14
|
def _scope_digest(kind: str, value: str) -> str:
|
|
21
15
|
digest = hashlib.sha256(f"{kind}\0{value}".encode("utf-8")).hexdigest()[:24]
|
|
22
16
|
return f"{kind}-{digest}"
|