ltcai 11.5.2 → 11.6.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 (439) hide show
  1. package/README.md +91 -148
  2. package/bin/ltcai.js +234 -24
  3. package/docs/CHANGELOG.md +75 -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 +21 -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-CToZnOHz.js} +1 -1
  96. package/static/app/assets/{AdminConsole-cf4npybT.js → AdminConsole-D5kbrBu8.js} +1 -1
  97. package/static/app/assets/{Brain-3VCSHFcn.js → Brain-C6zCdv4S.js} +1 -1
  98. package/static/app/assets/{BrainHome-Qm8eaztx.js → BrainHome-D4n3EDUt.js} +1 -1
  99. package/static/app/assets/{BrainSignals-DS9BtKOW.js → BrainSignals-CzeZ-vQ9.js} +1 -1
  100. package/static/app/assets/{Capture-DiQ219jW.js → Capture-DPcyTczq.js} +1 -1
  101. package/static/app/assets/{Chronicle-BGvuAchH.js → Chronicle-D3Nx-oWS.js} +1 -1
  102. package/static/app/assets/{CommandPalette-Bqhm0Urn.js → CommandPalette-DPPvpp28.js} +1 -1
  103. package/static/app/assets/{Library-BV6NnF0a.js → Library-Co2qTu3I.js} +1 -1
  104. package/static/app/assets/{LivingBrain-GzenJchP.js → LivingBrain-Bsmzwy8_.js} +1 -1
  105. package/static/app/assets/{ProductFlow-DEP6-vML.js → ProductFlow-CBLdmesT.js} +1 -1
  106. package/static/app/assets/{ReviewCard-CNZ7XjWG.js → ReviewCard-CfR6DLs7.js} +1 -1
  107. package/static/app/assets/{System-CieofHQa.js → System-Ce-P2YL6.js} +1 -1
  108. package/static/app/assets/arrow-left-DD5jFGHV.js +1 -0
  109. package/static/app/assets/{bot-B_K1Tdmw.js → bot-C5-XIww2.js} +1 -1
  110. package/static/app/assets/{brain-DWyaV1L1.js → brain-CFRJUvdX.js} +1 -1
  111. package/static/app/assets/{button-aTn4s84A.js → button-DI1KcQP-.js} +1 -1
  112. package/static/app/assets/circle-check-CY20XMCh.js +1 -0
  113. package/static/app/assets/{circle-pause-xKgeGXkT.js → circle-pause-C8HHyood.js} +1 -1
  114. package/static/app/assets/{circle-play-DkT6tYPX.js → circle-play-Cufc235E.js} +1 -1
  115. package/static/app/assets/{cpu-85xYObUC.js → cpu-DW2_JVsv.js} +1 -1
  116. package/static/app/assets/{download-B5Fm7YXo.js → download-gbdKTBb8.js} +1 -1
  117. package/static/app/assets/{folder-open-kk2Xa52u.js → folder-open-C9ydyX33.js} +1 -1
  118. package/static/app/assets/{hard-drive-DkA3zBW_.js → hard-drive-BxNMzBM3.js} +1 -1
  119. package/static/app/assets/index-BovSWRmQ.css +2 -0
  120. package/static/app/assets/{index-BMPdTmlY.js → index-q9XyDY7A.js} +3 -3
  121. package/static/app/assets/{input-B0nRf2jO.js → input-GLD94Y_K.js} +1 -1
  122. package/static/app/assets/{link-2-Dwb4gnTc.js → link-2-B4Y0gz1S.js} +1 -1
  123. package/static/app/assets/{permissionCopy-CQDUBrOZ.js → permissionCopy-CxrV0fvU.js} +1 -1
  124. package/static/app/assets/{primitives-SNp0LRJz.js → primitives-2ANdAsu2.js} +1 -1
  125. package/static/app/assets/search-DTxtjQ07.js +1 -0
  126. package/static/app/assets/{share-2-BsrxFglO.js → share-2-DxArfiuI.js} +1 -1
  127. package/static/app/assets/{shield-alert-5BStfp2_.js → shield-alert-CgftuFFs.js} +1 -1
  128. package/static/app/assets/{textarea-Cg8IUA-k.js → textarea-BHVBAoCr.js} +1 -1
  129. package/static/app/assets/{useFocusTrap-CYKvE46M.js → useFocusTrap-Dzq2j_OG.js} +1 -1
  130. package/static/app/assets/{useMutation-CSn9t1op.js → useMutation-BcqfMLNq.js} +1 -1
  131. package/static/app/assets/{useQuery-CY2OI2uy.js → useQuery-DBzLKCOv.js} +1 -1
  132. package/static/app/assets/{utils-Ddol2RWD.js → utils-B-Aah1bO.js} +1 -1
  133. package/static/app/assets/{workspace-BqDwOz_p.js → workspace-B6fFhoko.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/arrow-left-kfsrk0mv.js +0 -1
  437. package/static/app/assets/circle-check-qqLug9nU.js +0 -1
  438. package/static/app/assets/index-DxmOfNRi.css +0 -2
  439. package/static/app/assets/search-BcHqkjoy.js +0 -1
@@ -1,55 +0,0 @@
1
- """The rebinding half of the process-wide service singletons.
2
-
3
- Four wiring modules create one service each — the permission dial, the network
4
- boundary, the hybrid policy, the feature switchboard — and all four had the
5
- same problem and the same four-line answer to it: a lazy first caller (a tool
6
- dispatch, a feature gate) can ask for the service *before* routers know the
7
- configured data dir or the audit sink, and if the later explicit call were
8
- allowed to be a no-op the service would stay pinned to the fallback path with
9
- its audit events going nowhere.
10
-
11
- So explicit arguments rebind rather than being dropped. That rule was written
12
- out four times; it lives here once, because "the second caller silently loses"
13
- is precisely the kind of divergence that produces a second, invisible copy of
14
- the user's data and no failing test.
15
-
16
- The singleton *slot* deliberately stays a module global in each wiring module:
17
- the modules are the unit of process state, and the suite resets them by
18
- assigning ``_SHARED = None``.
19
- """
20
-
21
- from __future__ import annotations
22
-
23
- from pathlib import Path
24
- from typing import Any, Callable, Optional, TypeVar
25
-
26
- from latticeai.core.config import default_data_dir
27
-
28
- ServiceT = TypeVar("ServiceT")
29
-
30
- __all__ = ["singleton_data_dir", "rebind_singleton"]
31
-
32
-
33
- def singleton_data_dir(data_dir: Optional[Path]) -> Path:
34
- """Where a *first* lazy caller should put the store."""
35
- return Path(data_dir) if data_dir is not None else default_data_dir()
36
-
37
-
38
- def rebind_singleton(
39
- service: ServiceT,
40
- *,
41
- data_dir: Optional[Path] = None,
42
- audit: Optional[Callable[..., None]] = None,
43
- ) -> ServiceT:
44
- """Apply explicit arguments to an already-created singleton, then return it.
45
-
46
- ``None`` means "the caller did not say", never "unset it" — a router that
47
- mounts without an audit sink must not silence a sink an earlier caller
48
- already supplied.
49
- """
50
- rebindable: Any = service
51
- if data_dir is not None:
52
- rebindable.rebind_data_dir(Path(data_dir))
53
- if audit is not None:
54
- rebindable.rebind_audit(audit)
55
- return service
@@ -1,128 +0,0 @@
1
- """SSO / OIDC config + discovery seam extracted from the app factory.
2
-
3
- Owns the whole SSO surface that used to be inline in ``app_factory._build``:
4
- the env-default resolution, the ``sso_config.json`` load/save, the public
5
- (secret-stripped) view, and the OIDC discovery document cache.
6
-
7
- Unlike the previous split (config inline in the factory + a separate discovery
8
- cache in ``sso_runtime``), the discovery cache now lives in the *same* closure
9
- as ``save_sso_config``, so saving a new SSO config actually invalidates the
10
- cached discovery document. The old inline ``save_sso_config`` reassigned a
11
- factory-local cache variable that ``_get_sso_discovery`` never read, so the
12
- invalidation was a silent no-op — this consolidation fixes that.
13
- """
14
-
15
- from __future__ import annotations
16
-
17
- import json
18
- from pathlib import Path
19
- from typing import Any, Dict, Optional
20
-
21
-
22
- def build_sso_config_runtime(
23
- *,
24
- sso_file: Path,
25
- discovery_url: str,
26
- client_id: str,
27
- client_secret: str,
28
- redirect_uri: str,
29
- provider_name: str,
30
- logging: Any,
31
- ) -> Dict[str, Any]:
32
- """Return the SSO config helpers + discovery accessor as a name → value dict."""
33
-
34
- # Single shared discovery cache: save_sso_config and _get_sso_discovery both
35
- # close over it, so a config change is observed on the next discovery fetch.
36
- _discovery_cache: Dict[str, Any] = {"data": None, "url": ""}
37
- _sso_states: Dict[str, float] = {}
38
-
39
- def _sso_env_defaults() -> Dict[str, object]:
40
- return {
41
- "enabled": bool(discovery_url and client_id and client_secret),
42
- "provider_name": provider_name,
43
- "discovery_url": discovery_url,
44
- "client_id": client_id,
45
- "client_secret": client_secret,
46
- "redirect_uri": redirect_uri,
47
- "scopes": "openid email profile",
48
- }
49
-
50
- def load_sso_config() -> Dict[str, object]:
51
- config = _sso_env_defaults()
52
- if sso_file.exists():
53
- try:
54
- data = json.loads(sso_file.read_text(encoding="utf-8"))
55
- if isinstance(data, dict):
56
- config.update({k: v for k, v in data.items() if v is not None})
57
- except Exception as e:
58
- logging.warning("load_sso_config failed (using env/defaults): %s", e)
59
- config["provider_name"] = str(config.get("provider_name") or "SSO")
60
- config["discovery_url"] = str(config.get("discovery_url") or "")
61
- config["client_id"] = str(config.get("client_id") or "")
62
- config["client_secret"] = str(config.get("client_secret") or "")
63
- config["redirect_uri"] = str(config.get("redirect_uri") or redirect_uri)
64
- config["scopes"] = str(config.get("scopes") or "openid email profile")
65
- config["enabled"] = bool(config.get("enabled")) and bool(
66
- config["discovery_url"] and config["client_id"] and config["client_secret"]
67
- )
68
- return config
69
-
70
- def get_sso_settings() -> Dict[str, object]:
71
- return load_sso_config()
72
-
73
- def public_sso_config(config: Optional[Dict[str, object]] = None) -> Dict[str, object]:
74
- cfg = config or get_sso_settings()
75
- return {
76
- "enabled": bool(cfg.get("enabled")),
77
- "provider_name": cfg.get("provider_name") or "",
78
- "discovery_url": cfg.get("discovery_url") or "",
79
- "client_id": cfg.get("client_id") or "",
80
- "redirect_uri": cfg.get("redirect_uri") or redirect_uri,
81
- "scopes": cfg.get("scopes") or "openid email profile",
82
- "secret_configured": bool(cfg.get("client_secret")),
83
- }
84
-
85
- def save_sso_config(update: Dict[str, object]) -> Dict[str, object]:
86
- current = load_sso_config()
87
- if update.get("client_secret") == "":
88
- update.pop("client_secret", None)
89
- current.update({k: v for k, v in update.items() if v is not None})
90
- current["enabled"] = bool(current.get("enabled")) and bool(
91
- current.get("discovery_url") and current.get("client_id") and current.get("client_secret")
92
- )
93
- sso_file.write_text(json.dumps(current, ensure_ascii=False, indent=2), encoding="utf-8")
94
- _discovery_cache["data"] = None
95
- _discovery_cache["url"] = ""
96
- return current
97
-
98
- async def _get_sso_discovery() -> Optional[Dict]:
99
- settings = get_sso_settings()
100
- url = str(settings.get("discovery_url", "") or "")
101
- if _discovery_cache["data"] and _discovery_cache["url"] == url:
102
- return _discovery_cache["data"]
103
- if not url:
104
- return None
105
- try:
106
- import httpx as _httpx
107
- async with _httpx.AsyncClient() as c:
108
- r = await c.get(url, timeout=10)
109
- r.raise_for_status()
110
- _discovery_cache["data"] = r.json()
111
- _discovery_cache["url"] = url
112
- except Exception as e:
113
- logging.warning("SSO discovery failed: %s", e)
114
- return None
115
- return _discovery_cache["data"]
116
-
117
- return {
118
- "_sso_env_defaults": _sso_env_defaults,
119
- "load_sso_config": load_sso_config,
120
- "get_sso_settings": get_sso_settings,
121
- "public_sso_config": public_sso_config,
122
- "save_sso_config": save_sso_config,
123
- "_get_sso_discovery": _get_sso_discovery,
124
- "_sso_states": _sso_states,
125
- }
126
-
127
-
128
- __all__ = ["build_sso_config_runtime"]
@@ -1,106 +0,0 @@
1
- """User profile + provider API-key helpers extracted from the app factory.
2
-
3
- The helpers close over the user store, keyring adapter, identity migration, and
4
- plaintext-key policy. Returning callables preserves the legacy ``server_app``
5
- namespace while keeping ``app_factory._build`` focused on wiring.
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- from typing import Any, Dict, Optional
11
-
12
-
13
- def build_user_key_runtime(
14
- *,
15
- load_users: Any,
16
- save_users: Any,
17
- ensure_user_identity: Any,
18
- keyring: Any,
19
- allow_plaintext_api_keys: bool,
20
- logging: Any,
21
- http_exception: Any,
22
- ) -> Dict[str, Any]:
23
- """Return history-user and provider API-key helpers."""
24
-
25
- def get_history_user(email: Optional[str], nickname: Optional[str] = None) -> Dict:
26
- if not email:
27
- return {"user_email": None, "user_nickname": nickname or None}
28
- users = load_users()
29
- user = users.get(email, {})
30
- return {
31
- "user_email": email,
32
- "user_nickname": nickname or user.get("nickname") or user.get("name") or email,
33
- }
34
-
35
- def get_user_api_key(email: Optional[str], provider: str) -> Optional[str]:
36
- if not email:
37
- return None
38
- keyring_key = f"{email}:{provider}"
39
- if keyring is not None:
40
- try:
41
- key = keyring.get_password("LatticeAI", keyring_key)
42
- if key:
43
- return key.strip()
44
- except Exception as exc:
45
- logging.warning("keyring read failed for %s: %s", provider, exc)
46
- users = load_users()
47
- user = users.get(email) or {}
48
- api_keys = user.get("api_keys") or {}
49
- key = api_keys.get(provider)
50
- if isinstance(key, str) and key.strip() and allow_plaintext_api_keys:
51
- return key.strip()
52
- return None
53
-
54
- def set_user_api_key(email: str, provider: str, key: str) -> None:
55
- keyring_key = f"{email}:{provider}"
56
- if keyring is not None:
57
- try:
58
- keyring.set_password("LatticeAI", keyring_key, key)
59
- users = load_users()
60
- user = users.get(email)
61
- if user and "api_keys" in user:
62
- user["api_keys"].pop(provider, None)
63
- if not user["api_keys"]:
64
- user.pop("api_keys", None)
65
- save_users(users)
66
- return
67
- except Exception as exc:
68
- logging.warning("keyring write failed for %s: %s", provider, exc)
69
- if not allow_plaintext_api_keys:
70
- raise http_exception(
71
- status_code=500,
72
- detail="OS keyring에 API 키를 저장하지 못했습니다. keyring 설정을 확인하거나 LATTICEAI_ALLOW_PLAINTEXT_API_KEYS=true를 명시적으로 설정하세요.",
73
- )
74
-
75
- if not allow_plaintext_api_keys:
76
- raise http_exception(
77
- status_code=500,
78
- detail="keyring 패키지를 사용할 수 없어 API 키를 안전하게 저장할 수 없습니다.",
79
- )
80
-
81
- users = load_users()
82
- user = users.get(email)
83
- if not user:
84
- user = {
85
- "password_hash": "",
86
- "salt": "",
87
- "name": email,
88
- "nickname": email,
89
- "role": "user",
90
- "disabled": False,
91
- }
92
- ensure_user_identity(email, user)
93
- api_keys = user.get("api_keys") or {}
94
- api_keys[provider] = key
95
- user["api_keys"] = api_keys
96
- users[email] = user
97
- save_users(users)
98
-
99
- return {
100
- "get_history_user": get_history_user,
101
- "get_user_api_key": get_user_api_key,
102
- "set_user_api_key": set_user_api_key,
103
- }
104
-
105
-
106
- __all__ = ["build_user_key_runtime"]
@@ -1,92 +0,0 @@
1
- """FastAPI shell assembly for the application factory.
2
-
3
- This seam owns only the outer web shell: app construction, the request-side
4
- middleware (CSRF origin guard, CORS), and static asset mounts. Router
5
- registration stays in ``app_factory`` until the route snapshot/reorder step is
6
- reviewed.
7
- """
8
-
9
- from __future__ import annotations
10
-
11
- from pathlib import Path
12
- from typing import Any, Dict, Iterable, List
13
-
14
-
15
- def build_web_runtime(
16
- *,
17
- app_mode: str,
18
- app_version: str,
19
- lifespan: Any,
20
- default_host: str,
21
- default_port: int,
22
- cors_extra_origins: Iterable[str],
23
- cors_allow_network: bool,
24
- static_dir: Path,
25
- csrf_trusted_origins: Iterable[str] = (),
26
- ) -> Dict[str, Any]:
27
- """Create the FastAPI shell and mount static assets in legacy order."""
28
-
29
- from fastapi import FastAPI
30
- from fastapi.middleware.cors import CORSMiddleware
31
- from fastapi.staticfiles import StaticFiles
32
-
33
- from latticeai.core.csrf import CSRFOriginGuardMiddleware, CSRFOriginPolicy
34
- from latticeai.core.security import host_is_loopback
35
-
36
- app = FastAPI(
37
- title=f"Lattice AI Server ({app_mode})",
38
- version=app_version,
39
- lifespan=lifespan,
40
- )
41
-
42
- cors_allowed_origins = [
43
- f"http://localhost:{default_port}",
44
- f"http://127.0.0.1:{default_port}",
45
- *cors_extra_origins,
46
- ]
47
- if cors_allow_network:
48
- cors_allowed_origins = cors_allowed_origins + [
49
- f"http://{default_host}:{default_port}",
50
- f"https://{default_host}:{default_port}",
51
- ]
52
-
53
- # An origin that CORS already lets send *credentialed* cross-origin
54
- # requests is, by that decision, trusted with the session cookie; listing
55
- # it again here would be a second place to forget. The explicit
56
- # LATTICEAI_CSRF_TRUSTED_ORIGINS entries are for the reverse-proxy case,
57
- # where the public hostname is not the bind address.
58
- csrf_allowed_origins: List[str] = [
59
- *cors_allowed_origins,
60
- *csrf_trusted_origins,
61
- ]
62
- csrf_policy = CSRFOriginPolicy(
63
- trusted_origins=csrf_allowed_origins,
64
- server_host=default_host,
65
- server_port=default_port,
66
- bind_is_loopback=host_is_loopback(default_host),
67
- )
68
-
69
- # Registration order is stack order in reverse: the LAST middleware added
70
- # is the OUTERMOST. CORS must stay outside the guard so a rejected request
71
- # still comes back with the CORS headers the browser needs to surface the
72
- # 403 instead of an opaque network error.
73
- app.add_middleware(CSRFOriginGuardMiddleware, policy=csrf_policy)
74
- app.add_middleware(
75
- CORSMiddleware,
76
- allow_origins=cors_allowed_origins,
77
- allow_methods=["*"],
78
- allow_headers=["*"],
79
- allow_credentials=True,
80
- )
81
-
82
- static_dir.mkdir(parents=True, exist_ok=True)
83
- app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
84
- icons_dir = static_dir / "icons"
85
- if icons_dir.exists():
86
- app.mount("/icons", StaticFiles(directory=str(icons_dir)), name="icons")
87
-
88
- return {
89
- "app": app,
90
- "CORS_ALLOWED_ORIGINS": cors_allowed_origins,
91
- "CSRF_ALLOWED_ORIGINS": csrf_allowed_origins,
92
- }
@@ -1,51 +0,0 @@
1
- """Lazy compatibility facade over :mod:`latticeai.app_factory`.
2
-
3
- The application used to be assembled here at import time (MLX/GPU init,
4
- ~15 singletons, file creation under the data dir). All of that now lives in
5
- ``latticeai.app_factory.create_app``. This module keeps every historical
6
- module-level name (``app``, ``KNOWLEDGE_GRAPH``, ``load_users``,
7
- ``save_to_history``, …) importable for tests and legacy callers via module
8
- ``__getattr__`` — construction happens on *first attribute access*, never on
9
- import. Importing ``latticeai.server_app`` has no side effects.
10
- """
11
-
12
- from __future__ import annotations
13
-
14
- from typing import Any, List
15
-
16
- from latticeai.runtime.namespace_runtime import SERVER_APP_EXPORTS
17
-
18
-
19
- def _runtime():
20
- from latticeai.app_factory import get_shared_runtime
21
-
22
- return get_shared_runtime()
23
-
24
-
25
- def __getattr__(name: str) -> Any:
26
- if name.startswith("__") and name.endswith("__"):
27
- # Never let dunder probes (importlib, inspect, pickling) trigger the
28
- # full application construction.
29
- raise AttributeError(name)
30
- if name not in SERVER_APP_EXPORTS:
31
- raise AttributeError(f"module 'latticeai.server_app' has no attribute '{name}'")
32
- try:
33
- return getattr(_runtime(), name)
34
- except AttributeError as exc:
35
- raise AttributeError(
36
- f"module 'latticeai.server_app' has no attribute '{name}'"
37
- ) from exc
38
-
39
-
40
- def __dir__() -> List[str]:
41
- return sorted(set(globals()) | set(SERVER_APP_EXPORTS))
42
-
43
-
44
- def main() -> None:
45
- from latticeai.app_factory import main as _main
46
-
47
- _main()
48
-
49
-
50
- if __name__ == "__main__":
51
- main()
@@ -1,130 +0,0 @@
1
- """Application dependency context for router assembly.
2
-
3
- ``latticeai.app_factory.create_app`` builds one ``AppContext`` per app and
4
- hands it to router factories, replacing the historical 25-30-kwarg closure
5
- wiring. Every field defaults to ``None``-ish so tests can construct a context
6
- carrying only the dependencies a router actually touches.
7
-
8
- Fields are grouped by the consumer that motivated them; routers must treat the
9
- context as read-only.
10
- """
11
-
12
- from __future__ import annotations
13
-
14
- from dataclasses import dataclass
15
- from pathlib import Path
16
- from typing import Any, Callable, Optional
17
-
18
-
19
- @dataclass(frozen=True)
20
- class AppContext:
21
- # ── core configuration / paths ────────────────────────────────────────
22
- config: Any = None
23
- data_dir: Optional[Path] = None
24
- static_dir: Optional[Path] = None
25
- base_dir: Optional[Path] = None
26
- skills_dir: Optional[Path] = None
27
-
28
- # ── singletons ────────────────────────────────────────────────────────
29
- model_router: Any = None
30
- workspace_store: Any = None
31
- workspace_service: Any = None
32
- knowledge_graph: Any = None
33
- local_kg_watcher: Any = None
34
- chat_service: Any = None
35
- context_assembler: Any = None
36
- # Re-search loop (v9.9.6): conversation-scoped ledger of just-written
37
- # artifacts, so a follow-up turn sees them before indexing catches up.
38
- artifact_ledger: Any = None
39
- brain_memory: Any = None
40
- # Unified ingestion gateway (lattice_brain.ingestion.IngestionPipeline);
41
- # None when the knowledge graph is disabled.
42
- ingestion_pipeline: Any = None
43
- chat_agent_runtime: Any = None
44
- gardener: Any = None
45
- hooks: Any = None
46
- realtime_bus: Any = None
47
- capability_registry: Any = None
48
- # UX funnel metrics (latticeai.services.funnel_metrics); None in tests
49
- # that don't observe the funnel — every increment site is nil-safe.
50
- funnel_metrics: Any = None
51
-
52
- # ── auth / session callables ──────────────────────────────────────────
53
- require_user: Optional[Callable[..., str]] = None
54
- require_admin: Optional[Callable[..., tuple]] = None
55
- get_current_user: Optional[Callable[..., Optional[str]]] = None
56
- load_users: Optional[Callable[[], dict]] = None
57
- get_user_role: Optional[Callable[..., str]] = None
58
- enforce_rate_limit: Optional[Callable[..., None]] = None
59
- allowed_workspaces_for: Optional[Callable[..., Any]] = None
60
-
61
- # ── audit / history callables ─────────────────────────────────────────
62
- append_audit_event: Optional[Callable[..., None]] = None
63
- get_audit_log: Optional[Callable[[], list]] = None
64
- get_history: Optional[Callable[[], list]] = None
65
- get_history_user: Optional[Callable[..., dict]] = None
66
- save_to_history: Optional[Callable[..., None]] = None
67
- clear_history: Optional[Callable[..., dict]] = None
68
- clear_conversation: Optional[Callable[..., dict]] = None
69
- group_history_conversations: Optional[Callable[..., list]] = None
70
- get_conversation_messages: Optional[Callable[..., list]] = None
71
- conversation_title: Optional[Callable[..., str]] = None
72
-
73
- # ── knowledge graph access ────────────────────────────────────────────
74
- enable_graph: bool = False
75
- require_graph: Optional[Callable[[], None]] = None
76
- workspace_graph: Optional[Callable[[], Any]] = None
77
- graph_stats: Optional[Callable[[], dict]] = None
78
-
79
- # ── review center ─────────────────────────────────────────────────────
80
- # ``ReviewQueueService``, reached through a provider like
81
- # ``workspace_graph`` above: the queue is built in a later runtime phase
82
- # than this context, so a value captured here would be ``None`` forever.
83
- # Call it per request; ``None`` means no Review Center is wired (tests,
84
- # headless helpers) and the callers stage nothing rather than writing.
85
- review_queue: Optional[Callable[[], Any]] = None
86
-
87
- # ── workspace payload providers / skills ──────────────────────────────
88
- workspace_models: Optional[Callable[[], dict]] = None
89
- workspace_settings: Optional[Callable[[], dict]] = None
90
- scan_environment: Optional[Callable[[], Any]] = None
91
- local_sysinfo: Optional[Callable[..., Any]] = None
92
- get_recommendations: Optional[Callable[..., Any]] = None
93
- fetch_skills_marketplace: Optional[Callable[..., Any]] = None
94
- install_skill: Optional[Callable[..., Any]] = None
95
- remove_skill_directory: Optional[Callable[..., dict]] = None
96
- redact_secret_text: Optional[Callable[[str], str]] = None
97
- ui_file_response: Optional[Callable[..., Any]] = None
98
-
99
- # ── models ────────────────────────────────────────────────────────────
100
- public_model: str = ""
101
- local_model: str = ""
102
-
103
- # ── integrations ──────────────────────────────────────────────────────
104
- # Fired as on_chat_message(role, text, source) after a chat exchange is
105
- # persisted; ``None`` means no external chat mirror is registered. The
106
- # telegram bridge subscribes here only when ENABLE_TELEGRAM is truthy.
107
- on_chat_message: Optional[Callable[..., None]] = None
108
-
109
- def require(self, field: str) -> Any:
110
- """Return a dependency this router cannot operate without.
111
-
112
- Every field defaults to ``None`` so a test can build a context holding
113
- only what it exercises. A router that binds an absent dependency used
114
- to discover it as ``TypeError: 'NoneType' object is not callable``
115
- inside a request handler, far from the wiring mistake. Binding through
116
- ``require`` moves that to router construction with the field named.
117
-
118
- It is also what makes the binding statically honest: the declared type
119
- is ``Optional[...]``, so a type checker reports every call site as
120
- ``"None" not callable`` — 105 of them in the workspace router alone.
121
- ``require`` states the precondition once instead.
122
- """
123
- if field not in self.__dataclass_fields__:
124
- raise AttributeError(f"AppContext has no field {field!r}")
125
- value = getattr(self, field)
126
- if value is None:
127
- raise RuntimeError(
128
- f"AppContext.{field} is required by this router but was not provided"
129
- )
130
- return value