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.
- package/README.md +93 -148
- package/bin/ltcai.js +234 -24
- package/docs/CHANGELOG.md +119 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +8 -6
- package/docs/ENTERPRISE.md +2 -1
- package/docs/MULTI_AGENT_RUNTIME.md +12 -5
- package/docs/ONBOARDING.md +1 -1
- package/docs/OPERATIONS.md +6 -3
- package/docs/REALTIME_COLLABORATION.md +1 -1
- package/docs/TRUST_MODEL.md +1 -1
- package/docs/WHY_LATTICE.md +1 -1
- package/docs/WORKFLOW_DESIGNER.md +3 -2
- package/docs/kg-schema.md +1 -1
- package/docs/v11.6.0_ONE_DOOR_PLAN.md +170 -0
- package/lattice_brain/__init__.py +42 -79
- package/lattice_brain/graph/__init__.py +9 -24
- package/lattice_brain/graph/_kg_common/__init__.py +13 -24
- package/lattice_brain/ingestion/__init__.py +19 -58
- package/lattice_brain/ingestion/pipeline.py +20 -398
- package/lattice_brain/multimodal/__init__.py +7 -18
- package/lattice_brain/multimodal/images.py +6 -264
- package/lattice_brain/multimodal/video.py +8 -247
- package/lattice_brain/runtime/__init__.py +8 -79
- package/lattice_brain/runtime/hooks.py +22 -584
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/agent_worker_seam.py +7 -80
- package/latticeai/api/health.py +6 -20
- package/latticeai/api/local_files.py +16 -613
- package/latticeai/api/models.py +12 -87
- package/latticeai/api/search.py +17 -255
- package/latticeai/api/tools.py +69 -750
- package/latticeai/api/voice_capture.py +8 -70
- package/latticeai/api/worker_compute.py +842 -0
- package/latticeai/api/worker_seams.py +216 -0
- package/latticeai/app_factory.py +23 -232
- package/latticeai/cli/entrypoint.py +36 -249
- package/latticeai/core/agent_permission.py +16 -91
- package/latticeai/core/messages.py +89 -531
- package/latticeai/runtime/access_runtime.py +0 -14
- package/latticeai/runtime/bootstrap.py +10 -21
- package/latticeai/runtime/brain_runtime.py +35 -43
- package/latticeai/runtime/build_phases/__init__.py +21 -37
- package/latticeai/runtime/build_phases/features.py +99 -389
- package/latticeai/runtime/build_phases/foundation.py +82 -392
- package/latticeai/runtime/build_phases/web.py +91 -408
- package/latticeai/runtime/build_phases/worker_profile.py +244 -0
- package/latticeai/runtime/lifespan_runtime.py +7 -16
- package/latticeai/runtime/platform_services_runtime.py +1 -15
- package/latticeai/runtime/runtime_context.py +13 -130
- package/latticeai/runtime/security_runtime.py +10 -103
- package/latticeai/services/architecture_readiness.py +82 -43
- package/latticeai/services/model_runtime/__init__.py +2 -11
- package/latticeai/services/model_runtime/service.py +4 -28
- package/latticeai/services/p_reinforce.py +10 -261
- package/latticeai/services/product_readiness.py +31 -38
- package/latticeai/services/search_service.py +37 -795
- package/latticeai/services/tool_dispatch.py +30 -386
- package/latticeai/services/voice_capture.py +13 -107
- package/latticeai/tools/__init__.py +22 -49
- package/latticeai/tools/commands.py +0 -163
- package/latticeai/tools/computer.py +0 -39
- package/latticeai/tools/documents.py +1 -134
- package/latticeai/tools/filesystem.py +1 -247
- package/latticeai/tools/knowledge.py +1 -52
- package/latticeai/tools/local_files.py +0 -20
- package/latticeai/worker_app.py +75 -0
- package/package.json +2 -3
- package/requirements.txt +0 -5
- package/scripts/agent_eval.py +16 -28
- package/scripts/brain_quality_eval.py +20 -183
- package/scripts/bump_version.py +5 -5
- package/scripts/check_current_release_docs.mjs +7 -4
- package/scripts/check_openapi_drift.mjs +10 -0
- package/scripts/check_server_i18n.mjs +2 -18
- package/scripts/compose_openapi.py +377 -0
- package/scripts/export_openapi.py +32 -4
- package/scripts/gen_messages_catalog_fixture.py +302 -0
- package/scripts/gen_openapi_fragments.py +365 -0
- package/scripts/gen_redact_fixture.py +196 -0
- package/scripts/gen_worker_allowlist_fixture.py +115 -0
- package/scripts/generate_agent_parity_fixtures.py +33 -14
- package/scripts/openapi_route_families.json +2161 -0
- package/scripts/release_screen_claims.json +54 -0
- package/scripts/run_integration_tests.mjs +134 -29
- package/scripts/run_sidecar_e2e.mjs +104 -11
- package/scripts/wheel_smoke.py +32 -22
- package/src-tauri/Cargo.lock +375 -9
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/src/backend.rs +151 -45
- package/src-tauri/src/main.rs +18 -18
- package/src-tauri/src/topology.rs +58 -88
- package/src-tauri/tauri.conf.json +1 -2
- package/static/app/asset-manifest.json +41 -41
- package/static/app/assets/{Act-DcQizkl1.js β Act-BPcVAbOL.js} +1 -1
- package/static/app/assets/AdminConsole-Bw1ATQL0.js +1 -0
- package/static/app/assets/{Brain-3VCSHFcn.js β Brain-CT92Kos0.js} +2 -2
- package/static/app/assets/{BrainHome-Qm8eaztx.js β BrainHome-CFBkt1K_.js} +1 -1
- package/static/app/assets/{BrainSignals-DS9BtKOW.js β BrainSignals-ReLWF2H8.js} +1 -1
- package/static/app/assets/Capture-BsTokYkk.js +1 -0
- package/static/app/assets/{Chronicle-BGvuAchH.js β Chronicle-B6f0T9id.js} +1 -1
- package/static/app/assets/{CommandPalette-Bqhm0Urn.js β CommandPalette-CuvjTv1u.js} +1 -1
- package/static/app/assets/{Library-BV6NnF0a.js β Library-BGJbG9Hd.js} +1 -1
- package/static/app/assets/{LivingBrain-GzenJchP.js β LivingBrain-DGYK_Jsa.js} +1 -1
- package/static/app/assets/{ProductFlow-DEP6-vML.js β ProductFlow-DXBC6brE.js} +1 -1
- package/static/app/assets/{ReviewCard-CNZ7XjWG.js β ReviewCard-HXRle3qq.js} +2 -2
- package/static/app/assets/System-CMHSO9qM.js +1 -0
- package/static/app/assets/arrow-left-BfmkskWx.js +1 -0
- package/static/app/assets/{bot-B_K1Tdmw.js β bot-Cn8bWRuq.js} +1 -1
- package/static/app/assets/{brain-DWyaV1L1.js β brain-CQJberbE.js} +1 -1
- package/static/app/assets/{button-aTn4s84A.js β button-Ct9f2_oT.js} +1 -1
- package/static/app/assets/circle-check-DruOxB-4.js +1 -0
- package/static/app/assets/{circle-pause-xKgeGXkT.js β circle-pause-CmzC_apg.js} +1 -1
- package/static/app/assets/{circle-play-DkT6tYPX.js β circle-play-D8mW2aQ7.js} +1 -1
- package/static/app/assets/{cpu-85xYObUC.js β cpu-DZcdd0PZ.js} +1 -1
- package/static/app/assets/{download-B5Fm7YXo.js β download-bv1KEPGQ.js} +1 -1
- package/static/app/assets/{folder-open-kk2Xa52u.js β folder-open-d-Pip5gr.js} +1 -1
- package/static/app/assets/{hard-drive-DkA3zBW_.js β hard-drive-D20iavUb.js} +1 -1
- package/static/app/assets/index-D9x-kSNy.css +2 -0
- package/static/app/assets/{index-BMPdTmlY.js β index-Do83hDzJ.js} +3 -3
- package/static/app/assets/{input-B0nRf2jO.js β input-BLXVNmj1.js} +1 -1
- package/static/app/assets/{link-2-Dwb4gnTc.js β link-2-BPJOFlAy.js} +1 -1
- package/static/app/assets/{permissionCopy-CQDUBrOZ.js β permissionCopy-ChdJd493.js} +1 -1
- package/static/app/assets/primitives-Cv5tbZBY.js +1 -0
- package/static/app/assets/search-CT9aho2j.js +1 -0
- package/static/app/assets/{share-2-BsrxFglO.js β share-2-YNX_NtMU.js} +1 -1
- package/static/app/assets/{shield-alert-5BStfp2_.js β shield-alert-DuQ3zrVL.js} +1 -1
- package/static/app/assets/{textarea-Cg8IUA-k.js β textarea-DqwLnli4.js} +1 -1
- package/static/app/assets/{useFocusTrap-CYKvE46M.js β useFocusTrap-ZVI98jaW.js} +1 -1
- package/static/app/assets/{useMutation-CSn9t1op.js β useMutation-CVC4qv_D.js} +1 -1
- package/static/app/assets/{useQuery-CY2OI2uy.js β useQuery-C7BeG4HU.js} +1 -1
- package/static/app/assets/{utils-Ddol2RWD.js β utils-CiFtIdZq.js} +1 -1
- package/static/app/assets/{workspace-BqDwOz_p.js β workspace-DQz9vIId.js} +1 -1
- package/static/app/index.html +4 -4
- package/static/sw.js +1 -1
- package/lattice_brain/archive.py +0 -522
- package/lattice_brain/context.py +0 -325
- package/lattice_brain/conversations.py +0 -382
- package/lattice_brain/core.py +0 -82
- package/lattice_brain/graph/_kg_contract.py +0 -249
- package/lattice_brain/graph/curator.py +0 -676
- package/lattice_brain/graph/discovery.py +0 -595
- package/lattice_brain/graph/discovery_index/__init__.py +0 -35
- package/lattice_brain/graph/discovery_index/cleanup.py +0 -182
- package/lattice_brain/graph/discovery_index/extract.py +0 -137
- package/lattice_brain/graph/discovery_index/scan.py +0 -411
- package/lattice_brain/graph/discovery_index/upsert.py +0 -495
- package/lattice_brain/graph/documents.py +0 -380
- package/lattice_brain/graph/fusion.py +0 -395
- package/lattice_brain/graph/identity.py +0 -175
- package/lattice_brain/graph/image_vectors.py +0 -230
- package/lattice_brain/graph/ingest.py +0 -829
- package/lattice_brain/graph/network.py +0 -205
- package/lattice_brain/graph/proactive.py +0 -724
- package/lattice_brain/graph/projection/__init__.py +0 -42
- package/lattice_brain/graph/projection/curation.py +0 -500
- package/lattice_brain/graph/projection/v2_schema.py +0 -518
- package/lattice_brain/graph/provenance.py +0 -524
- package/lattice_brain/graph/rerank.py +0 -163
- package/lattice_brain/graph/retrieval/__init__.py +0 -54
- package/lattice_brain/graph/retrieval/context.py +0 -197
- package/lattice_brain/graph/retrieval/graph_view.py +0 -319
- package/lattice_brain/graph/retrieval/hybrid.py +0 -488
- package/lattice_brain/graph/retrieval/maintenance.py +0 -121
- package/lattice_brain/graph/retrieval/signals.py +0 -95
- package/lattice_brain/graph/retrieval_docgen.py +0 -253
- package/lattice_brain/graph/retrieval_policy.py +0 -180
- package/lattice_brain/graph/retrieval_reads.py +0 -769
- package/lattice_brain/graph/retrieval_vector/__init__.py +0 -42
- package/lattice_brain/graph/retrieval_vector/fingerprint.py +0 -97
- package/lattice_brain/graph/retrieval_vector/indexing.py +0 -347
- package/lattice_brain/graph/retrieval_vector/search.py +0 -560
- package/lattice_brain/graph/retrieval_vector/status.py +0 -374
- package/lattice_brain/graph/schema.py +0 -792
- package/lattice_brain/graph/store.py +0 -268
- package/lattice_brain/graph/vector_index/__init__.py +0 -85
- package/lattice_brain/graph/vector_index/base.py +0 -167
- package/lattice_brain/graph/vector_index/brute_force.py +0 -110
- package/lattice_brain/graph/vector_index/hnsw.py +0 -290
- package/lattice_brain/graph/vector_index/jobs.py +0 -287
- package/lattice_brain/graph/vector_index/quantized.py +0 -148
- package/lattice_brain/graph/vector_index/selector.py +0 -161
- package/lattice_brain/graph/write_master.py +0 -308
- package/lattice_brain/ingestion/_contract.py +0 -90
- package/lattice_brain/ingestion/folder_scan.py +0 -57
- package/lattice_brain/ingestion/folders.py +0 -258
- package/lattice_brain/ingestion/jobs_api.py +0 -107
- package/lattice_brain/ingestion/routing.py +0 -295
- package/lattice_brain/ingestion_jobs.py +0 -380
- package/lattice_brain/memory.py +0 -75
- package/lattice_brain/portability/__init__.py +0 -90
- package/lattice_brain/portability/_contract.py +0 -42
- package/lattice_brain/portability/backups.py +0 -338
- package/lattice_brain/portability/bundles.py +0 -136
- package/lattice_brain/portability/constants.py +0 -93
- package/lattice_brain/portability/fsops.py +0 -138
- package/lattice_brain/portability/service.py +0 -41
- package/lattice_brain/portability/sharing.py +0 -710
- package/lattice_brain/quality.py +0 -543
- package/lattice_brain/retrieval_benchmark_fixtures.py +0 -92
- package/lattice_brain/runtime/agent_runtime.py +0 -859
- package/lattice_brain/runtime/contracts.py +0 -460
- package/lattice_brain/runtime/multi_agent.py +0 -942
- package/lattice_brain/runtime/statuses.py +0 -10
- package/lattice_brain/sealed_box.py +0 -240
- package/lattice_brain/self_model.py +0 -675
- package/lattice_brain/sensitivity.py +0 -94
- package/lattice_brain/storage/__init__.py +0 -22
- package/lattice_brain/storage/base.py +0 -100
- package/lattice_brain/storage/docker.py +0 -105
- package/lattice_brain/storage/factory.py +0 -31
- package/lattice_brain/storage/migration.py +0 -191
- package/lattice_brain/storage/postgres.py +0 -123
- package/lattice_brain/storage/sqlite.py +0 -143
- package/lattice_brain/synthesis.py +0 -824
- package/lattice_brain/workflow.py +0 -497
- package/latticeai/api/admin.py +0 -471
- package/latticeai/api/agent_registry.py +0 -105
- package/latticeai/api/agents.py +0 -228
- package/latticeai/api/auth.py +0 -383
- package/latticeai/api/automation_intelligence.py +0 -401
- package/latticeai/api/brain_intelligence.py +0 -199
- package/latticeai/api/browser.py +0 -493
- package/latticeai/api/change_proposals.py +0 -89
- package/latticeai/api/chat.py +0 -572
- package/latticeai/api/chat_agent_http.py +0 -892
- package/latticeai/api/chat_contracts.py +0 -73
- package/latticeai/api/chat_documents.py +0 -276
- package/latticeai/api/chat_helpers.py +0 -460
- package/latticeai/api/chat_history.py +0 -101
- package/latticeai/api/chat_hybrid.py +0 -113
- package/latticeai/api/chat_intents.py +0 -646
- package/latticeai/api/chat_stream.py +0 -216
- package/latticeai/api/chronicle.py +0 -63
- package/latticeai/api/command_center.py +0 -51
- package/latticeai/api/computer_use.py +0 -474
- package/latticeai/api/evidence_actions.py +0 -48
- package/latticeai/api/features.py +0 -70
- package/latticeai/api/funnel_metrics.py +0 -31
- package/latticeai/api/garden.py +0 -34
- package/latticeai/api/hooks.py +0 -165
- package/latticeai/api/index_jobs.py +0 -145
- package/latticeai/api/invitations.py +0 -100
- package/latticeai/api/knowledge_graph.py +0 -536
- package/latticeai/api/marketplace.py +0 -105
- package/latticeai/api/mcp.py +0 -482
- package/latticeai/api/memory.py +0 -270
- package/latticeai/api/network.py +0 -81
- package/latticeai/api/network_boundary.py +0 -225
- package/latticeai/api/permission_mode.py +0 -61
- package/latticeai/api/permissions.py +0 -436
- package/latticeai/api/plugins.py +0 -126
- package/latticeai/api/portability.py +0 -391
- package/latticeai/api/project_sessions.py +0 -114
- package/latticeai/api/realtime.py +0 -118
- package/latticeai/api/review_queue.py +0 -364
- package/latticeai/api/security_dashboard.py +0 -604
- package/latticeai/api/setup.py +0 -319
- package/latticeai/api/static_routes.py +0 -354
- package/latticeai/api/ui_redirects.py +0 -26
- package/latticeai/api/workflow_designer.py +0 -394
- package/latticeai/api/workspace.py +0 -856
- package/latticeai/api/workspace_scope.py +0 -125
- package/latticeai/core/agent/__init__.py +0 -93
- package/latticeai/core/agent/_contract.py +0 -79
- package/latticeai/core/agent/context.py +0 -57
- package/latticeai/core/agent/deps.py +0 -125
- package/latticeai/core/agent/execution.py +0 -622
- package/latticeai/core/agent/planning.py +0 -145
- package/latticeai/core/agent/recovery.py +0 -157
- package/latticeai/core/agent/runtime.py +0 -210
- package/latticeai/core/agent/verification.py +0 -231
- package/latticeai/core/agent_eval.py +0 -739
- package/latticeai/core/agent_helpers.py +0 -493
- package/latticeai/core/agent_profiles.py +0 -110
- package/latticeai/core/agent_prompts.py +0 -171
- package/latticeai/core/agent_registry.py +0 -232
- package/latticeai/core/agent_state.py +0 -41
- package/latticeai/core/agent_trace.py +0 -104
- package/latticeai/core/artifact_ledger.py +0 -109
- package/latticeai/core/audit.py +0 -260
- package/latticeai/core/builtin_hooks.py +0 -105
- package/latticeai/core/context_builder.py +0 -394
- package/latticeai/core/document_generator.py +0 -103
- package/latticeai/core/enterprise.py +0 -154
- package/latticeai/core/enterprise_admin.py +0 -158
- package/latticeai/core/file_generation/__init__.py +0 -115
- package/latticeai/core/file_generation/bundles.py +0 -76
- package/latticeai/core/file_generation/extraction.py +0 -154
- package/latticeai/core/file_generation/inference.py +0 -235
- package/latticeai/core/file_generation/orchestration.py +0 -152
- package/latticeai/core/file_generation/prompting.py +0 -117
- package/latticeai/core/file_generation/repair.py +0 -114
- package/latticeai/core/file_generation/sanitize.py +0 -61
- package/latticeai/core/file_generation/validation.py +0 -201
- package/latticeai/core/invitations.py +0 -132
- package/latticeai/core/legacy_compatibility.py +0 -243
- package/latticeai/core/logging_safety.py +0 -46
- package/latticeai/core/marketplace.py +0 -293
- package/latticeai/core/mcp_catalog.py +0 -452
- package/latticeai/core/mcp_registry.py +0 -506
- package/latticeai/core/network_boundary.py +0 -168
- package/latticeai/core/oidc.py +0 -208
- package/latticeai/core/plugins.py +0 -432
- package/latticeai/core/product_hardening.py +0 -218
- package/latticeai/core/project_sessions.py +0 -337
- package/latticeai/core/realtime.py +0 -238
- package/latticeai/core/run_explain.py +0 -426
- package/latticeai/core/run_store.py +0 -252
- package/latticeai/core/timezones.py +0 -80
- package/latticeai/core/workspace_computer_memory.py +0 -84
- package/latticeai/core/workspace_graph_trace.py +0 -155
- package/latticeai/core/workspace_indexing.py +0 -102
- package/latticeai/core/workspace_memory.py +0 -77
- package/latticeai/core/workspace_onboarding.py +0 -104
- package/latticeai/core/workspace_os.py +0 -978
- package/latticeai/core/workspace_os_constants.py +0 -126
- package/latticeai/core/workspace_os_state.py +0 -180
- package/latticeai/core/workspace_os_utils.py +0 -103
- package/latticeai/core/workspace_permissions.py +0 -101
- package/latticeai/core/workspace_plugins.py +0 -97
- package/latticeai/core/workspace_relationships.py +0 -99
- package/latticeai/core/workspace_reorganization.py +0 -335
- package/latticeai/core/workspace_review_items.py +0 -112
- package/latticeai/core/workspace_runs.py +0 -726
- package/latticeai/core/workspace_skills.py +0 -109
- package/latticeai/core/workspace_snapshots.py +0 -198
- package/latticeai/core/workspace_timeline.py +0 -110
- package/latticeai/integrations/__init__.py +0 -0
- package/latticeai/integrations/telegram_bot/__init__.py +0 -123
- package/latticeai/integrations/telegram_bot/__main__.py +0 -17
- package/latticeai/integrations/telegram_bot/config.py +0 -86
- package/latticeai/integrations/telegram_bot/dispatch.py +0 -311
- package/latticeai/integrations/telegram_bot/flows.py +0 -478
- package/latticeai/integrations/telegram_bot/helpers.py +0 -322
- package/latticeai/integrations/telegram_bot/screens.py +0 -394
- package/latticeai/runtime/audit_runtime.py +0 -76
- package/latticeai/runtime/automation_runtime.py +0 -81
- package/latticeai/runtime/chat_wiring.py +0 -141
- package/latticeai/runtime/context_runtime.py +0 -66
- package/latticeai/runtime/feature_toggle_wiring.py +0 -157
- package/latticeai/runtime/history_runtime.py +0 -163
- package/latticeai/runtime/history_writer.py +0 -138
- package/latticeai/runtime/hooks_runtime.py +0 -77
- package/latticeai/runtime/model_wiring.py +0 -68
- package/latticeai/runtime/namespace_runtime.py +0 -163
- package/latticeai/runtime/network_boundary_wiring.py +0 -117
- package/latticeai/runtime/network_config_runtime.py +0 -56
- package/latticeai/runtime/permission_mode_wiring.py +0 -112
- package/latticeai/runtime/persistence_runtime.py +0 -159
- package/latticeai/runtime/platform_runtime_wiring.py +0 -89
- package/latticeai/runtime/review_wiring.py +0 -42
- package/latticeai/runtime/router_registration.py +0 -693
- package/latticeai/runtime/service_singletons.py +0 -55
- package/latticeai/runtime/sso_config_runtime.py +0 -128
- package/latticeai/runtime/user_key_runtime.py +0 -106
- package/latticeai/runtime/web_runtime.py +0 -92
- package/latticeai/server_app.py +0 -51
- package/latticeai/services/app_context.py +0 -130
- package/latticeai/services/automation_execution.py +0 -266
- package/latticeai/services/automation_intelligence.py +0 -614
- package/latticeai/services/brain_automation.py +0 -191
- package/latticeai/services/brain_intelligence/__init__.py +0 -58
- package/latticeai/services/brain_intelligence/_contract.py +0 -71
- package/latticeai/services/brain_intelligence/consistency.py +0 -193
- package/latticeai/services/brain_intelligence/constants.py +0 -47
- package/latticeai/services/brain_intelligence/digest.py +0 -258
- package/latticeai/services/brain_intelligence/health.py +0 -331
- package/latticeai/services/brain_intelligence/proposals.py +0 -259
- package/latticeai/services/brain_intelligence/sampling.py +0 -84
- package/latticeai/services/brain_intelligence/service.py +0 -48
- package/latticeai/services/change_proposals.py +0 -471
- package/latticeai/services/chat_service.py +0 -243
- package/latticeai/services/chronicle.py +0 -555
- package/latticeai/services/cloud_egress_audit.py +0 -85
- package/latticeai/services/cloud_extraction.py +0 -129
- package/latticeai/services/cloud_streaming.py +0 -268
- package/latticeai/services/cloud_token_guard.py +0 -84
- package/latticeai/services/command_center.py +0 -548
- package/latticeai/services/evidence_actions.py +0 -258
- package/latticeai/services/feature_toggles.py +0 -502
- package/latticeai/services/folder_watch.py +0 -520
- package/latticeai/services/funnel_metrics.py +0 -307
- package/latticeai/services/hybrid_chat.py +0 -316
- package/latticeai/services/hybrid_context.py +0 -228
- package/latticeai/services/hybrid_policy.py +0 -129
- package/latticeai/services/interop_bridges.py +0 -978
- package/latticeai/services/local_knowledge.py +0 -465
- package/latticeai/services/memory_service/__init__.py +0 -52
- package/latticeai/services/memory_service/_contract.py +0 -100
- package/latticeai/services/memory_service/brief.py +0 -431
- package/latticeai/services/memory_service/constants.py +0 -57
- package/latticeai/services/memory_service/maintenance.py +0 -138
- package/latticeai/services/memory_service/manager.py +0 -186
- package/latticeai/services/memory_service/proof.py +0 -136
- package/latticeai/services/memory_service/recall.py +0 -225
- package/latticeai/services/memory_service/service.py +0 -48
- package/latticeai/services/memory_service/stores.py +0 -110
- package/latticeai/services/mode_store.py +0 -132
- package/latticeai/services/model_recommendation.py +0 -224
- package/latticeai/services/model_runtime/cloud.py +0 -87
- package/latticeai/services/network_boundary_service.py +0 -117
- package/latticeai/services/obsidian_bridge.py +0 -609
- package/latticeai/services/openai_compatible_adapter.py +0 -101
- package/latticeai/services/permission_mode_service.py +0 -122
- package/latticeai/services/platform_runtime.py +0 -366
- package/latticeai/services/review_queue.py +0 -380
- package/latticeai/services/router_context.py +0 -59
- package/latticeai/services/run_executor.py +0 -387
- package/latticeai/services/self_model_service.py +0 -171
- package/latticeai/services/setup_detection.py +0 -147
- package/latticeai/services/triggers.py +0 -378
- package/latticeai/services/upload_service.py +0 -172
- package/latticeai/services/workspace_service.py +0 -165
- package/latticeai/setup/__init__.py +0 -25
- package/latticeai/setup/auto_setup.py +0 -846
- package/latticeai/setup/demo_corpus.py +0 -98
- package/latticeai/setup/wizard/__init__.py +0 -126
- package/latticeai/setup/wizard/catalog.py +0 -175
- package/latticeai/setup/wizard/detect.py +0 -302
- package/latticeai/setup/wizard/install.py +0 -348
- package/latticeai/setup/wizard/paths.py +0 -165
- package/latticeai/setup/wizard/plans.py +0 -74
- package/latticeai/setup/wizard/recommend.py +0 -320
- package/scripts/bench_agent_smoke.py +0 -409
- package/scripts/bench_models.py +0 -540
- package/scripts/bench_vector_index.py +0 -295
- package/scripts/funnel_soft_gate.py +0 -192
- package/scripts/generate_agent_loop_fixtures.py +0 -994
- package/scripts/generate_rust_parity_fixtures.py +0 -908
- package/scripts/migrate_brain_storage.py +0 -57
- package/scripts/parity_fixture_corpus_context.py +0 -162
- package/scripts/parity_fixture_corpus_docgen.py +0 -341
- package/scripts/profile_kg.py +0 -355
- package/server.py +0 -30
- package/static/app/assets/AdminConsole-cf4npybT.js +0 -1
- package/static/app/assets/Capture-DiQ219jW.js +0 -1
- package/static/app/assets/System-CieofHQa.js +0 -1
- package/static/app/assets/arrow-left-kfsrk0mv.js +0 -1
- package/static/app/assets/circle-check-qqLug9nU.js +0 -1
- package/static/app/assets/index-DxmOfNRi.css +0 -2
- package/static/app/assets/primitives-SNp0LRJz.js +0 -1
- package/static/app/assets/search-BcHqkjoy.js +0 -1
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
"""Machine-checkable architecture readiness gates for release work.
|
|
2
2
|
|
|
3
|
-
The current release keeps the major architecture priorities under an explicit
|
|
4
|
-
contract
|
|
5
|
-
|
|
6
|
-
must remain discoverable, ordered, and backed by tests
|
|
7
|
-
|
|
3
|
+
The current release keeps the major architecture priorities under an explicit
|
|
4
|
+
release contract. Agent permission gates, ToolRegistry, central Config, the
|
|
5
|
+
worker-only composition root, and the compute-side Knowledge Graph helpers
|
|
6
|
+
must remain discoverable, ordered, and backed by tests.
|
|
7
|
+
|
|
8
|
+
v11.6.0 retargeted every symbol probe at the worker-only tree: the product
|
|
9
|
+
HTTP surface, the Python agent loop, the graph writer and the orchestration
|
|
10
|
+
runtimes now live in Rust. Assertions were not deleted β their paths and
|
|
11
|
+
symbols now name the modules that still own those concerns in Python, or the
|
|
12
|
+
worker seam that is the Python half of a native owner.
|
|
8
13
|
"""
|
|
9
14
|
|
|
10
15
|
from __future__ import annotations
|
|
@@ -14,9 +19,7 @@ from dataclasses import dataclass
|
|
|
14
19
|
from pathlib import Path
|
|
15
20
|
from typing import Any, Dict, List
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
ARCHITECTURE_VERSION_TARGET = "11.5.2"
|
|
22
|
+
ARCHITECTURE_VERSION_TARGET = "11.7.0"
|
|
20
23
|
|
|
21
24
|
PREFERRED_REFACTORING_ORDER = [
|
|
22
25
|
"agent-runtime",
|
|
@@ -75,6 +78,41 @@ def _forbidden_patterns(root: Path, relative_path: str, patterns: List[str]) ->
|
|
|
75
78
|
return [pattern for pattern in patterns if pattern in source]
|
|
76
79
|
|
|
77
80
|
|
|
81
|
+
def legacy_shim_report(root: Path | None = None) -> Dict[str, Any]:
|
|
82
|
+
"""Sunset report for the root shim layer.
|
|
83
|
+
|
|
84
|
+
``latticeai.core.legacy_compatibility`` was deleted with the product
|
|
85
|
+
server. The remaining fact this gate still has to prove is: no root
|
|
86
|
+
``*.py`` is left, including ``server.py``.
|
|
87
|
+
"""
|
|
88
|
+
if root is None:
|
|
89
|
+
root = Path(__file__).resolve().parents[2]
|
|
90
|
+
lingering = sorted(path.name for path in root.glob("*.py"))
|
|
91
|
+
removed = [
|
|
92
|
+
"ltcai_cli.py",
|
|
93
|
+
"auto_setup.py",
|
|
94
|
+
"setup_wizard.py",
|
|
95
|
+
"mcp_registry.py",
|
|
96
|
+
"kg_schema.py",
|
|
97
|
+
"knowledge_graph.py",
|
|
98
|
+
"knowledge_graph_api.py",
|
|
99
|
+
"local_knowledge_api.py",
|
|
100
|
+
"llm_router.py",
|
|
101
|
+
"p_reinforce.py",
|
|
102
|
+
"telegram_bot.py",
|
|
103
|
+
"tools/",
|
|
104
|
+
"server.py",
|
|
105
|
+
]
|
|
106
|
+
return {
|
|
107
|
+
"status": "managed" if not lingering else "incomplete",
|
|
108
|
+
"remaining_count": len(lingering),
|
|
109
|
+
"shims": [],
|
|
110
|
+
"removed": [{"path": path} for path in removed],
|
|
111
|
+
"missing": [],
|
|
112
|
+
"lingering": lingering,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
78
116
|
def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
79
117
|
if root is None:
|
|
80
118
|
root = Path(__file__).resolve().parents[2]
|
|
@@ -118,13 +156,14 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
118
156
|
["from fastapi import HTTPException", "raise HTTPException"],
|
|
119
157
|
)
|
|
120
158
|
)
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
-
# scanned β checking only __init__.py would leave the gate blind one
|
|
124
|
-
# directory down.
|
|
159
|
+
# The Python agent loop package is gone. The compatibility alias is now
|
|
160
|
+
# scanned on the two Python files that still talk about permission mode.
|
|
125
161
|
agent_alias_forbidden = [
|
|
126
162
|
finding
|
|
127
|
-
for relative_path in
|
|
163
|
+
for relative_path in (
|
|
164
|
+
"latticeai/core/agent_permission.py",
|
|
165
|
+
"latticeai/api/agent_worker_seam.py",
|
|
166
|
+
)
|
|
128
167
|
for finding in _forbidden_patterns(
|
|
129
168
|
root,
|
|
130
169
|
relative_path,
|
|
@@ -137,13 +176,13 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
137
176
|
id="agent-runtime",
|
|
138
177
|
title="AgentRuntime boundary",
|
|
139
178
|
status="complete" if (
|
|
140
|
-
_symbol_exists("
|
|
179
|
+
_symbol_exists("latticeai.core.agent_permission.block_reason_for_tool")
|
|
141
180
|
and not agent_alias_forbidden
|
|
142
181
|
) else "incomplete",
|
|
143
182
|
evidence=[
|
|
144
|
-
"
|
|
145
|
-
"latticeai.api.
|
|
146
|
-
"tests/unit/
|
|
183
|
+
"latticeai.core.agent_permission.block_reason_for_tool",
|
|
184
|
+
"latticeai.api.agent_worker_seam.create_agent_worker_seam_router",
|
|
185
|
+
"tests/unit/test_agent_worker_seam.py",
|
|
147
186
|
],
|
|
148
187
|
),
|
|
149
188
|
ArchitectureGate(
|
|
@@ -167,7 +206,7 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
167
206
|
evidence=[
|
|
168
207
|
"latticeai.core.config.Config.from_env",
|
|
169
208
|
"latticeai.runtime.config_runtime.ConfigRuntime",
|
|
170
|
-
"tests/unit/
|
|
209
|
+
"tests/unit/test_runtime_context.py",
|
|
171
210
|
],
|
|
172
211
|
),
|
|
173
212
|
ArchitectureGate(
|
|
@@ -179,15 +218,15 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
179
218
|
for symbol in [
|
|
180
219
|
"latticeai.runtime.config_runtime.ConfigRuntime",
|
|
181
220
|
"latticeai.runtime.security_runtime.SecurityRuntime",
|
|
182
|
-
"latticeai.runtime.
|
|
183
|
-
"latticeai.
|
|
184
|
-
"latticeai.
|
|
221
|
+
"latticeai.runtime.runtime_context.RuntimeContext",
|
|
222
|
+
"latticeai.worker_app.create_worker_app",
|
|
223
|
+
"latticeai.app_factory.build_context",
|
|
185
224
|
]
|
|
186
225
|
)
|
|
187
226
|
and not factory_forbidden
|
|
188
227
|
) else "incomplete",
|
|
189
228
|
evidence=[
|
|
190
|
-
"latticeai.
|
|
229
|
+
"latticeai.worker_app.create_worker_app composition root",
|
|
191
230
|
"latticeai.api.* domain routers",
|
|
192
231
|
"latticeai.runtime.* runtime contexts",
|
|
193
232
|
],
|
|
@@ -195,11 +234,11 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
195
234
|
ArchitectureGate(
|
|
196
235
|
id="kg-hardening",
|
|
197
236
|
title="Knowledge Graph stabilization",
|
|
198
|
-
status="complete" if _symbol_exists("lattice_brain.
|
|
237
|
+
status="complete" if _symbol_exists("lattice_brain.embeddings.LocalEmbeddingModel") else "incomplete",
|
|
199
238
|
evidence=[
|
|
200
|
-
"lattice_brain.
|
|
201
|
-
"lattice_brain.
|
|
202
|
-
"tests/unit/
|
|
239
|
+
"lattice_brain.embeddings.LocalEmbeddingModel",
|
|
240
|
+
"lattice_brain.graph._kg_common.extraction",
|
|
241
|
+
"tests/unit/test_kg_common_exports.py",
|
|
203
242
|
],
|
|
204
243
|
),
|
|
205
244
|
ArchitectureGate(
|
|
@@ -217,8 +256,8 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
217
256
|
title="Legacy shim sunset plan",
|
|
218
257
|
status="complete" if shim_report["status"] == "managed" else "incomplete",
|
|
219
258
|
evidence=[
|
|
220
|
-
"latticeai.
|
|
221
|
-
"
|
|
259
|
+
"latticeai.services.architecture_readiness.legacy_shim_report",
|
|
260
|
+
"scripts/check_legacy_debt.mjs",
|
|
222
261
|
"tests/unit/test_legacy_root_shims.py",
|
|
223
262
|
],
|
|
224
263
|
),
|
|
@@ -228,17 +267,17 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
228
267
|
status="complete" if all(
|
|
229
268
|
_symbol_exists(s)
|
|
230
269
|
for s in [
|
|
231
|
-
"
|
|
232
|
-
"
|
|
233
|
-
"latticeai.
|
|
270
|
+
"latticeai.services.tool_dispatch.ToolDispatchService",
|
|
271
|
+
"latticeai.tools.execute_tool",
|
|
272
|
+
"latticeai.api.worker_compute.create_worker_compute_router",
|
|
234
273
|
]
|
|
235
274
|
) else "incomplete",
|
|
236
275
|
evidence=[
|
|
237
|
-
"
|
|
238
|
-
"
|
|
239
|
-
"latticeai.
|
|
240
|
-
"tests/unit/
|
|
241
|
-
"tests/unit/
|
|
276
|
+
"latticeai.services.tool_dispatch.ToolDispatchService",
|
|
277
|
+
"latticeai.tools.execute_tool",
|
|
278
|
+
"latticeai.api.worker_compute.create_worker_compute_router",
|
|
279
|
+
"tests/unit/test_tool_registry.py",
|
|
280
|
+
"tests/unit/test_worker_compute.py",
|
|
242
281
|
],
|
|
243
282
|
),
|
|
244
283
|
]
|
|
@@ -252,13 +291,13 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
252
291
|
"refactoring_order": list(PREFERRED_REFACTORING_ORDER),
|
|
253
292
|
"boundaries": {
|
|
254
293
|
"agent-runtime": {
|
|
255
|
-
"owner": "
|
|
256
|
-
"surface": "/
|
|
257
|
-
"status": "
|
|
294
|
+
"owner": "latticeai.core.agent_permission.block_reason_for_tool",
|
|
295
|
+
"surface": "/agent/llm + /agent/tool",
|
|
296
|
+
"status": "worker-seam",
|
|
258
297
|
},
|
|
259
298
|
"tool-registry": {
|
|
260
299
|
"owner": "latticeai.core.tool_registry.ToolRegistry",
|
|
261
|
-
"surface": "/
|
|
300
|
+
"surface": "/agent/tool",
|
|
262
301
|
"status": "registry",
|
|
263
302
|
},
|
|
264
303
|
"config-centralization": {
|
|
@@ -267,9 +306,9 @@ def architecture_readiness(root: Path | None = None) -> Dict[str, Any]:
|
|
|
267
306
|
"status": "typed-config",
|
|
268
307
|
},
|
|
269
308
|
"kg-hardening": {
|
|
270
|
-
"owner": "lattice_brain.
|
|
271
|
-
"strategy": "
|
|
272
|
-
"rollback": "
|
|
309
|
+
"owner": "lattice_brain.embeddings.LocalEmbeddingModel",
|
|
310
|
+
"strategy": "compute-only embedder and _kg_common helpers; writes are native",
|
|
311
|
+
"rollback": "committed rust/fixtures goldens; Python generators frozen at fc65e60",
|
|
273
312
|
},
|
|
274
313
|
},
|
|
275
314
|
"ordered_gate_ids": ordered_gate_ids,
|
|
@@ -8,8 +8,8 @@ Split into cohesive submodules in v11.3.0 (no behaviour change): ``state`` (the
|
|
|
8
8
|
immutable ``ModelRuntimeState`` and the consent gates), ``engines`` (engine
|
|
9
9
|
wrappers + the LM Studio client), ``download`` (Hugging Face readiness and
|
|
10
10
|
fetch), ``status`` (``engine_status`` / ``runtime_features`` / ``install_engine``),
|
|
11
|
-
``loading`` (identity resolution and the load entrypoints)
|
|
12
|
-
|
|
11
|
+
``loading`` (identity resolution and the load entrypoints) and ``service`` (the
|
|
12
|
+
bound ``ModelRuntimeService``). This module
|
|
13
13
|
re-exports every name the single file exposed, so
|
|
14
14
|
``latticeai.services.model_runtime.X`` keeps working β including the private
|
|
15
15
|
names ``model_loading._get_model_runtime_deps`` imports.
|
|
@@ -69,15 +69,6 @@ from latticeai.services.model_catalog import (
|
|
|
69
69
|
filter_lower_family_versions as filter_lower_family_versions,
|
|
70
70
|
)
|
|
71
71
|
from latticeai.services.model_errors import ModelRuntimeError as ModelRuntimeError
|
|
72
|
-
from latticeai.services.model_runtime.cloud import (
|
|
73
|
-
CLOUD_VERIFY_TTL_SECONDS as CLOUD_VERIFY_TTL_SECONDS,
|
|
74
|
-
)
|
|
75
|
-
from latticeai.services.model_runtime.cloud import (
|
|
76
|
-
_probe_cloud_model as _probe_cloud_model,
|
|
77
|
-
)
|
|
78
|
-
from latticeai.services.model_runtime.cloud import (
|
|
79
|
-
verify_cloud_models as verify_cloud_models,
|
|
80
|
-
)
|
|
81
72
|
from latticeai.services.model_runtime.download import (
|
|
82
73
|
download_hf_model as download_hf_model,
|
|
83
74
|
)
|
|
@@ -12,7 +12,6 @@ from __future__ import annotations
|
|
|
12
12
|
from dataclasses import dataclass, field
|
|
13
13
|
from typing import Any, AsyncIterator, Dict, List, Optional
|
|
14
14
|
|
|
15
|
-
from latticeai.services.model_runtime.cloud import verify_cloud_models
|
|
16
15
|
from latticeai.services.model_runtime.loading import (
|
|
17
16
|
prepare_and_load_model,
|
|
18
17
|
prepare_and_load_model_stream,
|
|
@@ -21,11 +20,7 @@ from latticeai.services.model_runtime.state import (
|
|
|
21
20
|
ModelRuntimeState,
|
|
22
21
|
create_model_runtime_state,
|
|
23
22
|
)
|
|
24
|
-
from latticeai.services.model_runtime.status import
|
|
25
|
-
engine_status,
|
|
26
|
-
install_engine,
|
|
27
|
-
runtime_features,
|
|
28
|
-
)
|
|
23
|
+
from latticeai.services.model_runtime.status import engine_status, runtime_features
|
|
29
24
|
|
|
30
25
|
|
|
31
26
|
def configure_model_runtime(**deps: Any) -> "ModelRuntimeService":
|
|
@@ -49,6 +44,9 @@ class ModelRuntimeService:
|
|
|
49
44
|
"""
|
|
50
45
|
|
|
51
46
|
state: ModelRuntimeState
|
|
47
|
+
#: Engine probes cache their cloud-provider answers here. It is per-service
|
|
48
|
+
#: rather than process-wide so a second application starts with an empty
|
|
49
|
+
#: cache instead of inheriting probe results it never ran.
|
|
52
50
|
_cloud_verify_cache: Dict[str, Dict[str, Any]] = field(default_factory=dict)
|
|
53
51
|
|
|
54
52
|
def runtime_features(self) -> Dict[str, Any]:
|
|
@@ -60,28 +58,6 @@ class ModelRuntimeService:
|
|
|
60
58
|
cloud_verify_cache=self._cloud_verify_cache,
|
|
61
59
|
)
|
|
62
60
|
|
|
63
|
-
def install_engine(
|
|
64
|
-
self,
|
|
65
|
-
engine: str,
|
|
66
|
-
confirmation_token: Optional[str] = None,
|
|
67
|
-
) -> Dict[str, Any]:
|
|
68
|
-
return install_engine(
|
|
69
|
-
engine,
|
|
70
|
-
confirmation_token=confirmation_token,
|
|
71
|
-
state=self.state,
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
async def verify_cloud_models(
|
|
75
|
-
self,
|
|
76
|
-
force: bool = False,
|
|
77
|
-
provider_filter: Optional[str] = None,
|
|
78
|
-
) -> Dict[str, Dict[str, Any]]:
|
|
79
|
-
return await verify_cloud_models(
|
|
80
|
-
force=force,
|
|
81
|
-
provider_filter=provider_filter,
|
|
82
|
-
state=self.state,
|
|
83
|
-
cache=self._cloud_verify_cache,
|
|
84
|
-
)
|
|
85
61
|
|
|
86
62
|
async def prepare_and_load_model(
|
|
87
63
|
self,
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
+
"""Where the knowledge garden lives, and what its folders mean.
|
|
2
|
+
|
|
3
|
+
``PReinforceGardener`` β vault import, note creation, brain-backed context β
|
|
4
|
+
was the writing half, and writing the vault is ``lattice-retrieval``'s
|
|
5
|
+
(``/garden/*``) since v11.6.0. The two constants stay because the worker's
|
|
6
|
+
read-only vault tools (``knowledge_search``, ``knowledge_tree``,
|
|
7
|
+
``obsidian_search``, ``obsidian_tree``) resolve their root through them, and a
|
|
8
|
+
second definition of "where the vault is" is exactly how a search and a save
|
|
9
|
+
end up in different directories.
|
|
1
10
|
"""
|
|
2
|
-
P-Reinforce Knowledge Gardener β notes capture with a brain-backed memory.
|
|
3
11
|
|
|
4
|
-
v4 (T4.3 garden absorption): the markdown vault is no longer a second brain.
|
|
5
|
-
The vault stays as the user-owned, Obsidian-compatible *mirror* (capability
|
|
6
|
-
preserved), but the Knowledge Graph is authoritative: notes created through
|
|
7
|
-
the API are ingested through the unified pipeline (provenance + hooks), the
|
|
8
|
-
existing vault is imported idempotently, and chat context comes from brain
|
|
9
|
-
queries instead of an O(n) vault scan per message.
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import logging
|
|
13
12
|
import os
|
|
14
|
-
import re
|
|
15
|
-
import shutil
|
|
16
|
-
from datetime import datetime
|
|
17
13
|
from pathlib import Path
|
|
18
|
-
from typing import Any, Optional
|
|
19
|
-
|
|
20
|
-
from latticeai.core.quiet import quiet
|
|
21
14
|
|
|
22
15
|
BRAIN_DIR = Path(
|
|
23
16
|
os.getenv("LATTICEAI_OBSIDIAN_VAULT_DIR")
|
|
@@ -34,248 +27,4 @@ STRUCTURE = {
|
|
|
34
27
|
}
|
|
35
28
|
|
|
36
29
|
|
|
37
|
-
|
|
38
|
-
def __init__(self, ingestion_pipeline: Any = None, knowledge_graph: Any = None):
|
|
39
|
-
self._pipeline = ingestion_pipeline
|
|
40
|
-
self._kg = knowledge_graph
|
|
41
|
-
self._ensure_structure()
|
|
42
|
-
|
|
43
|
-
def _ensure_structure(self):
|
|
44
|
-
for folder in STRUCTURE:
|
|
45
|
-
(BRAIN_DIR / folder).mkdir(parents=True, exist_ok=True)
|
|
46
|
-
# μΈλ±μ€ νμΌ
|
|
47
|
-
index_path = BRAIN_DIR / "INDEX.md"
|
|
48
|
-
if not index_path.exists():
|
|
49
|
-
index_path.write_text(self._render_index())
|
|
50
|
-
|
|
51
|
-
def _render_index(self) -> str:
|
|
52
|
-
lines = ["# π§ Lattice AI Brain β P-Reinforce Index\n"]
|
|
53
|
-
lines.append(f"*Generated: {datetime.now().strftime('%Y-%m-%d %H:%M')}*\n")
|
|
54
|
-
lines.append("\nThis folder is an Obsidian-compatible Markdown vault.\n")
|
|
55
|
-
lines.append("\nThe Knowledge Graph is the authoritative store; this vault is the\nuser-owned markdown mirror of garden notes.\n")
|
|
56
|
-
for folder, desc in STRUCTURE.items():
|
|
57
|
-
lines.append(f"## [{folder}](./{folder}/)\n_{desc}_\n")
|
|
58
|
-
lines.append("## Connector Status\n")
|
|
59
|
-
lines.append(f"- OCR engine: `{'tesseract' if shutil.which('tesseract') else 'not installed'}`\n")
|
|
60
|
-
return "\n".join(lines)
|
|
61
|
-
|
|
62
|
-
# ββ Classify ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
63
|
-
|
|
64
|
-
def _classify(self, text: str) -> str:
|
|
65
|
-
"""κ°λ¨ν κ·μΉ κΈ°λ° λΆλ₯ (LLM μμ΄λ λμ)"""
|
|
66
|
-
text_lower = text.lower()
|
|
67
|
-
|
|
68
|
-
code_signals = ["def ", "class ", "import ", "```", "function ", "const ", "let ", "var "]
|
|
69
|
-
if any(s in text for s in code_signals):
|
|
70
|
-
return "20_Skills"
|
|
71
|
-
|
|
72
|
-
wiki_signals = ["κ°λ
", "μ리", "μ΄λ", "what is", "how does", "definition", "explanation"]
|
|
73
|
-
if any(s in text_lower for s in wiki_signals):
|
|
74
|
-
return "10_Wiki"
|
|
75
|
-
|
|
76
|
-
project_signals = ["project", "νλ‘μ νΈ", "todo", "task", "μμ
", "κΈ°λ₯", "feature"]
|
|
77
|
-
if any(s in text_lower for s in project_signals):
|
|
78
|
-
return "30_Projects"
|
|
79
|
-
|
|
80
|
-
return "00_Raw"
|
|
81
|
-
|
|
82
|
-
# ββ File Naming βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
83
|
-
|
|
84
|
-
def _make_filename(self, text: str, folder: str) -> str:
|
|
85
|
-
# 첫 μ€μ μ λͺ©μΌλ‘
|
|
86
|
-
first_line = text.strip().split("\n")[0][:60]
|
|
87
|
-
# νμΌλͺ
μμ νκ²
|
|
88
|
-
safe = re.sub(r"[^\w\s-]", "", first_line).strip()
|
|
89
|
-
safe = re.sub(r"\s+", "_", safe)
|
|
90
|
-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
91
|
-
return f"{timestamp}_{safe or 'note'}.md"
|
|
92
|
-
|
|
93
|
-
# ββ Process βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
94
|
-
|
|
95
|
-
async def process(self, raw_data: str, category: Optional[str] = None) -> dict:
|
|
96
|
-
folder = category if category in STRUCTURE else self._classify(raw_data)
|
|
97
|
-
filename = self._make_filename(raw_data, folder)
|
|
98
|
-
filepath = BRAIN_DIR / folder / filename
|
|
99
|
-
|
|
100
|
-
# λ§ν¬λ€μ΄ λ―Έλ¬ (μ¬μ©μ μμ Obsidian νΈν μν°ν©νΈ)
|
|
101
|
-
content = self._wrap_markdown(raw_data, folder)
|
|
102
|
-
filepath.write_text(content, encoding="utf-8")
|
|
103
|
-
|
|
104
|
-
# μ€λ λ‘κ·Έμλ κΈ°λ‘
|
|
105
|
-
self._append_log(raw_data[:200], folder, filename)
|
|
106
|
-
|
|
107
|
-
result = {
|
|
108
|
-
"status": "saved",
|
|
109
|
-
"folder": folder,
|
|
110
|
-
"filename": filename,
|
|
111
|
-
"path": str(filepath),
|
|
112
|
-
"classified_as": folder,
|
|
113
|
-
"description": STRUCTURE[folder],
|
|
114
|
-
}
|
|
115
|
-
# λλ(Knowledge Graph)κ° μ μ μ μ₯μ: ν΅ν© μμ§ νμ΄νλΌμΈμΌλ‘ ingest.
|
|
116
|
-
result.update(self._ingest_note(raw_data, source_uri=str(filepath), folder=folder))
|
|
117
|
-
return result
|
|
118
|
-
|
|
119
|
-
def _ingest_note(self, text: str, *, source_uri: str, folder: str, title: Optional[str] = None) -> dict:
|
|
120
|
-
if self._pipeline is None:
|
|
121
|
-
return {"graph": "unavailable", "graph_detail": "ingestion pipeline not wired"}
|
|
122
|
-
try:
|
|
123
|
-
from lattice_brain.ingestion import IngestionItem
|
|
124
|
-
|
|
125
|
-
ingest = self._pipeline.ingest(
|
|
126
|
-
IngestionItem(
|
|
127
|
-
source_type="note",
|
|
128
|
-
title=title or text.strip().split("\n")[0][:80],
|
|
129
|
-
text=text,
|
|
130
|
-
source_uri=source_uri,
|
|
131
|
-
metadata={"garden_folder": folder, "pipeline": "p-reinforce"},
|
|
132
|
-
)
|
|
133
|
-
)
|
|
134
|
-
if ingest.status != "ok":
|
|
135
|
-
return {"graph": ingest.status, "graph_detail": ingest.detail}
|
|
136
|
-
return {
|
|
137
|
-
"graph": "ok",
|
|
138
|
-
"graph_node_id": ingest.node_id,
|
|
139
|
-
"provenance_id": ingest.provenance_id,
|
|
140
|
-
"duplicate": ingest.duplicate,
|
|
141
|
-
}
|
|
142
|
-
except Exception as exc:
|
|
143
|
-
logging.warning("garden note ingest failed: %s", exc)
|
|
144
|
-
return {"graph": "failed", "graph_detail": str(exc)}
|
|
145
|
-
|
|
146
|
-
def import_vault(self) -> dict:
|
|
147
|
-
"""Idempotent import of every existing vault note into the brain.
|
|
148
|
-
|
|
149
|
-
Content-hash dedup in the store makes re-runs safe; vault files are
|
|
150
|
-
never modified or deleted. INDEX.md and the daily logs are skipped.
|
|
151
|
-
"""
|
|
152
|
-
if self._pipeline is None:
|
|
153
|
-
return {"status": "unavailable", "imported": 0}
|
|
154
|
-
imported = duplicates = failed = 0
|
|
155
|
-
for file_path in sorted(BRAIN_DIR.rglob("*.md")):
|
|
156
|
-
if file_path.name == "INDEX.md" or "40_Log" in file_path.parts:
|
|
157
|
-
continue
|
|
158
|
-
try:
|
|
159
|
-
text = file_path.read_text(encoding="utf-8")
|
|
160
|
-
except Exception:
|
|
161
|
-
failed += 1
|
|
162
|
-
continue
|
|
163
|
-
folder = file_path.parent.name if file_path.parent != BRAIN_DIR else "00_Raw"
|
|
164
|
-
outcome = self._ingest_note(
|
|
165
|
-
text, source_uri=str(file_path), folder=folder, title=file_path.stem
|
|
166
|
-
)
|
|
167
|
-
if outcome.get("graph") == "ok":
|
|
168
|
-
if outcome.get("duplicate"):
|
|
169
|
-
duplicates += 1
|
|
170
|
-
else:
|
|
171
|
-
imported += 1
|
|
172
|
-
else:
|
|
173
|
-
failed += 1
|
|
174
|
-
if imported:
|
|
175
|
-
logging.info("garden: imported %d vault notes into the brain (%d already known)", imported, duplicates)
|
|
176
|
-
return {"status": "ok", "imported": imported, "duplicates": duplicates, "failed": failed}
|
|
177
|
-
|
|
178
|
-
def _wrap_markdown(self, raw: str, folder: str) -> str:
|
|
179
|
-
now = datetime.now().strftime("%Y-%m-%d %H:%M")
|
|
180
|
-
first_line = raw.strip().split("\n")[0][:80]
|
|
181
|
-
lines = [
|
|
182
|
-
f"# {first_line}",
|
|
183
|
-
f"\n> π `{folder}` | π {now} | Lattice AI MLX\n",
|
|
184
|
-
"---\n",
|
|
185
|
-
raw,
|
|
186
|
-
"\n\n---",
|
|
187
|
-
"*Auto-organized by P-Reinforce Gardener*",
|
|
188
|
-
]
|
|
189
|
-
return "\n".join(lines)
|
|
190
|
-
|
|
191
|
-
def _append_log(self, preview: str, folder: str, filename: str):
|
|
192
|
-
today = datetime.now().strftime("%Y-%m-%d")
|
|
193
|
-
log_path = BRAIN_DIR / "40_Log" / f"{today}.md"
|
|
194
|
-
entry = f"\n- [{datetime.now().strftime('%H:%M')}] β `{folder}/{filename}`\n > {preview[:100]}\n"
|
|
195
|
-
with open(log_path, "a", encoding="utf-8") as f:
|
|
196
|
-
if log_path.stat().st_size == 0 if log_path.exists() else True:
|
|
197
|
-
f.write(f"# π
Log β {today}\n")
|
|
198
|
-
f.write(entry)
|
|
199
|
-
|
|
200
|
-
# ββ Tree ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
201
|
-
|
|
202
|
-
def get_tree(self) -> dict:
|
|
203
|
-
"""μ§μ μ μ νμΌνΈλ¦¬ (λ§ν¬λ€μ΄ λ―Έλ¬ κΈ°μ€)."""
|
|
204
|
-
folders = []
|
|
205
|
-
for folder, desc in STRUCTURE.items():
|
|
206
|
-
folder_path = BRAIN_DIR / folder
|
|
207
|
-
files = []
|
|
208
|
-
if folder_path.exists():
|
|
209
|
-
for file_path in sorted(folder_path.glob("*.md")):
|
|
210
|
-
try:
|
|
211
|
-
stat = file_path.stat()
|
|
212
|
-
files.append({
|
|
213
|
-
"name": file_path.name,
|
|
214
|
-
"size_bytes": stat.st_size,
|
|
215
|
-
"modified_at": datetime.fromtimestamp(stat.st_mtime).isoformat(timespec="seconds"),
|
|
216
|
-
})
|
|
217
|
-
except OSError:
|
|
218
|
-
quiet()
|
|
219
|
-
continue
|
|
220
|
-
folders.append({"name": folder, "description": desc, "files": files, "count": len(files)})
|
|
221
|
-
return {"root": str(BRAIN_DIR), "folders": folders}
|
|
222
|
-
|
|
223
|
-
def get_relevant_context(
|
|
224
|
-
self,
|
|
225
|
-
query: str,
|
|
226
|
-
limit: int = 3,
|
|
227
|
-
*,
|
|
228
|
-
allowed_workspaces: Any = None,
|
|
229
|
-
) -> str:
|
|
230
|
-
"""μ§λ¬Έκ³Ό κ΄λ ¨λ μ μ λ
ΈνΈλ₯Ό λλμμ κ²μν΄ μ»¨ν
μ€νΈλ‘ λ°ν.
|
|
231
|
-
|
|
232
|
-
v4: μ±ν
λ§λ€ vault μ 체λ₯Ό rglob νλ O(n) μ€μΊμ λΈλ μΈ κ²μμΌλ‘
|
|
233
|
-
λ체. κ·Έλνκ° μμΌλ©΄(λΉνμ±) κΈ°μ‘΄ νμΌ μ€μΊμΌλ‘ μ μ§νκ² ν΄λ°±.
|
|
234
|
-
"""
|
|
235
|
-
if self._kg is not None:
|
|
236
|
-
try:
|
|
237
|
-
scope_kwargs = (
|
|
238
|
-
{"allowed_workspaces": allowed_workspaces}
|
|
239
|
-
if allowed_workspaces is not None
|
|
240
|
-
else {}
|
|
241
|
-
)
|
|
242
|
-
matches = self._kg.search(
|
|
243
|
-
query,
|
|
244
|
-
max(limit * 4, 8),
|
|
245
|
-
**scope_kwargs,
|
|
246
|
-
).get("matches", [])
|
|
247
|
-
results = []
|
|
248
|
-
for match in matches:
|
|
249
|
-
meta = match.get("metadata") or {}
|
|
250
|
-
if not (meta.get("garden_folder") or meta.get("pipeline") == "p-reinforce"):
|
|
251
|
-
continue
|
|
252
|
-
title = match.get("title") or "note"
|
|
253
|
-
body = match.get("summary") or ""
|
|
254
|
-
results.append(f"--- Document: {title} ---\n{body[:800]}")
|
|
255
|
-
if len(results) >= limit:
|
|
256
|
-
break
|
|
257
|
-
return "\n\n".join(results)
|
|
258
|
-
except Exception as exc:
|
|
259
|
-
logging.debug("garden brain context failed: %s", exc)
|
|
260
|
-
if allowed_workspaces is not None:
|
|
261
|
-
return ""
|
|
262
|
-
elif allowed_workspaces is not None:
|
|
263
|
-
return ""
|
|
264
|
-
return self._scan_vault_context(query, limit)
|
|
265
|
-
|
|
266
|
-
def _scan_vault_context(self, query: str, limit: int = 3) -> str:
|
|
267
|
-
results = []
|
|
268
|
-
for file_path in BRAIN_DIR.rglob("*.md"):
|
|
269
|
-
if file_path.name == "INDEX.md" or "40_Log" in str(file_path):
|
|
270
|
-
continue
|
|
271
|
-
try:
|
|
272
|
-
content = file_path.read_text(encoding="utf-8")
|
|
273
|
-
keywords = [k for k in re.split(r"\s+", query) if len(k) > 1]
|
|
274
|
-
if any(k.lower() in content.lower() for k in keywords):
|
|
275
|
-
results.append(f"--- Document: {file_path.name} ---\n{content[:800]}")
|
|
276
|
-
if len(results) >= limit:
|
|
277
|
-
break
|
|
278
|
-
except Exception:
|
|
279
|
-
quiet()
|
|
280
|
-
continue
|
|
281
|
-
return "\n\n".join(results)
|
|
30
|
+
__all__ = ["BRAIN_DIR", "STRUCTURE"]
|