ltcai 11.4.0 → 11.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -44
- package/docs/CHANGELOG.md +48 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/ONBOARDING.md +1 -1
- package/docs/OPERATIONS.md +1 -1
- package/docs/TRUST_MODEL.md +1 -1
- package/docs/WHY_LATTICE.md +1 -1
- package/docs/kg-schema.md +1 -1
- package/docs/v11.4.0_RUST_FOUNDATION_PLAN.md +11 -6
- package/docs/v11.5.0_RUST_COMPLETE_PLAN.md +145 -0
- package/docs/v11.5.1_RUST_FULL_LOOP_PLAN.md +85 -0
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/agent_worker_seam.py +389 -0
- package/latticeai/api/index_jobs.py +145 -0
- package/latticeai/core/legacy_compatibility.py +1 -1
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/messages.py +40 -0
- package/latticeai/core/workspace_os_constants.py +1 -1
- package/latticeai/runtime/build_phases/features.py +37 -2
- package/latticeai/services/architecture_readiness.py +1 -1
- package/latticeai/services/product_readiness.py +1 -1
- package/package.json +1 -1
- package/scripts/check_current_release_docs.mjs +1 -1
- package/scripts/check_server_i18n.mjs +2 -0
- package/scripts/chunking_parity_corpus.py +449 -0
- package/scripts/generate_agent_loop_fixtures.py +907 -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 +541 -103
- package/scripts/parity_fixture_corpus_docgen.py +341 -0
- package/scripts/release_screen_claims.json +21 -0
- package/src-tauri/Cargo.lock +53 -4
- package/src-tauri/Cargo.toml +11 -4
- package/src-tauri/src/backend.rs +251 -140
- package/src-tauri/src/main.rs +16 -4
- package/src-tauri/src/topology.rs +356 -0
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +41 -41
- package/static/app/assets/{Act-yYpYnn0v.js → Act-Drs_jd-O.js} +1 -1
- package/static/app/assets/{AdminConsole-DL3Cr5pL.js → AdminConsole-BqNx5oF6.js} +1 -1
- package/static/app/assets/{Brain-C1HBN0Wf.js → Brain-C7bdNmz-.js} +1 -1
- package/static/app/assets/{BrainHome-DoXRhUUC.js → BrainHome-DcTnINcI.js} +1 -1
- package/static/app/assets/{BrainSignals-6yR6ir5t.js → BrainSignals-Df1MRIPD.js} +1 -1
- package/static/app/assets/{Capture-CFIRsFNE.js → Capture-Dgsxvnbx.js} +1 -1
- package/static/app/assets/{Chronicle-BZbEgiwN.js → Chronicle-BrkTxJK1.js} +1 -1
- package/static/app/assets/{CommandPalette-D2pMxC2I.js → CommandPalette-DDziw7Oj.js} +1 -1
- package/static/app/assets/{Library-DwO3yZST.js → Library-CYxeuraA.js} +1 -1
- package/static/app/assets/{LivingBrain-Jn1GK0-S.js → LivingBrain-CNp6mvCm.js} +1 -1
- package/static/app/assets/{ProductFlow-B-w1R4Oo.js → ProductFlow-BVsowu3Z.js} +1 -1
- package/static/app/assets/{ReviewCard-6B27X8Vg.js → ReviewCard-D1LbOfJS.js} +1 -1
- package/static/app/assets/{System-DW8F-2xL.js → System-DcRAq7wj.js} +1 -1
- package/static/app/assets/arrow-left-BHYmOTWU.js +1 -0
- package/static/app/assets/{bot-IM_E_Y12.js → bot-BK2xQ9mN.js} +1 -1
- package/static/app/assets/{brain-Ci1CkWjM.js → brain-BZNztFBb.js} +1 -1
- package/static/app/assets/{button-COwyqfHM.js → button-CjueubVZ.js} +1 -1
- package/static/app/assets/circle-check-CLeWJr67.js +1 -0
- package/static/app/assets/{circle-pause-DEM4A1Y5.js → circle-pause-HRjSmpyY.js} +1 -1
- package/static/app/assets/{circle-play-C9djDuLd.js → circle-play-CMcKDVwu.js} +1 -1
- package/static/app/assets/{cpu-DFdo1gw-.js → cpu-B_MyTfYr.js} +1 -1
- package/static/app/assets/{download-SnJL6oqk.js → download-CTy0EByV.js} +1 -1
- package/static/app/assets/{folder-open-CqZeDkjE.js → folder-open-DF6bLhTg.js} +1 -1
- package/static/app/assets/{hard-drive-j1jJXYYf.js → hard-drive-CpWHG77C.js} +1 -1
- package/static/app/assets/{index-_u5iUHDr.js → index-Dd6abJHX.js} +3 -3
- package/static/app/assets/index-DxmOfNRi.css +2 -0
- package/static/app/assets/{input-B0lPdRQZ.js → input-bVgIRN3s.js} +1 -1
- package/static/app/assets/{link-2-CoFbooHS.js → link-2-bg6CG5Vk.js} +1 -1
- package/static/app/assets/{permissionCopy-BsyLxtao.js → permissionCopy-DFTf1HDZ.js} +1 -1
- package/static/app/assets/{primitives-DEbN-d6p.js → primitives-D7D-sQ3T.js} +1 -1
- package/static/app/assets/search-BgSVX6NG.js +1 -0
- package/static/app/assets/{share-2-CVtZ_ewX.js → share-2-BLzo7U4L.js} +1 -1
- package/static/app/assets/{shield-alert-CBi2GNWM.js → shield-alert-BmngqnsJ.js} +1 -1
- package/static/app/assets/{textarea-DNMpB5ih.js → textarea-DOSlAQQ3.js} +1 -1
- package/static/app/assets/{useFocusTrap-C83t3GXF.js → useFocusTrap-pZhgeee4.js} +1 -1
- package/static/app/assets/{useMutation-DtbJDoyz.js → useMutation-BMDwNk4I.js} +1 -1
- package/static/app/assets/{useQuery-Dcp1OChy.js → useQuery-CSjKttRo.js} +1 -1
- package/static/app/assets/{utils-BlZr7Pd4.js → utils-D3u_yv7B.js} +1 -1
- package/static/app/assets/{workspace-jJY4RuAV.js → workspace-H3bMjYXC.js} +1 -1
- package/static/app/index.html +4 -4
- package/static/sw.js +1 -1
- package/static/app/assets/arrow-left-DXvKg9U6.js +0 -1
- package/static/app/assets/circle-check-DfInj-qD.js +0 -1
- package/static/app/assets/index-BLPb5lmE.css +0 -2
- package/static/app/assets/search-BybIWPNd.js +0 -1
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""The document-generation half of the Python↔Rust parity corpus (v11.5.1).
|
|
3
|
+
|
|
4
|
+
``scripts/generate_rust_parity_fixtures.py`` owns the store and the goldens;
|
|
5
|
+
this module owns the rows and specs the **document-generation** ports need, so
|
|
6
|
+
neither file has to grow past the tree's file-size ceiling. Nothing here runs
|
|
7
|
+
anything — it is data plus one normalization helper.
|
|
8
|
+
|
|
9
|
+
Three things are shaped on purpose:
|
|
10
|
+
|
|
11
|
+
* **Every allow-listed node type appears.** ``search_for_document_generation``
|
|
12
|
+
admits fifteen types and boosts four of them; a corpus that only carried
|
|
13
|
+
``Document`` would prove the boost and the filter equally badly.
|
|
14
|
+
* **The Self-Model subgraph is real.** ``summary_for_prompt`` reads the legacy
|
|
15
|
+
``nodes`` table for ``self:%`` ids, so the profile rows are written through
|
|
16
|
+
the same write door as everything else, including the root the read excludes
|
|
17
|
+
and a ``self:`` row whose metadata carries no recognised kind (dropped).
|
|
18
|
+
* **``updated_at`` is spread against the frozen clock**, including one stamp
|
|
19
|
+
that does not parse — the recency term's ``0.0`` branch is otherwise
|
|
20
|
+
unreachable from a fixture whose every row is well formed.
|
|
21
|
+
|
|
22
|
+
:func:`normalize_multi_hop` is the one deliberate deviation, and it is a
|
|
23
|
+
*golden* normalization rather than a port divergence: see its docstring.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
29
|
+
|
|
30
|
+
WS_ALPHA = "ws-alpha"
|
|
31
|
+
WS_BETA = "ws-beta"
|
|
32
|
+
|
|
33
|
+
# ── the document-generation corpus ───────────────────────────────────────────
|
|
34
|
+
# (node_id, type, title, summary, metadata, workspace_id, updated_at)
|
|
35
|
+
DOCGEN_NODES: List[Tuple[str, str, str, str, Dict[str, Any], Optional[str], str]] = [
|
|
36
|
+
# ── the Self-Model subgraph (read by `summary_for_prompt`) ──────────────
|
|
37
|
+
# `self:root` is excluded by id, and `self:unknown:*` carries no
|
|
38
|
+
# `self_model_kind`, so `_row_to_fact` drops it — both are read branches
|
|
39
|
+
# that only exist if the fixture actually contains them.
|
|
40
|
+
("self:root", "Self", "나", "Brain이 사용자에 대해 알고 있는 사실의 뿌리입니다.",
|
|
41
|
+
{"self_model": True, "self_model_kind": "root"}, None, "2026-07-01T09:00:00"),
|
|
42
|
+
("self:decision:a1", "Decision", "문서는 한국어로 쓴다",
|
|
43
|
+
"문서는 한국어로 쓴다",
|
|
44
|
+
{"self_model": True, "self_model_kind": "decision", "origin": "user",
|
|
45
|
+
"confidence": 0.9, "signal": "ko_decision_marker", "workspace_id": WS_ALPHA},
|
|
46
|
+
WS_ALPHA, "2026-07-02T09:00:00"),
|
|
47
|
+
("self:habit:b2", "Habit", "매주 월요일 회의록을 정리한다",
|
|
48
|
+
"매주 월요일 회의록을 정리한다",
|
|
49
|
+
{"self_model": True, "self_model_kind": "habit", "origin": "extraction",
|
|
50
|
+
"confidence": 0.6, "signal": "ko_habit", "workspace_id": None},
|
|
51
|
+
None, "2026-07-03T09:00:00"),
|
|
52
|
+
("self:preference:c3", "Preference", "설명은 짧고 근거를 먼저",
|
|
53
|
+
"설명은 짧고 근거를 먼저",
|
|
54
|
+
{"self_model": True, "self_model_kind": "preference", "origin": "user",
|
|
55
|
+
"confidence": 0.8, "signal": "ko_prefer", "workspace_id": None},
|
|
56
|
+
None, "2026-07-04T09:00:00"),
|
|
57
|
+
("self:relationship:d4", "Relationship", "박민서 님과 빌드 파이프라인을 함께 본다",
|
|
58
|
+
"박민서 님과 빌드 파이프라인을 함께 본다",
|
|
59
|
+
{"self_model": True, "self_model_kind": "relationship", "origin": "extraction",
|
|
60
|
+
"confidence": 0.5, "signal": "ko_with", "workspace_id": WS_BETA},
|
|
61
|
+
WS_BETA, "2026-07-05T09:00:00"),
|
|
62
|
+
("self:trait:e5", "Self", "검색 품질 담당자",
|
|
63
|
+
"검색 품질 담당자",
|
|
64
|
+
{"self_model": True, "self_model_kind": "trait", "origin": "user",
|
|
65
|
+
"confidence": 0.7, "signal": "ko_role", "workspace_id": None},
|
|
66
|
+
None, "2026-07-06T09:00:00"),
|
|
67
|
+
("self:unknown:f6", "Concept", "kind가 없는 self 노드",
|
|
68
|
+
"self_model_kind가 없어 프로필에서 제외되는 행입니다.",
|
|
69
|
+
{"self_model": True}, None, "2026-07-07T09:00:00"),
|
|
70
|
+
# ── the proposal cluster: one hub document with more qualifying
|
|
71
|
+
# neighbours than the eight the related-concept join keeps ───────────
|
|
72
|
+
("doc:proposal", "Document", "제안서 초안: 검색 품질 개선",
|
|
73
|
+
"검색 품질 개선 제안서 초안입니다. 근거는 주간 회의 기록과 분기 리뷰 발표자료입니다.",
|
|
74
|
+
{"relative_path": "docs/proposal.md", "filename": "proposal.md", "ext": ".md"},
|
|
75
|
+
WS_ALPHA, "2026-07-30T09:00:00"),
|
|
76
|
+
("doc:release-notes", "Document", "Release notes for the retrieval port",
|
|
77
|
+
"Release notes describing the ranking port and the parity harness.",
|
|
78
|
+
{"source": "release"}, None, "2026-07-28T09:00:00"),
|
|
79
|
+
("file:meeting-minutes", "File", "meeting-minutes.md",
|
|
80
|
+
"회의록: 랭킹 개선과 온보딩 체크리스트를 확정했습니다.",
|
|
81
|
+
{"filename": "meeting-minutes.md", "relative_path": "notes/meeting-minutes.md"},
|
|
82
|
+
WS_ALPHA, "2026-08-01T11:00:00"),
|
|
83
|
+
("deck:proposal", "SlideDeck", "제안 발표자료",
|
|
84
|
+
"제안서 초안을 발표용으로 정리한 자료입니다.",
|
|
85
|
+
{"filename": "proposal.pptx", "ext": ".pptx"}, WS_BETA, "2026-07-29T09:00:00"),
|
|
86
|
+
("chat:proposal", "Chat", "제안서 관련 대화",
|
|
87
|
+
"제안서 초안을 어떻게 쓸지 논의한 대화입니다.",
|
|
88
|
+
{"conversation_id": "conv-f"}, WS_ALPHA, "2026-07-26T09:00:00"),
|
|
89
|
+
("task:proposal-review", "Task", "제안서 검토",
|
|
90
|
+
"제안서 초안을 검토하고 근거를 확인합니다.", {"status": "open"},
|
|
91
|
+
WS_ALPHA, "2026-07-27T09:00:00"),
|
|
92
|
+
("dec:doc-format", "Decision", "문서 형식은 마크다운으로 통일",
|
|
93
|
+
"문서 생성 결과는 마크다운으로 통일하기로 했습니다.", {},
|
|
94
|
+
WS_ALPHA, "2026-07-22T09:00:00"),
|
|
95
|
+
("feature:doc-generation", "Feature", "문서 생성",
|
|
96
|
+
"질문에서 문서를 만들어 주는 기능입니다.", {}, WS_ALPHA, "2026-07-25T09:00:00"),
|
|
97
|
+
("concept:proposal", "Concept", "제안서",
|
|
98
|
+
"제안서는 결정을 요청하는 문서입니다.", {}, None, "2026-07-24T09:00:00"),
|
|
99
|
+
("concept:evidence", "Concept", "근거",
|
|
100
|
+
"근거는 주장을 뒷받침하는 자료입니다.", {}, WS_ALPHA, "2026-07-23T09:00:00"),
|
|
101
|
+
("page:proposal-outline", "Page", "제안서 목차",
|
|
102
|
+
"제안서 목차 페이지입니다.", {}, None, "2026-07-21T09:00:00"),
|
|
103
|
+
("slide:proposal-1", "Slide", "제안 슬라이드 1",
|
|
104
|
+
"제안서 요약 슬라이드입니다.", {}, WS_BETA, "2026-07-19T09:00:00"),
|
|
105
|
+
("sheet:proposal-budget", "Spreadsheet", "proposal-budget.xlsx",
|
|
106
|
+
"제안서 예산 표입니다.", {"filename": "proposal-budget.xlsx", "ext": ".xlsx"},
|
|
107
|
+
WS_ALPHA, "2026-07-17T09:00:00"),
|
|
108
|
+
("img:proposal-sketch", "Image", "proposal-sketch.png",
|
|
109
|
+
"제안서 구조 스케치입니다.", {"filename": "proposal-sketch.png", "ext": ".png"},
|
|
110
|
+
WS_BETA, "2026-07-16T09:00:00"),
|
|
111
|
+
("imgtext:proposal-ocr", "ImageText", "제안서 스케치 OCR",
|
|
112
|
+
"제안서 구조: 배경, 근거, 결론.",
|
|
113
|
+
{"filename": "proposal-sketch.png", "ocr": True}, WS_BETA, "2026-07-16T09:01:00"),
|
|
114
|
+
("audio:proposal-call", "Audio", "proposal-call.m4a",
|
|
115
|
+
"제안서 관련 통화 녹음입니다.", {"filename": "proposal-call.m4a", "ext": ".m4a"},
|
|
116
|
+
WS_ALPHA, "2026-07-15T09:00:00"),
|
|
117
|
+
("code:doc-builder", "CodeFile", "context_builder.py",
|
|
118
|
+
"문서 생성 컨텍스트를 조합하는 코드입니다. 제안서 생성도 여기를 지납니다.",
|
|
119
|
+
{"filename": "context_builder.py",
|
|
120
|
+
"relative_path": "latticeai/core/context_builder.py"},
|
|
121
|
+
WS_ALPHA, "2026-07-14T09:00:00"),
|
|
122
|
+
# The recency term's `0.0` branch: a stamp `datetime.fromisoformat` refuses.
|
|
123
|
+
("doc:undated", "Document", "Undated 제안서 memo",
|
|
124
|
+
"An undated memo about 제안서; its stamp does not parse.", {},
|
|
125
|
+
None, "not-a-timestamp"),
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
# (from, to, type, weight, created_at) — appended to the base edge set.
|
|
129
|
+
DOCGEN_EDGES: List[Tuple[str, str, str, float, str]] = [
|
|
130
|
+
("doc:proposal", "concept:proposal", "mentions", 0.92, "2026-07-30T00:00:00"),
|
|
131
|
+
("doc:proposal", "concept:evidence", "mentions", 0.91, "2026-07-30T00:01:00"),
|
|
132
|
+
("doc:proposal", "feature:doc-generation", "relates_to", 0.90, "2026-07-30T00:02:00"),
|
|
133
|
+
("doc:proposal", "dec:doc-format", "relates_to", 0.89, "2026-07-30T00:03:00"),
|
|
134
|
+
("doc:proposal", "task:proposal-review", "relates_to", 0.88, "2026-07-30T00:04:00"),
|
|
135
|
+
("doc:proposal", "concept:retrieval", "mentions", 0.87, "2026-07-30T00:05:00"),
|
|
136
|
+
("doc:proposal", "concept:ranking", "mentions", 0.86, "2026-07-30T00:06:00"),
|
|
137
|
+
("doc:proposal", "feature:command-palette", "mentions", 0.85, "2026-07-30T00:07:00"),
|
|
138
|
+
("doc:proposal", "task:parity-harness", "relates_to", 0.84, "2026-07-30T00:08:00"),
|
|
139
|
+
("doc:proposal", "page:proposal-outline", "contains", 0.83, "2026-07-30T00:09:00"),
|
|
140
|
+
("deck:proposal", "doc:proposal", "relates_to", 0.82, "2026-07-29T00:00:00"),
|
|
141
|
+
("deck:proposal", "slide:proposal-1", "contains", 0.81, "2026-07-29T00:01:00"),
|
|
142
|
+
("file:meeting-minutes", "dec:doc-format", "relates_to", 0.80, "2026-07-28T00:00:00"),
|
|
143
|
+
("file:meeting-minutes", "meeting:weekly", "relates_to", 0.79, "2026-07-28T00:01:00"),
|
|
144
|
+
("chat:proposal", "doc:proposal", "mentions", 0.78, "2026-07-27T00:00:00"),
|
|
145
|
+
("img:proposal-sketch", "imgtext:proposal-ocr", "relates_to", 0.77, "2026-07-26T00:00:00"),
|
|
146
|
+
("imgtext:proposal-ocr", "concept:proposal", "mentions", 0.76, "2026-07-26T00:01:00"),
|
|
147
|
+
("audio:proposal-call", "task:proposal-review", "mentions", 0.75, "2026-07-25T00:00:00"),
|
|
148
|
+
("code:doc-builder", "feature:doc-generation", "relates_to", 0.74, "2026-07-24T00:00:00"),
|
|
149
|
+
("sheet:proposal-budget", "doc:proposal", "relates_to", 0.73, "2026-07-23T00:00:00"),
|
|
150
|
+
("doc:release-notes", "concept:ranking", "mentions", 0.72, "2026-07-22T00:00:00"),
|
|
151
|
+
("doc:undated", "concept:proposal", "mentions", 0.71, "2026-07-21T00:00:00"),
|
|
152
|
+
# The Self-Model's own shape: every fact points at the root.
|
|
153
|
+
("self:decision:a1", "self:root", "PART_OF", 1.0, "2026-07-02T00:00:00"),
|
|
154
|
+
("self:habit:b2", "self:root", "PART_OF", 1.0, "2026-07-03T00:00:00"),
|
|
155
|
+
("self:preference:c3", "self:root", "PART_OF", 1.0, "2026-07-04T00:00:00"),
|
|
156
|
+
("self:relationship:d4", "self:root", "PART_OF", 1.0, "2026-07-05T00:00:00"),
|
|
157
|
+
("self:trait:e5", "self:root", "PART_OF", 1.0, "2026-07-06T00:00:00"),
|
|
158
|
+
("self:unknown:f6", "self:root", "PART_OF", 1.0, "2026-07-07T00:00:00"),
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
# ── suite specs ──────────────────────────────────────────────────────────────
|
|
162
|
+
DOCGEN_SEARCH_SPECS: List[Dict[str, Any]] = [
|
|
163
|
+
{"key": "ko_proposal", "query": "제안서 초안"},
|
|
164
|
+
{"key": "ko_meeting", "query": "회의 결정 사항"},
|
|
165
|
+
{"key": "en_ranking", "query": "hybrid retrieval ranking"},
|
|
166
|
+
{"key": "ko_sketch", "query": "스케치"},
|
|
167
|
+
{"key": "ko_self_model", "query": "문서는 한국어로"},
|
|
168
|
+
{"key": "en_undated", "query": "Undated"},
|
|
169
|
+
{"key": "hub_deck", "query": "제안 발표자료"},
|
|
170
|
+
{"key": "tie", "query": "Tie candidate"},
|
|
171
|
+
{"key": "no_hit", "query": "zzqq wumpus nonsense"},
|
|
172
|
+
{"key": "empty_query", "query": ""},
|
|
173
|
+
{"key": "blank_query", "query": " "},
|
|
174
|
+
{"key": "limit_one", "query": "제안서", "limit": 1},
|
|
175
|
+
{"key": "limit_zero", "query": "제안서", "limit": 0},
|
|
176
|
+
{"key": "limit_over", "query": "제안서", "limit": 900},
|
|
177
|
+
{"key": "scoped_alpha", "query": "제안서", "allowed": [WS_ALPHA]},
|
|
178
|
+
{"key": "scoped_alpha_legacy", "query": "제안서", "allowed": [WS_ALPHA], "legacy": True},
|
|
179
|
+
{"key": "scoped_beta", "query": "제안서", "allowed": [WS_BETA]},
|
|
180
|
+
{"key": "scoped_empty", "query": "제안서", "allowed": []},
|
|
181
|
+
]
|
|
182
|
+
|
|
183
|
+
MULTI_HOP_SPECS: List[Dict[str, Any]] = [
|
|
184
|
+
*[{"key": f"hub_h{hops}", "node_ids": ["doc:proposal"], "max_hops": hops}
|
|
185
|
+
for hops in (0, 1, 2, 3)],
|
|
186
|
+
{"key": "hub_hneg", "node_ids": ["doc:proposal"], "max_hops": -1},
|
|
187
|
+
{"key": "multi_seed", "node_ids": ["doc:proposal", "dec:fusion-alpha"], "max_hops": 2},
|
|
188
|
+
{"key": "leaf", "node_ids": ["slide:proposal-1"], "max_hops": 2},
|
|
189
|
+
{"key": "isolated", "node_ids": ["tie:c"], "max_hops": 2},
|
|
190
|
+
{"key": "self_root", "node_ids": ["self:root"], "max_hops": 2},
|
|
191
|
+
{"key": "missing_seed", "node_ids": ["nope:missing"], "max_hops": 2},
|
|
192
|
+
{"key": "no_seeds", "node_ids": [], "max_hops": 2},
|
|
193
|
+
{"key": "scoped_alpha", "node_ids": ["doc:proposal"], "max_hops": 2,
|
|
194
|
+
"allowed": [WS_ALPHA]},
|
|
195
|
+
{"key": "scoped_alpha_legacy", "node_ids": ["doc:proposal"], "max_hops": 2,
|
|
196
|
+
"allowed": [WS_ALPHA], "legacy": True},
|
|
197
|
+
{"key": "scoped_beta", "node_ids": ["deck:proposal"], "max_hops": 2,
|
|
198
|
+
"allowed": [WS_BETA]},
|
|
199
|
+
{"key": "scoped_empty", "node_ids": ["doc:proposal"], "max_hops": 2, "allowed": []},
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
CONTEXT_DOCUMENT_SPECS: List[Dict[str, Any]] = [
|
|
203
|
+
{"key": "default", "query": "제안서 초안"},
|
|
204
|
+
{"key": "no_self_model", "query": "제안서 초안", "include_self_model": False},
|
|
205
|
+
{"key": "self_model_tokens_small", "query": "제안서 초안", "self_model_tokens": 12},
|
|
206
|
+
{"key": "budget_240", "query": "제안서 초안", "budget": 240},
|
|
207
|
+
{"key": "budget_120", "query": "제안서 초안", "budget": 120},
|
|
208
|
+
{"key": "budget_40", "query": "제안서 초안", "budget": 40},
|
|
209
|
+
{"key": "budget_one", "query": "제안서 초안", "budget": 1},
|
|
210
|
+
{"key": "budget_zero", "query": "제안서 초안", "budget": 0},
|
|
211
|
+
{"key": "hops_zero", "query": "제안서 초안", "max_hops": 0},
|
|
212
|
+
{"key": "hops_three", "query": "제안서 초안", "max_hops": 3},
|
|
213
|
+
{"key": "results_two", "query": "제안서 초안", "max_results": 2},
|
|
214
|
+
{"key": "ko_meeting", "query": "회의 결정 사항"},
|
|
215
|
+
{"key": "en_ranking", "query": "hybrid retrieval ranking"},
|
|
216
|
+
{"key": "ko_sketch", "query": "스케치"},
|
|
217
|
+
{"key": "fallback_lexical", "query": "박민서 님"},
|
|
218
|
+
{"key": "fallback_empty", "query": "zzqq wumpus nonsense"},
|
|
219
|
+
{"key": "empty_query", "query": ""},
|
|
220
|
+
{"key": "scoped_alpha", "query": "제안서 초안", "allowed": [WS_ALPHA]},
|
|
221
|
+
{"key": "scoped_alpha_legacy", "query": "제안서 초안", "allowed": [WS_ALPHA],
|
|
222
|
+
"legacy": True},
|
|
223
|
+
{"key": "scoped_empty", "query": "제안서 초안", "allowed": []},
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def normalize_multi_hop(payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
228
|
+
"""Order a ``multi_hop_context`` answer deterministically.
|
|
229
|
+
|
|
230
|
+
**This is a golden normalization, not a port divergence.** Python's
|
|
231
|
+
traversal iterates ``frontier``, a ``set`` — so the order in which the
|
|
232
|
+
nodes of one hop are appended (and therefore the order their incident
|
|
233
|
+
edges are appended) depends on string hashing, which CPython randomizes
|
|
234
|
+
per process unless ``PYTHONHASHSEED`` is pinned. The *contents* are fully
|
|
235
|
+
determined (which nodes are visited, which edges are collected, and every
|
|
236
|
+
node's hop label); only the sequence is not, so the live response ordering
|
|
237
|
+
is unspecified and there is nothing for a port to reproduce.
|
|
238
|
+
|
|
239
|
+
Both sides therefore sort before comparing: nodes by ``(hop, id)``, edges
|
|
240
|
+
by ``(from, to, type, weight)``. The Rust port emits that order natively —
|
|
241
|
+
it is deterministic where Python is not, which is a strictly stronger
|
|
242
|
+
promise and not a different answer.
|
|
243
|
+
"""
|
|
244
|
+
return {
|
|
245
|
+
"nodes": sorted(payload["nodes"], key=lambda node: (node["hop"], node["id"])),
|
|
246
|
+
"edges": sorted(
|
|
247
|
+
payload["edges"],
|
|
248
|
+
key=lambda edge: (edge["from"], edge["to"], edge["type"], edge["weight"]),
|
|
249
|
+
),
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class OrderedMultiHopStore:
|
|
254
|
+
"""The store, with ``multi_hop_context`` ordered deterministically.
|
|
255
|
+
|
|
256
|
+
``retrieve_context_for_generation`` feeds the traversal's node list into
|
|
257
|
+
``extra_nodes``, and the concept section renders the first eight of it — so
|
|
258
|
+
Python's unordered ``frontier`` iteration reaches the *rendered markdown*,
|
|
259
|
+
not only the traversal payload. Both sides therefore see the normalized
|
|
260
|
+
order (see :func:`normalize_multi_hop`); every other attribute is forwarded
|
|
261
|
+
to the real store untouched.
|
|
262
|
+
"""
|
|
263
|
+
|
|
264
|
+
def __init__(self, store: Any):
|
|
265
|
+
self._store = store
|
|
266
|
+
|
|
267
|
+
def __getattr__(self, name: str) -> Any:
|
|
268
|
+
return getattr(self._store, name)
|
|
269
|
+
|
|
270
|
+
def multi_hop_context(self, *args: Any, **kwargs: Any) -> Dict[str, Any]:
|
|
271
|
+
return normalize_multi_hop(self._store.multi_hop_context(*args, **kwargs))
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def _scope(spec: Dict[str, Any]) -> Dict[str, Any]:
|
|
275
|
+
"""The graph-layer scope every document-generation read takes."""
|
|
276
|
+
allowed = spec.get("allowed")
|
|
277
|
+
return {
|
|
278
|
+
"allowed_workspaces": None if allowed is None else set(allowed),
|
|
279
|
+
"include_legacy_global": spec.get("legacy", False),
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def run_docgen_search(harness: Any, spec: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
284
|
+
"""``KnowledgeGraphStore.search_for_document_generation`` for one spec."""
|
|
285
|
+
return harness.store.search_for_document_generation(
|
|
286
|
+
spec["query"], limit=spec.get("limit", 10), **_scope(spec)
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def run_multi_hop(harness: Any, spec: Dict[str, Any]) -> Dict[str, Any]:
|
|
291
|
+
"""``multi_hop_context`` for one spec, in the normalized order."""
|
|
292
|
+
return normalize_multi_hop(
|
|
293
|
+
harness.store.multi_hop_context(
|
|
294
|
+
spec["node_ids"], max_hops=spec.get("max_hops", 2), **_scope(spec)
|
|
295
|
+
)
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def run_context_document(harness: Any, spec: Dict[str, Any]) -> Dict[str, Any]:
|
|
300
|
+
"""``retrieve_context_for_generation`` plus the footnote over its sources.
|
|
301
|
+
|
|
302
|
+
The footnote is a second public entry point over the same ``sources`` list;
|
|
303
|
+
carrying it here proves that port too, without a suite of its own.
|
|
304
|
+
"""
|
|
305
|
+
from lattice_brain.self_model import DEFAULT_SUMMARY_TOKENS
|
|
306
|
+
from latticeai.core.context_builder import (
|
|
307
|
+
DEFAULT_DOCUMENT_CONTEXT_BUDGET,
|
|
308
|
+
format_sources_footnote,
|
|
309
|
+
retrieve_context_for_generation,
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
context = retrieve_context_for_generation(
|
|
313
|
+
OrderedMultiHopStore(harness.store),
|
|
314
|
+
spec["query"],
|
|
315
|
+
max_results=spec.get("max_results", 10),
|
|
316
|
+
max_hops=spec.get("max_hops", 2),
|
|
317
|
+
budget=spec.get("budget", DEFAULT_DOCUMENT_CONTEXT_BUDGET),
|
|
318
|
+
include_self_model=spec.get("include_self_model", True),
|
|
319
|
+
self_model_tokens=spec.get("self_model_tokens", DEFAULT_SUMMARY_TOKENS),
|
|
320
|
+
**_scope(spec),
|
|
321
|
+
)
|
|
322
|
+
return {
|
|
323
|
+
"context": context,
|
|
324
|
+
"sources_footnote": format_sources_footnote(context["sources"]),
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
#: The three document-generation suites, as the generator merges them into
|
|
329
|
+
#: :data:`SUITES` / :data:`SUITE_RUNNERS`. Keeping the pair side by side is what
|
|
330
|
+
#: stops a spec list from arriving without the runner that answers it.
|
|
331
|
+
DOCGEN_SUITES: Dict[str, List[Dict[str, Any]]] = {
|
|
332
|
+
"docgen_search": DOCGEN_SEARCH_SPECS,
|
|
333
|
+
"multi_hop": MULTI_HOP_SPECS,
|
|
334
|
+
"context_document": CONTEXT_DOCUMENT_SPECS,
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
DOCGEN_RUNNERS: Dict[str, Any] = {
|
|
338
|
+
"docgen_search": run_docgen_search,
|
|
339
|
+
"multi_hop": run_multi_hop,
|
|
340
|
+
"context_document": run_context_document,
|
|
341
|
+
}
|
|
@@ -21,6 +21,27 @@
|
|
|
21
21
|
"specific, not less."
|
|
22
22
|
],
|
|
23
23
|
|
|
24
|
+
"11.5.1": {
|
|
25
|
+
"_why": [
|
|
26
|
+
"Rust Full Loop release: agent-loop orchestrator port, worker seams,",
|
|
27
|
+
"doc-gen context builder — backend only. The frontend bundle is",
|
|
28
|
+
"untouched; no captured screen changes on purpose. All thirteen",
|
|
29
|
+
"measured but not gated. Known jitter: 05-memory-graph moves ~2-3%",
|
|
30
|
+
"between captures from the cytoscape layout (11.3.0-11.5.0 observed)."
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
"11.5.0": {
|
|
35
|
+
"_why": [
|
|
36
|
+
"Rust Complete release: backend/desktop-topology architecture only",
|
|
37
|
+
"(router mounts, front-door default, scheduler, safety kernel). The",
|
|
38
|
+
"frontend bundle is untouched; no captured screen changes on purpose.",
|
|
39
|
+
"All thirteen measured but not gated. Known jitter: 05-memory-graph",
|
|
40
|
+
"moves ~2-3% between captures from the cytoscape layout (observed at",
|
|
41
|
+
"11.3.0 and 11.4.0 with zero source change)."
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
|
|
24
45
|
"11.4.0": {
|
|
25
46
|
"_why": [
|
|
26
47
|
"Rust Foundation release: backend architecture only (rust/ workspace,",
|
package/src-tauri/Cargo.lock
CHANGED
|
@@ -1728,22 +1728,40 @@ dependencies = [
|
|
|
1728
1728
|
"unicode-segmentation",
|
|
1729
1729
|
]
|
|
1730
1730
|
|
|
1731
|
+
[[package]]
|
|
1732
|
+
name = "lattice-agent"
|
|
1733
|
+
version = "11.5.1"
|
|
1734
|
+
dependencies = [
|
|
1735
|
+
"axum",
|
|
1736
|
+
"base64 0.22.1",
|
|
1737
|
+
"fancy-regex",
|
|
1738
|
+
"futures-core",
|
|
1739
|
+
"getrandom 0.4.3",
|
|
1740
|
+
"reqwest 0.12.28",
|
|
1741
|
+
"serde",
|
|
1742
|
+
"serde_json",
|
|
1743
|
+
"sha2",
|
|
1744
|
+
"tokio",
|
|
1745
|
+
]
|
|
1746
|
+
|
|
1731
1747
|
[[package]]
|
|
1732
1748
|
name = "lattice-ai-desktop"
|
|
1733
|
-
version = "11.
|
|
1749
|
+
version = "11.5.1"
|
|
1734
1750
|
dependencies = [
|
|
1735
1751
|
"lattice-host",
|
|
1752
|
+
"lattice-jobs",
|
|
1736
1753
|
"plist",
|
|
1737
1754
|
"serde",
|
|
1738
1755
|
"serde_json",
|
|
1739
1756
|
"tauri",
|
|
1740
1757
|
"tauri-build",
|
|
1741
1758
|
"time",
|
|
1759
|
+
"tokio",
|
|
1742
1760
|
]
|
|
1743
1761
|
|
|
1744
1762
|
[[package]]
|
|
1745
1763
|
name = "lattice-core"
|
|
1746
|
-
version = "11.
|
|
1764
|
+
version = "11.5.1"
|
|
1747
1765
|
dependencies = [
|
|
1748
1766
|
"blake2",
|
|
1749
1767
|
"rusqlite",
|
|
@@ -1753,10 +1771,13 @@ dependencies = [
|
|
|
1753
1771
|
|
|
1754
1772
|
[[package]]
|
|
1755
1773
|
name = "lattice-host"
|
|
1756
|
-
version = "11.
|
|
1774
|
+
version = "11.5.1"
|
|
1757
1775
|
dependencies = [
|
|
1758
1776
|
"axum",
|
|
1777
|
+
"lattice-agent",
|
|
1759
1778
|
"lattice-core",
|
|
1779
|
+
"lattice-ingest",
|
|
1780
|
+
"lattice-jobs",
|
|
1760
1781
|
"lattice-retrieval",
|
|
1761
1782
|
"libc",
|
|
1762
1783
|
"reqwest 0.12.28",
|
|
@@ -1765,15 +1786,43 @@ dependencies = [
|
|
|
1765
1786
|
"tokio",
|
|
1766
1787
|
]
|
|
1767
1788
|
|
|
1789
|
+
[[package]]
|
|
1790
|
+
name = "lattice-ingest"
|
|
1791
|
+
version = "11.5.1"
|
|
1792
|
+
dependencies = [
|
|
1793
|
+
"axum",
|
|
1794
|
+
"lattice-core",
|
|
1795
|
+
"reqwest 0.12.28",
|
|
1796
|
+
"serde",
|
|
1797
|
+
"serde_json",
|
|
1798
|
+
"sha2",
|
|
1799
|
+
"tokio",
|
|
1800
|
+
]
|
|
1801
|
+
|
|
1802
|
+
[[package]]
|
|
1803
|
+
name = "lattice-jobs"
|
|
1804
|
+
version = "11.5.1"
|
|
1805
|
+
dependencies = [
|
|
1806
|
+
"axum",
|
|
1807
|
+
"lattice-core",
|
|
1808
|
+
"reqwest 0.12.28",
|
|
1809
|
+
"serde",
|
|
1810
|
+
"serde_json",
|
|
1811
|
+
"tokio",
|
|
1812
|
+
]
|
|
1813
|
+
|
|
1768
1814
|
[[package]]
|
|
1769
1815
|
name = "lattice-retrieval"
|
|
1770
|
-
version = "11.
|
|
1816
|
+
version = "11.5.1"
|
|
1771
1817
|
dependencies = [
|
|
1818
|
+
"axum",
|
|
1772
1819
|
"fancy-regex",
|
|
1773
1820
|
"lattice-core",
|
|
1821
|
+
"libc",
|
|
1774
1822
|
"rusqlite",
|
|
1775
1823
|
"serde",
|
|
1776
1824
|
"serde_json",
|
|
1825
|
+
"tokio",
|
|
1777
1826
|
]
|
|
1778
1827
|
|
|
1779
1828
|
[[package]]
|
package/src-tauri/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "lattice-ai-desktop"
|
|
3
|
-
version = "11.
|
|
3
|
+
version = "11.5.1"
|
|
4
4
|
description = "Lattice AI Digital Brain desktop shell"
|
|
5
5
|
authors = ["TaeSoo Park"]
|
|
6
6
|
edition = "2021"
|
|
@@ -15,7 +15,14 @@ time = "=0.3.36"
|
|
|
15
15
|
serde = { version = "1", features = ["derive"] }
|
|
16
16
|
serde_json = "1"
|
|
17
17
|
# The supervisor (command resolution, spawn, HTTP health gate, backoff restart,
|
|
18
|
-
# graceful stop)
|
|
19
|
-
# workspace member: `rust/` must stay buildable
|
|
20
|
-
# system libraries, so this crate deliberately sits
|
|
18
|
+
# graceful stop) and, since 11.5.0, the gateway this shell serves as its front
|
|
19
|
+
# door. A path dependency, not a workspace member: `rust/` must stay buildable
|
|
20
|
+
# on a CI runner with no tauri system libraries, so this crate deliberately sits
|
|
21
|
+
# outside that workspace.
|
|
21
22
|
lattice-host = { path = "../rust/lattice-host" }
|
|
23
|
+
# The jobs scheduler type the shell holds while the gateway exposes it on
|
|
24
|
+
# `/host/jobs`. Same reason for the path form.
|
|
25
|
+
lattice-jobs = { path = "../rust/lattice-jobs" }
|
|
26
|
+
# The gateway is an axum server and the shell drives it on tokio's runtime,
|
|
27
|
+
# which tauri already embeds.
|
|
28
|
+
tokio = { version = "1", features = ["sync", "time", "rt"] }
|