ltcai 11.5.2 → 11.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -148
- package/bin/ltcai.js +234 -24
- package/docs/CHANGELOG.md +75 -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 +21 -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-CToZnOHz.js} +1 -1
- package/static/app/assets/{AdminConsole-cf4npybT.js → AdminConsole-D5kbrBu8.js} +1 -1
- package/static/app/assets/{Brain-3VCSHFcn.js → Brain-C6zCdv4S.js} +1 -1
- package/static/app/assets/{BrainHome-Qm8eaztx.js → BrainHome-D4n3EDUt.js} +1 -1
- package/static/app/assets/{BrainSignals-DS9BtKOW.js → BrainSignals-CzeZ-vQ9.js} +1 -1
- package/static/app/assets/{Capture-DiQ219jW.js → Capture-DPcyTczq.js} +1 -1
- package/static/app/assets/{Chronicle-BGvuAchH.js → Chronicle-D3Nx-oWS.js} +1 -1
- package/static/app/assets/{CommandPalette-Bqhm0Urn.js → CommandPalette-DPPvpp28.js} +1 -1
- package/static/app/assets/{Library-BV6NnF0a.js → Library-Co2qTu3I.js} +1 -1
- package/static/app/assets/{LivingBrain-GzenJchP.js → LivingBrain-Bsmzwy8_.js} +1 -1
- package/static/app/assets/{ProductFlow-DEP6-vML.js → ProductFlow-CBLdmesT.js} +1 -1
- package/static/app/assets/{ReviewCard-CNZ7XjWG.js → ReviewCard-CfR6DLs7.js} +1 -1
- package/static/app/assets/{System-CieofHQa.js → System-Ce-P2YL6.js} +1 -1
- package/static/app/assets/arrow-left-DD5jFGHV.js +1 -0
- package/static/app/assets/{bot-B_K1Tdmw.js → bot-C5-XIww2.js} +1 -1
- package/static/app/assets/{brain-DWyaV1L1.js → brain-CFRJUvdX.js} +1 -1
- package/static/app/assets/{button-aTn4s84A.js → button-DI1KcQP-.js} +1 -1
- package/static/app/assets/circle-check-CY20XMCh.js +1 -0
- package/static/app/assets/{circle-pause-xKgeGXkT.js → circle-pause-C8HHyood.js} +1 -1
- package/static/app/assets/{circle-play-DkT6tYPX.js → circle-play-Cufc235E.js} +1 -1
- package/static/app/assets/{cpu-85xYObUC.js → cpu-DW2_JVsv.js} +1 -1
- package/static/app/assets/{download-B5Fm7YXo.js → download-gbdKTBb8.js} +1 -1
- package/static/app/assets/{folder-open-kk2Xa52u.js → folder-open-C9ydyX33.js} +1 -1
- package/static/app/assets/{hard-drive-DkA3zBW_.js → hard-drive-BxNMzBM3.js} +1 -1
- package/static/app/assets/index-BovSWRmQ.css +2 -0
- package/static/app/assets/{index-BMPdTmlY.js → index-q9XyDY7A.js} +3 -3
- package/static/app/assets/{input-B0nRf2jO.js → input-GLD94Y_K.js} +1 -1
- package/static/app/assets/{link-2-Dwb4gnTc.js → link-2-B4Y0gz1S.js} +1 -1
- package/static/app/assets/{permissionCopy-CQDUBrOZ.js → permissionCopy-CxrV0fvU.js} +1 -1
- package/static/app/assets/{primitives-SNp0LRJz.js → primitives-2ANdAsu2.js} +1 -1
- package/static/app/assets/search-DTxtjQ07.js +1 -0
- package/static/app/assets/{share-2-BsrxFglO.js → share-2-DxArfiuI.js} +1 -1
- package/static/app/assets/{shield-alert-5BStfp2_.js → shield-alert-CgftuFFs.js} +1 -1
- package/static/app/assets/{textarea-Cg8IUA-k.js → textarea-BHVBAoCr.js} +1 -1
- package/static/app/assets/{useFocusTrap-CYKvE46M.js → useFocusTrap-Dzq2j_OG.js} +1 -1
- package/static/app/assets/{useMutation-CSn9t1op.js → useMutation-BcqfMLNq.js} +1 -1
- package/static/app/assets/{useQuery-CY2OI2uy.js → useQuery-DBzLKCOv.js} +1 -1
- package/static/app/assets/{utils-Ddol2RWD.js → utils-B-Aah1bO.js} +1 -1
- package/static/app/assets/{workspace-BqDwOz_p.js → workspace-B6fFhoko.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/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/search-BcHqkjoy.js +0 -1
|
@@ -1,394 +0,0 @@
|
|
|
1
|
-
"""The command screens — one Lattice-server read (or upload) rendered for a phone.
|
|
2
|
-
|
|
3
|
-
Everything reachable from the main menu that answers a question about the
|
|
4
|
-
running system rather than driving a conversation: server status, loaded
|
|
5
|
-
models, Knowledge Graph counts, a screenshot, chat history, the web-UI link,
|
|
6
|
-
the MCP tool list, and document upload into the graph.
|
|
7
|
-
|
|
8
|
-
Each screen follows the same shape: an optimistic chat action, one call through
|
|
9
|
-
:func:`~latticeai.integrations.telegram_bot.config._server_client`, and a plain
|
|
10
|
-
Korean rendering of exactly what came back — an unreachable server produces an
|
|
11
|
-
empty payload, never an invented one.
|
|
12
|
-
|
|
13
|
-
Stubbing note: these functions read ``_server_client``, ``_mac_ram_used_gb``,
|
|
14
|
-
``send_photo``, ``send_message`` and ``download_telegram_file`` as *this*
|
|
15
|
-
module's globals, so a test standing in for any of them patches this module.
|
|
16
|
-
``get_web_url``/``get_graph_url`` are read here but resolve
|
|
17
|
-
``PUBLIC_WEB_URL``/``get_lan_ip``/``SERVER_PORT`` inside ``helpers``.
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
import asyncio
|
|
21
|
-
import os
|
|
22
|
-
import tempfile
|
|
23
|
-
from pathlib import Path
|
|
24
|
-
|
|
25
|
-
from latticeai.core.logging_safety import safe_log_text
|
|
26
|
-
from latticeai.core.quiet import quiet
|
|
27
|
-
|
|
28
|
-
from .config import (
|
|
29
|
-
API_URL,
|
|
30
|
-
BASE_URL,
|
|
31
|
-
GRAPH_STATS_URL,
|
|
32
|
-
HISTORY_URL,
|
|
33
|
-
MCP_TOOLS_URL,
|
|
34
|
-
MODELS_URL,
|
|
35
|
-
STATUS_URL,
|
|
36
|
-
UPLOAD_DOC_URL,
|
|
37
|
-
_server_client,
|
|
38
|
-
logger,
|
|
39
|
-
)
|
|
40
|
-
from .helpers import (
|
|
41
|
-
download_telegram_file,
|
|
42
|
-
get_graph_url,
|
|
43
|
-
get_web_url,
|
|
44
|
-
send_chat_action,
|
|
45
|
-
send_message,
|
|
46
|
-
send_photo,
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
# ── Main menu ─────────────────────────────────────────────────────────────────
|
|
50
|
-
|
|
51
|
-
MAIN_MENU = {
|
|
52
|
-
"inline_keyboard": [
|
|
53
|
-
[
|
|
54
|
-
{"text": "📊 서버 상태", "callback_data": "cmd:status"},
|
|
55
|
-
{"text": "🧠 현재 모델", "callback_data": "cmd:model"},
|
|
56
|
-
],
|
|
57
|
-
[
|
|
58
|
-
{"text": "🕸 Knowledge Graph", "callback_data": "cmd:graph"},
|
|
59
|
-
{"text": "📸 스크린샷", "callback_data": "cmd:screenshot"},
|
|
60
|
-
],
|
|
61
|
-
[
|
|
62
|
-
{"text": "📜 최근 대화 5건", "callback_data": "cmd:history"},
|
|
63
|
-
{"text": "🗑 기록 정리", "callback_data": "cmd:clear"},
|
|
64
|
-
],
|
|
65
|
-
[
|
|
66
|
-
{"text": "🔗 웹 UI 열기", "callback_data": "cmd:web"},
|
|
67
|
-
{"text": "🔌 MCP 도구 목록", "callback_data": "cmd:mcp"},
|
|
68
|
-
],
|
|
69
|
-
[
|
|
70
|
-
{"text": "🗂 변경 제안 검토", "callback_data": "cmd:review"},
|
|
71
|
-
],
|
|
72
|
-
]
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async def show_menu(client, chat_id):
|
|
76
|
-
await send_message(client, chat_id, "📱 Lattice AI 원격 제어 메뉴입니다.", reply_markup=MAIN_MENU)
|
|
77
|
-
|
|
78
|
-
# ── Server status ─────────────────────────────────────────────────────────────
|
|
79
|
-
|
|
80
|
-
async def _mac_ram_used_gb() -> str:
|
|
81
|
-
try:
|
|
82
|
-
vm_proc = await asyncio.create_subprocess_exec(
|
|
83
|
-
"vm_stat", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL
|
|
84
|
-
)
|
|
85
|
-
vm_out, _ = await vm_proc.communicate()
|
|
86
|
-
lines = vm_out.decode().splitlines()
|
|
87
|
-
|
|
88
|
-
# Parse page size from header line: "Mach Virtual Memory Statistics: (page size of 16384 bytes)"
|
|
89
|
-
page_size = 4096
|
|
90
|
-
if lines:
|
|
91
|
-
import re
|
|
92
|
-
m = re.search(r"page size of (\d+) bytes", lines[0])
|
|
93
|
-
if m:
|
|
94
|
-
page_size = int(m.group(1))
|
|
95
|
-
|
|
96
|
-
stats = {}
|
|
97
|
-
for line in lines[1:]:
|
|
98
|
-
if ":" in line:
|
|
99
|
-
k, _, v = line.partition(":")
|
|
100
|
-
try:
|
|
101
|
-
stats[k.strip()] = int(v.strip().rstrip(".")) * page_size
|
|
102
|
-
except ValueError:
|
|
103
|
-
quiet()
|
|
104
|
-
|
|
105
|
-
used = stats.get("Pages active", 0) + stats.get("Pages wired down", 0)
|
|
106
|
-
|
|
107
|
-
mem_proc = await asyncio.create_subprocess_exec(
|
|
108
|
-
"sysctl", "-n", "hw.memsize", stdout=asyncio.subprocess.PIPE
|
|
109
|
-
)
|
|
110
|
-
mem_out, _ = await mem_proc.communicate()
|
|
111
|
-
total = int(mem_out.strip())
|
|
112
|
-
return f"{used/1e9:.1f} GB / {total/1e9:.0f} GB"
|
|
113
|
-
except Exception:
|
|
114
|
-
return "N/A"
|
|
115
|
-
|
|
116
|
-
async def show_status(client, chat_id):
|
|
117
|
-
await send_chat_action(client, chat_id, "typing")
|
|
118
|
-
try:
|
|
119
|
-
async with _server_client() as lc:
|
|
120
|
-
res = await lc.get(STATUS_URL, timeout=5.0)
|
|
121
|
-
data = res.json() if res.status_code == 200 else {}
|
|
122
|
-
except Exception:
|
|
123
|
-
data = {}
|
|
124
|
-
|
|
125
|
-
ram = await _mac_ram_used_gb()
|
|
126
|
-
model = data.get("loaded_model") or "없음"
|
|
127
|
-
mode = data.get("mode") or "unknown"
|
|
128
|
-
state = "🟢 온라인" if data.get("status") == "online" else "🔴 오프라인"
|
|
129
|
-
|
|
130
|
-
text = (
|
|
131
|
-
f"📊 Lattice AI 서버 상태\n"
|
|
132
|
-
f"상태: {state}\n"
|
|
133
|
-
f"모드: {mode}\n"
|
|
134
|
-
f"모델: {model}\n"
|
|
135
|
-
f"RAM: {ram}"
|
|
136
|
-
)
|
|
137
|
-
await send_message(client, chat_id, text)
|
|
138
|
-
|
|
139
|
-
# ── Model info & unload ───────────────────────────────────────────────────────
|
|
140
|
-
|
|
141
|
-
async def show_model_info(client, chat_id):
|
|
142
|
-
await send_chat_action(client, chat_id, "typing")
|
|
143
|
-
try:
|
|
144
|
-
async with _server_client() as lc:
|
|
145
|
-
res = await lc.get(MODELS_URL, timeout=5.0)
|
|
146
|
-
data = res.json() if res.status_code == 200 else {}
|
|
147
|
-
except Exception:
|
|
148
|
-
data = {}
|
|
149
|
-
|
|
150
|
-
current = data.get("current") or "없음"
|
|
151
|
-
loaded = data.get("loaded") or []
|
|
152
|
-
loaded_str = "\n".join(f" - {m}" for m in loaded) if loaded else " 없음"
|
|
153
|
-
text = f"🧠 현재 모델: {current}\n\n로드된 모델:\n{loaded_str}"
|
|
154
|
-
|
|
155
|
-
markup = None
|
|
156
|
-
if loaded:
|
|
157
|
-
markup = {
|
|
158
|
-
"inline_keyboard": [
|
|
159
|
-
[{"text": f"🗑 {m} 언로드", "callback_data": f"model:unload:{m}"}]
|
|
160
|
-
for m in loaded
|
|
161
|
-
] + [[{"text": "↩ 메뉴로", "callback_data": "cmd:menu"}]]
|
|
162
|
-
}
|
|
163
|
-
await send_message(client, chat_id, text, reply_markup=markup)
|
|
164
|
-
|
|
165
|
-
def _unload_all_report(results: list[tuple[str, int]]) -> str:
|
|
166
|
-
"""Report an unload-all run from the statuses the server actually returned."""
|
|
167
|
-
failed = [(mid, code) for mid, code in results if code != 200]
|
|
168
|
-
if not failed:
|
|
169
|
-
return "✅ 모든 모델 언로드 완료. RAM이 해제되었습니다."
|
|
170
|
-
detail = ", ".join(f"{mid} ({code})" for mid, code in failed)
|
|
171
|
-
return (
|
|
172
|
-
f"일부 모델 언로드 실패: {detail}\n"
|
|
173
|
-
f"성공 {len(results) - len(failed)}개 / 실패 {len(failed)}개"
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
async def do_unload_model(client, chat_id, model_id: str = ""):
|
|
177
|
-
await send_chat_action(client, chat_id, "typing")
|
|
178
|
-
try:
|
|
179
|
-
results: list[tuple[str, int]] | None = None
|
|
180
|
-
async with _server_client() as lc:
|
|
181
|
-
if model_id:
|
|
182
|
-
res = await lc.delete(f"{BASE_URL}/models/unload/{model_id}", timeout=15.0)
|
|
183
|
-
else:
|
|
184
|
-
# Unload all: keep every delete's real status. Discarding them
|
|
185
|
-
# for a synthesized 200 reported "모든 모델 언로드 완료" even
|
|
186
|
-
# when a model refused to unload.
|
|
187
|
-
res = await lc.get(MODELS_URL, timeout=5.0)
|
|
188
|
-
if res.status_code == 200:
|
|
189
|
-
results = []
|
|
190
|
-
for mid in res.json().get("loaded") or []:
|
|
191
|
-
deleted = await lc.delete(f"{BASE_URL}/models/unload/{mid}", timeout=15.0)
|
|
192
|
-
results.append((mid, deleted.status_code))
|
|
193
|
-
if results is not None:
|
|
194
|
-
await send_message(client, chat_id, _unload_all_report(results))
|
|
195
|
-
elif res.status_code == 200:
|
|
196
|
-
await send_message(client, chat_id, f"✅ {model_id} 언로드 완료. RAM이 해제되었습니다.")
|
|
197
|
-
else:
|
|
198
|
-
await send_message(client, chat_id, f"언로드 실패 ({res.status_code})")
|
|
199
|
-
except Exception as e:
|
|
200
|
-
await send_message(client, chat_id, f"언로드 오류: {e}")
|
|
201
|
-
|
|
202
|
-
# ── Knowledge Graph stats ─────────────────────────────────────────────────────
|
|
203
|
-
|
|
204
|
-
async def show_graph_stats(client, chat_id):
|
|
205
|
-
await send_chat_action(client, chat_id, "typing")
|
|
206
|
-
try:
|
|
207
|
-
async with _server_client() as lc:
|
|
208
|
-
res = await lc.get(GRAPH_STATS_URL, timeout=5.0)
|
|
209
|
-
data = res.json() if res.status_code == 200 else {}
|
|
210
|
-
except Exception:
|
|
211
|
-
data = {}
|
|
212
|
-
|
|
213
|
-
nodes = data.get("nodes") or {}
|
|
214
|
-
edges = data.get("edges") or {}
|
|
215
|
-
total_nodes = sum(nodes.values())
|
|
216
|
-
total_edges = sum(edges.values())
|
|
217
|
-
|
|
218
|
-
node_lines = "\n".join(f" {t}: {c}" for t, c in sorted(nodes.items(), key=lambda x: -x[1])) or " 없음"
|
|
219
|
-
edge_lines = "\n".join(f" {t}: {c}" for t, c in sorted(edges.items(), key=lambda x: -x[1])[:8]) or " 없음"
|
|
220
|
-
|
|
221
|
-
text = (
|
|
222
|
-
f"🕸 Knowledge Graph 통계\n\n"
|
|
223
|
-
f"노드 총 {total_nodes}개:\n{node_lines}\n\n"
|
|
224
|
-
f"엣지 총 {total_edges}개:\n{edge_lines}\n\n"
|
|
225
|
-
f"그래프 보기: {get_graph_url()}"
|
|
226
|
-
)
|
|
227
|
-
markup = {
|
|
228
|
-
"inline_keyboard": [[
|
|
229
|
-
{"text": "🔗 그래프 열기", "url": get_graph_url()},
|
|
230
|
-
{"text": "↩ 메뉴로", "callback_data": "cmd:menu"},
|
|
231
|
-
]]
|
|
232
|
-
}
|
|
233
|
-
await send_message(client, chat_id, text, reply_markup=markup)
|
|
234
|
-
|
|
235
|
-
# ── Screenshot ────────────────────────────────────────────────────────────────
|
|
236
|
-
|
|
237
|
-
async def take_screenshot(client, chat_id):
|
|
238
|
-
await send_chat_action(client, chat_id, "upload_photo")
|
|
239
|
-
# mkstemp, not mktemp: mktemp only predicts an unused name, leaving a
|
|
240
|
-
# window in which anything can create that path first. mkstemp creates
|
|
241
|
-
# the file atomically with 0600.
|
|
242
|
-
_fd, _name = tempfile.mkstemp(suffix=".jpg")
|
|
243
|
-
os.close(_fd)
|
|
244
|
-
tmp = Path(_name)
|
|
245
|
-
try:
|
|
246
|
-
proc = await asyncio.create_subprocess_exec(
|
|
247
|
-
"screencapture", "-x", str(tmp),
|
|
248
|
-
stdout=asyncio.subprocess.DEVNULL,
|
|
249
|
-
stderr=asyncio.subprocess.DEVNULL,
|
|
250
|
-
)
|
|
251
|
-
await asyncio.wait_for(proc.communicate(), timeout=10.0)
|
|
252
|
-
if tmp.exists() and tmp.stat().st_size > 0:
|
|
253
|
-
await send_photo(client, chat_id, tmp, caption="현재 화면입니다.")
|
|
254
|
-
else:
|
|
255
|
-
await send_message(client, chat_id, "스크린샷 파일이 생성되지 않았습니다. screencapture가 설치되어 있는지 확인하세요.")
|
|
256
|
-
except asyncio.TimeoutError:
|
|
257
|
-
await send_message(client, chat_id, "스크린샷 시간 초과")
|
|
258
|
-
except FileNotFoundError:
|
|
259
|
-
await send_message(client, chat_id, "screencapture 명령이 없습니다. macOS에서만 동작합니다.")
|
|
260
|
-
except Exception as e:
|
|
261
|
-
await send_message(client, chat_id, f"스크린샷 오류: {e}")
|
|
262
|
-
finally:
|
|
263
|
-
try:
|
|
264
|
-
tmp.unlink(missing_ok=True)
|
|
265
|
-
except Exception:
|
|
266
|
-
quiet()
|
|
267
|
-
|
|
268
|
-
# ── History ───────────────────────────────────────────────────────────────────
|
|
269
|
-
|
|
270
|
-
async def show_history_summary(client, chat_id, n: int = 5):
|
|
271
|
-
await send_chat_action(client, chat_id, "typing")
|
|
272
|
-
try:
|
|
273
|
-
async with _server_client() as lc:
|
|
274
|
-
res = await lc.get(HISTORY_URL, timeout=10.0)
|
|
275
|
-
items = res.json() if res.status_code == 200 else []
|
|
276
|
-
except Exception:
|
|
277
|
-
items = []
|
|
278
|
-
|
|
279
|
-
if not items:
|
|
280
|
-
await send_message(client, chat_id, "저장된 대화 기록이 없습니다.")
|
|
281
|
-
return
|
|
282
|
-
|
|
283
|
-
recent = [i for i in items if i.get("role") == "user"][-n:]
|
|
284
|
-
lines = [f"📜 최근 사용자 메시지 {len(recent)}건\n"]
|
|
285
|
-
for item in recent:
|
|
286
|
-
ts = str(item.get("timestamp", ""))[:16]
|
|
287
|
-
src = item.get("source", "web")
|
|
288
|
-
content = str(item.get("content", ""))[:120].replace("\n", " ")
|
|
289
|
-
lines.append(f"[{ts}] ({src}) {content}")
|
|
290
|
-
await send_message(client, chat_id, "\n".join(lines))
|
|
291
|
-
|
|
292
|
-
async def clear_server_history(client, chat_id, keep_last=0):
|
|
293
|
-
try:
|
|
294
|
-
async with _server_client() as lc:
|
|
295
|
-
res = await lc.delete(HISTORY_URL, params={"keep_last": keep_last}, timeout=10.0)
|
|
296
|
-
data = res.json() if res.headers.get("content-type", "").startswith("application/json") else {}
|
|
297
|
-
if res.status_code == 200:
|
|
298
|
-
await send_message(client, chat_id, f"대화 기록을 정리했습니다. 삭제 {data.get('removed', 0)}개, 유지 {data.get('kept', 0)}개.")
|
|
299
|
-
else:
|
|
300
|
-
await send_message(client, chat_id, f"대화 기록 정리 실패: {res.status_code}")
|
|
301
|
-
except Exception as e:
|
|
302
|
-
await send_message(client, chat_id, f"대화 기록 정리 오류: {e}")
|
|
303
|
-
|
|
304
|
-
# ── Web UI link ───────────────────────────────────────────────────────────────
|
|
305
|
-
|
|
306
|
-
async def send_web_link(client, chat_id):
|
|
307
|
-
web_url = get_web_url()
|
|
308
|
-
text = (
|
|
309
|
-
"웹 UI 링크입니다.\n"
|
|
310
|
-
f"{web_url}\n\n"
|
|
311
|
-
"핸드폰이 Mac과 같은 Wi-Fi에 있어야 바로 열립니다. "
|
|
312
|
-
"외부망에서 쓰려면 LATTICEAI_PUBLIC_URL에 터널 주소를 설정하세요."
|
|
313
|
-
)
|
|
314
|
-
payload = {
|
|
315
|
-
"chat_id": chat_id,
|
|
316
|
-
"text": text,
|
|
317
|
-
"reply_markup": {
|
|
318
|
-
"inline_keyboard": [[
|
|
319
|
-
{"text": "Lattice AI Web 열기", "url": web_url},
|
|
320
|
-
{"text": "Knowledge Graph", "url": get_graph_url()},
|
|
321
|
-
]]
|
|
322
|
-
},
|
|
323
|
-
}
|
|
324
|
-
try:
|
|
325
|
-
# The Telegram client, like every other helper here. Sending this on the
|
|
326
|
-
# server client shipped the local bearer capability to api.telegram.org
|
|
327
|
-
# and failed outright whenever that token was unset.
|
|
328
|
-
await client.post(f"{API_URL}/sendMessage", json=payload)
|
|
329
|
-
except Exception as e:
|
|
330
|
-
logger.error("웹 링크 전송 실패: %s", safe_log_text(e))
|
|
331
|
-
|
|
332
|
-
# ── MCP tools ─────────────────────────────────────────────────────────────────
|
|
333
|
-
|
|
334
|
-
async def send_mcp_tools(client, chat_id):
|
|
335
|
-
try:
|
|
336
|
-
async with _server_client() as lc:
|
|
337
|
-
res = await lc.get(MCP_TOOLS_URL, timeout=10.0)
|
|
338
|
-
if res.status_code != 200:
|
|
339
|
-
await send_message(client, chat_id, f"MCP 도구 목록을 가져오지 못했습니다: {res.status_code}")
|
|
340
|
-
return
|
|
341
|
-
data = res.json()
|
|
342
|
-
names = [tool["name"] for tool in data.get("tools", [])]
|
|
343
|
-
await send_message(client, chat_id, "사용 가능한 MCP 도구:\n" + ("\n".join(f"- {n}" for n in names) or "없음"))
|
|
344
|
-
except Exception as e:
|
|
345
|
-
await send_message(client, chat_id, f"MCP 도구 조회 실패: {e}")
|
|
346
|
-
|
|
347
|
-
# ── Document upload → knowledge graph ────────────────────────────────────────
|
|
348
|
-
|
|
349
|
-
async def process_document_file(client, chat_id, file_id: str, filename: str, caption: str = ""):
|
|
350
|
-
await send_chat_action(client, chat_id, "upload_document")
|
|
351
|
-
raw = await download_telegram_file(client, file_id)
|
|
352
|
-
if not raw:
|
|
353
|
-
await send_message(client, chat_id, "파일 다운로드 실패")
|
|
354
|
-
return
|
|
355
|
-
|
|
356
|
-
suffix = Path(filename).suffix.lower()
|
|
357
|
-
allowed = {".pdf", ".docx", ".xlsx", ".pptx", ".txt", ".md", ".csv"}
|
|
358
|
-
if suffix not in allowed:
|
|
359
|
-
await send_message(client, chat_id,
|
|
360
|
-
f"지원하지 않는 파일 형식입니다({suffix}). "
|
|
361
|
-
f"지원 형식: {', '.join(sorted(allowed))}")
|
|
362
|
-
return
|
|
363
|
-
|
|
364
|
-
_fd, _name = tempfile.mkstemp(suffix=suffix) # see take_screenshot
|
|
365
|
-
os.close(_fd)
|
|
366
|
-
tmp = Path(_name)
|
|
367
|
-
try:
|
|
368
|
-
tmp.write_bytes(raw)
|
|
369
|
-
async with _server_client() as lc:
|
|
370
|
-
res = await lc.post(
|
|
371
|
-
UPLOAD_DOC_URL,
|
|
372
|
-
files={"file": (filename, raw)},
|
|
373
|
-
timeout=60.0,
|
|
374
|
-
)
|
|
375
|
-
if res.status_code == 200:
|
|
376
|
-
data = res.json()
|
|
377
|
-
chars = data.get("chars") or len(raw)
|
|
378
|
-
preview = str(data.get("preview") or "")[:300]
|
|
379
|
-
kg = data.get("knowledge_graph") or {}
|
|
380
|
-
node_id = kg.get("node_id", "")
|
|
381
|
-
text = (
|
|
382
|
-
f"✅ {filename} 수집 완료\n"
|
|
383
|
-
f"크기: {len(raw) // 1024} KB | 문자: {chars}\n"
|
|
384
|
-
f"노드: {node_id}\n"
|
|
385
|
-
f"\n미리보기:\n{preview}"
|
|
386
|
-
)
|
|
387
|
-
await send_message(client, chat_id, text)
|
|
388
|
-
else:
|
|
389
|
-
err = res.json().get("detail") if res.headers.get("content-type", "").startswith("application/json") else res.text
|
|
390
|
-
await send_message(client, chat_id, f"업로드 실패 ({res.status_code}): {err}")
|
|
391
|
-
except Exception as e:
|
|
392
|
-
await send_message(client, chat_id, f"문서 처리 오류: {e}")
|
|
393
|
-
finally:
|
|
394
|
-
tmp.unlink(missing_ok=True)
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
"""Audit log wiring extracted from app_factory _build for smaller closure.
|
|
2
|
-
|
|
3
|
-
Returns dict of get_audit_log / append_audit_event for legacy namespace.
|
|
4
|
-
"""
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
import json
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
from typing import Any, Callable, Dict, List, Optional
|
|
10
|
-
|
|
11
|
-
from latticeai.core import timezones
|
|
12
|
-
from latticeai.core.quiet import quiet
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def build_audit_runtime(
|
|
16
|
-
*,
|
|
17
|
-
audit_file: Path,
|
|
18
|
-
logging: Any,
|
|
19
|
-
redact_fn: Optional[Callable[[str], str]] = None,
|
|
20
|
-
) -> Dict[str, Any]:
|
|
21
|
-
_audit_lock: Any = __import__("threading").Lock()
|
|
22
|
-
audit_jsonl = audit_file.with_suffix(audit_file.suffix + ".jsonl")
|
|
23
|
-
|
|
24
|
-
def _read_audit() -> List[Dict[str, Any]]:
|
|
25
|
-
events: List[Dict[str, Any]] = []
|
|
26
|
-
if not audit_file.exists():
|
|
27
|
-
data = []
|
|
28
|
-
else:
|
|
29
|
-
try:
|
|
30
|
-
data = json.loads(audit_file.read_text(encoding="utf-8"))
|
|
31
|
-
except Exception:
|
|
32
|
-
data = []
|
|
33
|
-
if isinstance(data, list):
|
|
34
|
-
events.extend(item for item in data if isinstance(item, dict))
|
|
35
|
-
if audit_jsonl.exists():
|
|
36
|
-
try:
|
|
37
|
-
for line in audit_jsonl.read_text(encoding="utf-8").splitlines():
|
|
38
|
-
if not line.strip():
|
|
39
|
-
continue
|
|
40
|
-
item = json.loads(line)
|
|
41
|
-
if isinstance(item, dict):
|
|
42
|
-
events.append(item)
|
|
43
|
-
except Exception:
|
|
44
|
-
quiet()
|
|
45
|
-
return events[-5000:]
|
|
46
|
-
|
|
47
|
-
def _append(event_type: str, **payload: Any) -> None:
|
|
48
|
-
entry = {"event_type": event_type, "timestamp": timezones.now_iso()}
|
|
49
|
-
if payload:
|
|
50
|
-
entry.update(payload)
|
|
51
|
-
if redact_fn:
|
|
52
|
-
try:
|
|
53
|
-
for k in ("content", "content_preview", "message"):
|
|
54
|
-
if k in entry and isinstance(entry[k], str):
|
|
55
|
-
entry[k] = redact_fn(entry[k])
|
|
56
|
-
except Exception:
|
|
57
|
-
quiet()
|
|
58
|
-
with _audit_lock:
|
|
59
|
-
audit_file.parent.mkdir(parents=True, exist_ok=True)
|
|
60
|
-
with audit_jsonl.open("a", encoding="utf-8") as fh:
|
|
61
|
-
fh.write(json.dumps(entry, ensure_ascii=False, default=str))
|
|
62
|
-
fh.write("\n")
|
|
63
|
-
|
|
64
|
-
def get_audit_log() -> List[Dict[str, Any]]:
|
|
65
|
-
return _read_audit()
|
|
66
|
-
|
|
67
|
-
def append_audit_event(event_type: str, **payload: Any) -> None:
|
|
68
|
-
try:
|
|
69
|
-
_append(event_type, **payload)
|
|
70
|
-
except Exception as e:
|
|
71
|
-
logging.warning("audit append failed: %s", e)
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
"get_audit_log": get_audit_log,
|
|
75
|
-
"append_audit_event": append_audit_event,
|
|
76
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
"""Automation runtime assembly for review, trigger, agent, and run execution.
|
|
2
|
-
|
|
3
|
-
This module keeps the automation object graph behind one construction seam.
|
|
4
|
-
Router registration remains in ``app_factory`` so route order stays unchanged.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from typing import Any, Callable, Dict, Optional
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def build_automation_runtime(
|
|
13
|
-
*,
|
|
14
|
-
store: Any,
|
|
15
|
-
platform: Any,
|
|
16
|
-
data_dir: Any,
|
|
17
|
-
workspace_graph: Callable[..., Any],
|
|
18
|
-
append_audit_event: Callable[..., Any],
|
|
19
|
-
hooks: Any,
|
|
20
|
-
tz_name: Optional[str] = None,
|
|
21
|
-
) -> Dict[str, Any]:
|
|
22
|
-
"""Construct automation services and attach the run executor boundary."""
|
|
23
|
-
|
|
24
|
-
from lattice_brain.runtime.agent_runtime import AgentRuntime
|
|
25
|
-
from latticeai.services.review_queue import ReviewQueueService
|
|
26
|
-
from latticeai.services.run_executor import RunExecutor
|
|
27
|
-
from latticeai.services.triggers import TriggerService
|
|
28
|
-
|
|
29
|
-
review_queue = ReviewQueueService(store=store)
|
|
30
|
-
|
|
31
|
-
def _run_triggered_workflow(workflow_id: str, inputs: Dict[str, Any]) -> Dict[str, Any]:
|
|
32
|
-
trigger = (inputs or {}).get("__trigger__") or {}
|
|
33
|
-
return platform.run_workflow_by_id(
|
|
34
|
-
workflow_id,
|
|
35
|
-
trigger.get("user_email"),
|
|
36
|
-
trigger.get("workspace_id"),
|
|
37
|
-
with_agent=True,
|
|
38
|
-
inputs=inputs,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
trigger_service = TriggerService(
|
|
42
|
-
store=store,
|
|
43
|
-
run_workflow=_run_triggered_workflow,
|
|
44
|
-
data_dir=data_dir,
|
|
45
|
-
review_sink=review_queue,
|
|
46
|
-
tz_name=tz_name,
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
def _memory_ingest(**kwargs):
|
|
50
|
-
try:
|
|
51
|
-
# Delegate to store's upsert (enriches memories + KG automatically via internal graph.ingest_event)
|
|
52
|
-
return store.upsert_memory(**kwargs)
|
|
53
|
-
except Exception:
|
|
54
|
-
return None
|
|
55
|
-
|
|
56
|
-
agent_runtime = AgentRuntime(
|
|
57
|
-
store=store,
|
|
58
|
-
orchestrator_factory=platform.build_orchestrator,
|
|
59
|
-
workspace_graph=workspace_graph,
|
|
60
|
-
append_audit_event=append_audit_event,
|
|
61
|
-
hooks=hooks,
|
|
62
|
-
memory_ingest=_memory_ingest,
|
|
63
|
-
review_sink=review_queue,
|
|
64
|
-
)
|
|
65
|
-
run_executor = RunExecutor(
|
|
66
|
-
store=store,
|
|
67
|
-
agent_runtime=agent_runtime,
|
|
68
|
-
build_workflow_runners=platform.build_workflow_runners,
|
|
69
|
-
workspace_graph=workspace_graph,
|
|
70
|
-
append_audit_event=append_audit_event,
|
|
71
|
-
hooks=hooks,
|
|
72
|
-
review_sink=review_queue,
|
|
73
|
-
)
|
|
74
|
-
agent_runtime.attach_executor(run_executor)
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
"REVIEW_QUEUE": review_queue,
|
|
78
|
-
"TRIGGER_SERVICE": trigger_service,
|
|
79
|
-
"AGENT_RUNTIME": agent_runtime,
|
|
80
|
-
"RUN_EXECUTOR": run_executor,
|
|
81
|
-
}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
"""Chat and interaction wiring seam for ``latticeai.app_factory``."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from typing import Any, Optional
|
|
6
|
-
|
|
7
|
-
from latticeai.runtime.permission_mode_wiring import (
|
|
8
|
-
bind_dispatch_permission_mode,
|
|
9
|
-
resolve_active_permission_mode,
|
|
10
|
-
)
|
|
11
|
-
from latticeai.services.router_context import (
|
|
12
|
-
InteractionRouterContext,
|
|
13
|
-
ToolRouterContext,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def build_chat_agent_runtime_from_context(
|
|
18
|
-
*,
|
|
19
|
-
build_agent_runtime: Any,
|
|
20
|
-
model_router: Any,
|
|
21
|
-
execute_tool: Any,
|
|
22
|
-
recent_chat_context: Any,
|
|
23
|
-
clear_history: Any,
|
|
24
|
-
knowledge_save: Any,
|
|
25
|
-
audit: Any,
|
|
26
|
-
hooks: Any,
|
|
27
|
-
brain_memory: Any,
|
|
28
|
-
self_model_summary: Any = None,
|
|
29
|
-
) -> Any:
|
|
30
|
-
# Ensure dispatch + agent share the same autonomy dial before the runtime
|
|
31
|
-
# is constructed (process-wide service; data_dir refined later at router mount).
|
|
32
|
-
bind_dispatch_permission_mode()
|
|
33
|
-
return build_agent_runtime(
|
|
34
|
-
model_router=model_router,
|
|
35
|
-
execute_tool=execute_tool,
|
|
36
|
-
recent_chat_context=recent_chat_context,
|
|
37
|
-
clear_history=clear_history,
|
|
38
|
-
knowledge_save=knowledge_save,
|
|
39
|
-
audit=audit,
|
|
40
|
-
hooks=hooks,
|
|
41
|
-
brain_memory=brain_memory,
|
|
42
|
-
permission_mode=resolve_active_permission_mode,
|
|
43
|
-
# v11.2.0: a scoped resolver, not a snapshot — the profile a run sees is
|
|
44
|
-
# the one the Brain holds when the run starts, per user and workspace.
|
|
45
|
-
self_model_summary=self_model_summary,
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def build_interaction_contexts(
|
|
50
|
-
*,
|
|
51
|
-
config: Any,
|
|
52
|
-
ingestion_pipeline: Any,
|
|
53
|
-
data_dir: Any,
|
|
54
|
-
static_dir: Any,
|
|
55
|
-
model_router: Any,
|
|
56
|
-
require_user: Any,
|
|
57
|
-
require_admin: Any,
|
|
58
|
-
get_current_user: Any,
|
|
59
|
-
clear_history: Any,
|
|
60
|
-
append_audit_event: Any,
|
|
61
|
-
enforce_rate_limit: Any,
|
|
62
|
-
bytes_match_extension: Any,
|
|
63
|
-
classify_sensitive_message: Any,
|
|
64
|
-
save_to_history: Any,
|
|
65
|
-
enable_graph: bool,
|
|
66
|
-
knowledge_graph: Any,
|
|
67
|
-
require_graph: Any,
|
|
68
|
-
local_kg_watcher: Any,
|
|
69
|
-
load_mcp_installs: Any,
|
|
70
|
-
recommend_mcps: Any,
|
|
71
|
-
install_mcp: Any,
|
|
72
|
-
mcp_public_item: Any,
|
|
73
|
-
hooks: Any,
|
|
74
|
-
workspace_service: Any,
|
|
75
|
-
chat_context: Any,
|
|
76
|
-
search_service: Any,
|
|
77
|
-
allowed_workspaces_for: Any,
|
|
78
|
-
embedding_info: Any,
|
|
79
|
-
agent_registry: Any,
|
|
80
|
-
memory_service: Any,
|
|
81
|
-
platform: Any,
|
|
82
|
-
active_model_getter: Any = None,
|
|
83
|
-
brain_intelligence: Any = None,
|
|
84
|
-
) -> tuple[ToolRouterContext, InteractionRouterContext]:
|
|
85
|
-
tool_router_context = ToolRouterContext(
|
|
86
|
-
config=config,
|
|
87
|
-
ingestion_pipeline=ingestion_pipeline,
|
|
88
|
-
data_dir=data_dir,
|
|
89
|
-
static_dir=static_dir,
|
|
90
|
-
model_router=model_router,
|
|
91
|
-
require_user=require_user,
|
|
92
|
-
require_admin=require_admin,
|
|
93
|
-
get_current_user=get_current_user,
|
|
94
|
-
clear_history=clear_history,
|
|
95
|
-
append_audit_event=append_audit_event,
|
|
96
|
-
enforce_rate_limit=enforce_rate_limit,
|
|
97
|
-
bytes_match_extension=bytes_match_extension,
|
|
98
|
-
classify_sensitive_message=classify_sensitive_message,
|
|
99
|
-
save_to_history=save_to_history,
|
|
100
|
-
enable_graph=enable_graph,
|
|
101
|
-
knowledge_graph=knowledge_graph,
|
|
102
|
-
require_graph=require_graph,
|
|
103
|
-
local_kg_watcher=local_kg_watcher,
|
|
104
|
-
load_mcp_installs=load_mcp_installs,
|
|
105
|
-
recommend_mcps=recommend_mcps,
|
|
106
|
-
install_mcp=install_mcp,
|
|
107
|
-
mcp_public_item=mcp_public_item,
|
|
108
|
-
hooks=hooks,
|
|
109
|
-
workspace_service=workspace_service,
|
|
110
|
-
allowed_workspaces_for=allowed_workspaces_for,
|
|
111
|
-
)
|
|
112
|
-
interaction_router_context = InteractionRouterContext(
|
|
113
|
-
chat_context=chat_context,
|
|
114
|
-
search_service=search_service,
|
|
115
|
-
allowed_workspaces_for=allowed_workspaces_for,
|
|
116
|
-
require_user=require_user,
|
|
117
|
-
embedding_info=embedding_info,
|
|
118
|
-
tool_context=tool_router_context,
|
|
119
|
-
hooks=hooks,
|
|
120
|
-
agent_registry=agent_registry,
|
|
121
|
-
memory_service=memory_service,
|
|
122
|
-
platform=platform,
|
|
123
|
-
active_model_getter=active_model_getter,
|
|
124
|
-
brain_intelligence=brain_intelligence,
|
|
125
|
-
)
|
|
126
|
-
return tool_router_context, interaction_router_context
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def maybe_build_telegram_chat_mirror(
|
|
130
|
-
*,
|
|
131
|
-
enable_telegram: bool,
|
|
132
|
-
spawn: Any,
|
|
133
|
-
) -> Optional[Any]:
|
|
134
|
-
if not enable_telegram:
|
|
135
|
-
return None
|
|
136
|
-
|
|
137
|
-
def telegram_chat_mirror(role: str, text: str, source: Optional[str] = None) -> None:
|
|
138
|
-
from latticeai.integrations.telegram_bot import broadcast_web_chat
|
|
139
|
-
spawn(broadcast_web_chat(role, text), name="telegram_broadcast")
|
|
140
|
-
|
|
141
|
-
return telegram_chat_mirror
|