ltcai 11.2.0 → 11.5.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 +50 -53
- package/docs/CHANGELOG.md +87 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/MULTI_AGENT_RUNTIME.md +1 -1
- package/docs/ONBOARDING.md +1 -1
- package/docs/OPERATIONS.md +6 -2
- package/docs/PERMISSION_MODE.md +1 -1
- package/docs/TRUST_MODEL.md +1 -1
- package/docs/WHY_LATTICE.md +1 -1
- package/docs/kg-schema.md +2 -2
- package/docs/v11.3.0_PLAN.md +202 -0
- package/docs/v11.4.0_RUST_FOUNDATION_PLAN.md +181 -0
- package/docs/v11.5.0_RUST_COMPLETE_PLAN.md +145 -0
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/graph/_kg_common/__init__.py +287 -0
- package/lattice_brain/graph/_kg_common/extraction.py +516 -0
- package/lattice_brain/graph/_kg_common/relations.py +161 -0
- package/lattice_brain/graph/_kg_common/text.py +479 -0
- package/lattice_brain/graph/discovery_index/__init__.py +35 -0
- package/lattice_brain/graph/discovery_index/cleanup.py +182 -0
- package/lattice_brain/graph/discovery_index/extract.py +137 -0
- package/lattice_brain/graph/discovery_index/scan.py +411 -0
- package/lattice_brain/graph/discovery_index/upsert.py +495 -0
- package/lattice_brain/graph/projection/__init__.py +42 -0
- package/lattice_brain/graph/projection/curation.py +500 -0
- package/lattice_brain/graph/{projection.py → projection/v2_schema.py} +15 -477
- package/lattice_brain/graph/retrieval/__init__.py +54 -0
- package/lattice_brain/graph/retrieval/context.py +197 -0
- package/lattice_brain/graph/retrieval/graph_view.py +319 -0
- package/lattice_brain/graph/retrieval/hybrid.py +488 -0
- package/lattice_brain/graph/retrieval/maintenance.py +121 -0
- package/lattice_brain/graph/retrieval/signals.py +95 -0
- package/lattice_brain/graph/retrieval_vector/__init__.py +42 -0
- package/lattice_brain/graph/retrieval_vector/fingerprint.py +97 -0
- package/lattice_brain/graph/retrieval_vector/indexing.py +347 -0
- package/lattice_brain/graph/retrieval_vector/search.py +560 -0
- package/lattice_brain/graph/retrieval_vector/status.py +374 -0
- package/lattice_brain/ingestion/__init__.py +130 -0
- package/lattice_brain/ingestion/_contract.py +90 -0
- package/lattice_brain/ingestion/constants.py +127 -0
- package/lattice_brain/ingestion/folder_scan.py +57 -0
- package/lattice_brain/ingestion/folders.py +258 -0
- package/lattice_brain/ingestion/hashing.py +26 -0
- package/lattice_brain/ingestion/jobs_api.py +107 -0
- package/lattice_brain/ingestion/models.py +80 -0
- package/lattice_brain/ingestion/pipeline.py +486 -0
- package/lattice_brain/ingestion/quality.py +209 -0
- package/lattice_brain/ingestion/routing.py +295 -0
- package/lattice_brain/multimodal/__init__.py +164 -0
- package/lattice_brain/multimodal/audio.py +77 -0
- package/lattice_brain/multimodal/common.py +118 -0
- package/lattice_brain/multimodal/images.py +498 -0
- package/lattice_brain/multimodal/ports.py +169 -0
- package/lattice_brain/multimodal/video.py +410 -0
- package/lattice_brain/portability/__init__.py +90 -0
- package/lattice_brain/portability/_contract.py +42 -0
- package/lattice_brain/portability/backups.py +338 -0
- package/lattice_brain/portability/bundles.py +136 -0
- package/lattice_brain/portability/constants.py +93 -0
- package/lattice_brain/portability/fsops.py +138 -0
- package/lattice_brain/portability/service.py +41 -0
- package/lattice_brain/{portability.py → portability/sharing.py} +44 -677
- package/lattice_brain/runtime/__init__.py +1 -1
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/chronicle.py +63 -0
- package/latticeai/api/index_jobs.py +145 -0
- package/latticeai/core/agent/__init__.py +93 -0
- package/latticeai/core/agent/_contract.py +79 -0
- package/latticeai/core/agent/context.py +57 -0
- package/latticeai/core/agent/deps.py +125 -0
- package/latticeai/core/agent/execution.py +622 -0
- package/latticeai/core/agent/planning.py +145 -0
- package/latticeai/core/agent/recovery.py +157 -0
- package/latticeai/core/agent/runtime.py +210 -0
- package/latticeai/core/agent/verification.py +231 -0
- package/latticeai/core/embedding_providers/__init__.py +151 -0
- package/latticeai/core/embedding_providers/base.py +199 -0
- package/latticeai/core/embedding_providers/captions.py +162 -0
- package/latticeai/core/embedding_providers/profiles.py +126 -0
- package/latticeai/core/embedding_providers/text.py +350 -0
- package/latticeai/core/embedding_providers/vision.py +352 -0
- package/latticeai/core/file_generation/__init__.py +115 -0
- package/latticeai/core/file_generation/bundles.py +76 -0
- package/latticeai/core/file_generation/extraction.py +154 -0
- package/latticeai/core/file_generation/inference.py +235 -0
- package/latticeai/core/file_generation/orchestration.py +152 -0
- package/latticeai/core/file_generation/prompting.py +117 -0
- package/latticeai/core/file_generation/repair.py +114 -0
- package/latticeai/core/file_generation/sanitize.py +61 -0
- package/latticeai/core/file_generation/validation.py +201 -0
- package/latticeai/core/legacy_compatibility.py +1 -1
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/messages.py +14 -0
- package/latticeai/core/workspace_os_constants.py +1 -1
- package/latticeai/integrations/telegram_bot/__init__.py +123 -0
- package/latticeai/integrations/telegram_bot/__main__.py +17 -0
- package/latticeai/integrations/telegram_bot/config.py +86 -0
- package/latticeai/integrations/telegram_bot/dispatch.py +311 -0
- package/latticeai/integrations/telegram_bot/flows.py +478 -0
- package/latticeai/integrations/telegram_bot/helpers.py +322 -0
- package/latticeai/integrations/telegram_bot/screens.py +394 -0
- package/latticeai/models/router/__init__.py +88 -0
- package/latticeai/models/router/_contract.py +66 -0
- package/latticeai/models/router/branding.py +56 -0
- package/latticeai/models/router/catalog.py +69 -0
- package/latticeai/models/router/documents.py +199 -0
- package/latticeai/models/router/errors.py +37 -0
- package/latticeai/models/router/generation.py +258 -0
- package/latticeai/models/router/loading.py +291 -0
- package/latticeai/models/router/local_models.py +85 -0
- package/latticeai/models/router/registry.py +147 -0
- package/latticeai/runtime/build_phases/__init__.py +82 -0
- package/latticeai/runtime/build_phases/features.py +421 -0
- package/latticeai/runtime/build_phases/foundation.py +555 -0
- package/latticeai/runtime/build_phases/web.py +492 -0
- package/latticeai/runtime/runtime_context.py +1 -0
- package/latticeai/services/architecture_readiness.py +48 -19
- package/latticeai/services/brain_intelligence/__init__.py +58 -0
- package/latticeai/services/brain_intelligence/_contract.py +71 -0
- package/latticeai/services/brain_intelligence/consistency.py +193 -0
- package/latticeai/services/brain_intelligence/constants.py +47 -0
- package/latticeai/services/brain_intelligence/digest.py +258 -0
- package/latticeai/services/brain_intelligence/health.py +331 -0
- package/latticeai/services/brain_intelligence/proposals.py +264 -0
- package/latticeai/services/brain_intelligence/sampling.py +84 -0
- package/latticeai/services/brain_intelligence/service.py +48 -0
- package/latticeai/services/chronicle.py +557 -0
- package/latticeai/services/memory_service/__init__.py +52 -0
- package/latticeai/services/memory_service/_contract.py +100 -0
- package/latticeai/services/memory_service/brief.py +431 -0
- package/latticeai/services/memory_service/constants.py +57 -0
- package/latticeai/services/memory_service/maintenance.py +138 -0
- package/latticeai/services/memory_service/manager.py +186 -0
- package/latticeai/services/memory_service/proof.py +136 -0
- package/latticeai/services/memory_service/recall.py +225 -0
- package/latticeai/services/memory_service/service.py +48 -0
- package/latticeai/services/memory_service/stores.py +110 -0
- package/latticeai/services/model_runtime/__init__.py +322 -0
- package/latticeai/services/model_runtime/cloud.py +87 -0
- package/latticeai/services/model_runtime/download.py +282 -0
- package/latticeai/services/model_runtime/engines.py +341 -0
- package/latticeai/services/model_runtime/loading.py +178 -0
- package/latticeai/services/model_runtime/service.py +129 -0
- package/latticeai/services/model_runtime/state.py +131 -0
- package/latticeai/services/model_runtime/status.py +255 -0
- package/latticeai/services/product_readiness.py +15 -7
- package/latticeai/setup/wizard/__init__.py +126 -0
- package/latticeai/setup/wizard/catalog.py +172 -0
- package/latticeai/setup/wizard/detect.py +323 -0
- package/latticeai/setup/wizard/install.py +348 -0
- package/latticeai/setup/wizard/paths.py +168 -0
- package/latticeai/setup/wizard/plans.py +74 -0
- package/latticeai/setup/wizard/recommend.py +320 -0
- package/package.json +6 -2
- package/scripts/bump_version.py +14 -0
- package/scripts/capture_release_evidence.mjs +33 -21
- package/scripts/check_current_release_docs.mjs +1 -1
- package/scripts/check_i18n_namespace_coverage.mjs +41 -4
- package/scripts/check_max_file_lines.mjs +102 -0
- package/scripts/check_release_evidence_bound.mjs +30 -15
- package/scripts/check_screenshot_pixel_delta.py +34 -4
- package/scripts/check_server_i18n.mjs +2 -0
- package/scripts/chunking_parity_corpus.py +449 -0
- package/scripts/generate_agent_parity_fixtures.py +752 -0
- package/scripts/generate_chunking_parity_fixtures.py +259 -0
- package/scripts/generate_rust_parity_fixtures.py +997 -0
- package/scripts/lib/mock_server_fingerprint.mjs +94 -0
- package/scripts/release_screen_claims.json +42 -2
- package/src-tauri/Cargo.lock +404 -3
- package/src-tauri/Cargo.toml +13 -1
- package/src-tauri/src/backend.rs +460 -0
- package/src-tauri/src/folder.rs +33 -0
- package/src-tauri/src/main.rs +109 -399
- package/src-tauri/src/topology.rs +356 -0
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +41 -37
- package/static/app/assets/Act-CWnxSCgN.js +1 -0
- package/static/app/assets/AdminConsole-BEQYU6kF.js +1 -0
- package/static/app/assets/{Brain-tuhI4sOC.js → Brain-DWu1BhFg.js} +2 -2
- package/static/app/assets/BrainHome-95Hilr9R.js +2 -0
- package/static/app/assets/BrainSignals-QdeqCpAF.js +1 -0
- package/static/app/assets/Capture-BHpCxnzb.js +1 -0
- package/static/app/assets/Chronicle-B4xYKoed.js +1 -0
- package/static/app/assets/CommandPalette-BVXnttSz.js +1 -0
- package/static/app/assets/Library-DgYcHome.js +1 -0
- package/static/app/assets/{LivingBrain-DBwhto14.js → LivingBrain-CrJLDbf7.js} +1 -1
- package/static/app/assets/ProductFlow-DFlScKoJ.js +1 -0
- package/static/app/assets/ReviewCard-Cy5f48Pj.js +3 -0
- package/static/app/assets/System-NF8IfhTa.js +1 -0
- package/static/app/assets/arrow-left-DwkSYrjR.js +1 -0
- package/static/app/assets/{bot-Cia42c2h.js → bot-CucuhLhm.js} +1 -1
- package/static/app/assets/brain-BBnSryW_.js +1 -0
- package/static/app/assets/{button-2j2Ijzgq.js → button-C2GUj2Ai.js} +1 -1
- package/static/app/assets/circle-check-CxOVPwYq.js +1 -0
- package/static/app/assets/{circle-pause-BEFeWpVW.js → circle-pause-CbkWzBmG.js} +1 -1
- package/static/app/assets/{circle-play-ujXMcHxl.js → circle-play-7lEaqHdJ.js} +1 -1
- package/static/app/assets/{cpu-k4awryFq.js → cpu-DAlCXlIy.js} +1 -1
- package/static/app/assets/{download-DFbLJ_ig.js → download-RNhuuJwh.js} +1 -1
- package/static/app/assets/{folder-open-7y_b6xkM.js → folder-open-CLW4odzM.js} +1 -1
- package/static/app/assets/{hard-drive-Bidh02Kr.js → hard-drive-NKEiDIAJ.js} +1 -1
- package/static/app/assets/{index-DwDl9-8Y.css → index-BLPb5lmE.css} +1 -1
- package/static/app/assets/index-DMurvUuR.js +10 -0
- package/static/app/assets/input-D2UhPC1X.js +1 -0
- package/static/app/assets/link-2-6amKbP_P.js +1 -0
- package/static/app/assets/{permissionCopy-Bpb83Hx9.js → permissionCopy-Cu9TZtdR.js} +1 -1
- package/static/app/assets/primitives-gPsccucr.js +1 -0
- package/static/app/assets/search-Cj_TKk_2.js +1 -0
- package/static/app/assets/{share-2-BH1M-WNi.js → share-2-Bau7KkPq.js} +1 -1
- package/static/app/assets/{shield-alert-BlKdBXcG.js → shield-alert-BufNYypi.js} +1 -1
- package/static/app/assets/{textarea-CCWbUfFB.js → textarea-BQnVWhYs.js} +1 -1
- package/static/app/assets/{useFocusTrap-YdHQ7pJ1.js → useFocusTrap-B3_w60si.js} +1 -1
- package/static/app/assets/useMutation-BHhCflT6.js +1 -0
- package/static/app/assets/{useQuery-CXQiwbVT.js → useQuery-rBWfI-5t.js} +1 -1
- package/static/app/assets/utils-V_5-wxr5.js +4 -0
- package/static/app/assets/workspace-K1zjYUHj.js +1 -0
- package/static/app/index.html +4 -4
- package/static/sw.js +1 -1
- package/lattice_brain/graph/_kg_common.py +0 -1331
- package/lattice_brain/graph/discovery_index.py +0 -1141
- package/lattice_brain/graph/retrieval.py +0 -1120
- package/lattice_brain/graph/retrieval_vector.py +0 -1293
- package/lattice_brain/ingestion.py +0 -1525
- package/lattice_brain/multimodal.py +0 -1258
- package/latticeai/core/agent.py +0 -1465
- package/latticeai/core/embedding_providers.py +0 -1196
- package/latticeai/core/file_generation.py +0 -1047
- package/latticeai/integrations/telegram_bot.py +0 -1390
- package/latticeai/models/router.py +0 -1007
- package/latticeai/runtime/build_phases.py +0 -1450
- package/latticeai/services/brain_intelligence.py +0 -1083
- package/latticeai/services/memory_service.py +0 -1177
- package/latticeai/services/model_runtime.py +0 -1281
- package/latticeai/setup/wizard.py +0 -1310
- package/static/app/assets/Act-AWf0SAKp.js +0 -1
- package/static/app/assets/AdminConsole-D0u8Tiyj.js +0 -1
- package/static/app/assets/BrainHome-Ts7G_Ila.js +0 -2
- package/static/app/assets/BrainSignals-jMYgQ2Ar.js +0 -1
- package/static/app/assets/Capture-CqOSzyPr.js +0 -1
- package/static/app/assets/CommandPalette-DC0Bzh-I.js +0 -1
- package/static/app/assets/Library-CX-bbhmK.js +0 -1
- package/static/app/assets/ProductFlow-BHA2cfKI.js +0 -1
- package/static/app/assets/ReviewCard-BUhCKRNM.js +0 -3
- package/static/app/assets/System-Bu2t5hn1.js +0 -1
- package/static/app/assets/arrow-left-Dzwa5zRb.js +0 -1
- package/static/app/assets/brain-DJMoqrwx.js +0 -1
- package/static/app/assets/index-BpYkzcVm.js +0 -10
- package/static/app/assets/input-DSlJJxRs.js +0 -1
- package/static/app/assets/primitives-BCx6TvfG.js +0 -1
- package/static/app/assets/search-Cgy8cCFJ.js +0 -1
- package/static/app/assets/utils-zqPZJxdx.js +0 -4
- package/static/app/assets/workspace-DXTihhfU.js +0 -1
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# v11.4.0 — Rust Foundation (설계 문서)
|
|
2
|
+
|
|
3
|
+
> 상태: 계획 → 구현 → **출하됨(v11.4.0)**. Rust 전환의 단일 출처 설계
|
|
4
|
+
> 문서. 설계·기획: 본 문서. 목표 아키텍처는 아래 다이어그램, 이번
|
|
5
|
+
> 릴리스는 그 **Phase 1**이다.
|
|
6
|
+
|
|
7
|
+
## 목표 아키텍처 (전환 완료 시점의 모습)
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Desktop(Tauri) Browser Ext VS Code Ext
|
|
11
|
+
└────────────────┼────────────────┘
|
|
12
|
+
React / TypeScript
|
|
13
|
+
│
|
|
14
|
+
┌───────▼───────┐
|
|
15
|
+
│ Lattice Host │ Rust
|
|
16
|
+
│ (supervisor + │
|
|
17
|
+
│ IPC/API 관문) │
|
|
18
|
+
└───────┬───────┘
|
|
19
|
+
┌────────────────────┼────────────────────┐
|
|
20
|
+
lattice-core Agent Runtime IPC / API
|
|
21
|
+
(Brain·Graph· (Tools·Sandbox· (gateway,
|
|
22
|
+
Memory·Storage) Permission·Jobs) native routes)
|
|
23
|
+
│ │
|
|
24
|
+
Ingestion ──── Retrieval(Vector·BM25·KG → Fusion → Rerank
|
|
25
|
+
│ → Context Builder)
|
|
26
|
+
└──────────────┬──────────────┘
|
|
27
|
+
▼
|
|
28
|
+
Python AI Worker ← 최종적으로 Python이 맡는 유일한 층
|
|
29
|
+
(MLX · Ollama · Cloud → LLM, chat/agent 추론)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 왜 단계적인가 (정직성 원칙)
|
|
33
|
+
|
|
34
|
+
현 Python 플랫폼은 44개 라우터 파일 · ~448 라우트 · 40,488문 100.00%
|
|
35
|
+
커버리지 플로어 위에 있다. 이것을 한 릴리스에 재작성하는 것은 "전체
|
|
36
|
+
시스템에 지장 없음"과 양립할 수 없다. 그래서 각 릴리스가 **실제로
|
|
37
|
+
작동하고 증명된 Rust 조각**을 늘려가고, Python은 마지막에 AI Worker
|
|
38
|
+
(모델 추론)로 수렴한다. 11.4.0은 그 뼈대를 세운다.
|
|
39
|
+
|
|
40
|
+
## Phase 1 스코프 (11.4.0)
|
|
41
|
+
|
|
42
|
+
`rust/` cargo workspace 신설 — 3개 크레이트, 전부 tauri 비의존(우분투
|
|
43
|
+
CI에서 시스템 패키지 없이 테스트 가능):
|
|
44
|
+
|
|
45
|
+
### 1. `lattice-core` — Brain 저장소 읽기 층 + 임베딩 산술
|
|
46
|
+
|
|
47
|
+
- 데이터 디렉터리 해석: `LATTICEAI_DATA_DIR` → 기본 `~/.ltcai`,
|
|
48
|
+
DB는 `knowledge_graph.sqlite` (Python과 동일 파일).
|
|
49
|
+
- 읽기 전용 SQLite 접속(rusqlite `bundled` + **fts5 필수**): WAL,
|
|
50
|
+
`busy_timeout` 명시(Python은 미설정 — Rust가 양보하는 쪽).
|
|
51
|
+
- 스키마 리더: `kgv2_nodes`/`kgv2_edges` 뷰(어휘·그래프 lane),
|
|
52
|
+
`nodes`/`chunks`/`vector_embeddings`(벡터 lane),
|
|
53
|
+
`nodes_v2`(워크스페이스 스코핑) — **lane별 테이블 이원화는 Python
|
|
54
|
+
현행 그대로** 재현한다.
|
|
55
|
+
- 임베딩 모듈 = `lattice_brain/embeddings.py`의 1:1 포트:
|
|
56
|
+
토크나이저(`[a-z0-9][a-z0-9_.:/+-]{1,}` + latin 3-gram(len≥5) +
|
|
57
|
+
한국어 2-gram(len≥3)), blake2b-8 해시 bag-of-features(하위 비트 부호),
|
|
58
|
+
L2 정규화, `<f32` LE 인코딩/디코딩(4B/dim, 헤더 없음), 유사도는
|
|
59
|
+
**순수 내적**(dim 불일치는 하드 에러). 기본 dim 384,
|
|
60
|
+
모델 id `lattice-local-hash-v1:{dim}`.
|
|
61
|
+
|
|
62
|
+
### 2. `lattice-retrieval` — 네이티브 하이브리드 검색 (패리티 증명 동반)
|
|
63
|
+
|
|
64
|
+
패리티 대상은 **graph-layer `KnowledgeGraphStore.hybrid_search`**
|
|
65
|
+
(2채널 alpha 융합)와 그 구성 lane인 `search()`(키워드),
|
|
66
|
+
`vector_search()`(벡터). 서비스 층 3채널 융합(`SearchService`)은
|
|
67
|
+
traverse/relationship 의존이 커서 Phase 2로 명시 이월.
|
|
68
|
+
|
|
69
|
+
기본 env 구성(brute 백엔드, RRF/그래프 확장/이미지 융합/CE rerank 꺼짐)
|
|
70
|
+
에서 다음을 정확 재현:
|
|
71
|
+
|
|
72
|
+
- **키워드 lane**: trigram FTS5 `MATCH '"…"'`(내부 `"` 이중화,
|
|
73
|
+
len<3 → 빈 결과) → LIKE 폴백(`%q%`, `updated_at DESC, id ASC`) →
|
|
74
|
+
topic-term 보충(`limit*3`) → **(hits, type_boost, updated_at) 재점수**
|
|
75
|
+
(hits = topic 후보 12개의 대소문자 무시 부분일치 수, type_boost
|
|
76
|
+
집합 고정) + **2-pass 안정 정렬(id ASC → score DESC)**. 점수는
|
|
77
|
+
호출측 1/rank.
|
|
78
|
+
- **벡터 lane**: `embedding_model+dim` 필터, `indexed_at DESC` 후보
|
|
79
|
+
상한(기본 10000, `LATTICEAI_VECTOR_MAX_CANDIDATES`), 순차 f64 내적
|
|
80
|
+
(Python과 동일 누적 순서 → bit-exact), min_score 필터,
|
|
81
|
+
`(score, updated_at) DESC` 안정 정렬, recall/honesty 필드 동일.
|
|
82
|
+
- **정책**: `classify_query`(ko/en 정규식, code→recency→person→fact
|
|
83
|
+
우선순위)는 **원 질의**에, rewrite(공백 축약 + filler 3규칙,
|
|
84
|
+
remainder≥4)는 검색 질의에. recency 클래스만 half-life 14일 감쇠
|
|
85
|
+
`0.5 + 0.5*recency`.
|
|
86
|
+
- **융합**: lexical 1/rank, vector max-정규화, `alpha*vec+(1-α)*lex`,
|
|
87
|
+
`round(x,6)`(**banker's rounding** — CPython round와 동치 구현),
|
|
88
|
+
정렬 `(-score, node_id)`, identity rerank(`rerank_score=score`,
|
|
89
|
+
top_k 절단), 결과 JSON 필드·라벨(`fusion`, `sources`, `policy`,
|
|
90
|
+
`vector.*`) 전부 동형.
|
|
91
|
+
- **스코핑**: `allowed_workspaces=None` ⇒ 스코핑 없음(로컬 신뢰 소유자
|
|
92
|
+
기본 경로) — fail-closed로 바꾸지 않는다. 빈 집합 ⇒ 아무것도 매치
|
|
93
|
+
안 됨. legacy-global(NULL)은 `include_legacy_global`로만 포함.
|
|
94
|
+
|
|
95
|
+
**패리티 하네스(양방향 계약)**:
|
|
96
|
+
- `scripts/generate_rust_parity_fixtures.py`(Python)가 실제 Python
|
|
97
|
+
쓰기 경로로 소형 스토어를 빚어 `rust/fixtures/parity_store.sqlite`
|
|
98
|
+
+ 질의 세트(ko/en, 4 클래스, len<3, 무결과, 동점 tie) +
|
|
99
|
+
`rust/fixtures/golden/*.json`(Python 엔진의 hybrid/keyword/vector
|
|
100
|
+
출력)을 커밋 산출물로 생성.
|
|
101
|
+
- `tests/unit/test_rust_parity_contract.py`: 커밋된 fixture DB에 대해
|
|
102
|
+
Python 엔진을 다시 돌려 golden과 일치함을 상시 단언 — Python 쪽
|
|
103
|
+
의미 변경이 골든을 조용히 무효화하지 못한다.
|
|
104
|
+
- `lattice-retrieval`의 cargo 테스트: 같은 DB·같은 질의에 대해 Rust
|
|
105
|
+
출력 == 같은 golden. 점수는 기본 완전 일치(불가피한 tie 케이스만
|
|
106
|
+
1e-12, 사유 주석).
|
|
107
|
+
|
|
108
|
+
### 3. `lattice-host` — 수퍼바이저 + IPC/API 게이트웨이
|
|
109
|
+
|
|
110
|
+
- **수퍼바이저(lib + bin)**: Python 워커 스폰(명령 해석은 현행 Tauri
|
|
111
|
+
규칙 승계: `LATTICEAI_DESKTOP_BACKEND_CMD` → `ltcai` → python 후보 →
|
|
112
|
+
번들 트리; 현행 `sort()+dedup()`이 우선순위를 파괴하던 버그는 수정),
|
|
113
|
+
**`/health` HTTP 프로브**(현행 TCP 접속 프로브 대체), 크래시 시
|
|
114
|
+
지수 백오프 자동 재시작(상한·수동 정지 존중), 우아한 종료(SIGTERM →
|
|
115
|
+
유예 → SIGKILL), **포트 통일**: 기본 4825에서 시작해 빈 포트 탐색,
|
|
116
|
+
선택 포트를 워커 env(`LATTICEAI_PORT`)와 상위(Tauri `backend_origin`)
|
|
117
|
+
에 단일 출처로 공급. 로그는 기존 `~/.ltcai/desktop-sidecar.log` 계승.
|
|
118
|
+
- **게이트웨이(axum, 127.0.0.1 전용)**: `/host/health`·`/host/status`
|
|
119
|
+
(수퍼바이저 상태), 네이티브 `/rust/search/{hybrid,keyword,vector}`
|
|
120
|
+
(lattice-retrieval 직결, 읽기 전용), 그 외 전 경로는 워커로 리버스
|
|
121
|
+
프록시(스트리밍/SSE 통과). Phase 1에서는 **옵트인 front-door**
|
|
122
|
+
(`lattice-host` 바이너리 실행 시) — 기존 진입 경로(ltcai CLI,
|
|
123
|
+
브라우저 직접 접속)는 그대로 둔다. 비-loopback 바인드 거부.
|
|
124
|
+
|
|
125
|
+
### 4. Tauri 통합 (DMG가 새 기초 위에 올라탐)
|
|
126
|
+
|
|
127
|
+
`src-tauri`는 `lattice-host`를 path 의존으로 소비: `main.rs`의 ad-hoc
|
|
128
|
+
스폰/프로브/재시작 로직을 크레이트 호출로 대체(451줄 → 얇은 셸).
|
|
129
|
+
Tauri 명령 5종(`backend_origin`/`backend_status`/`restart_backend`/
|
|
130
|
+
`shutdown_backend`/`select_folder`)의 프론트 계약은 불변. 네트워크
|
|
131
|
+
토폴로지도 불변(웹뷰는 여전히 `{origin}/app`) — 사용자 가시 변화 없이
|
|
132
|
+
수퍼바이저 품질만 오른다(HTTP 헬스, 자동 재시작, 포트 충돌 처리).
|
|
133
|
+
|
|
134
|
+
### 5. 게이트/CI/버전
|
|
135
|
+
|
|
136
|
+
- ci.yml에 `rust` 잡 신설: ubuntu, stable 툴체인(핀), `cargo fmt
|
|
137
|
+
--check` + `clippy -D warnings` + `cargo test` — `rust/` workspace만
|
|
138
|
+
(tauri 시스템 의존 없음). src-tauri 빌드는 종전대로 릴리스 플로우
|
|
139
|
+
(macOS)에서.
|
|
140
|
+
- `check_max_file_lines.mjs`에 `*.rs` 추가(상한 1,000, `src-tauri/gen`
|
|
141
|
+
·`target` 제외). 모든 신규 Rust 파일 목표 ≤500줄.
|
|
142
|
+
- `scripts/bump_version.py`와 `test_version_consistency.py`에
|
|
143
|
+
`rust/Cargo.toml`(workspace.package.version, 크레이트는
|
|
144
|
+
`version.workspace = true`) 편입 — 버전 단일 출처 유지.
|
|
145
|
+
- Python 커버리지 플로어(문·분기 100%)와 프론트 100%는 그대로. Rust는
|
|
146
|
+
cargo 테스트 + 패리티 골든이 게이트.
|
|
147
|
+
|
|
148
|
+
### 명시적 비-목표 (Phase 1에서 하지 않는 것)
|
|
149
|
+
|
|
150
|
+
- 3채널 `SearchService.hybrid_search`/KG 읽기 API의 네이티브화(Phase 2),
|
|
151
|
+
- Ingestion(Watch/Parse/Chunk/Dedup)·Jobs/Events/Scheduler(Phase 2~3),
|
|
152
|
+
- Agent Runtime(Tools/Sandbox/Permission)의 Rust화(Phase 4),
|
|
153
|
+
- 게이트웨이의 기본 front-door 승격(Phase 2에서 e2e로 검증 후),
|
|
154
|
+
- HNSW/quantized 백엔드·CE rerank·이미지 late fusion 패리티(브루트
|
|
155
|
+
기본 경로만; 나머지는 요청 시 워커로 프록시되므로 기능 손실 없음).
|
|
156
|
+
|
|
157
|
+
## 로드맵 (다이어그램 → 릴리스 매핑)
|
|
158
|
+
|
|
159
|
+
| Phase | 릴리스 | 내용 | 상태 |
|
|
160
|
+
|---|---|---|---|
|
|
161
|
+
| 1 | **11.4.0** | workspace + core 읽기층 + retrieval 패리티 + host 수퍼바이저/게이트웨이(옵트인) + Tauri 통합 | **출하됨** |
|
|
162
|
+
| 2 | **11.5.0** | 게이트웨이 front-door 기본화(데스크톱), KG 읽기·3채널 검색·history 네이티브, Ingestion Watch/Chunk/Dedup | **출하됨** |
|
|
163
|
+
| 3 | **11.5.0** | Jobs/Events/Scheduler, Context Builder 네이티브 | **출하됨** |
|
|
164
|
+
| 4 | **11.5.0** | Agent Runtime(Tools·Sandbox·Permission) Rust화 — 단, 루프 오케스트레이션 이식은 명시적 비-목표로 남음(v11.5.0 계획 §4c) | **출하됨(커널)** |
|
|
165
|
+
|
|
166
|
+
Phase 2~4는 원래 11.5.x~12.0으로 나뉘어 있었으나 한 릴리스로 합쳐 출하했다
|
|
167
|
+
([`v11.5.0_RUST_COMPLETE_PLAN.md`](v11.5.0_RUST_COMPLETE_PLAN.md)). 아래 §
|
|
168
|
+
"명시적 비-목표"의 네 항목 중 마지막(HNSW/quantized·CE rerank·이미지 late
|
|
169
|
+
fusion 패리티)만 여전히 미이식이며, 나머지는 11.5.0에서 닫혔다.
|
|
170
|
+
|
|
171
|
+
## 릴리스 체크리스트 (11.4.0)
|
|
172
|
+
|
|
173
|
+
1. W1(host) ∥ W2(core+retrieval+패리티) → W3(Tauri·CI·게이트·버전 배선).
|
|
174
|
+
2. 전 게이트 로컬 그린(pytest 100% 플로어·프론트·lint 체인·cargo 3종)
|
|
175
|
+
+ fresh venv 재검증.
|
|
176
|
+
3. `bump_version.py 11.4.0`(rust workspace 포함) → OpenAPI 재생성 →
|
|
177
|
+
문서·releaseTheme("Rust Foundation") → claims(화면 무변경) →
|
|
178
|
+
`release:evidence` 재촬영(스크린샷 13종 + GIF) →
|
|
179
|
+
`release:artifacts`(DMG 포함) → validate/smoke.
|
|
180
|
+
4. 브랜치 `release/v11.4.0` 커밋·푸시 → PR로 CI 그린 → 태그
|
|
181
|
+
`v11.4.0` → GitHub Release(정확한 파일명 5종).
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# v11.5.0 — Rust Complete (설계 문서)
|
|
2
|
+
|
|
3
|
+
> 상태: 계획 → 구현 → **출하됨(v11.5.0)**. v11.4.0 Rust Foundation 계획의
|
|
4
|
+
> Phase 2·3·4를 한 릴리스로 완결한다. 원칙 불변: **작동하고 증명된
|
|
5
|
+
> 조각만 출하하고, Python 서버는 목표 다이어그램의 AI Worker로
|
|
6
|
+
> 수렴하되 제거되지 않는다.** 모든 네이티브 경로는 패리티 골든 또는
|
|
7
|
+
> 결정표 골든으로 잠근다.
|
|
8
|
+
>
|
|
9
|
+
> 통합 상태: **완료**. 네 크레이트의 라우터 팩토리는 게이트웨이의
|
|
10
|
+
> 리버스 프록시 폴스루보다 앞에 마운트되어 있고(`rust/lattice-host/src/gateway/mounts.rs`),
|
|
11
|
+
> 데스크톱은 기본으로 게이트웨이 토폴로지로 뜬다(`src-tauri/src/topology.rs`,
|
|
12
|
+
> 안전 밸브 3종 유지). §2a의 CSRF origin 주입과 SSE `X-Accel-Buffering`
|
|
13
|
+
> 보강도 배선 완료. §4c(에이전트 루프 오케스트레이션 이식)만 의도적으로
|
|
14
|
+
> 남아 있으며, 그 이유는 아래 본문 그대로다.
|
|
15
|
+
|
|
16
|
+
## Phase 2 — Front Door + 읽기/검색/히스토리 네이티브 + Ingestion 프리미티브
|
|
17
|
+
|
|
18
|
+
### 2a. 게이트웨이 front-door 기본화 (데스크톱)
|
|
19
|
+
- 정찰 확정 사실: 쿠키(host-only)·CSP(`connect-src 'self' http://127.0.0.1:*`)
|
|
20
|
+
·리다이렉트(전부 상대)는 origin 전환에 안전. **유일한 차단기는 CSRF
|
|
21
|
+
origin 정책이 워커 자신의 포트로 빌드되는 것**(web_runtime.py:42-67,
|
|
22
|
+
csrf.py:154-164 — Host는 프록시가 hop-by-hop으로 제거).
|
|
23
|
+
- 해소(Rust만으로): `worker_env`가
|
|
24
|
+
`LATTICEAI_CSRF_TRUSTED_ORIGINS=http://127.0.0.1:{gw},http://localhost:{gw}`
|
|
25
|
+
를 워커에 주입(config.py:170이 이미 파싱). 게이트웨이 SSE 프록시는
|
|
26
|
+
`X-Accel-Buffering: no`를 이벤트 스트림 응답에 보강.
|
|
27
|
+
- Tauri는 기본적으로 **게이트웨이 origin으로 항해**(`backend_origin` =
|
|
28
|
+
게이트웨이). `LATTICEAI_DESKTOP_BACKEND_ORIGIN`/`LATTICEAI_DESKTOP_DIRECT=1`
|
|
29
|
+
이면 종전 직결 유지(안전 밸브). e2e: 게이트웨이 경유 스모크 추가.
|
|
30
|
+
- 알려진 잔여(문서화): invite-link 절대 URL(Host 재작성), SSO redirect
|
|
31
|
+
기본값, permission UI 기본 URL — 데스크톱 front-door에서 워커 포트를
|
|
32
|
+
가리킴. 영향 좁음(관리자/SSO 경로), FEATURE_STATUS에 명시.
|
|
33
|
+
|
|
34
|
+
### 2b. 3채널 검색·KG 읽기·히스토리 네이티브 (lattice-retrieval 확장)
|
|
35
|
+
패리티 대상(정찰 §6·§7의 명세 그대로):
|
|
36
|
+
- `graph_search`: direct 1/rank + relationship 0.75/rank + traverse
|
|
37
|
+
이웃 0.45/rank, score=max 병합, **안정 정렬(동점 삽입순, id 타이브레이크
|
|
38
|
+
없음 — Python 그대로)**, graph_context 축적.
|
|
39
|
+
- `relationship_search`: 6-way LIKE, `ORDER BY weight DESC, created_at
|
|
40
|
+
DESC, id ASC`, 양 끝점 스코프 통과 시만 생존, 점수 없음.
|
|
41
|
+
- `traverse`: 무방향 BFS, 라운드당 `limit*3` 엣지 캡(라운드 종속성
|
|
42
|
+
포함 재현), visited<limit 게이트, 노드 수화 `updated_at DESC, id ASC`.
|
|
43
|
+
- 서비스층 `hybrid_search`(3채널): `weights` 명시=재작성/감쇠 없음,
|
|
44
|
+
None=policy 적용; 기여도 `w * max(score, 1/rank)` 합산; 채널 payload
|
|
45
|
+
에코; POST/GET 비대칭 재현.
|
|
46
|
+
- 히스토리 읽기: `_scope_sql`(빈 allowed+no-legacy ⇒ 1=0), 그룹핑
|
|
47
|
+
(`legacy-previous-history` 버킷, updated_at DESC), get_conversation
|
|
48
|
+
(전체 로드 후 필터 — 동일 재현), search(부분일치, "마지막 30그룹"
|
|
49
|
+
슬라이스 그대로).
|
|
50
|
+
- 골든: 기존 픽스처 스토어 확장(대화 행 추가) + 새 질의 세트,
|
|
51
|
+
Python 계약 테스트 확장. 게이트웨이 라우트:
|
|
52
|
+
`/rust/search/service-hybrid`, `/rust/graph/{search,relationships,traverse}`,
|
|
53
|
+
`/rust/history`, `/rust/history/{conversations,search}` (라우터 팩토리로
|
|
54
|
+
노출, X5가 마운트).
|
|
55
|
+
|
|
56
|
+
### 2c. lattice-ingest — Watch · Parse · Chunk · Dedup (단일 작성자 원칙)
|
|
57
|
+
- **typed chunking 1:1 포트**(_kg_common/text.py 명세 전부: plain 1200/160,
|
|
58
|
+
markdown 섹션 스택+200자 전방 병합, code 세그먼트 팩킹+1.5x 하드리밋,
|
|
59
|
+
prose 경계 백업 `max(start+1, end-overlap)`, overlap 클램프) +
|
|
60
|
+
chunk id `chunk:{sha256(f"{node}:{i}:{text}")[:24]}` (utf-8 replace).
|
|
61
|
+
- 해시 규약: `_clean_text`+sha256(text_hash), content_hash 이원 규약
|
|
62
|
+
(파일=바이트 sha256, 텍스트=`type|uri|text`) 그대로.
|
|
63
|
+
- 파일 워치: mtime 폴링 스냅샷(현행 folder_watch 의미론 — OS 워처
|
|
64
|
+
아님)을 Rust 타이머로; 변경 감지 시 **워커의 기존 인제스트 API로
|
|
65
|
+
위임**(`POST /knowledge-graph/ingest` type=note 또는 folder 재스캔
|
|
66
|
+
트리거) — 그래프 쓰기는 계속 Python 단일 작성자. Rust는 감지·파싱
|
|
67
|
+
(txt/md)·청킹·중복 판정까지 수행하고 결과를 검증 가능하게 반환.
|
|
68
|
+
- 패리티: 청킹 골든(Python 생성기 — 4전략 × 경계 케이스 · 한/영 ·
|
|
69
|
+
PDF 페이지 오프셋 산술) 완전 일치.
|
|
70
|
+
|
|
71
|
+
## Phase 3 — Jobs · Events · Scheduler + Context Builder
|
|
72
|
+
|
|
73
|
+
### 3a. lattice-jobs — 스케줄러 (문서화된 갭의 해소)
|
|
74
|
+
- FEATURE_STATUS:179-185 "아무것도 배경 임베드 큐를 몰지 않는다"를
|
|
75
|
+
닫는다: Rust 타이머(기본 60s, env 조절)가 워커의 **신규 additive
|
|
76
|
+
엔드포인트** `POST /api/index/drain`(이번 릴리스에 Python에 추가,
|
|
77
|
+
`IngestionPipeline.drain_vector_queue` 호출, require_user+게이트,
|
|
78
|
+
100% 커버)을 호출. 미완 ingestion job resume도 동일 타이머가
|
|
79
|
+
`GET /api/ingestion/jobs` → 조건부 `/resume`으로 재개(기본 꺼짐,
|
|
80
|
+
`LATTICEAI_JOBS_AUTORESUME=1` 옵트인).
|
|
81
|
+
- `/host/jobs` 상태 라우트: 마지막 틱 결과·다음 예정·큐 카운트
|
|
82
|
+
(`vector_jobs` 읽기 전용 카운트는 lattice-core로 직접).
|
|
83
|
+
- 이벤트: 틱 결과를 호스트 로그 + `/host/jobs`에 노출(간결·정직).
|
|
84
|
+
|
|
85
|
+
### 3b. Context Builder 네이티브 (lattice-retrieval 내 모듈)
|
|
86
|
+
- `lattice_brain/context.py`의 `ContextAssembler` 포트: approx_tokens
|
|
87
|
+
`(len+3)//4`, 고정 섹션 순서(memories→artifacts→knowledge→notes→recent),
|
|
88
|
+
greedy 예산 절단(`content[:remaining*4]`, 절단 후 재계측 동작 포함)
|
|
89
|
+
— 시임은 네이티브 검색/히스토리 리더로 주입. 골든: 동일 픽스처에서
|
|
90
|
+
Python 어셈블러 출력과 완전 일치. 게이트웨이 `/rust/context/assemble`.
|
|
91
|
+
- 문서 생성용 context_builder(B)는 Phase 4 이후로 명시 이월(
|
|
92
|
+
search_for_document_generation 의존).
|
|
93
|
+
|
|
94
|
+
## Phase 4 — Agent Runtime: Tools · Sandbox · Permission (안전 커널)
|
|
95
|
+
|
|
96
|
+
**다이어그램의 라벨(Tools/Process/Sandbox/Permission)을 Rust가 소유**하고,
|
|
97
|
+
LLM 추론·변이 도구 실행은 워커에 위임(그것이 AI Worker의 정의다).
|
|
98
|
+
|
|
99
|
+
### 4a. 권한 커널 — 결정표 패리티
|
|
100
|
+
- `normalize_mode`(별칭 표 포함), `effective_auto_approve`(모드×도구
|
|
101
|
+
집합×risk×change_class 전 분기), `is_circuit_breaker`(파괴 risk·루트/홈
|
|
102
|
+
경로·rm -rf 변형), `should_stage_proposal`, `plan_requires_approval`,
|
|
103
|
+
`block_reason_for_tool`(우선순위 체인), `classify_tool_call`
|
|
104
|
+
(MUTATING_TOOL_INVENTORY 27종) 전부 포트.
|
|
105
|
+
- **결정표 골든**: Python 생성기가 (mode × tool × policy × args)
|
|
106
|
+
그리드 수백 케이스의 판정을 JSON으로 떠서 커밋; Rust와 Python 양쪽
|
|
107
|
+
계약 테스트가 같은 골든을 상시 단언(11.4.0 방식).
|
|
108
|
+
|
|
109
|
+
### 4b. 도구 샌드박스 — 검증 패리티 + 네이티브 실행(읽기 전용)
|
|
110
|
+
- `run_command` 검증기 포트: shlex 분해, 실행경로/allowlist/셸 연산자/
|
|
111
|
+
find·rg 플래그/절대경로·`..`·심링크 이스케이프 규칙, env 치환
|
|
112
|
+
(HOME=AGENT_ROOT, 고정 PATH). **검증 판정 골든**(명령 문자열 그리드)
|
|
113
|
+
완전 일치. 통과한 읽기 전용 명령(pwd/ls/find/cat/head/tail/wc/rg)은
|
|
114
|
+
Rust가 직접 실행(타임아웃 30s·출력 12,000자 캡 동일).
|
|
115
|
+
- 파일 도구: `_resolve_path` 의미론(AGENT_ROOT 격리) + read/list 네이티브.
|
|
116
|
+
- 게이트웨이 `/rust/agent/preflight`(계획/도구콜 배열 + mode → 판정
|
|
117
|
+
목록)와 `/rust/agent/exec`(커널 통과 읽기 전용 명령만 실행; 그 외
|
|
118
|
+
는 판정과 함께 거부) — 변이는 절대 실행하지 않는다.
|
|
119
|
+
|
|
120
|
+
### 4c. 루프 위임 — `/rust/agent/run`
|
|
121
|
+
- 워커 `/agent`(SSE)로 턴을 위임하되 호스트가 `permission_mode`를
|
|
122
|
+
스탬프하고, 반환 계획에 커널 preflight를 병기해 표면에 제공.
|
|
123
|
+
Python 루프 자체의 재작성은 **명시적 비-목표**(결정 커널이 잠긴
|
|
124
|
+
지금, 루프 이식은 후속 릴리스의 기계적 작업으로 남긴다 — 이유:
|
|
125
|
+
AgentDeps 12개 시임의 실배선 검증 없이 이식하면 증명 없는 재작성).
|
|
126
|
+
|
|
127
|
+
## 게이트/검증/릴리스
|
|
128
|
+
|
|
129
|
+
- 신규 크레이트 3종(lattice-ingest/jobs/agent) 워크스페이스 편입,
|
|
130
|
+
전 파일 ≤1,000줄(목표 ≤500), fmt/clippy/test CI rust 잡 그대로.
|
|
131
|
+
- Python 추가분(drain 엔드포인트 등)은 문·분기 100% 유지.
|
|
132
|
+
- 골든 4계열(검색·히스토리/청킹/컨텍스트/권한·명령 판정) 모두
|
|
133
|
+
양방향(계약 pytest + cargo 테스트).
|
|
134
|
+
- 릴리스 절차는 11.4.0과 동일: bump 11.5.0 → 문서·테마("Rust
|
|
135
|
+
Complete") → evidence 재촬영(13종+GIF) → artifacts(DMG) →
|
|
136
|
+
main 커밋·푸시 → CI 그린.
|
|
137
|
+
|
|
138
|
+
## 정직한 경계 (FEATURE_STATUS에 그대로 기재)
|
|
139
|
+
|
|
140
|
+
- Python 서버는 계속 모든 제품 표면을 서빙한다 — front-door는
|
|
141
|
+
데스크톱 기본 + 옵트인 바이너리이며, 네이티브 라우트는 검증된
|
|
142
|
+
대체 경로다.
|
|
143
|
+
- 문서 파서 매트릭스(pdf/docx/xlsx/pptx)·임베딩 생산·LLM 추론·변이
|
|
144
|
+
도구 실행·그래프 쓰기는 워커 소유(설계상 단일 작성자/AI Worker).
|
|
145
|
+
- 에이전트 루프 오케스트레이션의 Rust 이식은 남는다(4c의 이유).
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SQLite knowledge graph for Lattice AI workspace memory.
|
|
3
|
+
|
|
4
|
+
The graph keeps raw event JSON, normalized node metadata, and edges in one
|
|
5
|
+
portable database so it can later migrate to Neo4j/Postgres without changing
|
|
6
|
+
the ingestion contract.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# ruff: noqa: F401,F841
|
|
10
|
+
|
|
11
|
+
import asyncio
|
|
12
|
+
import hashlib
|
|
13
|
+
import json
|
|
14
|
+
import logging
|
|
15
|
+
import math
|
|
16
|
+
import os
|
|
17
|
+
import platform
|
|
18
|
+
import re
|
|
19
|
+
import shutil
|
|
20
|
+
import sqlite3
|
|
21
|
+
import time
|
|
22
|
+
import zipfile
|
|
23
|
+
from collections import Counter
|
|
24
|
+
from contextlib import contextmanager
|
|
25
|
+
from datetime import datetime
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
from typing import Any, Dict, Iterable, Iterator, List, Optional, Tuple
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
from ..schema import EdgeType, KGStoreV2, NodeType, _exec_script
|
|
31
|
+
except Exception: # pragma: no cover - v2 schema is optional at import time
|
|
32
|
+
KGStoreV2 = None # type: ignore[assignment,misc]
|
|
33
|
+
NodeType = None # type: ignore[assignment,misc]
|
|
34
|
+
EdgeType = None # type: ignore[assignment,misc]
|
|
35
|
+
_exec_script = None # type: ignore[assignment]
|
|
36
|
+
|
|
37
|
+
from ...embeddings import LocalEmbeddingModel
|
|
38
|
+
from ..json_utils import _json, _safe_loads
|
|
39
|
+
from ..runtime import get_llm_router, set_llm_router
|
|
40
|
+
|
|
41
|
+
# Default read source for the graph queries: v2 reconstruction views.
|
|
42
|
+
# Override with LATTICEAI_KG_READ_V2=0 to fall back to the legacy tables.
|
|
43
|
+
_READ_FROM_V2_DEFAULT = os.getenv("LATTICEAI_KG_READ_V2", "1") != "0"
|
|
44
|
+
|
|
45
|
+
# Static constants (projection/format versions, local-ingestion classification
|
|
46
|
+
# tables, OS exclusion lists) live in ._kg_constants; re-exported here so every
|
|
47
|
+
# existing ``from ._kg_common import <CONST>`` site is unaffected.
|
|
48
|
+
from ...quiet import quiet
|
|
49
|
+
from .._kg_constants import ( # noqa: E402
|
|
50
|
+
_KG_DB_FORMAT_KEY,
|
|
51
|
+
_KG_DB_FORMAT_VERSION,
|
|
52
|
+
_PROJECTION_VERSION,
|
|
53
|
+
_V2_WRITE_MASTER_KEY,
|
|
54
|
+
COMMON_EXCLUDED_DIRS,
|
|
55
|
+
COMMON_EXCLUDED_FILE_NAMES,
|
|
56
|
+
COMMON_EXCLUDED_FILE_SUFFIXES,
|
|
57
|
+
GRAPH_SCHEMA_VERSION,
|
|
58
|
+
LINUX_EXCLUDED_PREFIXES,
|
|
59
|
+
LOCAL_CODE_EXTENSIONS,
|
|
60
|
+
LOCAL_DOCUMENT_EXTENSIONS,
|
|
61
|
+
LOCAL_IMAGE_EXTENSIONS,
|
|
62
|
+
LOCAL_SIZE_LIMITS,
|
|
63
|
+
LOCAL_SLIDE_EXTENSIONS,
|
|
64
|
+
LOCAL_SPREADSHEET_EXTENSIONS,
|
|
65
|
+
LOCAL_SUPPORTED_EXTENSIONS,
|
|
66
|
+
LOCAL_TEXT_EXTENSIONS,
|
|
67
|
+
MACOS_EXCLUDED_PREFIXES,
|
|
68
|
+
SENSITIVE_PATH_KEYWORDS,
|
|
69
|
+
WINDOWS_EXCLUDED_NAMES,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Pure fs/path/hash/classification helpers → ._kg_fsutil, re-exported so the
|
|
73
|
+
# static __all__ below forwards them to the graph mixins. Listed explicitly
|
|
74
|
+
# rather than star-imported: a star import here made every name in this
|
|
75
|
+
# module unverifiable to both ruff and mypy.
|
|
76
|
+
from .._kg_fsutil import ( # noqa: E402,F401
|
|
77
|
+
_current_os_type,
|
|
78
|
+
_drive_id_for_path,
|
|
79
|
+
_excluded_directory_reason,
|
|
80
|
+
_file_category,
|
|
81
|
+
_is_hidden_path,
|
|
82
|
+
_is_relative_to,
|
|
83
|
+
_node_type_for_category,
|
|
84
|
+
_now,
|
|
85
|
+
_parse_iso,
|
|
86
|
+
_parser_type_for_category,
|
|
87
|
+
_path_fingerprint,
|
|
88
|
+
_path_parts_lower,
|
|
89
|
+
_recency_score,
|
|
90
|
+
_root_warning,
|
|
91
|
+
_safe_iso_from_stat_mtime,
|
|
92
|
+
_sample_file,
|
|
93
|
+
_sensitive_file_reason,
|
|
94
|
+
_sha256_bytes,
|
|
95
|
+
_sha256_text,
|
|
96
|
+
_size_limit_for_category,
|
|
97
|
+
_slug,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# The logic this module used to hold inline lives in three cohesive submodules
|
|
101
|
+
# (v11.3.0 decomposition). Every name is re-exported below, so the twelve
|
|
102
|
+
# `from ._kg_common import *` consumers are unaffected — and `__all__` is still
|
|
103
|
+
# the single written-down star-import contract.
|
|
104
|
+
from .extraction import ( # noqa: E402
|
|
105
|
+
_CONCEPT_STOP,
|
|
106
|
+
_LLM_EXTRACT_CONCEPT_PROMPT,
|
|
107
|
+
_LLM_EXTRACT_TRIPLE_PROMPT,
|
|
108
|
+
ENABLE_LLM_EXTRACTION,
|
|
109
|
+
_extract_concepts,
|
|
110
|
+
_extract_concepts_rules,
|
|
111
|
+
_extract_triples,
|
|
112
|
+
_extract_triples_rules,
|
|
113
|
+
_llm_extract_concepts,
|
|
114
|
+
_llm_extract_triples,
|
|
115
|
+
_semantic_items,
|
|
116
|
+
_topic_candidates,
|
|
117
|
+
)
|
|
118
|
+
from .relations import ( # noqa: E402
|
|
119
|
+
_NOT_PERSON_WORDS,
|
|
120
|
+
COOCCURRENCE_CONCEPT_LIMIT,
|
|
121
|
+
COOCCURRENCE_EDGE_WEIGHT,
|
|
122
|
+
EDGE_VERB,
|
|
123
|
+
VERB_EDGE_WEIGHT,
|
|
124
|
+
_classify_node_type,
|
|
125
|
+
_infer_edge,
|
|
126
|
+
infer_edge_relation,
|
|
127
|
+
)
|
|
128
|
+
from .text import ( # noqa: E402
|
|
129
|
+
_CHUNK_STRATEGIES,
|
|
130
|
+
_CODE_BLANK_RUN_RE,
|
|
131
|
+
_CODE_BOUNDARY_LINE_RE,
|
|
132
|
+
_CODE_CHUNK_EXTENSIONS,
|
|
133
|
+
_MARKDOWN_CHUNK_EXTENSIONS,
|
|
134
|
+
_MARKDOWN_HEADING_RE,
|
|
135
|
+
_MARKDOWN_MIN_SECTION_CHARS,
|
|
136
|
+
_PROSE_CHUNK_EXTENSIONS,
|
|
137
|
+
_PROSE_MIN_SPAN_RATIO,
|
|
138
|
+
_PROSE_STRONG_BOUNDARY_RE,
|
|
139
|
+
_PROSE_WEAK_BOUNDARY_RE,
|
|
140
|
+
_chunks,
|
|
141
|
+
_clean_text,
|
|
142
|
+
_code_chunks,
|
|
143
|
+
_code_segment_spans,
|
|
144
|
+
_last_boundary,
|
|
145
|
+
_markdown_chunks,
|
|
146
|
+
_markdown_section_spans,
|
|
147
|
+
_merge_small_sections,
|
|
148
|
+
_plain_windows,
|
|
149
|
+
_prose_chunks,
|
|
150
|
+
chunk_strategy_for,
|
|
151
|
+
citation_locator,
|
|
152
|
+
page_for_offset,
|
|
153
|
+
pdf_page_offsets,
|
|
154
|
+
typed_chunk_meta_fields,
|
|
155
|
+
typed_chunks,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Static export list. This used to be `[name for name in globals() if not
|
|
159
|
+
# name.startswith("__")]`, which is invisible to a type checker: every
|
|
160
|
+
# `from ._kg_common import *` consumer then had *no* resolvable names, and
|
|
161
|
+
# mypy reported ~750 spurious `name-defined` errors across the graph
|
|
162
|
+
# package. `tests/unit/test_kg_common_exports.py` asserts this list still
|
|
163
|
+
# equals what the computed expression would produce, so it cannot drift.
|
|
164
|
+
__all__ = [
|
|
165
|
+
"Any",
|
|
166
|
+
"COMMON_EXCLUDED_DIRS",
|
|
167
|
+
"COMMON_EXCLUDED_FILE_NAMES",
|
|
168
|
+
"COMMON_EXCLUDED_FILE_SUFFIXES",
|
|
169
|
+
"COOCCURRENCE_CONCEPT_LIMIT",
|
|
170
|
+
"COOCCURRENCE_EDGE_WEIGHT",
|
|
171
|
+
"Counter",
|
|
172
|
+
"Dict",
|
|
173
|
+
"EDGE_VERB",
|
|
174
|
+
"ENABLE_LLM_EXTRACTION",
|
|
175
|
+
"EdgeType",
|
|
176
|
+
"GRAPH_SCHEMA_VERSION",
|
|
177
|
+
"Iterable",
|
|
178
|
+
"Iterator",
|
|
179
|
+
"KGStoreV2",
|
|
180
|
+
"LINUX_EXCLUDED_PREFIXES",
|
|
181
|
+
"LOCAL_CODE_EXTENSIONS",
|
|
182
|
+
"LOCAL_DOCUMENT_EXTENSIONS",
|
|
183
|
+
"LOCAL_IMAGE_EXTENSIONS",
|
|
184
|
+
"LOCAL_SIZE_LIMITS",
|
|
185
|
+
"LOCAL_SLIDE_EXTENSIONS",
|
|
186
|
+
"LOCAL_SPREADSHEET_EXTENSIONS",
|
|
187
|
+
"LOCAL_SUPPORTED_EXTENSIONS",
|
|
188
|
+
"LOCAL_TEXT_EXTENSIONS",
|
|
189
|
+
"List",
|
|
190
|
+
"LocalEmbeddingModel",
|
|
191
|
+
"MACOS_EXCLUDED_PREFIXES",
|
|
192
|
+
"NodeType",
|
|
193
|
+
"Optional",
|
|
194
|
+
"Path",
|
|
195
|
+
"SENSITIVE_PATH_KEYWORDS",
|
|
196
|
+
"Tuple",
|
|
197
|
+
"VERB_EDGE_WEIGHT",
|
|
198
|
+
"WINDOWS_EXCLUDED_NAMES",
|
|
199
|
+
"_CHUNK_STRATEGIES",
|
|
200
|
+
"_CODE_BLANK_RUN_RE",
|
|
201
|
+
"_CODE_BOUNDARY_LINE_RE",
|
|
202
|
+
"_CODE_CHUNK_EXTENSIONS",
|
|
203
|
+
"_CONCEPT_STOP",
|
|
204
|
+
"_KG_DB_FORMAT_KEY",
|
|
205
|
+
"_KG_DB_FORMAT_VERSION",
|
|
206
|
+
"_LLM_EXTRACT_CONCEPT_PROMPT",
|
|
207
|
+
"_LLM_EXTRACT_TRIPLE_PROMPT",
|
|
208
|
+
"_MARKDOWN_CHUNK_EXTENSIONS",
|
|
209
|
+
"_MARKDOWN_HEADING_RE",
|
|
210
|
+
"_MARKDOWN_MIN_SECTION_CHARS",
|
|
211
|
+
"_NOT_PERSON_WORDS",
|
|
212
|
+
"_PROJECTION_VERSION",
|
|
213
|
+
"_PROSE_CHUNK_EXTENSIONS",
|
|
214
|
+
"_PROSE_MIN_SPAN_RATIO",
|
|
215
|
+
"_PROSE_STRONG_BOUNDARY_RE",
|
|
216
|
+
"_PROSE_WEAK_BOUNDARY_RE",
|
|
217
|
+
"_READ_FROM_V2_DEFAULT",
|
|
218
|
+
"_V2_WRITE_MASTER_KEY",
|
|
219
|
+
"_chunks",
|
|
220
|
+
"_classify_node_type",
|
|
221
|
+
"_clean_text",
|
|
222
|
+
"_code_chunks",
|
|
223
|
+
"_code_segment_spans",
|
|
224
|
+
"_current_os_type",
|
|
225
|
+
"_drive_id_for_path",
|
|
226
|
+
"_excluded_directory_reason",
|
|
227
|
+
"_exec_script",
|
|
228
|
+
"_extract_concepts",
|
|
229
|
+
"_extract_concepts_rules",
|
|
230
|
+
"_extract_triples",
|
|
231
|
+
"_extract_triples_rules",
|
|
232
|
+
"_file_category",
|
|
233
|
+
"_infer_edge",
|
|
234
|
+
"_is_hidden_path",
|
|
235
|
+
"_is_relative_to",
|
|
236
|
+
"_json",
|
|
237
|
+
"_last_boundary",
|
|
238
|
+
"_llm_extract_concepts",
|
|
239
|
+
"_llm_extract_triples",
|
|
240
|
+
"_markdown_chunks",
|
|
241
|
+
"_markdown_section_spans",
|
|
242
|
+
"_merge_small_sections",
|
|
243
|
+
"_node_type_for_category",
|
|
244
|
+
"_now",
|
|
245
|
+
"_parse_iso",
|
|
246
|
+
"_parser_type_for_category",
|
|
247
|
+
"_path_fingerprint",
|
|
248
|
+
"_path_parts_lower",
|
|
249
|
+
"_plain_windows",
|
|
250
|
+
"_prose_chunks",
|
|
251
|
+
"_recency_score",
|
|
252
|
+
"_root_warning",
|
|
253
|
+
"_safe_iso_from_stat_mtime",
|
|
254
|
+
"_safe_loads",
|
|
255
|
+
"_sample_file",
|
|
256
|
+
"_semantic_items",
|
|
257
|
+
"_sensitive_file_reason",
|
|
258
|
+
"_sha256_bytes",
|
|
259
|
+
"_sha256_text",
|
|
260
|
+
"_size_limit_for_category",
|
|
261
|
+
"_slug",
|
|
262
|
+
"_topic_candidates",
|
|
263
|
+
"asyncio",
|
|
264
|
+
"chunk_strategy_for",
|
|
265
|
+
"citation_locator",
|
|
266
|
+
"contextmanager",
|
|
267
|
+
"datetime",
|
|
268
|
+
"get_llm_router",
|
|
269
|
+
"hashlib",
|
|
270
|
+
"infer_edge_relation",
|
|
271
|
+
"json",
|
|
272
|
+
"logging",
|
|
273
|
+
"math",
|
|
274
|
+
"os",
|
|
275
|
+
"page_for_offset",
|
|
276
|
+
"pdf_page_offsets",
|
|
277
|
+
"platform",
|
|
278
|
+
"quiet",
|
|
279
|
+
"re",
|
|
280
|
+
"set_llm_router",
|
|
281
|
+
"shutil",
|
|
282
|
+
"sqlite3",
|
|
283
|
+
"time",
|
|
284
|
+
"typed_chunk_meta_fields",
|
|
285
|
+
"typed_chunks",
|
|
286
|
+
"zipfile",
|
|
287
|
+
]
|