mirobody 0.0.0.dev0__py3-none-any.whl
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.
- mirobody/__init__.py +14 -0
- mirobody/chat/__init__.py +22 -0
- mirobody/chat/adapters/__init__.py +1 -0
- mirobody/chat/adapters/base.py +414 -0
- mirobody/chat/adapters/http.py +436 -0
- mirobody/chat/agent.py +374 -0
- mirobody/chat/asr.py +535 -0
- mirobody/chat/file.py +263 -0
- mirobody/chat/history.py +286 -0
- mirobody/chat/mcp_loader.py +116 -0
- mirobody/chat/memory.py +570 -0
- mirobody/chat/message.py +688 -0
- mirobody/chat/model.py +101 -0
- mirobody/chat/service.py +580 -0
- mirobody/chat/session.py +222 -0
- mirobody/chat/session_share.py +291 -0
- mirobody/chat/summary.py +147 -0
- mirobody/chat/unified_chat_service.py +137 -0
- mirobody/chat/user.py +70 -0
- mirobody/chat/user_config.py +265 -0
- mirobody/chat/user_profile.py +1944 -0
- mirobody/indicator/README.md +354 -0
- mirobody/indicator/__init__.py +0 -0
- mirobody/indicator/__main__.py +3 -0
- mirobody/indicator/concept_graph.py +319 -0
- mirobody/indicator/embed.py +71 -0
- mirobody/indicator/health/__init__.py +0 -0
- mirobody/indicator/health/bridge.py +520 -0
- mirobody/indicator/health/common.py +347 -0
- mirobody/indicator/health/embeddings_db.py +221 -0
- mirobody/indicator/health/embeddings_ref.py +475 -0
- mirobody/indicator/health/graph_builder.py +180 -0
- mirobody/indicator/health/locales/__init__.py +78 -0
- mirobody/indicator/health/locales/cn.py +65 -0
- mirobody/indicator/health/merge.py +290 -0
- mirobody/indicator/health/search.py +320 -0
- mirobody/indicator/health/siblings.py +781 -0
- mirobody/indicator/health/taxonomy.py +379 -0
- mirobody/indicator/health/test.py +223 -0
- mirobody/indicator/main.py +275 -0
- mirobody/indicator/mapping.py +110 -0
- mirobody/indicator/search.py +161 -0
- mirobody/indicator/taxonomy.py +260 -0
- mirobody/mcp/__init__.py +29 -0
- mirobody/mcp/resource.py +146 -0
- mirobody/mcp/service.py +730 -0
- mirobody/mcp/tool.py +741 -0
- mirobody/pub/__init__.py +0 -0
- mirobody/pub/agents/README.md +146 -0
- mirobody/pub/agents/__init__.py +34 -0
- mirobody/pub/agents/baseline_agent.py +1336 -0
- mirobody/pub/agents/deep/backend.py +952 -0
- mirobody/pub/agents/deep/e2b_backend.py +278 -0
- mirobody/pub/agents/deep/errors.py +14 -0
- mirobody/pub/agents/deep/middleware/__init__.py +15 -0
- mirobody/pub/agents/deep/middleware/prompt_caching.py +423 -0
- mirobody/pub/agents/deep/parser.py +228 -0
- mirobody/pub/agents/deep/prompt_builder.py +69 -0
- mirobody/pub/agents/deep/prompts/theta_health.jinja +290 -0
- mirobody/pub/agents/deep/prompts/theta_health_simple.jinja +117 -0
- mirobody/pub/agents/deep/store.py +505 -0
- mirobody/pub/agents/deep/tool_loader.py +196 -0
- mirobody/pub/agents/deep/utils/__init__.py +62 -0
- mirobody/pub/agents/deep/utils/constants.py +181 -0
- mirobody/pub/agents/deep/utils/funcs.py +167 -0
- mirobody/pub/agents/deep/utils/message_converter.py +528 -0
- mirobody/pub/agents/deep_agent.py +622 -0
- mirobody/pub/agents/mix/__init__.py +14 -0
- mirobody/pub/agents/mix/middleware/__init__.py +9 -0
- mirobody/pub/agents/mix/middleware/generate_answer.py +124 -0
- mirobody/pub/agents/mix/mixin.py +1279 -0
- mirobody/pub/agents/mix/prompts/orchestrator.jinja +36 -0
- mirobody/pub/agents/mix/prompts/responder.jinja +131 -0
- mirobody/pub/agents/mix_agent.py +490 -0
- mirobody/pub/agents/utils/__init__.py +11 -0
- mirobody/pub/agents/utils/cache_config.py +15 -0
- mirobody/pub/agents/utils/file.py +249 -0
- mirobody/pub/htdoc/__/auth/experiments.js +2 -0
- mirobody/pub/htdoc/__/auth/handler +15 -0
- mirobody/pub/htdoc/__/auth/handler.js +564 -0
- mirobody/pub/htdoc/__/auth/iframe +13 -0
- mirobody/pub/htdoc/__/auth/iframe.js +579 -0
- mirobody/pub/htdoc/assets/RenderHistoryList-CLPxljzD.js +1 -0
- mirobody/pub/htdoc/assets/RenderHistoryList-Cl2Afq4j.css +1 -0
- mirobody/pub/htdoc/assets/RenderHistoryList-legacy-Co4M_wLe.js +1 -0
- mirobody/pub/htdoc/assets/account-BG6qgOO9.js +1 -0
- mirobody/pub/htdoc/assets/account-legacy-BuPwnMo9.js +1 -0
- mirobody/pub/htdoc/assets/file-legacy-B1OPz9YG.js +1 -0
- mirobody/pub/htdoc/assets/file-vlwc8DpB.js +1 -0
- mirobody/pub/htdoc/assets/index--IFYfMXy.css +1 -0
- mirobody/pub/htdoc/assets/index-1_UgC3m0.css +1 -0
- mirobody/pub/htdoc/assets/index-5LMo7Lk4.js +1 -0
- mirobody/pub/htdoc/assets/index-BDCGenv1.css +1 -0
- mirobody/pub/htdoc/assets/index-BWLyl4Ry.js +1 -0
- mirobody/pub/htdoc/assets/index-Bivsa4xI.js +1 -0
- mirobody/pub/htdoc/assets/index-C32k5tCH.js +1 -0
- mirobody/pub/htdoc/assets/index-C3z8gN2O.css +1 -0
- mirobody/pub/htdoc/assets/index-CQj7TbUh.css +1 -0
- mirobody/pub/htdoc/assets/index-CVBl6l0A.css +1 -0
- mirobody/pub/htdoc/assets/index-ClPsPNIh.js +1 -0
- mirobody/pub/htdoc/assets/index-DBdtM01z.js +1 -0
- mirobody/pub/htdoc/assets/index-DFNSEqZI.js +1 -0
- mirobody/pub/htdoc/assets/index-DGSYSAta.js +1 -0
- mirobody/pub/htdoc/assets/index-DMNolwBO.css +1 -0
- mirobody/pub/htdoc/assets/index-DVDIPMfE.js +1 -0
- mirobody/pub/htdoc/assets/index-Du57KEca.js +1 -0
- mirobody/pub/htdoc/assets/index-DuTRpth9.js +2 -0
- mirobody/pub/htdoc/assets/index-LabuL4U_.js +1 -0
- mirobody/pub/htdoc/assets/index-SyEx1qzm.css +1 -0
- mirobody/pub/htdoc/assets/index-legacy-1j3_J-0Y.js +1 -0
- mirobody/pub/htdoc/assets/index-legacy-BGOD2yAB.js +1 -0
- mirobody/pub/htdoc/assets/index-legacy-BSdui2GF.js +1 -0
- mirobody/pub/htdoc/assets/index-legacy-C2Fq83tF.js +1 -0
- mirobody/pub/htdoc/assets/index-legacy-CHEGF-C1.js +1 -0
- mirobody/pub/htdoc/assets/index-legacy-Ck4nK7Ou.js +1 -0
- mirobody/pub/htdoc/assets/index-legacy-Cwqts7Oq.js +1 -0
- mirobody/pub/htdoc/assets/index-legacy-DhpHlDQT.js +1 -0
- mirobody/pub/htdoc/assets/index-legacy-Dl45gcop.js +23 -0
- mirobody/pub/htdoc/assets/index-legacy-DpkSGxx1.js +1 -0
- mirobody/pub/htdoc/assets/index-legacy-MuQw6dPg.js +1 -0
- mirobody/pub/htdoc/assets/index-legacy-Y-c2SyKN.js +1 -0
- mirobody/pub/htdoc/assets/index-legacy-ZeQ9g8Jb.js +1 -0
- mirobody/pub/htdoc/assets/index-legacy-uIT6h2W_.js +1 -0
- mirobody/pub/htdoc/assets/index-mABjyEMg.js +1 -0
- mirobody/pub/htdoc/assets/index-qDL7KYga.css +1 -0
- mirobody/pub/htdoc/assets/index-tk-1X7yk.js +1 -0
- mirobody/pub/htdoc/assets/index-wi8RMjZA.css +1 -0
- mirobody/pub/htdoc/assets/index-y-oi3J7w.css +1 -0
- mirobody/pub/htdoc/assets/input-BL_pYmlS.js +1 -0
- mirobody/pub/htdoc/assets/input-legacy-DqSq0IOV.js +1 -0
- mirobody/pub/htdoc/assets/logo-MLEW-e8g.svg +6 -0
- mirobody/pub/htdoc/assets/logo-legacy-e9JydjKK.js +1 -0
- mirobody/pub/htdoc/assets/logo-wU4jU3J-.js +1 -0
- mirobody/pub/htdoc/assets/mcp_feature_eg-CcZqNkG5.png +0 -0
- mirobody/pub/htdoc/assets/mcp_feature_eg_cn-CFatLA2c.png +0 -0
- mirobody/pub/htdoc/assets/new-CFFfz_aJ.js +1 -0
- mirobody/pub/htdoc/assets/new-legacy-CoOAEW9y.js +1 -0
- mirobody/pub/htdoc/assets/polyfills-legacy-CtzgJ65B.js +4 -0
- mirobody/pub/htdoc/assets/useUpload-CMuIcES4.js +1 -0
- mirobody/pub/htdoc/assets/useUpload-legacy-mMCZZnaO.js +1 -0
- mirobody/pub/htdoc/assets/vendor-antd-CIj8s3ay.js +1 -0
- mirobody/pub/htdoc/assets/vendor-antd-legacy-BpsiSKce.js +15 -0
- mirobody/pub/htdoc/assets/vendor-eruda-CwRho7qZ.js +1 -0
- mirobody/pub/htdoc/assets/vendor-eruda-legacy-CnYNKfym.js +1 -0
- mirobody/pub/htdoc/assets/vendor-firebase-D-efta1e.js +1 -0
- mirobody/pub/htdoc/assets/vendor-firebase-legacy-SmJg7pDS.js +1434 -0
- mirobody/pub/htdoc/assets/vendor-monaco-Mti7B50H.js +1 -0
- mirobody/pub/htdoc/assets/vendor-monaco-legacy-18169DkE.js +1 -0
- mirobody/pub/htdoc/github-markdown-light.css +1006 -0
- mirobody/pub/htdoc/index.html +34 -0
- mirobody/pub/htdoc/mirobody.svg +4 -0
- mirobody/pub/prompts/theta_health.jinja +134 -0
- mirobody/pub/resources/chart_url.html +102 -0
- mirobody/pub/resources/chart_url.json +24 -0
- mirobody/pub/resources/upload.html +130 -0
- mirobody/pub/resources/upload.json +12 -0
- mirobody/pub/tools/README.md +112 -0
- mirobody/pub/tools/__init__.py +95 -0
- mirobody/pub/tools/_chart_service_schema_loader.py +115 -0
- mirobody/pub/tools/chart_schema/area.json +94 -0
- mirobody/pub/tools/chart_schema/bar.json +95 -0
- mirobody/pub/tools/chart_schema/boxplot.json +88 -0
- mirobody/pub/tools/chart_schema/column.json +95 -0
- mirobody/pub/tools/chart_schema/district-map.json +115 -0
- mirobody/pub/tools/chart_schema/dual-axes.json +96 -0
- mirobody/pub/tools/chart_schema/fishbone-diagram.json +85 -0
- mirobody/pub/tools/chart_schema/flow-diagram.json +78 -0
- mirobody/pub/tools/chart_schema/funnel.json +72 -0
- mirobody/pub/tools/chart_schema/histogram.json +77 -0
- mirobody/pub/tools/chart_schema/line.json +89 -0
- mirobody/pub/tools/chart_schema/liquid.json +64 -0
- mirobody/pub/tools/chart_schema/mind-map.json +85 -0
- mirobody/pub/tools/chart_schema/network-graph.json +78 -0
- mirobody/pub/tools/chart_schema/organization-chart.json +103 -0
- mirobody/pub/tools/chart_schema/path-map.json +45 -0
- mirobody/pub/tools/chart_schema/pie.json +77 -0
- mirobody/pub/tools/chart_schema/pin-map.json +59 -0
- mirobody/pub/tools/chart_schema/radar.json +79 -0
- mirobody/pub/tools/chart_schema/sankey.json +81 -0
- mirobody/pub/tools/chart_schema/scatter.json +86 -0
- mirobody/pub/tools/chart_schema/venn.json +81 -0
- mirobody/pub/tools/chart_service.py +1051 -0
- mirobody/pub/tools/code_service.py +114 -0
- mirobody/pub/tools/file_read_service.py +347 -0
- mirobody/pub/tools/file_write_service.py +110 -0
- mirobody/pub/tools/files_utils/__init__.py +132 -0
- mirobody/pub/tools/files_utils/backend.py +160 -0
- mirobody/pub/tools/files_utils/compat.py +240 -0
- mirobody/pub/tools/files_utils/eviction.py +121 -0
- mirobody/pub/tools/files_utils/global_files.py +376 -0
- mirobody/pub/tools/memory_service.py +112 -0
- mirobody/pub/tools/render-chart.js +106 -0
- mirobody/pub/tools/todo_service.py +168 -0
- mirobody/pub/tools_health/__init__.py +0 -0
- mirobody/pub/tools_health/genetic_service.py +259 -0
- mirobody/pub/tools_health/health_indicator_service.py +327 -0
- mirobody/pub/tools_health/user_service.py +101 -0
- mirobody/pulse/CLAUDE.md +228 -0
- mirobody/pulse/README.md +1960 -0
- mirobody/pulse/__init__.py +53 -0
- mirobody/pulse/apple/INTEGRATION_GUIDE.md +283 -0
- mirobody/pulse/apple/README.md +127 -0
- mirobody/pulse/apple/__init__.py +24 -0
- mirobody/pulse/apple/models.py +269 -0
- mirobody/pulse/apple/platform.py +137 -0
- mirobody/pulse/apple/provider.py +387 -0
- mirobody/pulse/apple/services/__init__.py +0 -0
- mirobody/pulse/apple/services/database_service.py +116 -0
- mirobody/pulse/apple/statistics_service.py +168 -0
- mirobody/pulse/base.py +220 -0
- mirobody/pulse/core/README.md +370 -0
- mirobody/pulse/core/__init__.py +85 -0
- mirobody/pulse/core/aggregate_indicator/README.md +393 -0
- mirobody/pulse/core/aggregate_indicator/TEST_README.md +291 -0
- mirobody/pulse/core/aggregate_indicator/__init__.py +56 -0
- mirobody/pulse/core/aggregate_indicator/aggregators/__init__.py +13 -0
- mirobody/pulse/core/aggregate_indicator/aggregators/base.py +84 -0
- mirobody/pulse/core/aggregate_indicator/aggregators/sql_aggregator.py +1534 -0
- mirobody/pulse/core/aggregate_indicator/database_service.py +85 -0
- mirobody/pulse/core/aggregate_indicator/derived_aggregator.py +430 -0
- mirobody/pulse/core/aggregate_indicator/derived_task.py +61 -0
- mirobody/pulse/core/aggregate_indicator/models.py +154 -0
- mirobody/pulse/core/aggregate_indicator/naming.py +69 -0
- mirobody/pulse/core/aggregate_indicator/rule_generator.py +174 -0
- mirobody/pulse/core/aggregate_indicator/service.py +253 -0
- mirobody/pulse/core/aggregate_indicator/startup.py +102 -0
- mirobody/pulse/core/aggregate_indicator/task.py +119 -0
- mirobody/pulse/core/aggregate_indicator/test_aggregator.py +726 -0
- mirobody/pulse/core/aggregate_indicator/test_cgm_indicators.py +427 -0
- mirobody/pulse/core/auth.py +47 -0
- mirobody/pulse/core/constants.py +266 -0
- mirobody/pulse/core/data_quality_service.py +269 -0
- mirobody/pulse/core/database.py +600 -0
- mirobody/pulse/core/distributed_lock.py +305 -0
- mirobody/pulse/core/fhir_mapping.py +253 -0
- mirobody/pulse/core/indicators_info.py +3084 -0
- mirobody/pulse/core/insight/__init__.py +15 -0
- mirobody/pulse/core/insight/baseline_engine.py +250 -0
- mirobody/pulse/core/insight/database_service.py +429 -0
- mirobody/pulse/core/insight/engine_task.py +457 -0
- mirobody/pulse/core/insight/eval_agent.py +220 -0
- mirobody/pulse/core/insight/hypothesis_agent.py +197 -0
- mirobody/pulse/core/insight/indicator_aliases.py +307 -0
- mirobody/pulse/core/insight/insight_agent.py +278 -0
- mirobody/pulse/core/insight/models.py +241 -0
- mirobody/pulse/core/insight/recipe_registry.py +94 -0
- mirobody/pulse/core/insight/recipes/__init__.py +95 -0
- mirobody/pulse/core/insight/recipes/r01_multi_signal.py +131 -0
- mirobody/pulse/core/insight/recipes/r02_single_sustained.py +116 -0
- mirobody/pulse/core/insight/recipes/r03_trend.py +184 -0
- mirobody/pulse/core/insight/recipes/r04_recovery.py +110 -0
- mirobody/pulse/core/insight/recipes/r05_weekday_pattern.py +76 -0
- mirobody/pulse/core/insight/recipes/r06_glucose.py +79 -0
- mirobody/pulse/core/insight/startup.py +40 -0
- mirobody/pulse/core/manage_service.py +359 -0
- mirobody/pulse/core/models.py +151 -0
- mirobody/pulse/core/monitor/__init__.py +3 -0
- mirobody/pulse/core/monitor/collector_service.py +512 -0
- mirobody/pulse/core/monitor/collector_task.py +112 -0
- mirobody/pulse/core/monitor/coverage_service.py +282 -0
- mirobody/pulse/core/monitor/platform_mapping.py +34 -0
- mirobody/pulse/core/monitor/query_service.py +544 -0
- mirobody/pulse/core/monitor/startup.py +65 -0
- mirobody/pulse/core/monitor/user_profile_service.py +253 -0
- mirobody/pulse/core/push_service.py +134 -0
- mirobody/pulse/core/scheduler.py +506 -0
- mirobody/pulse/core/units.py +856 -0
- mirobody/pulse/core/user.py +395 -0
- mirobody/pulse/core/user_health_service.py +321 -0
- mirobody/pulse/core/value_range_validator.py +172 -0
- mirobody/pulse/data_upload/models/__init__.py +3 -0
- mirobody/pulse/data_upload/models/requests.py +100 -0
- mirobody/pulse/data_upload/repositories/__init__.py +3 -0
- mirobody/pulse/data_upload/repositories/health_data.py +110 -0
- mirobody/pulse/data_upload/services/__init__.py +18 -0
- mirobody/pulse/data_upload/services/base.py +78 -0
- mirobody/pulse/data_upload/services/upload_health.py +540 -0
- mirobody/pulse/file_parser/FILE_PROCESSING_GUIDE.md +845 -0
- mirobody/pulse/file_parser/__init__.py +23 -0
- mirobody/pulse/file_parser/config.py +82 -0
- mirobody/pulse/file_parser/file_processor.py +160 -0
- mirobody/pulse/file_parser/file_upload_manager.py +1510 -0
- mirobody/pulse/file_parser/handlers/audio.py +39 -0
- mirobody/pulse/file_parser/handlers/base.py +613 -0
- mirobody/pulse/file_parser/handlers/csv.py +72 -0
- mirobody/pulse/file_parser/handlers/excel.py +52 -0
- mirobody/pulse/file_parser/handlers/factory.py +135 -0
- mirobody/pulse/file_parser/handlers/genetic.py +113 -0
- mirobody/pulse/file_parser/handlers/image.py +65 -0
- mirobody/pulse/file_parser/handlers/pdf.py +65 -0
- mirobody/pulse/file_parser/handlers/text.py +84 -0
- mirobody/pulse/file_parser/services/__init__.py +0 -0
- mirobody/pulse/file_parser/services/async_file_processor.py +243 -0
- mirobody/pulse/file_parser/services/compressed_file_processor.py +544 -0
- mirobody/pulse/file_parser/services/content_extractor.py +165 -0
- mirobody/pulse/file_parser/services/content_formatter.py +612 -0
- mirobody/pulse/file_parser/services/database_services.py +1441 -0
- mirobody/pulse/file_parser/services/db_utils.py +290 -0
- mirobody/pulse/file_parser/services/file_abstract_extractor.py +981 -0
- mirobody/pulse/file_parser/services/file_db_service.py +962 -0
- mirobody/pulse/file_parser/services/file_llm_analyzer.py +685 -0
- mirobody/pulse/file_parser/services/file_processing_service.py +1339 -0
- mirobody/pulse/file_parser/services/file_uploader.py +212 -0
- mirobody/pulse/file_parser/services/food_recognizer.py +271 -0
- mirobody/pulse/file_parser/services/genetic_processor.py +693 -0
- mirobody/pulse/file_parser/services/indicator_extractor.py +990 -0
- mirobody/pulse/file_parser/services/list_my_data.py +47 -0
- mirobody/pulse/file_parser/services/pdf_splitter.py +363 -0
- mirobody/pulse/file_parser/services/prompts/__init__.py +0 -0
- mirobody/pulse/file_parser/services/prompts/file_abstract_prompt.py +98 -0
- mirobody/pulse/file_parser/services/prompts/file_indicator_extract.py +321 -0
- mirobody/pulse/file_parser/services/prompts/file_original_text_prompt.py +25 -0
- mirobody/pulse/file_parser/services/prompts/food_prompts.py +195 -0
- mirobody/pulse/file_parser/services/temp_file_manager.py +152 -0
- mirobody/pulse/file_parser/tools/__init__.py +1 -0
- mirobody/pulse/file_parser/tools/utils_sync_dim_table.py +658 -0
- mirobody/pulse/gate_tests/README.md +58 -0
- mirobody/pulse/gate_tests/__init__.py +0 -0
- mirobody/pulse/gate_tests/conftest.py +12 -0
- mirobody/pulse/gate_tests/fixtures/apple_health/body_nutrition_001.json +255 -0
- mirobody/pulse/gate_tests/fixtures/apple_health/sleep_001.json +287 -0
- mirobody/pulse/gate_tests/fixtures/apple_health/vitals_activity_001.json +372 -0
- mirobody/pulse/gate_tests/fixtures/theta_garmin/activities.json +206 -0
- mirobody/pulse/gate_tests/fixtures/theta_garmin/bodyComps.json +56 -0
- mirobody/pulse/gate_tests/fixtures/theta_garmin/dailies.json +183 -0
- mirobody/pulse/gate_tests/fixtures/theta_garmin/pulseOx.json +63 -0
- mirobody/pulse/gate_tests/fixtures/theta_garmin/respiration.json +91 -0
- mirobody/pulse/gate_tests/fixtures/theta_garmin/sleeps.json +307 -0
- mirobody/pulse/gate_tests/fixtures/theta_garmin/stress.json +65 -0
- mirobody/pulse/gate_tests/fixtures/theta_garmin/userMetrics.json +56 -0
- mirobody/pulse/gate_tests/fixtures/theta_oura/daily_activity.json +317 -0
- mirobody/pulse/gate_tests/fixtures/theta_oura/daily_spo2.json +93 -0
- mirobody/pulse/gate_tests/fixtures/theta_oura/heartrate.json +134 -0
- mirobody/pulse/gate_tests/fixtures/theta_oura/personal_info.json +117 -0
- mirobody/pulse/gate_tests/fixtures/theta_oura/sleep.json +366 -0
- mirobody/pulse/gate_tests/fixtures/theta_whoop/body_measurements.json +140 -0
- mirobody/pulse/gate_tests/fixtures/theta_whoop/cycles.json +158 -0
- mirobody/pulse/gate_tests/fixtures/theta_whoop/recoveries.json +185 -0
- mirobody/pulse/gate_tests/fixtures/theta_whoop/sleeps.json +294 -0
- mirobody/pulse/gate_tests/fixtures/theta_whoop/workouts.json +253 -0
- mirobody/pulse/gate_tests/format_tester.py +377 -0
- mirobody/pulse/gate_tests/test_format_data.py +24 -0
- mirobody/pulse/manager.py +251 -0
- mirobody/pulse/router/__init__.py +42 -0
- mirobody/pulse/router/apple_router.py +372 -0
- mirobody/pulse/router/file_router.py +893 -0
- mirobody/pulse/router/food_router.py +466 -0
- mirobody/pulse/router/manage_router.py +1126 -0
- mirobody/pulse/router/middleware.py +204 -0
- mirobody/pulse/router/public_router.py +1252 -0
- mirobody/pulse/router/session_share_router.py +166 -0
- mirobody/pulse/router/skill_router.py +390 -0
- mirobody/pulse/router/user_router.py +515 -0
- mirobody/pulse/setup.py +91 -0
- mirobody/pulse/theta/README.md +107 -0
- mirobody/pulse/theta/__init__.py +41 -0
- mirobody/pulse/theta/mirobody_garmin_connect/__init__.py +0 -0
- mirobody/pulse/theta/mirobody_garmin_connect/provider_garmin.py +1675 -0
- mirobody/pulse/theta/mirobody_oura/DESIGN.md +133 -0
- mirobody/pulse/theta/mirobody_oura/__init__.py +1 -0
- mirobody/pulse/theta/mirobody_oura/provider_oura.py +589 -0
- mirobody/pulse/theta/mirobody_pgsql/__init__.py +8 -0
- mirobody/pulse/theta/mirobody_pgsql/provider_pgsql.py +196 -0
- mirobody/pulse/theta/mirobody_whoop/__init__.py +0 -0
- mirobody/pulse/theta/mirobody_whoop/provider_whoop.py +1219 -0
- mirobody/pulse/theta/platform/__init__.py +10 -0
- mirobody/pulse/theta/platform/base.py +597 -0
- mirobody/pulse/theta/platform/database_service.py +554 -0
- mirobody/pulse/theta/platform/oauth2.py +261 -0
- mirobody/pulse/theta/platform/platform.py +555 -0
- mirobody/pulse/theta/platform/pull_task.py +166 -0
- mirobody/pulse/theta/platform/startup.py +50 -0
- mirobody/pulse/theta/platform/utils.py +368 -0
- mirobody/res/concept_graph.bin +3 -0
- mirobody/res/sql/00_init_schema.sql +324 -0
- mirobody/res/sql/01_basedata.sql +298 -0
- mirobody/res/sql/02_settings.sql +56 -0
- mirobody/res/sql/10_health_tab.sql +75 -0
- mirobody/res/sql/20_migration_add_reconnect_connect_info.sql +14 -0
- mirobody/res/sql/21_health_user_profile_by_system.sql +8 -0
- mirobody/res/sql/27_add_tags_to_sessions.sql +13 -0
- mirobody/res/sql/28_add_platform_to_series_data.sql +6 -0
- mirobody/res/sql/30_add_fhir_mapping_to_th_series_data.sql +4 -0
- mirobody/res/sql/31_user_custom_skills.sql +27 -0
- mirobody/res/sql/34_add_session_status_fields.sql +6 -0
- mirobody/res/sql/36_add_ethnicity_to_health_app_user.sql +2 -0
- mirobody/res/sql/39_create_th_files.sql +71 -0
- mirobody/res/sql/42_create_unit_type_and_indicator_full_dim.sql +8 -0
- mirobody/res/sql/44_th_sessions_add_status.sql +1 -0
- mirobody/res/sql/53_add_action_type_to_user_profile.sql +4 -0
- mirobody/res/sql/55_health_data_oura.sql +12 -0
- mirobody/res/sql/75_2_monitor_tables.sql +8 -0
- mirobody/res/sql/75_monitor_tables.sql +48 -0
- mirobody/res/sql/76_indicator_valid_rules.sql +156 -0
- mirobody/res/sql/77_insight_results.sql +54 -0
- mirobody/res/sql/90_deepagents.sql +48 -0
- mirobody/res/sql/91_create_webauthn_credentials.sql +20 -0
- mirobody/res/sql/92_add_mfa_enabled.sql +2 -0
- mirobody/res/sql/93_th_series_data_unmapped_indicator_idx.sql +20 -0
- mirobody/res/taxonomy.bin +3 -0
- mirobody/server/__init__.py +5 -0
- mirobody/server/middlewares.py +219 -0
- mirobody/server/server.py +574 -0
- mirobody/server/worker.py +75 -0
- mirobody/task/__init__.py +25 -0
- mirobody/task/base.py +163 -0
- mirobody/task/indicator_sync.py +411 -0
- mirobody/task/loader.py +87 -0
- mirobody/task/profile_refresh.py +66 -0
- mirobody/user/__init__.py +14 -0
- mirobody/user/apple.py +128 -0
- mirobody/user/email.py +514 -0
- mirobody/user/firebase.py +108 -0
- mirobody/user/google.py +46 -0
- mirobody/user/jwt.py +266 -0
- mirobody/user/oauth_service.py +823 -0
- mirobody/user/sharing.py +2236 -0
- mirobody/user/user.py +252 -0
- mirobody/user/user_service.py +627 -0
- mirobody/user/webauthn.py +924 -0
- mirobody/utils/__init__.py +43 -0
- mirobody/utils/config/README.md +598 -0
- mirobody/utils/config/__init__.py +9 -0
- mirobody/utils/config/config.py +1035 -0
- mirobody/utils/config/encrypt.py +62 -0
- mirobody/utils/config/http.py +60 -0
- mirobody/utils/config/llm.py +242 -0
- mirobody/utils/config/log.py +22 -0
- mirobody/utils/config/postgresql.py +247 -0
- mirobody/utils/config/redis.py +131 -0
- mirobody/utils/config/redis_compat/README.md +59 -0
- mirobody/utils/config/redis_compat/__init__.py +3 -0
- mirobody/utils/config/redis_compat/__main__.py +23 -0
- mirobody/utils/config/redis_compat/client.py +220 -0
- mirobody/utils/config/redis_compat/pubsub.py +110 -0
- mirobody/utils/config/redis_compat/resp.py +67 -0
- mirobody/utils/config/redis_compat/server.py +360 -0
- mirobody/utils/config/redis_compat/store_memory.py +314 -0
- mirobody/utils/config/redis_compat/store_pg.py +550 -0
- mirobody/utils/config/storage/__init__.py +7 -0
- mirobody/utils/config/storage/abstract.py +289 -0
- mirobody/utils/config/storage/aliyun.py +306 -0
- mirobody/utils/config/storage/aws.py +258 -0
- mirobody/utils/config/storage/constants.py +2 -0
- mirobody/utils/config/storage/factory.py +44 -0
- mirobody/utils/config/storage/local.py +319 -0
- mirobody/utils/data.py +124 -0
- mirobody/utils/db.py +136 -0
- mirobody/utils/distributed_websocket.py +190 -0
- mirobody/utils/embedding.py +149 -0
- mirobody/utils/http.py +218 -0
- mirobody/utils/i18n.py +194 -0
- mirobody/utils/llm/__init__.py +156 -0
- mirobody/utils/llm/adapters/__init__.py +12 -0
- mirobody/utils/llm/adapters/base.py +103 -0
- mirobody/utils/llm/adapters/factory.py +77 -0
- mirobody/utils/llm/adapters/gemini_adapter.py +175 -0
- mirobody/utils/llm/adapters/openai_adapter.py +158 -0
- mirobody/utils/llm/adapters/volcengine_adapter.py +135 -0
- mirobody/utils/llm/clients.py +258 -0
- mirobody/utils/llm/config.py +315 -0
- mirobody/utils/llm/file_processors.py +898 -0
- mirobody/utils/llm/hipaa_policy.py +124 -0
- mirobody/utils/llm/interface.py +112 -0
- mirobody/utils/llm/utils.py +615 -0
- mirobody/utils/locales/chat_service.json +9 -0
- mirobody/utils/locales/content_extractor.json +16 -0
- mirobody/utils/locales/file_processor.json +268 -0
- mirobody/utils/locales/file_uploader.json +240 -0
- mirobody/utils/locales/indicator_extractor.json +136 -0
- mirobody/utils/locales/load_genetic_data.json +158 -0
- mirobody/utils/locales/temp_file_manager.json +9 -0
- mirobody/utils/log.py +280 -0
- mirobody/utils/req_ctx.py +24 -0
- mirobody/utils/truncate.py +57 -0
- mirobody/utils/utils_audio.py +266 -0
- mirobody/utils/utils_auth.py +143 -0
- mirobody/utils/utils_encrypt.py +181 -0
- mirobody/utils/utils_files/__init__.py +0 -0
- mirobody/utils/utils_files/utils_oss.py +589 -0
- mirobody/utils/utils_files/utils_s3.py +305 -0
- mirobody/utils/utils_user.py +201 -0
- mirobody-0.0.0.dev0.dist-info/METADATA +698 -0
- mirobody-0.0.0.dev0.dist-info/RECORD +488 -0
- mirobody-0.0.0.dev0.dist-info/WHEEL +5 -0
- mirobody-0.0.0.dev0.dist-info/licenses/LICENSE +192 -0
- mirobody-0.0.0.dev0.dist-info/licenses/LICENSE-3RD-PARTY +72 -0
- mirobody-0.0.0.dev0.dist-info/top_level.txt +1 -0
mirobody/__init__.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Version in YYYYMMDD.HHMMSS format.
|
|
2
|
+
|
|
3
|
+
Resolution order:
|
|
4
|
+
1. importlib.metadata — works after the package is installed (prod + editable dev).
|
|
5
|
+
2. MIROBODY_VERSION env var — CI sets this before `python -m build`.
|
|
6
|
+
3. "0.0.0.dev0" sentinel — running from source tree without installation.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
from importlib.metadata import version as _version
|
|
11
|
+
__version__ = _version("mirobody")
|
|
12
|
+
except Exception:
|
|
13
|
+
import os
|
|
14
|
+
__version__ = os.environ.get("MIROBODY_VERSION") or "0.0.0.dev0"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from .agent import (
|
|
2
|
+
load_agents_from_module,
|
|
3
|
+
load_agents_from_directory,
|
|
4
|
+
load_agents_from_directories,
|
|
5
|
+
|
|
6
|
+
get_global_agent_count,
|
|
7
|
+
get_global_agents,
|
|
8
|
+
|
|
9
|
+
get_agent,
|
|
10
|
+
get_global_agent,
|
|
11
|
+
|
|
12
|
+
get_llm_client_by_name,
|
|
13
|
+
|
|
14
|
+
detect_language
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
from .service import ChatService
|
|
18
|
+
|
|
19
|
+
from .user_config import (
|
|
20
|
+
get_user_mcps,
|
|
21
|
+
get_user_prompt_by_name
|
|
22
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .http import HTTPChatAdapter
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base adapter class for chat protocols
|
|
3
|
+
|
|
4
|
+
Defines the interface and common logic that all protocol adapters share.
|
|
5
|
+
Subclasses implement protocol-specific details (HTTP SSE, WebSocket, etc.).
|
|
6
|
+
|
|
7
|
+
All user_id parameters are consistently typed as str throughout.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio, json, logging
|
|
11
|
+
|
|
12
|
+
from abc import ABC, abstractmethod
|
|
13
|
+
from typing import Any, AsyncGenerator
|
|
14
|
+
|
|
15
|
+
from mirobody.chat.unified_chat_service import UnifiedChatService
|
|
16
|
+
|
|
17
|
+
from ..message import (
|
|
18
|
+
save_message,
|
|
19
|
+
get_last_message,
|
|
20
|
+
chat_list_setter_hollywell
|
|
21
|
+
)
|
|
22
|
+
from ..model import ChatStreamRequest
|
|
23
|
+
|
|
24
|
+
from ...utils import get_query_user_id
|
|
25
|
+
|
|
26
|
+
#-----------------------------------------------------------------------------
|
|
27
|
+
# Constants
|
|
28
|
+
#-----------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
class PERMISSION_ENUM:
|
|
31
|
+
"""Permission type identifiers"""
|
|
32
|
+
chat = "chat"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class PERMISSION_LEVEL_ENUM:
|
|
36
|
+
"""Permission level values"""
|
|
37
|
+
no_permission = 0
|
|
38
|
+
read = 1
|
|
39
|
+
write = 2
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class CHUNK_TYPE_ENUMS:
|
|
43
|
+
"""Chunk type identifiers for streaming responses"""
|
|
44
|
+
|
|
45
|
+
reply = "reply"
|
|
46
|
+
queryTitle = "queryTitle"
|
|
47
|
+
queryArguments = "queryArguments"
|
|
48
|
+
queryDetail = "queryDetail"
|
|
49
|
+
thinking = "thinking"
|
|
50
|
+
report = "report"
|
|
51
|
+
image = "image"
|
|
52
|
+
food_snap = "food_snap"
|
|
53
|
+
costStatistics = "costStatistics"
|
|
54
|
+
|
|
55
|
+
non_streaming_types = {
|
|
56
|
+
"food_snap" : 1,
|
|
57
|
+
"report" : 1
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def get_streaming_types(cls):
|
|
62
|
+
"""Types that should be forwarded to frontend"""
|
|
63
|
+
return [cls.reply, cls.queryTitle, cls.queryArguments, cls.queryDetail, cls.thinking, cls.costStatistics, cls.image]
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def get_thinking_types(cls):
|
|
67
|
+
"""Types considered as 'thinking' content"""
|
|
68
|
+
return [cls.thinking, cls.queryDetail, cls.queryArguments, cls.queryTitle]
|
|
69
|
+
|
|
70
|
+
#-----------------------------------------------------------------------------
|
|
71
|
+
# Base Adapter
|
|
72
|
+
#-----------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
class ChatProtocolAdapter(ABC):
|
|
75
|
+
"""
|
|
76
|
+
Abstract base class for chat protocol adapters.
|
|
77
|
+
|
|
78
|
+
Provides common logic for all protocols:
|
|
79
|
+
- Permission validation
|
|
80
|
+
- Message saving (user question, assistant response)
|
|
81
|
+
- Message history retrieval
|
|
82
|
+
- Chat extraction logging
|
|
83
|
+
|
|
84
|
+
Subclasses must implement:
|
|
85
|
+
- handle_request(): Protocol-specific request handling
|
|
86
|
+
- stream_output(): Protocol-specific output formatting
|
|
87
|
+
- get_session_id(): Protocol-specific session ID extraction
|
|
88
|
+
|
|
89
|
+
Note: All user_id parameters are typed as str for consistency.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
def __init__(self, chat_service: UnifiedChatService):
|
|
93
|
+
"""
|
|
94
|
+
Initialize adapter with the chat service.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
chat_service: Instance of UnifiedChatService
|
|
98
|
+
"""
|
|
99
|
+
self.chat_service: UnifiedChatService = chat_service
|
|
100
|
+
self.scene: str = "web" # Default scene, subclasses can override
|
|
101
|
+
|
|
102
|
+
# =========================================================================
|
|
103
|
+
# Abstract methods - must be implemented by subclasses
|
|
104
|
+
# =========================================================================
|
|
105
|
+
|
|
106
|
+
@abstractmethod
|
|
107
|
+
async def handle_request(
|
|
108
|
+
self,
|
|
109
|
+
params: ChatStreamRequest,
|
|
110
|
+
**kwargs
|
|
111
|
+
) -> AsyncGenerator[str, None]:
|
|
112
|
+
"""
|
|
113
|
+
Main entry point for handling a chat request.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
params: Chat request parameters (includes user_id as str)
|
|
117
|
+
**kwargs: Additional protocol-specific arguments
|
|
118
|
+
|
|
119
|
+
Yields:
|
|
120
|
+
Protocol-specific formatted output (e.g., SSE strings for HTTP)
|
|
121
|
+
"""
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
@abstractmethod
|
|
125
|
+
async def stream_output(
|
|
126
|
+
self,
|
|
127
|
+
chunks: AsyncGenerator[dict[str, Any], None],
|
|
128
|
+
context: dict[str, Any]
|
|
129
|
+
) -> AsyncGenerator[str, None]:
|
|
130
|
+
"""
|
|
131
|
+
Convert unified output chunks to protocol-specific format.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
chunks: Raw chunks from UnifiedChatService
|
|
135
|
+
context: Request context for background processing
|
|
136
|
+
|
|
137
|
+
Yields:
|
|
138
|
+
Protocol-specific formatted output
|
|
139
|
+
"""
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
@abstractmethod
|
|
143
|
+
def get_session_id(self, params: ChatStreamRequest) -> str:
|
|
144
|
+
"""
|
|
145
|
+
Extract session_id for database storage.
|
|
146
|
+
|
|
147
|
+
Different protocols may use different session ID sources:
|
|
148
|
+
- HTTP: Uses params.session_id
|
|
149
|
+
- WebSocket: May use trace_id
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
params: Chat request parameters
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
Session ID string
|
|
156
|
+
"""
|
|
157
|
+
pass
|
|
158
|
+
|
|
159
|
+
# =========================================================================
|
|
160
|
+
# Common methods - shared by all protocols
|
|
161
|
+
# =========================================================================
|
|
162
|
+
|
|
163
|
+
def get_scene(self) -> str:
|
|
164
|
+
"""
|
|
165
|
+
Get the scene identifier for this adapter.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Scene string (e.g., 'web' for HTTP)
|
|
169
|
+
"""
|
|
170
|
+
return self.scene
|
|
171
|
+
|
|
172
|
+
#-------------------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
async def validate_permissions(
|
|
175
|
+
self,
|
|
176
|
+
params: ChatStreamRequest,
|
|
177
|
+
user_id: str,
|
|
178
|
+
**kwargs
|
|
179
|
+
) -> bool:
|
|
180
|
+
"""
|
|
181
|
+
Validate help-ask permissions.
|
|
182
|
+
|
|
183
|
+
In help-ask scenarios, user A can query user B's data if they have
|
|
184
|
+
the appropriate chat permissions.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
params: Chat request parameters
|
|
188
|
+
user_id: Current user ID (str)
|
|
189
|
+
**kwargs: Additional arguments (e.g., token for HTTP)
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
True if permissions are valid, False otherwise
|
|
193
|
+
"""
|
|
194
|
+
# If not help-ask scenario (querying own data), always allow
|
|
195
|
+
if not params.query_user_id or params.query_user_id == user_id:
|
|
196
|
+
return True
|
|
197
|
+
|
|
198
|
+
# Validate help-ask permissions
|
|
199
|
+
permission_kwargs = {"permission": [PERMISSION_ENUM.chat]}
|
|
200
|
+
if "token" in kwargs:
|
|
201
|
+
permission_kwargs["token"] = kwargs["token"]
|
|
202
|
+
|
|
203
|
+
permission_result = await get_query_user_id(
|
|
204
|
+
params.query_user_id,
|
|
205
|
+
user_id,
|
|
206
|
+
**permission_kwargs
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
if not permission_result.get("success"):
|
|
210
|
+
logging.error(f"Permission validation failed: {permission_result.get('error')}")
|
|
211
|
+
return False
|
|
212
|
+
|
|
213
|
+
permissions = permission_result.get("permissions", {})
|
|
214
|
+
if permissions.get(PERMISSION_ENUM.chat, 0) < PERMISSION_LEVEL_ENUM.read:
|
|
215
|
+
logging.error(f"Insufficient chat permissions for user {user_id} to query {params.query_user_id}")
|
|
216
|
+
return False
|
|
217
|
+
|
|
218
|
+
return True
|
|
219
|
+
|
|
220
|
+
#-------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
async def save_user_question(
|
|
223
|
+
self,
|
|
224
|
+
params: ChatStreamRequest,
|
|
225
|
+
user_id: str
|
|
226
|
+
) -> str:
|
|
227
|
+
"""
|
|
228
|
+
Save user question to database.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
params: Chat request parameters
|
|
232
|
+
user_id: User ID (str)
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
The saved message ID
|
|
236
|
+
"""
|
|
237
|
+
return await save_message(
|
|
238
|
+
user_id=user_id,
|
|
239
|
+
query_user_id=params.query_user_id or user_id,
|
|
240
|
+
content=params.question,
|
|
241
|
+
role='user',
|
|
242
|
+
session_id=self.get_session_id(params),
|
|
243
|
+
scene=self.get_scene(),
|
|
244
|
+
agent=params.agent,
|
|
245
|
+
message_type="text",
|
|
246
|
+
msg_id=params.msg_id,
|
|
247
|
+
provider=params.provider
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
#-------------------------------------------------------------------------
|
|
251
|
+
|
|
252
|
+
async def save_assistant_response(
|
|
253
|
+
self,
|
|
254
|
+
reply_id: str,
|
|
255
|
+
params: ChatStreamRequest,
|
|
256
|
+
user_id: str,
|
|
257
|
+
content: Any,
|
|
258
|
+
question_msg_id: str
|
|
259
|
+
) -> str:
|
|
260
|
+
"""
|
|
261
|
+
Save assistant response to database.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
reply_id: Response message ID
|
|
265
|
+
params: Chat request parameters
|
|
266
|
+
user_id: User ID (str)
|
|
267
|
+
content: Response content (element_list)
|
|
268
|
+
question_msg_id: ID of the question this responds to
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
The saved message ID
|
|
272
|
+
"""
|
|
273
|
+
return await save_message(
|
|
274
|
+
user_id=user_id,
|
|
275
|
+
query_user_id=params.query_user_id or user_id,
|
|
276
|
+
content=content,
|
|
277
|
+
role='assistant',
|
|
278
|
+
session_id=self.get_session_id(params),
|
|
279
|
+
scene=self.get_scene(),
|
|
280
|
+
agent=params.agent,
|
|
281
|
+
msg_id=reply_id,
|
|
282
|
+
question_id=question_msg_id,
|
|
283
|
+
message_type="text",
|
|
284
|
+
provider=params.provider
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
#-------------------------------------------------------------------------
|
|
288
|
+
|
|
289
|
+
async def get_message_history(
|
|
290
|
+
self,
|
|
291
|
+
user_id: str,
|
|
292
|
+
query_user_id: str | None = None,
|
|
293
|
+
session_id: str | None = None,
|
|
294
|
+
scene: str | None = None
|
|
295
|
+
) -> list:
|
|
296
|
+
"""
|
|
297
|
+
Get message history for a session.
|
|
298
|
+
|
|
299
|
+
Processes raw messages to:
|
|
300
|
+
1. Extract file information from JSON content
|
|
301
|
+
2. Filter consecutive assistant messages
|
|
302
|
+
3. Remove trailing assistant message for web scene
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
user_id: User ID (str)
|
|
306
|
+
query_user_id: Query user ID for help-ask scenarios
|
|
307
|
+
session_id: Session ID
|
|
308
|
+
scene: Scene identifier (uses adapter's scene if not provided)
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
Processed list of messages
|
|
312
|
+
"""
|
|
313
|
+
effective_scene = scene or self.get_scene()
|
|
314
|
+
messages = await get_last_message(user_id, query_user_id, session_id, scene=effective_scene)
|
|
315
|
+
|
|
316
|
+
# Process messages to extract files from JSON content
|
|
317
|
+
new_messages = []
|
|
318
|
+
for m in messages:
|
|
319
|
+
content = m.get("content", "")
|
|
320
|
+
role = m.get("role", "user")
|
|
321
|
+
|
|
322
|
+
try:
|
|
323
|
+
data = json.loads(content)
|
|
324
|
+
if role == "user" and "files" in data:
|
|
325
|
+
files = data["files"]
|
|
326
|
+
new_msg = dict(
|
|
327
|
+
role="user",
|
|
328
|
+
files=[dict(
|
|
329
|
+
s3_key=f["file_key"],
|
|
330
|
+
file_name=f["filename"],
|
|
331
|
+
file_type=f["type"]
|
|
332
|
+
) for f in files],
|
|
333
|
+
type="file"
|
|
334
|
+
)
|
|
335
|
+
new_messages.append(new_msg)
|
|
336
|
+
else:
|
|
337
|
+
new_messages.append(m)
|
|
338
|
+
except (json.JSONDecodeError, TypeError):
|
|
339
|
+
new_messages.append(m)
|
|
340
|
+
|
|
341
|
+
# Filter out consecutive assistant messages, keeping only the last one in each sequence
|
|
342
|
+
filtered_messages = []
|
|
343
|
+
for i, msg in enumerate(new_messages):
|
|
344
|
+
if msg.get("role") != "assistant":
|
|
345
|
+
filtered_messages.append(msg)
|
|
346
|
+
else:
|
|
347
|
+
# Keep this assistant message if it's the last or next is not assistant
|
|
348
|
+
if i == len(new_messages) - 1 or new_messages[i + 1].get("role") != "assistant":
|
|
349
|
+
filtered_messages.append(msg)
|
|
350
|
+
else:
|
|
351
|
+
logging.debug(f"Skipping consecutive assistant message at index {i}")
|
|
352
|
+
|
|
353
|
+
return filtered_messages
|
|
354
|
+
|
|
355
|
+
#-------------------------------------------------------------------------
|
|
356
|
+
|
|
357
|
+
async def log_chat_extraction(
|
|
358
|
+
self,
|
|
359
|
+
params: ChatStreamRequest,
|
|
360
|
+
user_id: str,
|
|
361
|
+
msg_id: str
|
|
362
|
+
):
|
|
363
|
+
"""
|
|
364
|
+
Log chat for extraction (fire-and-forget).
|
|
365
|
+
|
|
366
|
+
Only logs for self-queries (not help-ask scenarios).
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
params: Chat request parameters
|
|
370
|
+
user_id: User ID (str)
|
|
371
|
+
msg_id: Message ID
|
|
372
|
+
"""
|
|
373
|
+
if params.question and (params.query_user_id == user_id):
|
|
374
|
+
asyncio.create_task(
|
|
375
|
+
chat_list_setter_hollywell(
|
|
376
|
+
user_id=user_id,
|
|
377
|
+
msg_id=msg_id,
|
|
378
|
+
question=params.question
|
|
379
|
+
)
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
#-------------------------------------------------------------------------
|
|
383
|
+
async def prepare_unified_input(
|
|
384
|
+
self,
|
|
385
|
+
params: ChatStreamRequest,
|
|
386
|
+
user_id: int,
|
|
387
|
+
messages: list,
|
|
388
|
+
) -> dict[str, Any]:
|
|
389
|
+
"""
|
|
390
|
+
Prepare input for UnifiedChatService (common logic)
|
|
391
|
+
"""
|
|
392
|
+
|
|
393
|
+
messages = messages + [dict(role="user", content=params.question)]
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
'user_id': str(user_id),
|
|
397
|
+
'query_user_id': params.query_user_id or str(user_id),
|
|
398
|
+
'content': params.question,
|
|
399
|
+
'agent': params.agent,
|
|
400
|
+
'messages': messages,
|
|
401
|
+
'enable_mcp': bool(params.enable_mcp),
|
|
402
|
+
'trace_id': params.trace_id,
|
|
403
|
+
'session_id': self.get_session_id(params),
|
|
404
|
+
'group_id': params.group_id,
|
|
405
|
+
'file_list': params.file_list,
|
|
406
|
+
'files_data': getattr(params, 'files_data', None), # Pass downloaded file content
|
|
407
|
+
'prompt_name': params.prompt_name,
|
|
408
|
+
'token': params.token or '',
|
|
409
|
+
'language': params.language or '',
|
|
410
|
+
'timezone': params.timezone or '',
|
|
411
|
+
'provider': params.provider
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
#-----------------------------------------------------------------------------
|