ltcai 11.7.0 → 12.0.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 +100 -76
- package/docs/BENCHMARKS.md +9 -2
- package/docs/CHANGELOG.md +249 -0
- package/docs/CI_AND_RELEASE_GATES.md +126 -41
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +271 -103
- package/docs/ENTERPRISE.md +1 -1
- package/docs/LEGACY_COMPATIBILITY.md +10 -6
- package/docs/MULTI_AGENT_RUNTIME.md +4 -4
- package/docs/ONBOARDING.md +16 -4
- package/docs/OPERATIONS.md +14 -1
- package/docs/PERMISSION_MODE.md +14 -9
- package/docs/REALTIME_COLLABORATION.md +1 -1
- package/docs/ROADMAP.md +113 -0
- package/docs/TRUST_MODEL.md +28 -7
- package/docs/USABILITY_AUDIT.md +5 -0
- package/docs/WHY_LATTICE.md +13 -5
- package/docs/WORKFLOW_DESIGNER.md +2 -2
- package/docs/kg-schema.md +57 -7
- package/docs/mcp-tools.md +93 -82
- 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/extraction.py +459 -105
- package/lattice_brain/graph/_kg_common/normalize.py +305 -0
- package/lattice_brain/graph/_kg_common/patterns.py +275 -0
- package/lattice_brain/graph/_kg_common/relations.py +12 -3
- package/lattice_brain/graph/_kg_common/sections.py +107 -0
- package/lattice_brain/graph/_kg_common/text.py +14 -450
- package/lattice_brain/graph/_kg_constants.py +7 -0
- 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 +44 -1
- package/latticeai/api/models.py +18 -110
- package/latticeai/api/search.py +7 -30
- package/latticeai/api/worker_compute.py +127 -106
- package/latticeai/api/worker_seams.py +17 -2
- package/latticeai/core/embedding_providers/__init__.py +16 -0
- package/latticeai/core/embedding_providers/autodetect.py +302 -0
- package/latticeai/core/embedding_providers/base.py +25 -0
- package/latticeai/core/embedding_providers/profiles.py +44 -0
- package/latticeai/core/embedding_providers/text.py +74 -8
- 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/core/vector_index/__init__.py +61 -0
- package/latticeai/core/vector_index/hnsw.py +383 -0
- package/latticeai/core/vector_index/sidecar.py +329 -0
- package/latticeai/models/router/catalog.py +2 -2
- package/latticeai/models/router/generation.py +176 -30
- package/latticeai/models/router/loading.py +150 -9
- package/latticeai/runtime/access_runtime.py +7 -4
- package/latticeai/runtime/brain_runtime.py +43 -9
- 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 +29 -27
- 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 +39 -12
- package/latticeai/services/search_service.py +7 -0
- package/latticeai/services/voice_capture.py +8 -28
- package/latticeai/tools/__init__.py +12 -47
- package/latticeai/tools/commands.py +9 -15
- package/latticeai/tools/documents.py +12 -0
- package/latticeai/tools/knowledge.py +0 -6
- package/latticeai/tools/markup.py +152 -0
- package/package.json +4 -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 +4 -1
- package/scripts/export_openapi.py +5 -4
- package/scripts/gen_worker_allowlist_fixture.py +2 -2
- package/scripts/openapi_route_families.json +19 -74
- package/scripts/publish_release.mjs +157 -0
- package/scripts/release_screen_claims.json +144 -28
- package/src-tauri/Cargo.lock +45 -10
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +47 -41
- package/static/app/assets/Act-Cf1L2709.js +2 -0
- package/static/app/assets/AdminConsole-DPAbLTYV.js +1 -0
- package/static/app/assets/Brain-DqamGrj-.js +2 -0
- package/static/app/assets/BrainHome-MHe2_RYs.js +2 -0
- package/static/app/assets/BrainSignals-CQPPfyyH.js +1 -0
- package/static/app/assets/Capture-DGdIH_Zc.js +1 -0
- package/static/app/assets/Chronicle-C-UlCJoJ.js +1 -0
- package/static/app/assets/CommandPalette-WNT4EqUX.js +1 -0
- package/static/app/assets/DigitalBrainExplorer-CEBH5Cwc.js +321 -0
- package/static/app/assets/Library-C6xd1dlf.js +1 -0
- package/static/app/assets/LivingBrain-BEk-0ohw.js +1 -0
- package/static/app/assets/ProductFlow-CZLm5iXh.js +1 -0
- package/static/app/assets/QueryClientProvider-B3OjqSyJ.js +1 -0
- package/static/app/assets/{ReviewCard-HXRle3qq.js → ReviewCard-CEHG6evf.js} +2 -2
- package/static/app/assets/RunsListPanel-CLtEJSRW.js +1 -0
- package/static/app/assets/System-CAxwBUXw.js +1 -0
- package/static/app/assets/WorkflowGraph-Dj10RuGE.js +1 -0
- package/static/app/assets/WorkflowsPanel-Kyeh_LIT.js +2 -0
- package/static/app/assets/actHelpers-CtSmK9Dw.js +1 -0
- package/static/app/assets/arrow-left-CRl5EO4D.js +1 -0
- package/static/app/assets/{bot-Cn8bWRuq.js → bot-DhUGRel2.js} +1 -1
- package/static/app/assets/brain-CLkhHsHF.js +1 -0
- package/static/app/assets/button-CmaEqG1T.js +1 -0
- package/static/app/assets/circle-check-CFgejkOS.js +1 -0
- package/static/app/assets/{circle-pause-CmzC_apg.js → circle-pause-l96izbxj.js} +1 -1
- package/static/app/assets/{circle-play-D8mW2aQ7.js → circle-play-CrZa25_q.js} +1 -1
- package/static/app/assets/{cpu-DZcdd0PZ.js → cpu-BaXudqwl.js} +1 -1
- package/static/app/assets/{download-bv1KEPGQ.js → download-hCVFPiyc.js} +1 -1
- package/static/app/assets/{folder-open-d-Pip5gr.js → folder-open-CHL82Yp7.js} +1 -1
- package/static/app/assets/{hard-drive-D20iavUb.js → hard-drive-DDzET7lk.js} +1 -1
- package/static/app/assets/index-CB93CZWW.css +2 -0
- package/static/app/assets/index-D2H-wSl6.js +13 -0
- package/static/app/assets/input-Df1CAY_I.js +1 -0
- package/static/app/assets/jsx-runtime-bzQ4Vb5N.js +1 -0
- package/static/app/assets/{link-2-BPJOFlAy.js → link-2-xNnTIX1_.js} +1 -1
- package/static/app/assets/{permissionCopy-ChdJd493.js → permissionCopy-D3aWHco-.js} +1 -1
- package/static/app/assets/primitives-BioD2slS.js +1 -0
- package/static/app/assets/search-BzBw8YcW.js +1 -0
- package/static/app/assets/{share-2-YNX_NtMU.js → share-2-FkzGf8Df.js} +1 -1
- package/static/app/assets/{shield-alert-DuQ3zrVL.js → shield-alert-B3dwzik4.js} +1 -1
- package/static/app/assets/sourceMeta-DQSY_tah.js +1 -0
- package/static/app/assets/textarea-P8o6pvOP.js +1 -0
- package/static/app/assets/useFocusTrap-hswOIkXE.js +1 -0
- package/static/app/assets/useMutation-OJLrYSRA.js +1 -0
- package/static/app/assets/workspace-BCuk3Ku9.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/Act-BPcVAbOL.js +0 -1
- package/static/app/assets/AdminConsole-Bw1ATQL0.js +0 -1
- package/static/app/assets/Brain-CT92Kos0.js +0 -321
- package/static/app/assets/BrainHome-CFBkt1K_.js +0 -2
- package/static/app/assets/BrainSignals-ReLWF2H8.js +0 -1
- package/static/app/assets/Capture-BsTokYkk.js +0 -1
- package/static/app/assets/Chronicle-B6f0T9id.js +0 -1
- package/static/app/assets/CommandPalette-CuvjTv1u.js +0 -1
- package/static/app/assets/Library-BGJbG9Hd.js +0 -1
- package/static/app/assets/LivingBrain-DGYK_Jsa.js +0 -1
- package/static/app/assets/ProductFlow-DXBC6brE.js +0 -1
- package/static/app/assets/System-CMHSO9qM.js +0 -1
- package/static/app/assets/arrow-left-BfmkskWx.js +0 -1
- package/static/app/assets/brain-CQJberbE.js +0 -1
- package/static/app/assets/button-Ct9f2_oT.js +0 -1
- package/static/app/assets/circle-check-DruOxB-4.js +0 -1
- package/static/app/assets/index-D9x-kSNy.css +0 -2
- package/static/app/assets/index-Do83hDzJ.js +0 -10
- package/static/app/assets/input-BLXVNmj1.js +0 -1
- package/static/app/assets/primitives-Cv5tbZBY.js +0 -1
- package/static/app/assets/search-CT9aho2j.js +0 -1
- package/static/app/assets/textarea-DqwLnli4.js +0 -1
- package/static/app/assets/useFocusTrap-ZVI98jaW.js +0 -1
- package/static/app/assets/useMutation-CVC4qv_D.js +0 -1
- package/static/app/assets/useQuery-C7BeG4HU.js +0 -1
- package/static/app/assets/utils-CiFtIdZq.js +0 -4
- package/static/app/assets/workspace-DQz9vIId.js +0 -1
package/latticeai/api/tools.py
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
"""The document parser routes — the two ``/tools/*`` that are pure compute.
|
|
2
|
-
|
|
3
|
-
This module used to be the direct tool surface: ~30 ``/tools/*`` routes, the
|
|
4
|
-
upload door, the MCP catalogue, computer-use, the permission gateway and the
|
|
5
|
-
local-file browser, all composed into one router. Every one of those is a write,
|
|
6
|
-
an OS actuator, an exec, or platform state, and v11.6.0 serves them from
|
|
7
|
-
``lattice-host``.
|
|
8
|
-
|
|
9
|
-
Two survive, because parsing a document is compute and nothing else:
|
|
10
|
-
|
|
11
|
-
``POST /tools/read_document``
|
|
12
|
-
Text plus metadata out of a ``.pdf`` / ``.docx`` / ``.xlsx`` / ``.pptx`` /
|
|
13
|
-
plain-text file. The same parser matrix ``POST /worker/parse`` wraps.
|
|
14
|
-
|
|
15
|
-
``GET /tools/pdf_pages``
|
|
16
|
-
Up to twenty PDF pages rasterised to base64 PNG through pypdfium2.
|
|
17
|
-
|
|
18
|
-
**The approval hop is gone, and the confinement is now absolute.** Both routes
|
|
19
|
-
used to accept an approval token minted by ``/permissions/*`` and, with one,
|
|
20
|
-
read a file anywhere on the disk. ``/permissions/*`` is a native platform route
|
|
21
|
-
now and the approval queue is native state, so a token this process is handed is
|
|
22
|
-
one it cannot verify — and a check against an always-empty local queue is not a
|
|
23
|
-
weaker guard, it is a guard that refuses everything while looking like it works.
|
|
24
|
-
Both routes therefore refuse outright outside ``AGENT_ROOT``. Reading an
|
|
25
|
-
arbitrary path on the user's behalf is the host's call to make, with the
|
|
26
|
-
approval record it actually holds.
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
from __future__ import annotations
|
|
30
|
-
|
|
31
|
-
import base64
|
|
32
|
-
import io
|
|
33
|
-
import logging
|
|
34
|
-
from pathlib import Path
|
|
35
|
-
from typing import Optional
|
|
36
|
-
|
|
37
|
-
from fastapi import APIRouter, Request
|
|
38
|
-
from pydantic import BaseModel
|
|
39
|
-
|
|
40
|
-
from lattice_brain.runtime.hooks import dispatch_tool
|
|
41
|
-
from latticeai.core.messages import http_error, resolve_language
|
|
42
|
-
from latticeai.tools import AGENT_ROOT, ToolError, read_document
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class ToolPathRequest(BaseModel):
|
|
46
|
-
path: str = "."
|
|
47
|
-
approval_token: Optional[str] = None
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def create_tools_router(*, require_user) -> APIRouter:
|
|
51
|
-
router = APIRouter()
|
|
52
|
-
|
|
53
|
-
def _confined(request: Request, raw: str) -> Path:
|
|
54
|
-
"""Resolve ``raw`` under ``AGENT_ROOT`` or refuse.
|
|
55
|
-
|
|
56
|
-
Relative paths are taken from the workspace root, which is what every
|
|
57
|
-
caller of these two routes sends. An absolute path is accepted only when
|
|
58
|
-
it is already inside the workspace, so ``../`` and ``/etc/passwd`` reach
|
|
59
|
-
the same refusal by the same rule.
|
|
60
|
-
"""
|
|
61
|
-
candidate = Path(raw).expanduser()
|
|
62
|
-
target = (
|
|
63
|
-
candidate.resolve()
|
|
64
|
-
if candidate.is_absolute()
|
|
65
|
-
else (AGENT_ROOT / candidate).resolve()
|
|
66
|
-
)
|
|
67
|
-
if target != AGENT_ROOT and AGENT_ROOT not in target.parents:
|
|
68
|
-
raise http_error(403, "tools.path_outside_workspace", resolve_language(request))
|
|
69
|
-
return target
|
|
70
|
-
|
|
71
|
-
@router.post("/tools/read_document")
|
|
72
|
-
async def tools_read_document(req: ToolPathRequest, request: Request):
|
|
73
|
-
current_user = require_user(request)
|
|
74
|
-
target = _confined(request, req.path)
|
|
75
|
-
try:
|
|
76
|
-
result = dispatch_tool(
|
|
77
|
-
None,
|
|
78
|
-
"read_document",
|
|
79
|
-
{"path": str(target)},
|
|
80
|
-
lambda: read_document(str(target)),
|
|
81
|
-
user_email=current_user,
|
|
82
|
-
source="workspace",
|
|
83
|
-
)
|
|
84
|
-
except ToolError as exc:
|
|
85
|
-
raise http_error(400, "worker_compute.parse_failed", resolve_language(request)) from exc
|
|
86
|
-
return {"status": "ok", "workspace": str(AGENT_ROOT), "result": result}
|
|
87
|
-
|
|
88
|
-
@router.get("/tools/pdf_pages")
|
|
89
|
-
async def tools_pdf_pages(path: str, request: Request, approval_token: Optional[str] = None):
|
|
90
|
-
"""Render PDF pages as base64 PNG images using pypdfium2 (Apache-2.0)."""
|
|
91
|
-
require_user(request)
|
|
92
|
-
# Accepted and ignored: the host still sends the token it minted, and
|
|
93
|
-
# rejecting the request for carrying one would break a caller for a
|
|
94
|
-
# field this process no longer has any way to check.
|
|
95
|
-
_ = approval_token
|
|
96
|
-
target = _confined(request, path)
|
|
97
|
-
if not target.exists() or not target.is_file():
|
|
98
|
-
raise http_error(404, "common.file_not_found", resolve_language(request))
|
|
99
|
-
import pypdfium2 as pdfium
|
|
100
|
-
doc = None
|
|
101
|
-
try:
|
|
102
|
-
doc = pdfium.PdfDocument(str(target))
|
|
103
|
-
total = len(doc)
|
|
104
|
-
pages = []
|
|
105
|
-
for i in range(min(total, 20)): # 최대 20페이지
|
|
106
|
-
page = doc[i]
|
|
107
|
-
bitmap = page.render(scale=1.5)
|
|
108
|
-
pil_image = bitmap.to_pil()
|
|
109
|
-
buf = io.BytesIO()
|
|
110
|
-
pil_image.save(buf, format="PNG")
|
|
111
|
-
b64 = base64.b64encode(buf.getvalue()).decode()
|
|
112
|
-
pages.append({"page": i + 1, "b64": b64})
|
|
113
|
-
return {"total": total, "pages": pages}
|
|
114
|
-
except Exception as e:
|
|
115
|
-
raise http_error(500, "tools.pdf_render_failed", resolve_language(request), reason=e)
|
|
116
|
-
finally:
|
|
117
|
-
if doc is not None:
|
|
118
|
-
try:
|
|
119
|
-
doc.close()
|
|
120
|
-
except Exception as e:
|
|
121
|
-
logging.warning("pypdfium2 doc close failed: %s", e)
|
|
122
|
-
|
|
123
|
-
return router
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
__all__ = ["ToolPathRequest", "create_tools_router"]
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"""Voice capability router (v9.9.7).
|
|
2
|
-
|
|
3
|
-
``GET /api/capture/voice/status`` — what this machine can actually do with a
|
|
4
|
-
voice memo. Capture and storage are native (``POST /api/capture/voice`` moved
|
|
5
|
-
to ``lattice-platform`` in §W3b, and calls ``POST /worker/asr`` for the
|
|
6
|
-
transcript); whether a local transcriber exists at all is a fact about this
|
|
7
|
-
process, so the probe stays here.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from __future__ import annotations
|
|
11
|
-
|
|
12
|
-
from typing import Any, Callable
|
|
13
|
-
|
|
14
|
-
from fastapi import APIRouter, Request
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def create_voice_capture_router(
|
|
18
|
-
*,
|
|
19
|
-
service: Any,
|
|
20
|
-
require_user: Callable[[Request], Any],
|
|
21
|
-
) -> APIRouter:
|
|
22
|
-
router = APIRouter()
|
|
23
|
-
|
|
24
|
-
@router.get("/api/capture/voice/status")
|
|
25
|
-
async def voice_status(request: Request):
|
|
26
|
-
require_user(request)
|
|
27
|
-
return service.status()
|
|
28
|
-
|
|
29
|
-
return router
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
__all__ = ["create_voice_capture_router"]
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
"""Agent-loop permission-mode gates (v9.9.8) — the two the parity fixtures pin.
|
|
2
|
-
|
|
3
|
-
These were the Python loop's mode tables, called by ``SingleAgentRuntime`` and
|
|
4
|
-
``build_agent_runtime``. Orchestration moved to ``lattice-agent`` in v11.6.0 and
|
|
5
|
-
the Python loop is gone, so **nothing in the worker imports this module**.
|
|
6
|
-
|
|
7
|
-
It survives for one reason, stated so it is not read as a leftover:
|
|
8
|
-
``scripts/generate_agent_parity_fixtures.py`` produces the committed goldens
|
|
9
|
-
``rust/fixtures`` holds for the Rust loop's permission gates, and it derives
|
|
10
|
-
them from :func:`block_reason_for_tool` and :func:`non_auto_plan_steps` here.
|
|
11
|
-
Deleting these two would leave the Rust side asserting against fixtures no
|
|
12
|
-
Python could regenerate — the fixtures would still pass, and would stop meaning
|
|
13
|
-
anything. The rest of the module (``call_mode_source``, ``resolve_deps_mode``,
|
|
14
|
-
``approval_requirements_for``) went with the loop that called it.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
from __future__ import annotations
|
|
18
|
-
|
|
19
|
-
from typing import Any, List, Mapping, Optional, Sequence
|
|
20
|
-
|
|
21
|
-
from latticeai.core.permission_mode import (
|
|
22
|
-
PermissionMode,
|
|
23
|
-
effective_auto_approve,
|
|
24
|
-
is_circuit_breaker,
|
|
25
|
-
normalize_mode,
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def non_auto_plan_steps(
|
|
30
|
-
mode: PermissionMode | str,
|
|
31
|
-
steps: Sequence[Mapping[str, Any]],
|
|
32
|
-
tool_governance: Mapping[str, Mapping[str, Any]],
|
|
33
|
-
*,
|
|
34
|
-
governed_tools: Optional[Any] = None,
|
|
35
|
-
) -> List[Any]:
|
|
36
|
-
"""Plan steps that still need approval under the active mode."""
|
|
37
|
-
mode = normalize_mode(mode)
|
|
38
|
-
governed = frozenset(governed_tools or ())
|
|
39
|
-
non_auto: List[Any] = []
|
|
40
|
-
for step in steps:
|
|
41
|
-
name = step.get("action")
|
|
42
|
-
if not name:
|
|
43
|
-
continue
|
|
44
|
-
if name in governed and mode == PermissionMode.STRICT:
|
|
45
|
-
# Strict keeps governor tools out of the plan-level block (per-call).
|
|
46
|
-
continue
|
|
47
|
-
policy = dict(tool_governance.get(name) or {
|
|
48
|
-
"auto_approve": False, "risk": "write", "destructive": False,
|
|
49
|
-
"shell": False, "network": False, "sandbox": "workspace", "rollback": "none",
|
|
50
|
-
})
|
|
51
|
-
if effective_auto_approve(mode, str(name), policy):
|
|
52
|
-
continue
|
|
53
|
-
non_auto.append(name)
|
|
54
|
-
return non_auto
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def block_reason_for_tool(
|
|
58
|
-
mode: PermissionMode | str,
|
|
59
|
-
name: str,
|
|
60
|
-
policy: Mapping[str, Any],
|
|
61
|
-
args: Mapping[str, Any],
|
|
62
|
-
*,
|
|
63
|
-
approved_by_human: bool = False,
|
|
64
|
-
governor_allows_additive: bool = False,
|
|
65
|
-
) -> Optional[str]:
|
|
66
|
-
"""Return a block reason, or None when the call may proceed."""
|
|
67
|
-
mode = normalize_mode(mode)
|
|
68
|
-
breaker = is_circuit_breaker(name, policy, args)
|
|
69
|
-
if breaker:
|
|
70
|
-
return f"BLOCKED: {breaker}"
|
|
71
|
-
if policy.get("risk") == "destructive" or policy.get("destructive"):
|
|
72
|
-
return f"BLOCKED: destructive action '{name}' not permitted in agent mode."
|
|
73
|
-
if approved_by_human or governor_allows_additive:
|
|
74
|
-
return None
|
|
75
|
-
if effective_auto_approve(mode, name, policy, args=args):
|
|
76
|
-
return None
|
|
77
|
-
if policy.get("auto_approve"):
|
|
78
|
-
return None
|
|
79
|
-
return f"BLOCKED: action '{name}' requires explicit approval (mode={mode.value})."
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
__all__ = [
|
|
83
|
-
"block_reason_for_tool",
|
|
84
|
-
"non_auto_plan_steps",
|
|
85
|
-
]
|
package/scripts/agent_eval.py
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Agent-loop evaluation gate — native since v11.6.0.
|
|
3
|
-
|
|
4
|
-
The deterministic scenario suite used to live in
|
|
5
|
-
``latticeai.core.agent_eval`` and drive ``SingleAgentRuntime``. That loop is
|
|
6
|
-
``lattice-agent`` now. CI still invokes this path; we verify the native suite
|
|
7
|
-
is present rather than importing the deleted Python runtime.
|
|
8
|
-
|
|
9
|
-
Last Python generating tree: commit fc65e60.
|
|
10
|
-
Goldens: ``rust/fixtures/agent_loop/golden/`` (FROZEN).
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
from __future__ import annotations
|
|
14
|
-
|
|
15
|
-
from pathlib import Path
|
|
16
|
-
|
|
17
|
-
REPO = Path(__file__).resolve().parents[1]
|
|
18
|
-
REQUIRED = (
|
|
19
|
-
REPO / "rust" / "lattice-agent" / "tests" / "agent_loop.rs",
|
|
20
|
-
REPO / "rust" / "fixtures" / "agent_loop" / "golden",
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def main() -> int:
|
|
25
|
-
missing = [str(path.relative_to(REPO)) for path in REQUIRED if not path.exists()]
|
|
26
|
-
if missing:
|
|
27
|
-
print("agent-loop-eval: FAIL missing native artifacts:", missing)
|
|
28
|
-
return 1
|
|
29
|
-
print("agent-loop-eval: native lattice-agent suite present (Python loop retired)")
|
|
30
|
-
return 0
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if __name__ == "__main__":
|
|
34
|
-
raise SystemExit(main())
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Brain recall / KG quality eval — native since v11.6.0.
|
|
3
|
-
|
|
4
|
-
This used to import ``KnowledgeGraphStore``, ``RetrievalBenchmarkRunner`` and
|
|
5
|
-
``MemoryService`` and run the Python retrieval bench. Retrieval and the
|
|
6
|
-
store are ``lattice-retrieval`` / ``lattice-core`` now. CI still invokes
|
|
7
|
-
this path; we verify the native goldens and the worker embedder report
|
|
8
|
-
are present.
|
|
9
|
-
|
|
10
|
-
Last Python generating tree: commit fc65e60.
|
|
11
|
-
Goldens: ``rust/fixtures/golden/`` (FROZEN).
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
from __future__ import annotations
|
|
15
|
-
|
|
16
|
-
from pathlib import Path
|
|
17
|
-
|
|
18
|
-
REPO = Path(__file__).resolve().parents[1]
|
|
19
|
-
REQUIRED = (
|
|
20
|
-
REPO / "rust" / "fixtures" / "golden" / "manifest.json",
|
|
21
|
-
REPO / "rust" / "fixtures" / "parity_store.sqlite",
|
|
22
|
-
REPO / "latticeai" / "api" / "search.py",
|
|
23
|
-
REPO / "latticeai" / "services" / "search_service.py",
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def main() -> int:
|
|
28
|
-
missing = [str(path.relative_to(REPO)) for path in REQUIRED if not path.exists()]
|
|
29
|
-
if missing:
|
|
30
|
-
print("brain-quality-eval: FAIL missing native artifacts:", missing)
|
|
31
|
-
return 1
|
|
32
|
-
print("brain-quality-eval: native retrieval goldens present (Python store retired)")
|
|
33
|
-
return 0
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if __name__ == "__main__":
|
|
37
|
-
raise SystemExit(main())
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Legacy debt gate (9.9.1): the root shim layer stays removed.
|
|
3
|
-
//
|
|
4
|
-
// Fails when:
|
|
5
|
-
// 1. a Python module other than server.py appears at the repository root;
|
|
6
|
-
// 2. any source tree imports a removed root shim module;
|
|
7
|
-
// 3. a removed shim directory (tools/) reappears at the root.
|
|
8
|
-
//
|
|
9
|
-
// Mirror of tests/unit/test_legacy_root_shims.py, but static and runnable in
|
|
10
|
-
// `npm run lint` without a Python environment.
|
|
11
|
-
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
12
|
-
import { join, relative } from "node:path";
|
|
13
|
-
|
|
14
|
-
const repo = join(import.meta.dirname, "..");
|
|
15
|
-
|
|
16
|
-
const ALLOWED_ROOT_MODULES = new Set(["server.py"]);
|
|
17
|
-
const REMOVED_ROOT_DIRS = ["tools"];
|
|
18
|
-
const REMOVED_MODULES = [
|
|
19
|
-
"ltcai_cli",
|
|
20
|
-
"auto_setup",
|
|
21
|
-
"setup_wizard",
|
|
22
|
-
"mcp_registry",
|
|
23
|
-
"kg_schema",
|
|
24
|
-
"knowledge_graph",
|
|
25
|
-
"knowledge_graph_api",
|
|
26
|
-
"local_knowledge_api",
|
|
27
|
-
"llm_router",
|
|
28
|
-
"p_reinforce",
|
|
29
|
-
"telegram_bot",
|
|
30
|
-
"tools",
|
|
31
|
-
];
|
|
32
|
-
// Trees that must not import removed shims. static/app and node_modules are
|
|
33
|
-
// build output; src-tauri/target is compiler output.
|
|
34
|
-
const SOURCE_TREES = ["latticeai", "lattice_brain", "tests", "scripts", "bin"];
|
|
35
|
-
|
|
36
|
-
const failures = [];
|
|
37
|
-
|
|
38
|
-
for (const entry of readdirSync(repo)) {
|
|
39
|
-
if (entry.endsWith(".py") && !ALLOWED_ROOT_MODULES.has(entry)) {
|
|
40
|
-
failures.push(`root module reappeared: ${entry} — put code in latticeai/ or lattice_brain/`);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
for (const dir of REMOVED_ROOT_DIRS) {
|
|
44
|
-
if (existsSync(join(repo, dir))) {
|
|
45
|
-
failures.push(`removed root package reappeared: ${dir}/ — use latticeai.${dir} instead`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const modulePattern = REMOVED_MODULES.join("|");
|
|
50
|
-
const pyImport = new RegExp(`^\\s*(?:import\\s+(?:${modulePattern})\\b|from\\s+(?:${modulePattern})\\s+import\\b)`);
|
|
51
|
-
const jsSpawn = new RegExp(`(?:${modulePattern})\\.py\\b`);
|
|
52
|
-
|
|
53
|
-
function* walk(dir) {
|
|
54
|
-
for (const entry of readdirSync(dir)) {
|
|
55
|
-
if (entry === "__pycache__" || entry === "node_modules" || entry === ".venv") continue;
|
|
56
|
-
const full = join(dir, entry);
|
|
57
|
-
const st = statSync(full);
|
|
58
|
-
if (st.isDirectory()) yield* walk(full);
|
|
59
|
-
else yield full;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
for (const tree of SOURCE_TREES) {
|
|
64
|
-
const base = join(repo, tree);
|
|
65
|
-
if (!existsSync(base)) continue;
|
|
66
|
-
for (const file of walk(base)) {
|
|
67
|
-
const rel = relative(repo, file);
|
|
68
|
-
if (/\.py$/.test(file)) {
|
|
69
|
-
const lines = readFileSync(file, "utf8").split("\n");
|
|
70
|
-
lines.forEach((line, i) => {
|
|
71
|
-
if (pyImport.test(line)) {
|
|
72
|
-
failures.push(`${rel}:${i + 1} imports a removed root shim: ${line.trim()}`);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
} else if (/\.(mjs|cjs|js)$/.test(file) && !/\.min\.js$/.test(file)) {
|
|
76
|
-
const lines = readFileSync(file, "utf8").split("\n");
|
|
77
|
-
lines.forEach((line, i) => {
|
|
78
|
-
if (jsSpawn.test(line) && !line.includes("check_legacy_debt")) {
|
|
79
|
-
failures.push(`${rel}:${i + 1} references a removed root shim file: ${line.trim()}`);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (failures.length > 0) {
|
|
87
|
-
console.error("legacy debt gate FAILED:");
|
|
88
|
-
for (const failure of failures) console.error(` - ${failure}`);
|
|
89
|
-
process.exit(1);
|
|
90
|
-
}
|
|
91
|
-
console.log("legacy debt gate ok: root shim layer stays removed (server.py only)");
|
package/scripts/check_python.py
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Discover-and-syntax-check every first-party Python module.
|
|
3
|
-
|
|
4
|
-
Replaces the hand-maintained ``py_compile`` enumeration in CI and
|
|
5
|
-
``package.json``: walks the repository, skips vendored / virtualenv / build /
|
|
6
|
-
cache / generated directories, and checks everything that remains. New
|
|
7
|
-
modules are picked up automatically — there is nothing to update when a file is
|
|
8
|
-
added, so the syntax gate can never silently fall behind the codebase.
|
|
9
|
-
|
|
10
|
-
Unlike ``py_compile``, this script does not write ``.pyc`` files or create
|
|
11
|
-
``__pycache__`` directories. Validation should not dirty a developer's working
|
|
12
|
-
tree or leave generated files for later lint passes to trip over.
|
|
13
|
-
|
|
14
|
-
Usage::
|
|
15
|
-
|
|
16
|
-
python scripts/check_python.py # syntax-check all discovered modules
|
|
17
|
-
python scripts/check_python.py --list # just print what would be checked
|
|
18
|
-
|
|
19
|
-
Exit code is non-zero if any module fails to parse.
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
from __future__ import annotations
|
|
23
|
-
|
|
24
|
-
import sys
|
|
25
|
-
from pathlib import Path
|
|
26
|
-
|
|
27
|
-
ROOT = Path(__file__).resolve().parent.parent
|
|
28
|
-
|
|
29
|
-
# Directory names excluded anywhere in the tree: virtualenvs, build/cache
|
|
30
|
-
# artifacts, generated agent output, and vendored snapshots of older releases.
|
|
31
|
-
EXCLUDE_DIRS = {
|
|
32
|
-
".git",
|
|
33
|
-
".venv",
|
|
34
|
-
"venv",
|
|
35
|
-
"env",
|
|
36
|
-
".build-venv",
|
|
37
|
-
".npm-cache",
|
|
38
|
-
"build",
|
|
39
|
-
"dist",
|
|
40
|
-
"node_modules",
|
|
41
|
-
"__pycache__",
|
|
42
|
-
".pytest_cache",
|
|
43
|
-
".mypy_cache",
|
|
44
|
-
".ruff_cache",
|
|
45
|
-
"agent_workspace",
|
|
46
|
-
"outputs",
|
|
47
|
-
"playwright-report",
|
|
48
|
-
"test-results",
|
|
49
|
-
"ltcai.egg-info",
|
|
50
|
-
"output",
|
|
51
|
-
".ltcai",
|
|
52
|
-
".ltcai-brain",
|
|
53
|
-
".ltcai-test",
|
|
54
|
-
# Vendored snapshot of an older packaged release — not part of the build.
|
|
55
|
-
"ltcai-0.3.1",
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def iter_modules():
|
|
60
|
-
for path in ROOT.rglob("*.py"):
|
|
61
|
-
parts = path.relative_to(ROOT).parts
|
|
62
|
-
if any(part in EXCLUDE_DIRS for part in parts):
|
|
63
|
-
continue
|
|
64
|
-
yield path
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def check_syntax(path: Path) -> str | None:
|
|
68
|
-
"""Return a human-readable failure string, or ``None`` when syntax is valid."""
|
|
69
|
-
|
|
70
|
-
try:
|
|
71
|
-
compile(path.read_bytes(), str(path), "exec", dont_inherit=True)
|
|
72
|
-
except (OSError, SyntaxError, ValueError) as exc:
|
|
73
|
-
return f"{path.relative_to(ROOT)}: {exc}"
|
|
74
|
-
return None
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def main(argv: list[str]) -> int:
|
|
78
|
-
modules = sorted(iter_modules())
|
|
79
|
-
if "--list" in argv:
|
|
80
|
-
for path in modules:
|
|
81
|
-
print(path.relative_to(ROOT))
|
|
82
|
-
return 0
|
|
83
|
-
|
|
84
|
-
failures: list[str] = []
|
|
85
|
-
for path in modules:
|
|
86
|
-
failure = check_syntax(path)
|
|
87
|
-
if failure:
|
|
88
|
-
failures.append(failure)
|
|
89
|
-
|
|
90
|
-
if failures:
|
|
91
|
-
print("\n".join(failures))
|
|
92
|
-
print(f"check:python FAILED — {len(failures)} of {len(modules)} module(s) did not parse")
|
|
93
|
-
return 1
|
|
94
|
-
|
|
95
|
-
print(f"check:python OK — syntax-checked {len(modules)} modules")
|
|
96
|
-
return 0
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if __name__ == "__main__":
|
|
100
|
-
raise SystemExit(main(sys.argv[1:]))
|