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
|
@@ -6,13 +6,11 @@ Path resolution reads ``latticeai.tools.AGENT_ROOT`` so tests can redirect the s
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
import io
|
|
10
9
|
import json
|
|
11
10
|
import re
|
|
12
|
-
import zipfile
|
|
13
11
|
from html.parser import HTMLParser
|
|
14
12
|
from pathlib import Path
|
|
15
|
-
from typing import Any, Dict, List, Optional
|
|
13
|
+
from typing import Any, Dict, List, Optional
|
|
16
14
|
|
|
17
15
|
import latticeai.tools as tools
|
|
18
16
|
from latticeai.core.quiet import quiet
|
|
@@ -118,52 +116,6 @@ def read_file(path: str, offset: int = 0, limit: int = 0, line_numbers: bool = T
|
|
|
118
116
|
return result
|
|
119
117
|
|
|
120
118
|
|
|
121
|
-
def write_file(path: str, content: str) -> Dict[str, Any]:
|
|
122
|
-
target = _resolve_path(path)
|
|
123
|
-
if len(content.encode("utf-8")) > MAX_FILE_BYTES:
|
|
124
|
-
raise ToolError("Content is too large to write.")
|
|
125
|
-
target.parent.mkdir(parents=True, exist_ok=True)
|
|
126
|
-
target.write_text(content, encoding="utf-8")
|
|
127
|
-
return {"path": _relative(target), "bytes": target.stat().st_size}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def edit_file(path: str, old_string: str, new_string: str, replace_all: bool = False) -> Dict[str, Any]:
|
|
131
|
-
"""Precise diff-style edit: replace `old_string` with `new_string` in `path`.
|
|
132
|
-
|
|
133
|
-
Fails when `old_string` is missing or appears more than once (unless
|
|
134
|
-
replace_all=True). This forces the caller to read the file first and pass
|
|
135
|
-
enough surrounding context to uniquely identify the edit site — the same
|
|
136
|
-
discipline Claude Code uses for safe edits.
|
|
137
|
-
"""
|
|
138
|
-
if old_string == new_string:
|
|
139
|
-
raise ToolError("old_string and new_string are identical; nothing to change.")
|
|
140
|
-
target = _resolve_path(path)
|
|
141
|
-
if not target.exists() or not target.is_file():
|
|
142
|
-
raise ToolError("File does not exist.")
|
|
143
|
-
if target.stat().st_size > MAX_FILE_BYTES:
|
|
144
|
-
raise ToolError("File is too large to edit.")
|
|
145
|
-
|
|
146
|
-
original = target.read_text(encoding="utf-8")
|
|
147
|
-
occurrences = original.count(old_string)
|
|
148
|
-
if occurrences == 0:
|
|
149
|
-
raise ToolError("old_string not found in file. Read the file first and copy the exact bytes (including whitespace).")
|
|
150
|
-
if occurrences > 1 and not replace_all:
|
|
151
|
-
raise ToolError(f"old_string is ambiguous: appears {occurrences} times. Add more context to make it unique, or pass replace_all=true.")
|
|
152
|
-
|
|
153
|
-
updated = original.replace(old_string, new_string) if replace_all else original.replace(old_string, new_string, 1)
|
|
154
|
-
if len(updated.encode("utf-8")) > MAX_FILE_BYTES:
|
|
155
|
-
raise ToolError("Resulting file would exceed the workspace size limit.")
|
|
156
|
-
target.write_text(updated, encoding="utf-8")
|
|
157
|
-
|
|
158
|
-
edited_line = original[: original.find(old_string)].count("\n") + 1
|
|
159
|
-
return {
|
|
160
|
-
"path": _relative(target),
|
|
161
|
-
"replacements": occurrences if replace_all else 1,
|
|
162
|
-
"bytes": target.stat().st_size,
|
|
163
|
-
"first_edit_line": edited_line,
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
|
|
167
119
|
_GREP_BINARY_EXTS = {".png", ".jpg", ".jpeg", ".gif", ".webp", ".pdf", ".zip", ".tar",
|
|
168
120
|
".gz", ".bz2", ".xz", ".7z", ".mp3", ".mp4", ".mov", ".wav",
|
|
169
121
|
".woff", ".woff2", ".ttf", ".eot", ".ico", ".db", ".sqlite",
|
|
@@ -281,46 +233,6 @@ def todo_read() -> Dict[str, Any]:
|
|
|
281
233
|
return {"todos": todos, "path": _TODO_REL_PATH}
|
|
282
234
|
|
|
283
235
|
|
|
284
|
-
def todo_write(todos: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
285
|
-
"""Replace the agent's TODO list. Each todo: {id, content, status}.
|
|
286
|
-
|
|
287
|
-
Status must be one of: pending, in_progress, completed.
|
|
288
|
-
At most one todo should be in_progress at any time — the agent enforces
|
|
289
|
-
this convention; the tool only warns if violated.
|
|
290
|
-
"""
|
|
291
|
-
if not isinstance(todos, list):
|
|
292
|
-
raise ToolError("todos must be a list.")
|
|
293
|
-
if len(todos) > 50:
|
|
294
|
-
raise ToolError("Too many todos (max 50). Split into smaller batches.")
|
|
295
|
-
|
|
296
|
-
cleaned: List[Dict[str, Any]] = []
|
|
297
|
-
in_progress_count = 0
|
|
298
|
-
for idx, raw in enumerate(todos, start=1):
|
|
299
|
-
if not isinstance(raw, dict):
|
|
300
|
-
raise ToolError(f"Todo #{idx} is not an object.")
|
|
301
|
-
content = str(raw.get("content") or "").strip()
|
|
302
|
-
if not content:
|
|
303
|
-
raise ToolError(f"Todo #{idx} is missing 'content'.")
|
|
304
|
-
status = str(raw.get("status") or "pending").strip().lower()
|
|
305
|
-
if status not in _TODO_ALLOWED_STATUS:
|
|
306
|
-
raise ToolError(f"Todo #{idx} has invalid status '{status}'. Use one of {sorted(_TODO_ALLOWED_STATUS)}.")
|
|
307
|
-
if status == "in_progress":
|
|
308
|
-
in_progress_count += 1
|
|
309
|
-
cleaned.append({
|
|
310
|
-
"id": str(raw.get("id") or idx),
|
|
311
|
-
"content": content[:240],
|
|
312
|
-
"status": status,
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
target = _todo_file()
|
|
316
|
-
target.write_text(json.dumps(cleaned, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
317
|
-
return {
|
|
318
|
-
"todos": cleaned,
|
|
319
|
-
"path": _TODO_REL_PATH,
|
|
320
|
-
"warning": "More than one todo is in_progress; keep only one active at a time." if in_progress_count > 1 else None,
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
|
|
324
236
|
def search_files(query: str, path: str = ".", max_results: int = 20) -> Dict[str, Any]:
|
|
325
237
|
if not query:
|
|
326
238
|
raise ToolError("Query is required.")
|
|
@@ -434,166 +346,8 @@ def preview_url(path: str = "index.html") -> Dict[str, Any]:
|
|
|
434
346
|
}
|
|
435
347
|
|
|
436
348
|
|
|
437
|
-
def create_web_project(path: str, framework: str = "react", template: str = "vite") -> Dict[str, Any]:
|
|
438
|
-
framework = str(framework or "").strip().lower()
|
|
439
|
-
template = str(template or "").strip().lower()
|
|
440
|
-
if framework != "react" or template != "vite":
|
|
441
|
-
raise ToolError("Only React + Vite template is currently supported.")
|
|
442
|
-
if not path:
|
|
443
|
-
raise ToolError("Project path is required.")
|
|
444
|
-
|
|
445
|
-
root = _resolve_path(path)
|
|
446
|
-
root.mkdir(parents=True, exist_ok=True)
|
|
447
|
-
|
|
448
|
-
files = {
|
|
449
|
-
"package.json": json.dumps(
|
|
450
|
-
{
|
|
451
|
-
"name": Path(path).name.replace(" ", "-").lower() or "vite-react-app",
|
|
452
|
-
"private": True,
|
|
453
|
-
"version": "0.0.0",
|
|
454
|
-
"type": "module",
|
|
455
|
-
"scripts": {
|
|
456
|
-
"dev": "vite",
|
|
457
|
-
"build": "vite build",
|
|
458
|
-
"preview": "vite preview",
|
|
459
|
-
},
|
|
460
|
-
"dependencies": {
|
|
461
|
-
"react": "^18.3.1",
|
|
462
|
-
"react-dom": "^18.3.1",
|
|
463
|
-
},
|
|
464
|
-
"devDependencies": {
|
|
465
|
-
"@vitejs/plugin-react": "^4.3.1",
|
|
466
|
-
"vite": "^5.4.0",
|
|
467
|
-
},
|
|
468
|
-
},
|
|
469
|
-
ensure_ascii=False,
|
|
470
|
-
indent=2,
|
|
471
|
-
) + "\n",
|
|
472
|
-
"index.html": """<!doctype html>
|
|
473
|
-
<html lang="en">
|
|
474
|
-
<head>
|
|
475
|
-
<meta charset="UTF-8" />
|
|
476
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
477
|
-
<title>Vite React App</title>
|
|
478
|
-
</head>
|
|
479
|
-
<body>
|
|
480
|
-
<div id="root"></div>
|
|
481
|
-
<script type="module" src="/src/main.jsx"></script>
|
|
482
|
-
</body>
|
|
483
|
-
</html>
|
|
484
|
-
""",
|
|
485
|
-
"vite.config.js": """import { defineConfig } from 'vite'
|
|
486
|
-
import react from '@vitejs/plugin-react'
|
|
487
|
-
|
|
488
|
-
export default defineConfig({
|
|
489
|
-
plugins: [react()],
|
|
490
|
-
})
|
|
491
|
-
""",
|
|
492
|
-
"README.md": """# Vite React App
|
|
493
|
-
|
|
494
|
-
## Run
|
|
495
|
-
|
|
496
|
-
```bash
|
|
497
|
-
npm install
|
|
498
|
-
npm run dev
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
## Build
|
|
502
|
-
|
|
503
|
-
```bash
|
|
504
|
-
npm run build
|
|
505
|
-
npm run preview
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
## Lattice AI Notes
|
|
509
|
-
|
|
510
|
-
- Inspect `package.json` and existing config files before adding new libraries.
|
|
511
|
-
- If you add Tailwind CSS, framer-motion, TypeScript, or other tooling, add the required config files too.
|
|
512
|
-
- Do not report the app as complete until `npm run build` succeeds.
|
|
513
|
-
""",
|
|
514
|
-
"src/main.jsx": """import React from 'react'
|
|
515
|
-
import ReactDOM from 'react-dom/client'
|
|
516
|
-
import App from './App.jsx'
|
|
517
|
-
import './index.css'
|
|
518
|
-
|
|
519
|
-
ReactDOM.createRoot(document.getElementById('root')).render(
|
|
520
|
-
<React.StrictMode>
|
|
521
|
-
<App />
|
|
522
|
-
</React.StrictMode>,
|
|
523
|
-
)
|
|
524
|
-
""",
|
|
525
|
-
"src/App.jsx": """import { useState } from 'react'
|
|
526
|
-
|
|
527
|
-
export default function App() {
|
|
528
|
-
const [count, setCount] = useState(0)
|
|
529
|
-
return (
|
|
530
|
-
<main style={{ maxWidth: 760, margin: '48px auto', padding: '0 20px', fontFamily: 'system-ui, sans-serif' }}>
|
|
531
|
-
<h1>Vite + React</h1>
|
|
532
|
-
<p>Starter generated by Lattice AI agent.</p>
|
|
533
|
-
<p style={{ color: '#555', lineHeight: 1.6 }}>
|
|
534
|
-
Inspect the current setup before adding new UI libraries, then verify
|
|
535
|
-
changes with <code>npm run build</code>.
|
|
536
|
-
</p>
|
|
537
|
-
<button onClick={() => setCount((c) => c + 1)}>count is {count}</button>
|
|
538
|
-
</main>
|
|
539
|
-
)
|
|
540
|
-
}
|
|
541
|
-
""",
|
|
542
|
-
"src/index.css": """* { box-sizing: border-box; }
|
|
543
|
-
body { margin: 0; background: #f6f7fb; color: #111; }
|
|
544
|
-
button { padding: 10px 14px; border-radius: 10px; border: 1px solid #d6d6d6; background: #fff; cursor: pointer; }
|
|
545
|
-
""",
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
created: List[str] = []
|
|
549
|
-
total_bytes = 0
|
|
550
|
-
for rel_path, content in files.items():
|
|
551
|
-
target = (root / rel_path).resolve()
|
|
552
|
-
target.parent.mkdir(parents=True, exist_ok=True)
|
|
553
|
-
target.write_text(content, encoding="utf-8")
|
|
554
|
-
created.append(_relative(target))
|
|
555
|
-
total_bytes += target.stat().st_size
|
|
556
|
-
|
|
557
|
-
return {
|
|
558
|
-
"path": _relative(root),
|
|
559
|
-
"framework": framework,
|
|
560
|
-
"template": template,
|
|
561
|
-
"created_files": created,
|
|
562
|
-
"file_count": len(created),
|
|
563
|
-
"bytes": total_bytes,
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
|
|
567
349
|
# Generous cap for a generated-project archive — the workspace itself caps
|
|
568
350
|
# individual files at MAX_FILE_BYTES, this only bounds pathological trees.
|
|
569
351
|
MAX_ZIP_TOTAL_BYTES = 50_000_000
|
|
570
352
|
|
|
571
353
|
|
|
572
|
-
def zip_workspace_dir(path: str, max_total_bytes: int = MAX_ZIP_TOTAL_BYTES) -> Tuple[bytes, str]:
|
|
573
|
-
"""Zip one workspace directory for download; confinement-safe by design.
|
|
574
|
-
|
|
575
|
-
Path resolution goes through the sandboxed ``_resolve_path`` (traversal
|
|
576
|
-
outside the agent workspace raises ``ToolError``), symlinks are skipped so
|
|
577
|
-
an in-workspace link can never leak files from elsewhere, and the archive
|
|
578
|
-
root is the directory name itself (``todo-app/index.html``).
|
|
579
|
-
"""
|
|
580
|
-
target = _resolve_path(path)
|
|
581
|
-
if target == tools.AGENT_ROOT:
|
|
582
|
-
raise ToolError("Cannot zip the entire workspace root — pick a project directory.")
|
|
583
|
-
if not target.exists() or not target.is_dir():
|
|
584
|
-
raise ToolError("Path is not a directory in the workspace.")
|
|
585
|
-
|
|
586
|
-
buffer = io.BytesIO()
|
|
587
|
-
total = 0
|
|
588
|
-
with zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED) as archive:
|
|
589
|
-
for child in sorted(target.rglob("*")):
|
|
590
|
-
if child.is_symlink() or not child.is_file():
|
|
591
|
-
continue
|
|
592
|
-
resolved = child.resolve()
|
|
593
|
-
if target not in resolved.parents:
|
|
594
|
-
continue # defense in depth — never archive escaped paths
|
|
595
|
-
total += child.stat().st_size
|
|
596
|
-
if total > max_total_bytes:
|
|
597
|
-
raise ToolError("Directory is too large to zip.")
|
|
598
|
-
archive.write(child, arcname=str(child.relative_to(target.parent)))
|
|
599
|
-
return buffer.getvalue(), f"{target.name}.zip"
|
|
@@ -8,7 +8,7 @@ from typing import Any, Dict, List, Optional
|
|
|
8
8
|
|
|
9
9
|
from latticeai.core.quiet import quiet
|
|
10
10
|
from latticeai.services.p_reinforce import BRAIN_DIR, STRUCTURE
|
|
11
|
-
from latticeai.tools import
|
|
11
|
+
from latticeai.tools import ToolError
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def _safe_brain_folder(folder: str) -> str:
|
|
@@ -48,36 +48,6 @@ def knowledge_scope_root(
|
|
|
48
48
|
)
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
def knowledge_save(
|
|
52
|
-
content: str,
|
|
53
|
-
folder: str = "00_Raw",
|
|
54
|
-
title: Optional[str] = None,
|
|
55
|
-
*,
|
|
56
|
-
workspace_id: Optional[str] = None,
|
|
57
|
-
user_email: Optional[str] = None,
|
|
58
|
-
) -> Dict[str, Any]:
|
|
59
|
-
folder = _safe_brain_folder(folder)
|
|
60
|
-
if not content:
|
|
61
|
-
raise ToolError("Knowledge content is required.")
|
|
62
|
-
if len(content.encode("utf-8")) > MAX_FILE_BYTES:
|
|
63
|
-
raise ToolError("Knowledge content is too large.")
|
|
64
|
-
|
|
65
|
-
root = knowledge_scope_root(workspace_id=workspace_id, user_email=user_email)
|
|
66
|
-
target_dir = root / folder
|
|
67
|
-
target_dir.mkdir(parents=True, exist_ok=True)
|
|
68
|
-
safe_title = title or content.strip().splitlines()[0][:60] or "note"
|
|
69
|
-
safe_title = "".join(ch if ch.isalnum() or ch in (" ", "-", "_") else "" for ch in safe_title).strip()
|
|
70
|
-
safe_title = "_".join(safe_title.split()) or "note"
|
|
71
|
-
filename = f"{safe_title}.md"
|
|
72
|
-
target = target_dir / filename
|
|
73
|
-
counter = 2
|
|
74
|
-
while target.exists():
|
|
75
|
-
target = target_dir / f"{safe_title}_{counter}.md"
|
|
76
|
-
counter += 1
|
|
77
|
-
target.write_text(content, encoding="utf-8")
|
|
78
|
-
return {"folder": folder, "filename": target.name, "path": str(target)}
|
|
79
|
-
|
|
80
|
-
|
|
81
51
|
def knowledge_search(
|
|
82
52
|
query: str,
|
|
83
53
|
max_results: int = 5,
|
|
@@ -133,27 +103,6 @@ def knowledge_tree(
|
|
|
133
103
|
return {"root": str(scope_root), "entries": entries}
|
|
134
104
|
|
|
135
105
|
|
|
136
|
-
def obsidian_save(
|
|
137
|
-
content: str,
|
|
138
|
-
folder: str = "00_Raw",
|
|
139
|
-
title: Optional[str] = None,
|
|
140
|
-
*,
|
|
141
|
-
workspace_id: Optional[str] = None,
|
|
142
|
-
user_email: Optional[str] = None,
|
|
143
|
-
) -> Dict[str, Any]:
|
|
144
|
-
root = knowledge_scope_root(workspace_id=workspace_id, user_email=user_email)
|
|
145
|
-
result = knowledge_save(
|
|
146
|
-
content,
|
|
147
|
-
folder,
|
|
148
|
-
title,
|
|
149
|
-
workspace_id=workspace_id,
|
|
150
|
-
user_email=user_email,
|
|
151
|
-
)
|
|
152
|
-
result["vault_root"] = str(root)
|
|
153
|
-
result["obsidian_uri_hint"] = f"obsidian://open?path={result['path']}"
|
|
154
|
-
return result
|
|
155
|
-
|
|
156
|
-
|
|
157
106
|
def obsidian_search(
|
|
158
107
|
query: str,
|
|
159
108
|
max_results: int = 5,
|
|
@@ -5,7 +5,6 @@ from __future__ import annotations
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Any, Dict
|
|
7
7
|
|
|
8
|
-
from latticeai.core.tool_registry import LOCAL_WRITE_BLOCKED_PREFIXES
|
|
9
8
|
from latticeai.tools import LOCAL_MAX_FILE_BYTES, ToolError
|
|
10
9
|
|
|
11
10
|
|
|
@@ -48,25 +47,6 @@ def local_read(path: str) -> Dict[str, Any]:
|
|
|
48
47
|
return {"path": str(target), "size": size, "content": content}
|
|
49
48
|
|
|
50
49
|
|
|
51
|
-
def local_write(path: str, content: str) -> Dict[str, Any]:
|
|
52
|
-
"""Write content to any path on the local filesystem (requires user approval via UI)."""
|
|
53
|
-
target = Path(path).expanduser().resolve()
|
|
54
|
-
normalized = str(target).replace("\\", "/")
|
|
55
|
-
for prefix in LOCAL_WRITE_BLOCKED_PREFIXES:
|
|
56
|
-
blocked = normalized == prefix.rstrip("/") or normalized.startswith(prefix)
|
|
57
|
-
if blocked:
|
|
58
|
-
raise ToolError("차단된 시스템 경로에는 쓸 수 없습니다.")
|
|
59
|
-
if len(content.encode("utf-8")) > LOCAL_MAX_FILE_BYTES:
|
|
60
|
-
raise ToolError("내용이 너무 큽니다.")
|
|
61
|
-
try:
|
|
62
|
-
target.parent.mkdir(parents=True, exist_ok=True)
|
|
63
|
-
target.write_text(content, encoding="utf-8")
|
|
64
|
-
except PermissionError as exc:
|
|
65
|
-
raise ToolError(f"쓰기 권한 없음: {exc}") from exc
|
|
66
|
-
return {"path": str(target), "bytes": target.stat().st_size}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
50
|
def desktop_bridge_status() -> Dict[str, Any]:
|
|
71
51
|
return {
|
|
72
52
|
"status": "requires_desktop_bridge",
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""The AI-Worker application profile (v11.6.0, plan §WP-I6).
|
|
2
|
+
|
|
3
|
+
``create_app`` builds the product server: 464 routes, the SPA, the whole
|
|
4
|
+
platform. v11.6.0 moves 439 of those into ``lattice-host`` and leaves Python as
|
|
5
|
+
what the system diagram has always drawn — the **AI Worker**: it infers with the
|
|
6
|
+
loaded MLX model, it runs tool handlers, it is the single writer of the Brain,
|
|
7
|
+
it stages proposals, it parses documents and it produces embeddings.
|
|
8
|
+
|
|
9
|
+
``create_worker_app`` is that process's entrypoint. It is deliberately *not* a
|
|
10
|
+
second assembly: it runs the same construction ``create_app`` does and then
|
|
11
|
+
applies the worker profile (:mod:`latticeai.runtime.build_phases.worker_profile`),
|
|
12
|
+
which mounts the three v11.6.0 seams and reduces the route table to the 25
|
|
13
|
+
KEEP_WORKER routes, the graph single-writer door and those seams. Two reasons
|
|
14
|
+
for that shape rather than a slimmer phase list:
|
|
15
|
+
|
|
16
|
+
* the routers the worker keeps are constructed by the same phases as everything
|
|
17
|
+
else — the document tools and the model lifecycle come out of
|
|
18
|
+
``phase_interaction``, the voice and index-drain surfaces out of
|
|
19
|
+
``phase_platform_features`` — so a "worker phase list" would have to split
|
|
20
|
+
four modules that WP-P1 is about to delete outright;
|
|
21
|
+
* the contract the Rust gateway needs *now* is the allowlist, and an allowlist
|
|
22
|
+
is a fact about the served surface, not about how it was assembled. Deleting
|
|
23
|
+
the complement (plan §Wave 3) leaves this function unchanged.
|
|
24
|
+
|
|
25
|
+
The host launches it as an ASGI factory::
|
|
26
|
+
|
|
27
|
+
uvicorn latticeai.worker_app:create_worker_app --factory --host 127.0.0.1 --port 8000
|
|
28
|
+
|
|
29
|
+
and gates the worker's readiness on ``GET /health``, whose ``access`` block —
|
|
30
|
+
``require_auth`` and ``externally_reachable`` — the supervisor reads to decide
|
|
31
|
+
whether its own native lanes may talk to this process. That route is on the
|
|
32
|
+
worker profile for exactly that reason.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
from __future__ import annotations
|
|
36
|
+
|
|
37
|
+
from typing import TYPE_CHECKING, Optional
|
|
38
|
+
|
|
39
|
+
from latticeai.app_factory import build_context
|
|
40
|
+
from latticeai.runtime.build_phases.worker_profile import phase_worker_routes
|
|
41
|
+
|
|
42
|
+
if TYPE_CHECKING: # imports for annotations only — keep module import light
|
|
43
|
+
from fastapi import FastAPI
|
|
44
|
+
|
|
45
|
+
from latticeai.core.config import Config
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def create_worker_app(config: "Optional[Config]" = None) -> "FastAPI":
|
|
49
|
+
"""Build the FastAPI application an AI-Worker process serves."""
|
|
50
|
+
ctx = build_context(config)
|
|
51
|
+
phase_worker_routes(ctx)
|
|
52
|
+
return ctx.app
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def main() -> None:
|
|
56
|
+
"""Serve the worker profile (``python -m latticeai.worker_app``).
|
|
57
|
+
|
|
58
|
+
The host normally spawns uvicorn against the factory itself; this exists so
|
|
59
|
+
a person debugging a worker can start one the same way, on the same address
|
|
60
|
+
the configuration names.
|
|
61
|
+
"""
|
|
62
|
+
import uvicorn
|
|
63
|
+
|
|
64
|
+
from latticeai.core.config import Config
|
|
65
|
+
|
|
66
|
+
config = Config.from_env()
|
|
67
|
+
uvicorn.run(
|
|
68
|
+
create_worker_app(config),
|
|
69
|
+
host=config.host,
|
|
70
|
+
port=config.port,
|
|
71
|
+
log_level="info",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
__all__ = ["create_worker_app", "main"]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ltcai",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.7.0",
|
|
4
4
|
"description": "Lattice AI — local-first Digital Brain that keeps your knowledge durable across any AI model.",
|
|
5
5
|
"homepage": "https://github.com/TaeSooPark-PTS/LatticeAI#readme",
|
|
6
6
|
"repository": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dev": "node scripts/run_python.mjs -m latticeai.cli.entrypoint --reload",
|
|
20
20
|
"build": "npm run build:assets && npm run build:python",
|
|
21
21
|
"frontend:dev": "vite --host 127.0.0.1",
|
|
22
|
-
"frontend:openapi": "node scripts/run_python.mjs scripts/export_openapi.py frontend/openapi.json && npx openapi-typescript frontend/openapi.json -o frontend/src/api/openapi.ts",
|
|
22
|
+
"frontend:openapi": "node scripts/run_python.mjs scripts/export_openapi.py .openapi-worker.json && node scripts/run_python.mjs scripts/compose_openapi.py --worker-spec .openapi-worker.json --output frontend/openapi.json && rm -f .openapi-worker.json && npx openapi-typescript frontend/openapi.json -o frontend/src/api/openapi.ts",
|
|
23
23
|
"frontend:openapi:check": "node scripts/check_openapi_drift.mjs",
|
|
24
24
|
"build:assets": "vite build && node scripts/build_frontend_assets.mjs",
|
|
25
25
|
"build:python": "node scripts/run_python.mjs -m build",
|
|
@@ -90,7 +90,6 @@
|
|
|
90
90
|
"bin/ltcai.js",
|
|
91
91
|
"LICENSE",
|
|
92
92
|
"requirements.txt",
|
|
93
|
-
"server.py",
|
|
94
93
|
"latticeai/**/*.py",
|
|
95
94
|
"lattice_brain/**/*.py",
|
|
96
95
|
"skills/",
|
package/requirements.txt
CHANGED
|
@@ -7,11 +7,6 @@ openai>=1.30,<3
|
|
|
7
7
|
python-docx>=1.1,<2
|
|
8
8
|
openpyxl>=3.1,<4
|
|
9
9
|
python-pptx>=0.6.23,<2
|
|
10
|
-
python-multipart>=0.0.9,<0.1
|
|
11
10
|
keyring>=24,<26
|
|
12
|
-
authlib>=1.3,<2
|
|
13
|
-
cryptography>=42,<49
|
|
14
11
|
pdfplumber>=0.11,<0.12
|
|
15
12
|
pypdfium2>=4.30,<6
|
|
16
|
-
watchdog>=4,<7
|
|
17
|
-
psycopg[binary]>=3.2,<4
|
package/scripts/agent_eval.py
CHANGED
|
@@ -1,44 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Agent-loop evaluation gate
|
|
2
|
+
"""Agent-loop evaluation gate — native since v11.6.0.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
The deterministic scenario suite used to live in
|
|
5
|
+
``latticeai.core.agent_eval`` and drive ``SingleAgentRuntime``. That loop is
|
|
6
|
+
``lattice-agent`` now. CI still invokes this path; we verify the native suite
|
|
7
|
+
is present rather than importing the deleted Python runtime.
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
Last Python generating tree: commit fc65e60.
|
|
10
|
+
Goldens: ``rust/fixtures/agent_loop/golden/`` (FROZEN).
|
|
9
11
|
"""
|
|
10
12
|
|
|
11
13
|
from __future__ import annotations
|
|
12
14
|
|
|
13
|
-
import json
|
|
14
|
-
import sys
|
|
15
15
|
from pathlib import Path
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
REPO = Path(__file__).resolve().parents[1]
|
|
18
|
+
REQUIRED = (
|
|
19
|
+
REPO / "rust" / "lattice-agent" / "tests" / "agent_loop.rs",
|
|
20
|
+
REPO / "rust" / "fixtures" / "agent_loop" / "golden",
|
|
21
|
+
)
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
def main() -> int:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"scenarios": report["scenarios"],
|
|
27
|
-
"passed": report["passed"],
|
|
28
|
-
"success_rate": report["success_rate"],
|
|
29
|
-
"parse_errors": report["parse_errors"],
|
|
30
|
-
"parse_recovered": report["parse_recovered"],
|
|
31
|
-
"recovery_rate": report["recovery_rate"],
|
|
32
|
-
}
|
|
33
|
-
if verbose:
|
|
34
|
-
print(json.dumps(report, ensure_ascii=False, indent=2))
|
|
35
|
-
failures = [r for r in report["results"] if not r["ok"]]
|
|
36
|
-
if failures:
|
|
37
|
-
print(f"agent-loop-eval: FAIL {headline}")
|
|
38
|
-
for result in failures:
|
|
39
|
-
print(f" ✗ {result['name']}: {'; '.join(result['failures'])}")
|
|
25
|
+
missing = [str(path.relative_to(REPO)) for path in REQUIRED if not path.exists()]
|
|
26
|
+
if missing:
|
|
27
|
+
print("agent-loop-eval: FAIL missing native artifacts:", missing)
|
|
40
28
|
return 1
|
|
41
|
-
print(
|
|
29
|
+
print("agent-loop-eval: native lattice-agent suite present (Python loop retired)")
|
|
42
30
|
return 0
|
|
43
31
|
|
|
44
32
|
|