ltcai 11.5.2 → 11.7.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.
Files changed (443) hide show
  1. package/README.md +93 -148
  2. package/bin/ltcai.js +234 -24
  3. package/docs/CHANGELOG.md +119 -0
  4. package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
  5. package/docs/DEVELOPMENT.md +8 -6
  6. package/docs/ENTERPRISE.md +2 -1
  7. package/docs/MULTI_AGENT_RUNTIME.md +12 -5
  8. package/docs/ONBOARDING.md +1 -1
  9. package/docs/OPERATIONS.md +6 -3
  10. package/docs/REALTIME_COLLABORATION.md +1 -1
  11. package/docs/TRUST_MODEL.md +1 -1
  12. package/docs/WHY_LATTICE.md +1 -1
  13. package/docs/WORKFLOW_DESIGNER.md +3 -2
  14. package/docs/kg-schema.md +1 -1
  15. package/docs/v11.6.0_ONE_DOOR_PLAN.md +170 -0
  16. package/lattice_brain/__init__.py +42 -79
  17. package/lattice_brain/graph/__init__.py +9 -24
  18. package/lattice_brain/graph/_kg_common/__init__.py +13 -24
  19. package/lattice_brain/ingestion/__init__.py +19 -58
  20. package/lattice_brain/ingestion/pipeline.py +20 -398
  21. package/lattice_brain/multimodal/__init__.py +7 -18
  22. package/lattice_brain/multimodal/images.py +6 -264
  23. package/lattice_brain/multimodal/video.py +8 -247
  24. package/lattice_brain/runtime/__init__.py +8 -79
  25. package/lattice_brain/runtime/hooks.py +22 -584
  26. package/latticeai/__init__.py +1 -1
  27. package/latticeai/api/agent_worker_seam.py +7 -80
  28. package/latticeai/api/health.py +6 -20
  29. package/latticeai/api/local_files.py +16 -613
  30. package/latticeai/api/models.py +12 -87
  31. package/latticeai/api/search.py +17 -255
  32. package/latticeai/api/tools.py +69 -750
  33. package/latticeai/api/voice_capture.py +8 -70
  34. package/latticeai/api/worker_compute.py +842 -0
  35. package/latticeai/api/worker_seams.py +216 -0
  36. package/latticeai/app_factory.py +23 -232
  37. package/latticeai/cli/entrypoint.py +36 -249
  38. package/latticeai/core/agent_permission.py +16 -91
  39. package/latticeai/core/messages.py +89 -531
  40. package/latticeai/runtime/access_runtime.py +0 -14
  41. package/latticeai/runtime/bootstrap.py +10 -21
  42. package/latticeai/runtime/brain_runtime.py +35 -43
  43. package/latticeai/runtime/build_phases/__init__.py +21 -37
  44. package/latticeai/runtime/build_phases/features.py +99 -389
  45. package/latticeai/runtime/build_phases/foundation.py +82 -392
  46. package/latticeai/runtime/build_phases/web.py +91 -408
  47. package/latticeai/runtime/build_phases/worker_profile.py +244 -0
  48. package/latticeai/runtime/lifespan_runtime.py +7 -16
  49. package/latticeai/runtime/platform_services_runtime.py +1 -15
  50. package/latticeai/runtime/runtime_context.py +13 -130
  51. package/latticeai/runtime/security_runtime.py +10 -103
  52. package/latticeai/services/architecture_readiness.py +82 -43
  53. package/latticeai/services/model_runtime/__init__.py +2 -11
  54. package/latticeai/services/model_runtime/service.py +4 -28
  55. package/latticeai/services/p_reinforce.py +10 -261
  56. package/latticeai/services/product_readiness.py +31 -38
  57. package/latticeai/services/search_service.py +37 -795
  58. package/latticeai/services/tool_dispatch.py +30 -386
  59. package/latticeai/services/voice_capture.py +13 -107
  60. package/latticeai/tools/__init__.py +22 -49
  61. package/latticeai/tools/commands.py +0 -163
  62. package/latticeai/tools/computer.py +0 -39
  63. package/latticeai/tools/documents.py +1 -134
  64. package/latticeai/tools/filesystem.py +1 -247
  65. package/latticeai/tools/knowledge.py +1 -52
  66. package/latticeai/tools/local_files.py +0 -20
  67. package/latticeai/worker_app.py +75 -0
  68. package/package.json +2 -3
  69. package/requirements.txt +0 -5
  70. package/scripts/agent_eval.py +16 -28
  71. package/scripts/brain_quality_eval.py +20 -183
  72. package/scripts/bump_version.py +5 -5
  73. package/scripts/check_current_release_docs.mjs +7 -4
  74. package/scripts/check_openapi_drift.mjs +10 -0
  75. package/scripts/check_server_i18n.mjs +2 -18
  76. package/scripts/compose_openapi.py +377 -0
  77. package/scripts/export_openapi.py +32 -4
  78. package/scripts/gen_messages_catalog_fixture.py +302 -0
  79. package/scripts/gen_openapi_fragments.py +365 -0
  80. package/scripts/gen_redact_fixture.py +196 -0
  81. package/scripts/gen_worker_allowlist_fixture.py +115 -0
  82. package/scripts/generate_agent_parity_fixtures.py +33 -14
  83. package/scripts/openapi_route_families.json +2161 -0
  84. package/scripts/release_screen_claims.json +54 -0
  85. package/scripts/run_integration_tests.mjs +134 -29
  86. package/scripts/run_sidecar_e2e.mjs +104 -11
  87. package/scripts/wheel_smoke.py +32 -22
  88. package/src-tauri/Cargo.lock +375 -9
  89. package/src-tauri/Cargo.toml +1 -1
  90. package/src-tauri/src/backend.rs +151 -45
  91. package/src-tauri/src/main.rs +18 -18
  92. package/src-tauri/src/topology.rs +58 -88
  93. package/src-tauri/tauri.conf.json +1 -2
  94. package/static/app/asset-manifest.json +41 -41
  95. package/static/app/assets/{Act-DcQizkl1.js → Act-BPcVAbOL.js} +1 -1
  96. package/static/app/assets/AdminConsole-Bw1ATQL0.js +1 -0
  97. package/static/app/assets/{Brain-3VCSHFcn.js → Brain-CT92Kos0.js} +2 -2
  98. package/static/app/assets/{BrainHome-Qm8eaztx.js → BrainHome-CFBkt1K_.js} +1 -1
  99. package/static/app/assets/{BrainSignals-DS9BtKOW.js → BrainSignals-ReLWF2H8.js} +1 -1
  100. package/static/app/assets/Capture-BsTokYkk.js +1 -0
  101. package/static/app/assets/{Chronicle-BGvuAchH.js → Chronicle-B6f0T9id.js} +1 -1
  102. package/static/app/assets/{CommandPalette-Bqhm0Urn.js → CommandPalette-CuvjTv1u.js} +1 -1
  103. package/static/app/assets/{Library-BV6NnF0a.js → Library-BGJbG9Hd.js} +1 -1
  104. package/static/app/assets/{LivingBrain-GzenJchP.js → LivingBrain-DGYK_Jsa.js} +1 -1
  105. package/static/app/assets/{ProductFlow-DEP6-vML.js → ProductFlow-DXBC6brE.js} +1 -1
  106. package/static/app/assets/{ReviewCard-CNZ7XjWG.js → ReviewCard-HXRle3qq.js} +2 -2
  107. package/static/app/assets/System-CMHSO9qM.js +1 -0
  108. package/static/app/assets/arrow-left-BfmkskWx.js +1 -0
  109. package/static/app/assets/{bot-B_K1Tdmw.js → bot-Cn8bWRuq.js} +1 -1
  110. package/static/app/assets/{brain-DWyaV1L1.js → brain-CQJberbE.js} +1 -1
  111. package/static/app/assets/{button-aTn4s84A.js → button-Ct9f2_oT.js} +1 -1
  112. package/static/app/assets/circle-check-DruOxB-4.js +1 -0
  113. package/static/app/assets/{circle-pause-xKgeGXkT.js → circle-pause-CmzC_apg.js} +1 -1
  114. package/static/app/assets/{circle-play-DkT6tYPX.js → circle-play-D8mW2aQ7.js} +1 -1
  115. package/static/app/assets/{cpu-85xYObUC.js → cpu-DZcdd0PZ.js} +1 -1
  116. package/static/app/assets/{download-B5Fm7YXo.js → download-bv1KEPGQ.js} +1 -1
  117. package/static/app/assets/{folder-open-kk2Xa52u.js → folder-open-d-Pip5gr.js} +1 -1
  118. package/static/app/assets/{hard-drive-DkA3zBW_.js → hard-drive-D20iavUb.js} +1 -1
  119. package/static/app/assets/index-D9x-kSNy.css +2 -0
  120. package/static/app/assets/{index-BMPdTmlY.js → index-Do83hDzJ.js} +3 -3
  121. package/static/app/assets/{input-B0nRf2jO.js → input-BLXVNmj1.js} +1 -1
  122. package/static/app/assets/{link-2-Dwb4gnTc.js → link-2-BPJOFlAy.js} +1 -1
  123. package/static/app/assets/{permissionCopy-CQDUBrOZ.js → permissionCopy-ChdJd493.js} +1 -1
  124. package/static/app/assets/primitives-Cv5tbZBY.js +1 -0
  125. package/static/app/assets/search-CT9aho2j.js +1 -0
  126. package/static/app/assets/{share-2-BsrxFglO.js → share-2-YNX_NtMU.js} +1 -1
  127. package/static/app/assets/{shield-alert-5BStfp2_.js → shield-alert-DuQ3zrVL.js} +1 -1
  128. package/static/app/assets/{textarea-Cg8IUA-k.js → textarea-DqwLnli4.js} +1 -1
  129. package/static/app/assets/{useFocusTrap-CYKvE46M.js → useFocusTrap-ZVI98jaW.js} +1 -1
  130. package/static/app/assets/{useMutation-CSn9t1op.js → useMutation-CVC4qv_D.js} +1 -1
  131. package/static/app/assets/{useQuery-CY2OI2uy.js → useQuery-C7BeG4HU.js} +1 -1
  132. package/static/app/assets/{utils-Ddol2RWD.js → utils-CiFtIdZq.js} +1 -1
  133. package/static/app/assets/{workspace-BqDwOz_p.js → workspace-DQz9vIId.js} +1 -1
  134. package/static/app/index.html +4 -4
  135. package/static/sw.js +1 -1
  136. package/lattice_brain/archive.py +0 -522
  137. package/lattice_brain/context.py +0 -325
  138. package/lattice_brain/conversations.py +0 -382
  139. package/lattice_brain/core.py +0 -82
  140. package/lattice_brain/graph/_kg_contract.py +0 -249
  141. package/lattice_brain/graph/curator.py +0 -676
  142. package/lattice_brain/graph/discovery.py +0 -595
  143. package/lattice_brain/graph/discovery_index/__init__.py +0 -35
  144. package/lattice_brain/graph/discovery_index/cleanup.py +0 -182
  145. package/lattice_brain/graph/discovery_index/extract.py +0 -137
  146. package/lattice_brain/graph/discovery_index/scan.py +0 -411
  147. package/lattice_brain/graph/discovery_index/upsert.py +0 -495
  148. package/lattice_brain/graph/documents.py +0 -380
  149. package/lattice_brain/graph/fusion.py +0 -395
  150. package/lattice_brain/graph/identity.py +0 -175
  151. package/lattice_brain/graph/image_vectors.py +0 -230
  152. package/lattice_brain/graph/ingest.py +0 -829
  153. package/lattice_brain/graph/network.py +0 -205
  154. package/lattice_brain/graph/proactive.py +0 -724
  155. package/lattice_brain/graph/projection/__init__.py +0 -42
  156. package/lattice_brain/graph/projection/curation.py +0 -500
  157. package/lattice_brain/graph/projection/v2_schema.py +0 -518
  158. package/lattice_brain/graph/provenance.py +0 -524
  159. package/lattice_brain/graph/rerank.py +0 -163
  160. package/lattice_brain/graph/retrieval/__init__.py +0 -54
  161. package/lattice_brain/graph/retrieval/context.py +0 -197
  162. package/lattice_brain/graph/retrieval/graph_view.py +0 -319
  163. package/lattice_brain/graph/retrieval/hybrid.py +0 -488
  164. package/lattice_brain/graph/retrieval/maintenance.py +0 -121
  165. package/lattice_brain/graph/retrieval/signals.py +0 -95
  166. package/lattice_brain/graph/retrieval_docgen.py +0 -253
  167. package/lattice_brain/graph/retrieval_policy.py +0 -180
  168. package/lattice_brain/graph/retrieval_reads.py +0 -769
  169. package/lattice_brain/graph/retrieval_vector/__init__.py +0 -42
  170. package/lattice_brain/graph/retrieval_vector/fingerprint.py +0 -97
  171. package/lattice_brain/graph/retrieval_vector/indexing.py +0 -347
  172. package/lattice_brain/graph/retrieval_vector/search.py +0 -560
  173. package/lattice_brain/graph/retrieval_vector/status.py +0 -374
  174. package/lattice_brain/graph/schema.py +0 -792
  175. package/lattice_brain/graph/store.py +0 -268
  176. package/lattice_brain/graph/vector_index/__init__.py +0 -85
  177. package/lattice_brain/graph/vector_index/base.py +0 -167
  178. package/lattice_brain/graph/vector_index/brute_force.py +0 -110
  179. package/lattice_brain/graph/vector_index/hnsw.py +0 -290
  180. package/lattice_brain/graph/vector_index/jobs.py +0 -287
  181. package/lattice_brain/graph/vector_index/quantized.py +0 -148
  182. package/lattice_brain/graph/vector_index/selector.py +0 -161
  183. package/lattice_brain/graph/write_master.py +0 -308
  184. package/lattice_brain/ingestion/_contract.py +0 -90
  185. package/lattice_brain/ingestion/folder_scan.py +0 -57
  186. package/lattice_brain/ingestion/folders.py +0 -258
  187. package/lattice_brain/ingestion/jobs_api.py +0 -107
  188. package/lattice_brain/ingestion/routing.py +0 -295
  189. package/lattice_brain/ingestion_jobs.py +0 -380
  190. package/lattice_brain/memory.py +0 -75
  191. package/lattice_brain/portability/__init__.py +0 -90
  192. package/lattice_brain/portability/_contract.py +0 -42
  193. package/lattice_brain/portability/backups.py +0 -338
  194. package/lattice_brain/portability/bundles.py +0 -136
  195. package/lattice_brain/portability/constants.py +0 -93
  196. package/lattice_brain/portability/fsops.py +0 -138
  197. package/lattice_brain/portability/service.py +0 -41
  198. package/lattice_brain/portability/sharing.py +0 -710
  199. package/lattice_brain/quality.py +0 -543
  200. package/lattice_brain/retrieval_benchmark_fixtures.py +0 -92
  201. package/lattice_brain/runtime/agent_runtime.py +0 -859
  202. package/lattice_brain/runtime/contracts.py +0 -460
  203. package/lattice_brain/runtime/multi_agent.py +0 -942
  204. package/lattice_brain/runtime/statuses.py +0 -10
  205. package/lattice_brain/sealed_box.py +0 -240
  206. package/lattice_brain/self_model.py +0 -675
  207. package/lattice_brain/sensitivity.py +0 -94
  208. package/lattice_brain/storage/__init__.py +0 -22
  209. package/lattice_brain/storage/base.py +0 -100
  210. package/lattice_brain/storage/docker.py +0 -105
  211. package/lattice_brain/storage/factory.py +0 -31
  212. package/lattice_brain/storage/migration.py +0 -191
  213. package/lattice_brain/storage/postgres.py +0 -123
  214. package/lattice_brain/storage/sqlite.py +0 -143
  215. package/lattice_brain/synthesis.py +0 -824
  216. package/lattice_brain/workflow.py +0 -497
  217. package/latticeai/api/admin.py +0 -471
  218. package/latticeai/api/agent_registry.py +0 -105
  219. package/latticeai/api/agents.py +0 -228
  220. package/latticeai/api/auth.py +0 -383
  221. package/latticeai/api/automation_intelligence.py +0 -401
  222. package/latticeai/api/brain_intelligence.py +0 -199
  223. package/latticeai/api/browser.py +0 -493
  224. package/latticeai/api/change_proposals.py +0 -89
  225. package/latticeai/api/chat.py +0 -572
  226. package/latticeai/api/chat_agent_http.py +0 -892
  227. package/latticeai/api/chat_contracts.py +0 -73
  228. package/latticeai/api/chat_documents.py +0 -276
  229. package/latticeai/api/chat_helpers.py +0 -460
  230. package/latticeai/api/chat_history.py +0 -101
  231. package/latticeai/api/chat_hybrid.py +0 -113
  232. package/latticeai/api/chat_intents.py +0 -646
  233. package/latticeai/api/chat_stream.py +0 -216
  234. package/latticeai/api/chronicle.py +0 -63
  235. package/latticeai/api/command_center.py +0 -51
  236. package/latticeai/api/computer_use.py +0 -474
  237. package/latticeai/api/evidence_actions.py +0 -48
  238. package/latticeai/api/features.py +0 -70
  239. package/latticeai/api/funnel_metrics.py +0 -31
  240. package/latticeai/api/garden.py +0 -34
  241. package/latticeai/api/hooks.py +0 -165
  242. package/latticeai/api/index_jobs.py +0 -145
  243. package/latticeai/api/invitations.py +0 -100
  244. package/latticeai/api/knowledge_graph.py +0 -536
  245. package/latticeai/api/marketplace.py +0 -105
  246. package/latticeai/api/mcp.py +0 -482
  247. package/latticeai/api/memory.py +0 -270
  248. package/latticeai/api/network.py +0 -81
  249. package/latticeai/api/network_boundary.py +0 -225
  250. package/latticeai/api/permission_mode.py +0 -61
  251. package/latticeai/api/permissions.py +0 -436
  252. package/latticeai/api/plugins.py +0 -126
  253. package/latticeai/api/portability.py +0 -391
  254. package/latticeai/api/project_sessions.py +0 -114
  255. package/latticeai/api/realtime.py +0 -118
  256. package/latticeai/api/review_queue.py +0 -364
  257. package/latticeai/api/security_dashboard.py +0 -604
  258. package/latticeai/api/setup.py +0 -319
  259. package/latticeai/api/static_routes.py +0 -354
  260. package/latticeai/api/ui_redirects.py +0 -26
  261. package/latticeai/api/workflow_designer.py +0 -394
  262. package/latticeai/api/workspace.py +0 -856
  263. package/latticeai/api/workspace_scope.py +0 -125
  264. package/latticeai/core/agent/__init__.py +0 -93
  265. package/latticeai/core/agent/_contract.py +0 -79
  266. package/latticeai/core/agent/context.py +0 -57
  267. package/latticeai/core/agent/deps.py +0 -125
  268. package/latticeai/core/agent/execution.py +0 -622
  269. package/latticeai/core/agent/planning.py +0 -145
  270. package/latticeai/core/agent/recovery.py +0 -157
  271. package/latticeai/core/agent/runtime.py +0 -210
  272. package/latticeai/core/agent/verification.py +0 -231
  273. package/latticeai/core/agent_eval.py +0 -739
  274. package/latticeai/core/agent_helpers.py +0 -493
  275. package/latticeai/core/agent_profiles.py +0 -110
  276. package/latticeai/core/agent_prompts.py +0 -171
  277. package/latticeai/core/agent_registry.py +0 -232
  278. package/latticeai/core/agent_state.py +0 -41
  279. package/latticeai/core/agent_trace.py +0 -104
  280. package/latticeai/core/artifact_ledger.py +0 -109
  281. package/latticeai/core/audit.py +0 -260
  282. package/latticeai/core/builtin_hooks.py +0 -105
  283. package/latticeai/core/context_builder.py +0 -394
  284. package/latticeai/core/document_generator.py +0 -103
  285. package/latticeai/core/enterprise.py +0 -154
  286. package/latticeai/core/enterprise_admin.py +0 -158
  287. package/latticeai/core/file_generation/__init__.py +0 -115
  288. package/latticeai/core/file_generation/bundles.py +0 -76
  289. package/latticeai/core/file_generation/extraction.py +0 -154
  290. package/latticeai/core/file_generation/inference.py +0 -235
  291. package/latticeai/core/file_generation/orchestration.py +0 -152
  292. package/latticeai/core/file_generation/prompting.py +0 -117
  293. package/latticeai/core/file_generation/repair.py +0 -114
  294. package/latticeai/core/file_generation/sanitize.py +0 -61
  295. package/latticeai/core/file_generation/validation.py +0 -201
  296. package/latticeai/core/invitations.py +0 -132
  297. package/latticeai/core/legacy_compatibility.py +0 -243
  298. package/latticeai/core/logging_safety.py +0 -46
  299. package/latticeai/core/marketplace.py +0 -293
  300. package/latticeai/core/mcp_catalog.py +0 -452
  301. package/latticeai/core/mcp_registry.py +0 -506
  302. package/latticeai/core/network_boundary.py +0 -168
  303. package/latticeai/core/oidc.py +0 -208
  304. package/latticeai/core/plugins.py +0 -432
  305. package/latticeai/core/product_hardening.py +0 -218
  306. package/latticeai/core/project_sessions.py +0 -337
  307. package/latticeai/core/realtime.py +0 -238
  308. package/latticeai/core/run_explain.py +0 -426
  309. package/latticeai/core/run_store.py +0 -252
  310. package/latticeai/core/timezones.py +0 -80
  311. package/latticeai/core/workspace_computer_memory.py +0 -84
  312. package/latticeai/core/workspace_graph_trace.py +0 -155
  313. package/latticeai/core/workspace_indexing.py +0 -102
  314. package/latticeai/core/workspace_memory.py +0 -77
  315. package/latticeai/core/workspace_onboarding.py +0 -104
  316. package/latticeai/core/workspace_os.py +0 -978
  317. package/latticeai/core/workspace_os_constants.py +0 -126
  318. package/latticeai/core/workspace_os_state.py +0 -180
  319. package/latticeai/core/workspace_os_utils.py +0 -103
  320. package/latticeai/core/workspace_permissions.py +0 -101
  321. package/latticeai/core/workspace_plugins.py +0 -97
  322. package/latticeai/core/workspace_relationships.py +0 -99
  323. package/latticeai/core/workspace_reorganization.py +0 -335
  324. package/latticeai/core/workspace_review_items.py +0 -112
  325. package/latticeai/core/workspace_runs.py +0 -726
  326. package/latticeai/core/workspace_skills.py +0 -109
  327. package/latticeai/core/workspace_snapshots.py +0 -198
  328. package/latticeai/core/workspace_timeline.py +0 -110
  329. package/latticeai/integrations/__init__.py +0 -0
  330. package/latticeai/integrations/telegram_bot/__init__.py +0 -123
  331. package/latticeai/integrations/telegram_bot/__main__.py +0 -17
  332. package/latticeai/integrations/telegram_bot/config.py +0 -86
  333. package/latticeai/integrations/telegram_bot/dispatch.py +0 -311
  334. package/latticeai/integrations/telegram_bot/flows.py +0 -478
  335. package/latticeai/integrations/telegram_bot/helpers.py +0 -322
  336. package/latticeai/integrations/telegram_bot/screens.py +0 -394
  337. package/latticeai/runtime/audit_runtime.py +0 -76
  338. package/latticeai/runtime/automation_runtime.py +0 -81
  339. package/latticeai/runtime/chat_wiring.py +0 -141
  340. package/latticeai/runtime/context_runtime.py +0 -66
  341. package/latticeai/runtime/feature_toggle_wiring.py +0 -157
  342. package/latticeai/runtime/history_runtime.py +0 -163
  343. package/latticeai/runtime/history_writer.py +0 -138
  344. package/latticeai/runtime/hooks_runtime.py +0 -77
  345. package/latticeai/runtime/model_wiring.py +0 -68
  346. package/latticeai/runtime/namespace_runtime.py +0 -163
  347. package/latticeai/runtime/network_boundary_wiring.py +0 -117
  348. package/latticeai/runtime/network_config_runtime.py +0 -56
  349. package/latticeai/runtime/permission_mode_wiring.py +0 -112
  350. package/latticeai/runtime/persistence_runtime.py +0 -159
  351. package/latticeai/runtime/platform_runtime_wiring.py +0 -89
  352. package/latticeai/runtime/review_wiring.py +0 -42
  353. package/latticeai/runtime/router_registration.py +0 -693
  354. package/latticeai/runtime/service_singletons.py +0 -55
  355. package/latticeai/runtime/sso_config_runtime.py +0 -128
  356. package/latticeai/runtime/user_key_runtime.py +0 -106
  357. package/latticeai/runtime/web_runtime.py +0 -92
  358. package/latticeai/server_app.py +0 -51
  359. package/latticeai/services/app_context.py +0 -130
  360. package/latticeai/services/automation_execution.py +0 -266
  361. package/latticeai/services/automation_intelligence.py +0 -614
  362. package/latticeai/services/brain_automation.py +0 -191
  363. package/latticeai/services/brain_intelligence/__init__.py +0 -58
  364. package/latticeai/services/brain_intelligence/_contract.py +0 -71
  365. package/latticeai/services/brain_intelligence/consistency.py +0 -193
  366. package/latticeai/services/brain_intelligence/constants.py +0 -47
  367. package/latticeai/services/brain_intelligence/digest.py +0 -258
  368. package/latticeai/services/brain_intelligence/health.py +0 -331
  369. package/latticeai/services/brain_intelligence/proposals.py +0 -259
  370. package/latticeai/services/brain_intelligence/sampling.py +0 -84
  371. package/latticeai/services/brain_intelligence/service.py +0 -48
  372. package/latticeai/services/change_proposals.py +0 -471
  373. package/latticeai/services/chat_service.py +0 -243
  374. package/latticeai/services/chronicle.py +0 -555
  375. package/latticeai/services/cloud_egress_audit.py +0 -85
  376. package/latticeai/services/cloud_extraction.py +0 -129
  377. package/latticeai/services/cloud_streaming.py +0 -268
  378. package/latticeai/services/cloud_token_guard.py +0 -84
  379. package/latticeai/services/command_center.py +0 -548
  380. package/latticeai/services/evidence_actions.py +0 -258
  381. package/latticeai/services/feature_toggles.py +0 -502
  382. package/latticeai/services/folder_watch.py +0 -520
  383. package/latticeai/services/funnel_metrics.py +0 -307
  384. package/latticeai/services/hybrid_chat.py +0 -316
  385. package/latticeai/services/hybrid_context.py +0 -228
  386. package/latticeai/services/hybrid_policy.py +0 -129
  387. package/latticeai/services/interop_bridges.py +0 -978
  388. package/latticeai/services/local_knowledge.py +0 -465
  389. package/latticeai/services/memory_service/__init__.py +0 -52
  390. package/latticeai/services/memory_service/_contract.py +0 -100
  391. package/latticeai/services/memory_service/brief.py +0 -431
  392. package/latticeai/services/memory_service/constants.py +0 -57
  393. package/latticeai/services/memory_service/maintenance.py +0 -138
  394. package/latticeai/services/memory_service/manager.py +0 -186
  395. package/latticeai/services/memory_service/proof.py +0 -136
  396. package/latticeai/services/memory_service/recall.py +0 -225
  397. package/latticeai/services/memory_service/service.py +0 -48
  398. package/latticeai/services/memory_service/stores.py +0 -110
  399. package/latticeai/services/mode_store.py +0 -132
  400. package/latticeai/services/model_recommendation.py +0 -224
  401. package/latticeai/services/model_runtime/cloud.py +0 -87
  402. package/latticeai/services/network_boundary_service.py +0 -117
  403. package/latticeai/services/obsidian_bridge.py +0 -609
  404. package/latticeai/services/openai_compatible_adapter.py +0 -101
  405. package/latticeai/services/permission_mode_service.py +0 -122
  406. package/latticeai/services/platform_runtime.py +0 -366
  407. package/latticeai/services/review_queue.py +0 -380
  408. package/latticeai/services/router_context.py +0 -59
  409. package/latticeai/services/run_executor.py +0 -387
  410. package/latticeai/services/self_model_service.py +0 -171
  411. package/latticeai/services/setup_detection.py +0 -147
  412. package/latticeai/services/triggers.py +0 -378
  413. package/latticeai/services/upload_service.py +0 -172
  414. package/latticeai/services/workspace_service.py +0 -165
  415. package/latticeai/setup/__init__.py +0 -25
  416. package/latticeai/setup/auto_setup.py +0 -846
  417. package/latticeai/setup/demo_corpus.py +0 -98
  418. package/latticeai/setup/wizard/__init__.py +0 -126
  419. package/latticeai/setup/wizard/catalog.py +0 -175
  420. package/latticeai/setup/wizard/detect.py +0 -302
  421. package/latticeai/setup/wizard/install.py +0 -348
  422. package/latticeai/setup/wizard/paths.py +0 -165
  423. package/latticeai/setup/wizard/plans.py +0 -74
  424. package/latticeai/setup/wizard/recommend.py +0 -320
  425. package/scripts/bench_agent_smoke.py +0 -409
  426. package/scripts/bench_models.py +0 -540
  427. package/scripts/bench_vector_index.py +0 -295
  428. package/scripts/funnel_soft_gate.py +0 -192
  429. package/scripts/generate_agent_loop_fixtures.py +0 -994
  430. package/scripts/generate_rust_parity_fixtures.py +0 -908
  431. package/scripts/migrate_brain_storage.py +0 -57
  432. package/scripts/parity_fixture_corpus_context.py +0 -162
  433. package/scripts/parity_fixture_corpus_docgen.py +0 -341
  434. package/scripts/profile_kg.py +0 -355
  435. package/server.py +0 -30
  436. package/static/app/assets/AdminConsole-cf4npybT.js +0 -1
  437. package/static/app/assets/Capture-DiQ219jW.js +0 -1
  438. package/static/app/assets/System-CieofHQa.js +0 -1
  439. package/static/app/assets/arrow-left-kfsrk0mv.js +0 -1
  440. package/static/app/assets/circle-check-qqLug9nU.js +0 -1
  441. package/static/app/assets/index-DxmOfNRi.css +0 -2
  442. package/static/app/assets/primitives-SNp0LRJz.js +0 -1
  443. package/static/app/assets/search-BcHqkjoy.js +0 -1
@@ -14,6 +14,11 @@
14
14
  //! navigates to the gateway, and the worker is told to trust that origin so
15
15
  //! cookie-authenticated writes still work through the proxy hop.
16
16
  //!
17
+ //! 11.6.0 One Door: the Python-direct topologies are gone. The shell always
18
+ //! boots or attaches through lattice-host. The window health-gates on
19
+ //! `GET {origin}/health` — the **host** surface at the same origin the window
20
+ //! loads, not a bare worker port.
21
+ //!
17
22
  //! Which arrangement is chosen lives in [`crate::topology`]; what this module
18
23
  //! adds is the running of it, and the five IPC contracts on top (unchanged in
19
24
  //! name, type and meaning — the new status fields are additive).
@@ -26,10 +31,18 @@ use lattice_host::supervisor::{
26
31
  wait_for_health, HostProbe, Supervisor, SupervisorConfig, SupervisorError, SystemProbe,
27
32
  WorkerStatus,
28
33
  };
34
+
29
35
  use serde::Serialize;
30
36
 
31
37
  use crate::topology::{self, Plan, Topology};
32
38
 
39
+ /// The module the host supervises. I6's launch string is
40
+ /// `uvicorn latticeai.worker_app:create_worker_app --factory`; the module form
41
+ /// reads `LATTICEAI_PORT` from the supervisor, so we do not have to know the
42
+ /// internal port at pin time.
43
+ const WORKER_MODULE: &str = "latticeai.worker_app";
44
+ const BACKEND_CMD_ENV: &str = "LATTICEAI_DESKTOP_BACKEND_CMD";
45
+
33
46
  /// The desktop shell's view of the worker.
34
47
  ///
35
48
  /// The first six fields are the contract `latticeApi.desktopBackendStatus`
@@ -54,14 +67,14 @@ pub struct BackendStatus {
54
67
  pub healthy: bool,
55
68
  /// The chosen port — authoritative, not the configured preference.
56
69
  pub port: u16,
57
- /// `false` when the shell only fronts a worker it did not start.
70
+ /// `false` when the shell only fronts a host it did not start.
58
71
  pub supervised: bool,
59
72
  /// How many times the supervisor restarted the worker after a crash.
60
73
  pub restarts: u32,
61
74
  /// Seconds since the current worker process started.
62
75
  pub uptime_seconds: Option<u64>,
63
- /// Which arrangement this shell is running: `gateway`, `direct`,
64
- /// `external` or `disabled` (11.5.0, additive).
76
+ /// Which arrangement this shell is running: `gateway` or `external`
77
+ /// (11.5.0, additive; `direct`/`disabled` retired in 11.6.0).
65
78
  pub topology: String,
66
79
  /// Where the worker itself answers. Equal to `origin` unless a gateway is
67
80
  /// in front of it (11.5.0, additive).
@@ -94,14 +107,71 @@ pub struct DesktopBackend {
94
107
  jobs: Option<Arc<lattice_jobs::Scheduler>>,
95
108
  /// Why the front door is not there, when it could not be bound.
96
109
  ///
97
- /// `None` means "nothing went wrong" — including in the topologies that
98
- /// serve no gateway at all, where the worker *is* the front door.
110
+ /// `None` means "nothing went wrong" — including in the topology that
111
+ /// attaches to someone else's host, where this process serves no gateway.
99
112
  gateway_error: Mutex<Option<String>>,
100
113
  }
101
114
 
115
+ /// True when the packaged Resources tree already carries a worker.
116
+ ///
117
+ /// Leave `LATTICEAI_DESKTOP_BACKEND_CMD` unset in that case so the supervisor
118
+ /// can point `PYTHONPATH` at the tree (its bundled-tree rule). Integrator
119
+ /// must flip `WORKER_MODULE` from `latticeai.cli.entrypoint` to
120
+ /// `latticeai.worker_app`.
121
+ fn bundled_worker_present(probe: &dyn HostProbe) -> bool {
122
+ let Some(resources) = probe.resource_dir() else {
123
+ return false;
124
+ };
125
+ for root in [resources.join("_up_"), resources] {
126
+ if probe.is_file(&root.join("latticeai").join("worker_app.py"))
127
+ || probe.is_file(&root.join("latticeai").join("cli").join("entrypoint.py"))
128
+ {
129
+ return true;
130
+ }
131
+ }
132
+ false
133
+ }
134
+
135
+ /// Command that pins the supervisor onto the worker, or `None` when an
136
+ /// existing override / bundled tree should win.
137
+ ///
138
+ /// `bin/ltcai.js` is now the **host** front door. If the supervisor still
139
+ /// treats `ltcai` on `PATH` as a worker (lattice-host rule 2), it would spawn
140
+ /// another host and recurse. Pinning `python -m latticeai.worker_app` closes
141
+ /// that hatch in the unpackaged shell. A caller that already set
142
+ /// `LATTICEAI_DESKTOP_BACKEND_CMD` is left alone.
143
+ fn worker_launch_command(probe: &dyn HostProbe) -> Option<String> {
144
+ if probe
145
+ .env_var(BACKEND_CMD_ENV)
146
+ .filter(|value| !value.trim().is_empty())
147
+ .is_some()
148
+ {
149
+ return None;
150
+ }
151
+ if bundled_worker_present(probe) {
152
+ return None;
153
+ }
154
+ let candidates = lattice_host::supervisor::command::python_candidates(probe);
155
+ let python = candidates
156
+ .iter()
157
+ .find(|program| probe.module_importable(program, WORKER_MODULE))
158
+ .cloned()
159
+ .or_else(|| candidates.first().cloned())
160
+ .unwrap_or_else(|| "python3".into());
161
+ Some(format!("{python} -m {WORKER_MODULE}"))
162
+ }
163
+
164
+ /// Pin the worker launch on the real process environment, once.
165
+ fn pin_worker_launch_if_needed(probe: &dyn HostProbe) {
166
+ if let Some(command) = worker_launch_command(probe) {
167
+ std::env::set_var(BACKEND_CMD_ENV, command);
168
+ }
169
+ }
170
+
102
171
  impl DesktopBackend {
103
172
  /// Resolve against the real machine.
104
173
  pub fn resolve() -> Result<Self, SupervisorError> {
174
+ pin_worker_launch_if_needed(&SystemProbe);
105
175
  Self::with_probe(Arc::new(SystemProbe))
106
176
  }
107
177
 
@@ -180,7 +250,8 @@ impl DesktopBackend {
180
250
  ///
181
251
  /// A failure here is logged rather than fatal — the window still opens, and
182
252
  /// the browser's own "cannot connect" plus this line is a better failure
183
- /// than a shell that exits. `LATTICEAI_DESKTOP_DIRECT=1` is the way out.
253
+ /// than a shell that exits. Attach to a running host with
254
+ /// `LATTICEAI_DESKTOP_BACKEND_ORIGIN` if this process cannot bind.
184
255
  async fn start_gateway(&self) {
185
256
  let Some(port) = self.plan.gateway_port else {
186
257
  return;
@@ -194,7 +265,8 @@ impl DesktopBackend {
194
265
  Err(err) => {
195
266
  let message = format!(
196
267
  "the gateway could not bind {addr}: {err} — \
197
- set LATTICEAI_DESKTOP_DIRECT=1 to run the worker as the front door"
268
+ set LATTICEAI_PORT to a free port, or \
269
+ LATTICEAI_DESKTOP_BACKEND_ORIGIN to an already-running lattice-host"
198
270
  );
199
271
  eprintln!("lattice-ai-desktop: {message}");
200
272
  // Recorded, not only logged: `plan.origin` names the port that
@@ -258,18 +330,12 @@ impl DesktopBackend {
258
330
  .agent_root()
259
331
  }
260
332
 
261
- /// Wait for `GET {origin}/health`, so the webview never lands on a page the
262
- /// worker has not started serving yet.
333
+ /// Wait for `GET {origin}/health` on the **host** origin the window loads.
263
334
  ///
264
335
  /// Replaces the old TCP-connect probe, which proved only that *something*
265
- /// had bound the port. In the gateway topology this probes through the
266
- /// proxy, which is the honest question: can the page the window is about to
267
- /// open reach a healthy worker? With the kill switch on there is nothing to
268
- /// wait for and this returns immediately.
336
+ /// had bound the port. After One Door this is never a bare worker port:
337
+ /// `plan.origin` is the in-process gateway or the attached lattice-host.
269
338
  pub async fn wait_until_serving(&self) -> bool {
270
- if self.plan.disabled {
271
- return false;
272
- }
273
339
  wait_for_health(
274
340
  &self.supervisor.client(),
275
341
  &self.plan.origin,
@@ -349,8 +415,8 @@ impl DesktopBackend {
349
415
  }
350
416
  if !self.supervised() {
351
417
  return format!(
352
- "external worker at {} (not started here)",
353
- self.plan.worker_origin
418
+ "external lattice-host at {} (not started here)",
419
+ self.plan.origin
354
420
  );
355
421
  }
356
422
  match &status.last_error {
@@ -384,16 +450,18 @@ mod tests {
384
450
  }
385
451
 
386
452
  #[test]
387
- fn the_direct_hatch_restores_the_previous_topology() {
453
+ fn a_retired_direct_flag_still_fronts_the_gateway() {
388
454
  let shell = backend(
389
455
  StaticProbe::new()
390
456
  .with_env(DIRECT_ENV, "1")
391
457
  .with_env(PORT_ENV, "41841"),
392
458
  );
393
- assert_eq!(shell.topology(), Topology::Direct);
394
- assert_eq!(shell.origin(), "http://127.0.0.1:41841");
395
- assert_eq!(shell.plan.worker_origin, shell.plan.origin);
396
- assert!(shell.jobs.is_none(), "no gateway, no /host/jobs to drive");
459
+ assert_eq!(shell.topology(), Topology::Gateway);
460
+ assert_ne!(shell.plan.worker_origin, shell.plan.origin);
461
+ assert!(
462
+ shell.jobs.is_some(),
463
+ "gateway topology still mounts /host/jobs"
464
+ );
397
465
  }
398
466
 
399
467
  #[test]
@@ -403,28 +471,33 @@ mod tests {
403
471
  assert_eq!(shell.app_url(), "http://127.0.0.1:9100/app");
404
472
  assert!(!shell.supervised());
405
473
  assert_eq!(shell.topology(), Topology::External);
474
+ assert!(
475
+ shell.jobs.is_none(),
476
+ "an attached host is not ours to schedule"
477
+ );
406
478
  }
407
479
 
408
480
  #[test]
409
- fn the_kill_switch_spawns_nothing_but_still_names_an_origin() {
410
- let shell = backend(StaticProbe::new().with_env(NO_BACKEND_ENV, "1"));
411
- assert!(!shell.supervised());
412
- assert!(shell.plan.disabled, "nothing will answer, so nothing waits");
413
- assert!(shell.origin().starts_with("http://127.0.0.1:"));
481
+ fn a_retired_kill_switch_still_fronts_the_gateway() {
482
+ let shell = backend(
483
+ StaticProbe::new()
484
+ .with_env(NO_BACKEND_ENV, "1")
485
+ .with_env(PORT_ENV, "41845"),
486
+ );
487
+ assert!(shell.supervised());
488
+ assert_eq!(shell.topology(), Topology::Gateway);
489
+ assert_eq!(shell.origin(), "http://127.0.0.1:41845");
414
490
  }
415
491
 
416
492
  #[test]
417
- fn an_explicit_origin_outranks_the_kill_switch() {
493
+ fn an_explicit_origin_outranks_the_retired_kill_switch() {
418
494
  let shell = backend(
419
495
  StaticProbe::new()
420
496
  .with_env(NO_BACKEND_ENV, "1")
421
497
  .with_env(ORIGIN_ENV, "http://127.0.0.1:9100"),
422
498
  );
423
499
  assert!(!shell.supervised(), "still nothing is spawned");
424
- assert!(
425
- !shell.plan.disabled,
426
- "a worker was named, so the shell waits"
427
- );
500
+ assert_eq!(shell.topology(), Topology::External);
428
501
  }
429
502
 
430
503
  #[test]
@@ -437,19 +510,19 @@ mod tests {
437
510
  shell.command_text(&status),
438
511
  "unavailable: worker unavailable"
439
512
  );
440
- status.command = Some("/usr/bin/python3 -m latticeai.cli.entrypoint".into());
513
+ status.command = Some("/usr/bin/python3 -m latticeai.worker_app".into());
441
514
  assert_eq!(
442
515
  shell.command_text(&status),
443
- "/usr/bin/python3 -m latticeai.cli.entrypoint"
516
+ "/usr/bin/python3 -m latticeai.worker_app"
444
517
  );
445
518
  }
446
519
 
447
520
  #[test]
448
- fn an_external_worker_is_named_by_its_own_origin() {
521
+ fn an_external_host_is_named_by_its_own_origin() {
449
522
  let shell = backend(StaticProbe::new().with_env(ORIGIN_ENV, "http://127.0.0.1:9100"));
450
523
  assert_eq!(
451
524
  shell.command_text(&WorkerStatus::idle(9100, false)),
452
- "external worker at http://127.0.0.1:9100 (not started here)"
525
+ "external lattice-host at http://127.0.0.1:9100 (not started here)"
453
526
  );
454
527
  }
455
528
 
@@ -470,18 +543,18 @@ mod tests {
470
543
  }
471
544
 
472
545
  #[test]
473
- fn a_direct_shell_reports_no_gateway_origin() {
474
- let shell = backend(StaticProbe::new().with_env(DIRECT_ENV, "1"));
475
- let value =
476
- serde_json::to_value(shell.render(&WorkerStatus::idle(4825, true))).expect("serialise");
477
- assert_eq!(value["topology"], "direct");
546
+ fn an_external_shell_reports_no_local_gateway_origin() {
547
+ let shell = backend(StaticProbe::new().with_env(ORIGIN_ENV, "http://127.0.0.1:9100"));
548
+ let value = serde_json::to_value(shell.render(&WorkerStatus::idle(9100, false)))
549
+ .expect("serialise");
550
+ assert_eq!(value["topology"], "external");
478
551
  assert!(value["gateway_origin"].is_null());
479
552
  assert_eq!(value["worker_origin"], value["origin"]);
480
553
  }
481
554
 
482
555
  #[test]
483
556
  fn stopping_a_gateway_that_never_started_is_a_no_op() {
484
- let shell = backend(StaticProbe::new().with_env(DIRECT_ENV, "1"));
557
+ let shell = backend(StaticProbe::new().with_env(ORIGIN_ENV, "http://127.0.0.1:9100"));
485
558
  shell.stop_gateway();
486
559
  shell.stop_gateway();
487
560
  }
@@ -492,7 +565,7 @@ mod tests {
492
565
  fn a_healthy_shell_names_no_gateway_error() {
493
566
  for probe in [
494
567
  StaticProbe::new().with_env(PORT_ENV, "41844"),
495
- StaticProbe::new().with_env(DIRECT_ENV, "1"),
568
+ StaticProbe::new().with_env(ORIGIN_ENV, "http://127.0.0.1:9100"),
496
569
  ] {
497
570
  let shell = backend(probe);
498
571
  assert_eq!(shell.gateway_error(), None);
@@ -518,9 +591,13 @@ mod tests {
518
591
  let reason = shell.gateway_error().expect("the failure is recorded");
519
592
  assert!(reason.contains("could not bind"), "{reason}");
520
593
  assert!(
521
- reason.contains("LATTICEAI_DESKTOP_DIRECT"),
594
+ reason.contains("LATTICEAI_DESKTOP_BACKEND_ORIGIN"),
522
595
  "the way out is named: {reason}"
523
596
  );
597
+ assert!(
598
+ !reason.contains("LATTICEAI_DESKTOP_DIRECT"),
599
+ "the retired hatch must not be offered: {reason}"
600
+ );
524
601
  assert!(
525
602
  shell.app_url().contains(&port.to_string()),
526
603
  "app_url still names the port nothing bound — which is why boot must \
@@ -531,4 +608,33 @@ mod tests {
531
608
  assert_eq!(value["gateway_error"], reason);
532
609
  drop(occupied);
533
610
  }
611
+
612
+ #[test]
613
+ fn an_existing_backend_cmd_is_left_alone() {
614
+ let probe = StaticProbe::new().with_env(BACKEND_CMD_ENV, "custom-worker --flag");
615
+ assert_eq!(worker_launch_command(&probe), None);
616
+ }
617
+
618
+ #[test]
619
+ fn a_bundled_tree_is_left_to_the_supervisor() {
620
+ let probe = StaticProbe::new()
621
+ .with_resource_dir("/app/Resources")
622
+ .with_file("/app/Resources/latticeai/worker_app.py");
623
+ assert_eq!(worker_launch_command(&probe), None);
624
+ let legacy = StaticProbe::new()
625
+ .with_resource_dir("/app/Resources")
626
+ .with_file("/app/Resources/_up_/latticeai/cli/entrypoint.py");
627
+ assert_eq!(worker_launch_command(&legacy), None);
628
+ }
629
+
630
+ #[test]
631
+ fn an_unpackaged_shell_pins_the_worker_module() {
632
+ let probe = StaticProbe::new().with_importable("/opt/homebrew/bin/python3");
633
+ let command = worker_launch_command(&probe).expect("pin");
634
+ assert!(command.ends_with("-m latticeai.worker_app"), "{command}");
635
+ assert!(
636
+ !command.contains("latticeai.cli.entrypoint"),
637
+ "the product server is gone: {command}"
638
+ );
639
+ }
534
640
  }
@@ -9,13 +9,14 @@
9
9
  //! stops the worker.
10
10
  //!
11
11
  //! Since 11.5.0 the shell also *serves* that front door: the gateway runs
12
- //! in-process on the public port and the worker sits behind it (see
13
- //! [`topology`] for the arrangement and its escape hatches).
12
+ //! in-process on the public port and the worker sits behind it. 11.6.0 One
13
+ //! Door drops the Python-direct escape hatches — see [`topology`].
14
14
  //!
15
15
  //! The five command names and their response shapes are unchanged — the
16
16
  //! frontend (`frontend/src/api/base.ts`, `frontend/src/api/client.ts`) invokes
17
- //! them by name and reads `backend_status` as a plain record. The fields added
18
- //! in 11.5.0 are additive; nothing was renamed or removed.
17
+ //! `backend_origin`, `backend_status` and `select_folder` by name and reads
18
+ //! `backend_status` as a plain record. The fields added in 11.5.0 are
19
+ //! additive; nothing was renamed or removed.
19
20
 
20
21
  mod backend;
21
22
  mod folder;
@@ -60,11 +61,12 @@ fn select_folder() -> Option<String> {
60
61
  folder::select_folder()
61
62
  }
62
63
 
63
- /// Bring the worker up, then point the webview at `{origin}/app`.
64
+ /// Bring the host up, then point the webview at `{origin}/app`.
64
65
  ///
65
- /// The navigation waits on the worker's own `GET /health` rather than on a TCP
66
- /// connect: a bound socket only proves something is listening, and landing on
67
- /// `/app` before the routes exist is what used to show a blank window.
66
+ /// The navigation waits on the **host's** `GET /health` at the same origin the
67
+ /// window loads — never a bare Python worker. A bound socket only proves
68
+ /// something is listening, and landing on `/app` before the host answers is
69
+ /// what used to show a blank window.
68
70
  fn boot(app: &tauri::App) {
69
71
  let Some(window) = app.get_webview_window("main") else {
70
72
  return;
@@ -75,13 +77,7 @@ fn boot(app: &tauri::App) {
75
77
 
76
78
  let shell = Arc::clone(&app.state::<Arc<DesktopBackend>>());
77
79
  tauri::async_runtime::spawn(async move {
78
- let status = shell.start().await;
79
- if !status.healthy && !shell.supervised() {
80
- // A supervised worker already had its health gate inside `start`;
81
- // an adopted one (LATTICEAI_DESKTOP_BACKEND_ORIGIN) still needs it.
82
- // Waiting in both places would double the worst case.
83
- shell.wait_until_serving().await;
84
- }
80
+ shell.start().await;
85
81
  // One reason not to navigate, and it is not "the worker is slow": if
86
82
  // this shell was supposed to serve the front door and could not bind
87
83
  // it, `app_url` names a port nothing will ever listen on, and sending
@@ -92,9 +88,13 @@ fn boot(app: &tauri::App) {
92
88
  eprintln!("lattice-ai-desktop: staying on the bundled shell — {reason}");
93
89
  return;
94
90
  }
95
- // Otherwise navigate either way, as the shell always has: a window
96
- // showing the browser's own "cannot connect" is more use than a window
97
- // showing nothing while a worker that will never arrive is waited for.
91
+ // Host /health at the origin the window is about to load. An attached
92
+ // host (LATTICEAI_DESKTOP_BACKEND_ORIGIN) never ran start_gateway, so
93
+ // this is also the first time we wait for it.
94
+ shell.wait_until_serving().await;
95
+ // Navigate either way: a window showing the browser's own "cannot
96
+ // connect" is more use than a window showing nothing while a host that
97
+ // will never arrive is waited for.
98
98
  if let Ok(url) = tauri::Url::parse(&shell.app_url()) {
99
99
  let _ = window.navigate(url);
100
100
  }