From 78f938791aeb45f21a37a0d5c61cfa2d263f5906 Mon Sep 17 00:00:00 2001 From: Yuuuu <1569752928@qq.com> Date: Sun, 15 Mar 2026 18:40:00 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=A7=E7=BB=AD=E4=BC=98=E5=8C=96=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E7=BB=93=E6=9E=84=E8=BF=9B=E4=B8=80=E6=AD=A5=E6=94=B9?= =?UTF-8?q?=E8=BF=9B=E6=96=87=E6=A1=A3=E6=9B=B4=E6=96=B0=E4=B8=8E=E7=BA=A6?= =?UTF-8?q?=E6=9D=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 112 +++++++---- backend/app/__init__.py | 2 + backend/app/api/__init__.py | 16 +- .../api/{rag.py => ai_logs_api/__init__.py} | 2 +- .../helpers.py} | 2 +- .../api/{ai_logs.py => ai_logs_api/routes.py} | 10 +- backend/app/api/ai_pmo.py | 5 - backend/app/api/ai_pmo_api/shared.py | 6 +- backend/app/api/ai_steward.py | 5 - .../ai_steward_api/routes_brief_blockers.py | 2 +- .../app/api/ai_steward_api/routes_capture.py | 6 +- .../api/ai_steward_api/routes_conflicts.py | 6 +- .../api/ai_steward_api/routes_stats_config.py | 6 +- .../app/api/ai_steward_api/routes_workflow.py | 6 +- backend/app/api/ai_steward_api/shared.py | 22 +-- backend/app/api/audit.py | 2 +- backend/app/api/auth.py | 2 +- backend/app/api/budget.py | 4 +- backend/app/api/context.py | 4 +- .../app/api/endpoints/skill_api/bindings.py | 4 +- .../app/api/endpoints/skill_api/recommend.py | 4 +- backend/app/api/endpoints/skill_api/tags.py | 4 +- .../app/api/endpoints/skill_api/workload.py | 4 +- backend/app/api/experiments.py | 2 +- backend/app/api/feedbacks.py | 2 +- backend/app/api/feishu.py | 7 - backend/app/api/feishu_api/config_routes.py | 6 +- .../api/feishu_api/long_connection_routes.py | 2 +- backend/app/api/feishu_api/message_routes.py | 4 +- backend/app/api/feishu_api/test_routes.py | 6 +- backend/app/api/knowledge_graph.py | 6 +- backend/app/api/llm_engines.py | 4 +- backend/app/api/model_capability.py | 5 - .../app/api/model_capability_api/shared.py | 12 +- backend/app/api/model_routing.py | 4 +- backend/app/api/notifications.py | 2 +- backend/app/api/projects.py | 5 - backend/app/api/projects_api/shared.py | 8 +- backend/app/api/prompt_profiles.py | 4 +- backend/app/api/rag_api/shared.py | 4 +- backend/app/api/recipes.py | 4 +- backend/app/api/router.py | 24 +-- backend/app/api/scheduler.py | 10 +- .../__init__.py} | 2 +- .../helpers.py} | 2 +- .../routes.py} | 12 +- .../schemas.py} | 0 backend/app/api/signals.py | 7 - backend/app/api/signals_api/feedback.py | 2 +- backend/app/api/signals_api/ingest_fetch.py | 12 +- backend/app/api/signals_api/list_create.py | 2 +- .../{users.py => skill_tags_api/__init__.py} | 2 +- .../contracts.py} | 2 +- .../routes.py} | 16 +- backend/app/api/sstc_api/shared.py | 21 +- backend/app/api/task_briefs.py | 4 +- backend/app/api/tasks.py | 8 +- backend/app/api/users_api/shared.py | 6 +- backend/app/api/webhooks.py | 6 +- backend/app/api/wecom.py | 7 - backend/app/api/wecom_api/config.py | 4 +- backend/app/api/wecom_api/messaging.py | 4 +- backend/app/api/wecom_api/webhook.py | 4 +- backend/app/api/workloads.py | 4 +- backend/app/{ => core}/database.py | 8 +- backend/app/{ => core}/events.py | 0 backend/app/{ => core}/events_models.py | 2 +- .../startup/db_guard.py} | 4 +- .../startup/feishu_outbox.py} | 8 +- .../startup/model_probe.py} | 4 +- .../startup/world_model_warmup.py} | 12 +- backend/app/{ => core}/websocket.py | 2 +- backend/app/dependencies/auth.py | 2 +- backend/app/dependencies/permissions.py | 2 +- backend/app/deps.py | 5 + backend/app/dispatcher.py | 180 ----------------- backend/app/dispatcher_rules.py | 179 ----------------- backend/app/main.py | 20 +- backend/app/services/adaptive_rag_service.py | 5 - .../adaptive_rag_service/shared_imports.py | 16 +- .../services/ai_orchestration_run/__init__.py | 5 + .../service.py} | 4 +- .../app/services/ai_pmo_cadence_service.py | 5 - .../app/services/ai_pmo_decision/shared.py | 2 +- .../app/services/ai_pmo_decision_runtime.py | 21 -- backend/app/services/ai_pmo_intent/shared.py | 4 +- backend/app/services/ai_pmo_intent_routing.py | 3 - .../app/services/ai_pmo_kernel/__init__.py | 19 ++ .../{ => ai_pmo_kernel}/ai_agent_kernel.py | 0 .../ai_pmo_domain_workflow.py | 2 +- .../ai_pmo_kernel_mixins_closure.py | 0 .../ai_pmo_kernel_mixins_closure_data.py | 2 +- .../ai_pmo_kernel_mixins_closure_helpers.py | 2 +- .../ai_pmo_kernel_mixins_closure_payload.py | 2 +- .../ai_pmo_kernel_mixins_followup.py | 0 ...o_kernel_mixins_followup_project_signal.py | 0 ..._mixins_followup_project_signal_actions.py | 2 +- ...l_mixins_followup_project_signal_resume.py | 2 +- .../ai_pmo_kernel_mixins_followup_records.py | 2 +- .../ai_pmo_kernel_mixins_followup_routing.py | 2 +- ...pmo_kernel_mixins_followup_verification.py | 2 +- .../ai_pmo_kernel_mixins_ingress.py | 2 +- .../ai_pmo_kernel_mixins_ingress_render.py | 2 +- .../ai_pmo_kernel_mixins_ingress_storage.py | 2 +- .../ai_pmo_kernel_mixins_intent.py | 0 .../ai_pmo_kernel_mixins_intent_llm.py | 2 +- .../ai_pmo_kernel_mixins_intent_resolve.py | 2 +- .../ai_pmo_kernel_mixins_intent_rules.py | 2 +- .../ai_pmo_kernel_mixins_world_model.py | 4 +- ...i_pmo_kernel_mixins_world_model_session.py | 2 +- .../ai_pmo_kernel_runtime.py | 2 +- .../ai_pmo_reply_renderer.py | 2 +- .../ai_pmo_review_service.py | 2 +- .../ai_pmo_typed_executor.py | 4 +- .../ai_pmo_typed_executor_common.py | 20 +- .../ai_pmo_typed_executor_mixins_parse.py | 0 .../ai_pmo_workflow_runtime.py | 8 +- backend/app/services/ai_pmo_kernel_common.py | 5 - .../ai_pmo_kernel_common_core/__init__.py | 6 +- .../ai_pmo_kernel_common_core/imports.py | 28 +-- .../ai_pmo_kernel_ingress_flow/shared.py | 2 +- .../ai_pmo_kernel_mixins_ingress_flow.py | 5 - ...mo_kernel_mixins_world_model_aggregates.py | 7 - .../ai_pmo_kernel_mixins_world_model_core.py | 7 - backend/app/services/ai_pmo_kernel_service.py | 5 - .../mixin_basics.py | 2 +- .../mixin_project.py | 2 +- .../shared.py | 2 +- .../mixin_builder.py | 2 +- .../mixin_cache.py | 2 +- .../mixin_project.py | 2 +- .../ai_pmo_kernel_world_model_core/shared.py | 2 +- .../mixin_analysis.py | 2 +- .../mixin_context.py | 2 +- .../mixin_discover.py | 2 +- .../ai_pmo_typed_executor_discovery/shared.py | 2 +- .../mixin_execute_query_project.py | 2 +- .../mixin_execute_signal_create.py | 2 +- .../mixin_execute_signal_source.py | 2 +- .../mixin_helpers.py | 2 +- .../ai_pmo_typed_executor_execute/service.py | 2 +- .../ai_pmo_typed_executor_execute/shared.py | 2 +- .../ai_pmo_typed_executor_mixins_discovery.py | 5 - .../ai_pmo_typed_executor_mixins_execute.py | 5 - backend/app/services/ai_service.py | 5 - .../mixin_business_analysis.py | 12 +- .../ai_service_core/mixin_business_tasks.py | 6 +- .../mixin_runtime_prompt_retry.py | 6 +- .../app/services/ai_service_core/shared.py | 2 +- backend/app/services/ai_steward.py | 5 - .../app/services/ai_steward_service/shared.py | 6 +- .../app/services/alignment_orchestrator.py | 0 .../services/audit_query_service/__init__.py | 5 + .../service.py} | 6 +- backend/app/services/auditor.py | 3 - backend/app/services/auth/__init__.py | 19 ++ .../app/services/{auth.py => auth/service.py} | 2 +- backend/app/services/auto_merger.py | 19 -- .../auto_merger_core/mixin_events_guard.py | 6 +- .../app/services/auto_merger_core/shared.py | 2 +- backend/app/services/blocker_detection.py | 8 - .../services/blocker_detection_core/shared.py | 2 +- .../services/budget_enforcement_service.py | 5 - backend/app/services/codegen.py | 19 -- backend/app/services/cognitive_conflict.py | 8 - .../cognitive_conflict_core/shared.py | 2 +- backend/app/services/context_cache.py | 5 - backend/app/services/daily_briefing.py | 5 - .../services/daily_briefing_core/shared.py | 2 +- backend/app/services/domain.py | 21 -- .../app/services/domain_core/mixin_crud.py | 6 +- .../domain_core/mixin_runtime_stats.py | 2 +- backend/app/services/event_workflow.py | 3 - .../services/event_workflow_core/shared.py | 4 +- .../app/services/experiment_sync_service.py | 5 - backend/app/services/feishu_integration.py | 5 - .../feishu_integration_service/shared.py | 6 +- .../app/services/feishu_long_connection.py | 13 -- .../feishu_long_connection_core/shared.py | 2 +- .../app/services/feishu_outbox/__init__.py | 5 + .../service.py} | 2 +- .../app/services/feishu_signal_pipeline.py | 5 - .../feishu_signal_pipeline/shared_core.py | 30 +-- backend/app/services/integration.py | 27 --- .../lark_service.py} | 0 .../integration_core/mixin_clients.py | 4 +- .../services/integration_core/mixin_sync.py | 4 +- .../plane_service.py} | 0 backend/app/services/llm.py | 5 - backend/app/services/llm_client.py | 184 ------------------ .../services/llm_service/shared_part_01.py | 4 +- .../cost_optimization_service.py | 2 +- .../model_capability/mixin_cost_tracking.py | 2 +- .../model_lifecycle_service.py | 2 +- .../app/services/model_capability/shared.py | 2 +- .../app/services/model_capability_service.py | 5 - .../model_context_bundle/mixin_build.py | 2 +- .../model_context_bundle/mixin_verify.py | 2 +- .../services/model_context_bundle/shared.py | 6 +- .../services/model_context_bundle_service.py | 15 -- .../app/services/model_routing/__init__.py | 5 + .../service.py} | 4 +- .../services/notification_service/__init__.py | 5 + .../service.py} | 4 +- .../operation_catalog_service/__init__.py | 5 + .../service.py} | 2 +- .../operation_log_service/__init__.py | 5 + .../service.py} | 4 +- .../app/services/project_knowledge_graph.py | 5 - .../project_knowledge_graph_service/shared.py | 4 +- .../app/services/project_member/__init__.py | 15 ++ .../service.py} | 4 +- .../app/services/prompt_profile/__init__.py | 5 + .../service.py} | 6 +- backend/app/services/recipe/__init__.py | 5 + .../{recipe_service.py => recipe/service.py} | 10 +- backend/app/services/scheduler_center.py | 15 -- .../scheduler_center_core/ai_pmo_cadence.py | 2 +- .../scheduler_center_core/knowledge_graph.py | 2 +- .../services/scheduler_center_core/shared.py | 7 +- .../scheduler_center_core/workload.py | 10 +- backend/app/services/signal_capture.py | 5 - .../external_fetcher.py} | 0 .../impact_analyzer.py} | 0 .../mixin_external_sources.py | 2 +- .../mixin_source_analyzers.py | 2 +- .../services/signal_capture_service/shared.py | 12 +- backend/app/services/signal_planner/shared.py | 10 +- .../signal_strategic_analysis_service.py | 4 +- .../app/services/signal_planner_service.py | 5 - .../signal_source_orchestration/shared.py | 8 +- .../signal_source_orchestration_service.py | 5 - .../services/signal_source_repair/shared.py | 2 +- .../services/signal_source_repair_service.py | 15 -- backend/app/services/skill/shared.py | 2 +- .../{ => skill}/skill_score_service.py | 10 +- backend/app/services/skill_service.py | 3 - backend/app/services/sstc/shared.py | 24 +-- backend/app/services/sstc_service.py | 3 - backend/app/services/symbol_index_service.py | 5 - backend/app/services/task_brief_service.py | 5 - backend/app/services/task_persistence.py | 35 ---- .../services/task_persistence_core/persist.py | 2 +- .../services/task_persistence_core/shared.py | 2 +- backend/app/services/wecom/__init__.py | 5 + .../service.py} | 4 +- backend/app/services/workload/shared.py | 2 +- .../{ => workload}/workload_alert_service.py | 2 +- backend/app/services/workload_service.py | 20 -- backend/app/state.py | 18 -- .../project_command_utils.py | 0 backend/app/utils/project_members.py | 2 +- backend/app/{ => utils}/seed_projects.py | 6 +- .../app/{ => utils}/seed_projects_helpers.py | 0 backend/evals/feishu_replay_eval.py | 4 +- .../evals/rag_project_understanding_eval.py | 2 +- .../scripts/backfill_orphan_signal_links.py | 2 +- backend/{ => scripts/dev}/check_users.py | 6 +- backend/{ => scripts/dev}/seed_all.py | 9 +- backend/{ => scripts/legacy}/init_db.py | 15 +- 260 files changed, 641 insertions(+), 1455 deletions(-) create mode 100644 backend/app/__init__.py rename backend/app/api/{rag.py => ai_logs_api/__init__.py} (67%) rename backend/app/api/{ai_logs_utils.py => ai_logs_api/helpers.py} (97%) rename backend/app/api/{ai_logs.py => ai_logs_api/routes.py} (96%) delete mode 100644 backend/app/api/ai_pmo.py delete mode 100644 backend/app/api/ai_steward.py delete mode 100644 backend/app/api/feishu.py delete mode 100644 backend/app/api/model_capability.py delete mode 100644 backend/app/api/projects.py rename backend/app/api/{sstc.py => signal_sources_api/__init__.py} (66%) rename backend/app/api/{signal_sources_utils.py => signal_sources_api/helpers.py} (98%) rename backend/app/api/{signal_sources.py => signal_sources_api/routes.py} (96%) rename backend/app/api/{signal_sources_models.py => signal_sources_api/schemas.py} (100%) delete mode 100644 backend/app/api/signals.py rename backend/app/api/{users.py => skill_tags_api/__init__.py} (65%) rename backend/app/api/{skill_tags_contracts.py => skill_tags_api/contracts.py} (97%) rename backend/app/api/{skill_tags.py => skill_tags_api/routes.py} (96%) delete mode 100644 backend/app/api/wecom.py rename backend/app/{ => core}/database.py (97%) rename backend/app/{ => core}/events.py (100%) rename backend/app/{ => core}/events_models.py (98%) rename backend/app/{main_db_guard.py => core/startup/db_guard.py} (97%) rename backend/app/{main_feishu_outbox.py => core/startup/feishu_outbox.py} (94%) rename backend/app/{main_model_probe.py => core/startup/model_probe.py} (97%) rename backend/app/{main_warmup.py => core/startup/world_model_warmup.py} (94%) rename backend/app/{ => core}/websocket.py (99%) create mode 100644 backend/app/deps.py delete mode 100644 backend/app/dispatcher.py delete mode 100644 backend/app/dispatcher_rules.py delete mode 100644 backend/app/services/adaptive_rag_service.py create mode 100644 backend/app/services/ai_orchestration_run/__init__.py rename backend/app/services/{ai_orchestration_run_service.py => ai_orchestration_run/service.py} (98%) delete mode 100644 backend/app/services/ai_pmo_cadence_service.py delete mode 100644 backend/app/services/ai_pmo_decision_runtime.py delete mode 100644 backend/app/services/ai_pmo_intent_routing.py create mode 100644 backend/app/services/ai_pmo_kernel/__init__.py rename backend/app/services/{ => ai_pmo_kernel}/ai_agent_kernel.py (100%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_domain_workflow.py (98%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_closure.py (100%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_closure_data.py (99%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_closure_helpers.py (98%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_closure_payload.py (99%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_followup.py (100%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_followup_project_signal.py (100%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_followup_project_signal_actions.py (99%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_followup_project_signal_resume.py (99%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_followup_records.py (98%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_followup_routing.py (99%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_followup_verification.py (99%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_ingress.py (85%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_ingress_render.py (99%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_ingress_storage.py (99%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_intent.py (100%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_intent_llm.py (99%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_intent_resolve.py (98%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_intent_rules.py (99%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_world_model.py (69%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_mixins_world_model_session.py (98%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_kernel_runtime.py (97%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_reply_renderer.py (99%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_review_service.py (98%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_typed_executor.py (81%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_typed_executor_common.py (82%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_typed_executor_mixins_parse.py (100%) rename backend/app/services/{ => ai_pmo_kernel}/ai_pmo_workflow_runtime.py (97%) delete mode 100644 backend/app/services/ai_pmo_kernel_common.py delete mode 100644 backend/app/services/ai_pmo_kernel_mixins_ingress_flow.py delete mode 100644 backend/app/services/ai_pmo_kernel_mixins_world_model_aggregates.py delete mode 100644 backend/app/services/ai_pmo_kernel_mixins_world_model_core.py delete mode 100644 backend/app/services/ai_pmo_kernel_service.py delete mode 100644 backend/app/services/ai_pmo_typed_executor_mixins_discovery.py delete mode 100644 backend/app/services/ai_pmo_typed_executor_mixins_execute.py delete mode 100644 backend/app/services/ai_service.py delete mode 100644 backend/app/services/ai_steward.py delete mode 100644 backend/app/services/alignment_orchestrator.py create mode 100644 backend/app/services/audit_query_service/__init__.py rename backend/app/services/{audit_query_service.py => audit_query_service/service.py} (95%) delete mode 100644 backend/app/services/auditor.py create mode 100644 backend/app/services/auth/__init__.py rename backend/app/services/{auth.py => auth/service.py} (99%) delete mode 100644 backend/app/services/auto_merger.py delete mode 100644 backend/app/services/blocker_detection.py delete mode 100644 backend/app/services/budget_enforcement_service.py delete mode 100644 backend/app/services/codegen.py delete mode 100644 backend/app/services/cognitive_conflict.py delete mode 100644 backend/app/services/context_cache.py delete mode 100644 backend/app/services/daily_briefing.py delete mode 100644 backend/app/services/domain.py delete mode 100644 backend/app/services/event_workflow.py delete mode 100644 backend/app/services/experiment_sync_service.py delete mode 100644 backend/app/services/feishu_integration.py delete mode 100644 backend/app/services/feishu_long_connection.py create mode 100644 backend/app/services/feishu_outbox/__init__.py rename backend/app/services/{feishu_outbox_service.py => feishu_outbox/service.py} (98%) delete mode 100644 backend/app/services/feishu_signal_pipeline.py delete mode 100644 backend/app/services/integration.py rename backend/app/services/{lark.py => integration_core/lark_service.py} (100%) rename backend/app/services/{plane.py => integration_core/plane_service.py} (100%) delete mode 100644 backend/app/services/llm.py delete mode 100644 backend/app/services/llm_client.py rename backend/app/services/{ => model_capability}/cost_optimization_service.py (98%) rename backend/app/services/{ => model_capability}/model_lifecycle_service.py (99%) delete mode 100644 backend/app/services/model_capability_service.py delete mode 100644 backend/app/services/model_context_bundle_service.py create mode 100644 backend/app/services/model_routing/__init__.py rename backend/app/services/{model_routing_service.py => model_routing/service.py} (99%) create mode 100644 backend/app/services/notification_service/__init__.py rename backend/app/services/{notification_service.py => notification_service/service.py} (99%) create mode 100644 backend/app/services/operation_catalog_service/__init__.py rename backend/app/services/{operation_catalog_service.py => operation_catalog_service/service.py} (97%) create mode 100644 backend/app/services/operation_log_service/__init__.py rename backend/app/services/{operation_log_service.py => operation_log_service/service.py} (93%) delete mode 100644 backend/app/services/project_knowledge_graph.py create mode 100644 backend/app/services/project_member/__init__.py rename backend/app/services/{project_member_service.py => project_member/service.py} (98%) create mode 100644 backend/app/services/prompt_profile/__init__.py rename backend/app/services/{prompt_profile_service.py => prompt_profile/service.py} (98%) create mode 100644 backend/app/services/recipe/__init__.py rename backend/app/services/{recipe_service.py => recipe/service.py} (96%) delete mode 100644 backend/app/services/scheduler_center.py delete mode 100644 backend/app/services/signal_capture.py rename backend/app/services/{fetcher.py => signal_capture_service/external_fetcher.py} (100%) rename backend/app/services/{analyzer.py => signal_capture_service/impact_analyzer.py} (100%) rename backend/app/services/{ => signal_planner}/signal_strategic_analysis_service.py (97%) delete mode 100644 backend/app/services/signal_planner_service.py delete mode 100644 backend/app/services/signal_source_orchestration_service.py delete mode 100644 backend/app/services/signal_source_repair_service.py rename backend/app/services/{ => skill}/skill_score_service.py (96%) delete mode 100644 backend/app/services/skill_service.py delete mode 100644 backend/app/services/sstc_service.py delete mode 100644 backend/app/services/symbol_index_service.py delete mode 100644 backend/app/services/task_brief_service.py delete mode 100644 backend/app/services/task_persistence.py create mode 100644 backend/app/services/wecom/__init__.py rename backend/app/services/{wecom_integration.py => wecom/service.py} (98%) rename backend/app/services/{ => workload}/workload_alert_service.py (99%) delete mode 100644 backend/app/services/workload_service.py delete mode 100644 backend/app/state.py rename backend/app/{services => utils}/project_command_utils.py (100%) rename backend/app/{ => utils}/seed_projects.py (97%) rename backend/app/{ => utils}/seed_projects_helpers.py (100%) rename backend/{ => scripts/dev}/check_users.py (83%) rename backend/{ => scripts/dev}/seed_all.py (97%) rename backend/{ => scripts/legacy}/init_db.py (79%) diff --git a/CLAUDE.md b/CLAUDE.md index 84c7eea5..5d85d784 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -34,8 +34,11 @@ AIProjectManger/ ```text backend/ ├── app/ +│ ├── __init__.py # app 包入口(根目录轻量化后保留) │ ├── api/ # 路由层(含 endpoints) │ ├── core/ # 配置、日志、核心能力 +│ │ └── startup/ # 启动阶段拆分模块(db guard/outbox/probe/warmup) +│ ├── deps.py # 共享依赖导出(get_db/AsyncSessionLocal) │ ├── dependencies/ # 鉴权/租户等依赖注入 │ ├── middleware/ # 请求中间件(审计上下文注入等) │ ├── models/ # SQLAlchemy 模型 @@ -53,25 +56,27 @@ backend/ │ ├── 20260311_expand_user_workload_ratio_precision.py # user_workloads.workload_ratio 精度扩容(10,2) │ └── 20260311_add_conversation_sessions_table.py # 飞书多轮会话上下文持久化表 ├── scripts/ # 后端运维/数据修复脚本 -│ └── backfill_orphan_signal_links.py # 回填孤立 signal 的 project_signal_links +│ ├── backfill_orphan_signal_links.py # 回填孤立 signal 的 project_signal_links +│ ├── dev/ # 开发辅助脚本(check_users/seed_all) +│ └── legacy/ # 历史脚本(仅保留兼容参考,不作为主流程) ├── requirements.txt # Python 依赖 ├── Dockerfile └── (tests 已移除) ``` - 新增:`backend/app/api/llm_providers.py`(AI 管家 LLM provider preset 配置读取接口) -- 新增:`backend/app/services/ai_agent_kernel.py`(双 Agent 共享决策内核:复杂度路由/执行门控/修正识别) +- 新增:`backend/app/services/ai_pmo_kernel/ai_agent_kernel.py`(双 Agent 共享决策内核:复杂度路由/执行门控/修正识别) - 新增:`backend/app/utils/timezone.py`(统一北京时间工具:`now_cn_aware/now_cn_naive`) - 新增:`backend/app/utils/audited_write.py`(写接口审计上下文、caller 归一、北京时间格式化) - 新增:`backend/app/middleware/audit_context.py`(请求级 trace/interface/caller 注入) - 新增:`backend/app/api/audit.py`(审计查询接口:`GET /audit/operations`) -- 新增:`backend/app/services/audit_query_service.py`(operation_logs 过滤与序列化) +- 新增:`backend/app/services/audit_query_service/service.py`(operation_logs 过滤与序列化) - 新增:`backend/app/services/signal_source_repair_service.py`(脏信号源回填服务) - 新增:`backend/alembic/versions/20260311_shift_all_timestamps_to_beijing.py`(全库历史时间 +8h,数据库默认时区切到 Asia/Shanghai) - 新增:`backend/alembic/versions/20260312_add_signal_planner_fields.py`(signals 增加 planner 状态字段与索引) -- 新增:`backend/app/services/signal_strategic_analysis_service.py`(Signal Planner 写回收口) -- 新增:`backend/app/services/feishu_outbox_service.py`(复用 reply_hash 的 outbox 入队收口) +- 新增:`backend/app/services/signal_planner/signal_strategic_analysis_service.py`(Signal Planner 写回收口) +- 新增:`backend/app/services/feishu_outbox/service.py`(复用 reply_hash 的 outbox 入队收口) - 新增:`backend/app/services/signal_planner_service.py`(Signal Planner 异步分析服务) -- 新增:`backend/app/services/model_routing_service.py`(函数级模型路由配置服务) +- 新增:`backend/app/services/model_routing/service.py`(函数级模型路由配置服务) - 新增:`backend/app/services/task_brief_service.py`(增量任务包中心服务) - 新增:`backend/app/services/model_context_bundle_service.py`(双模型上下文组包/能力汇总/消费验证服务) - 新增:`backend/app/api/model_routing.py`(模型路由配置接口) @@ -84,42 +89,42 @@ backend/ - 更新:`backend/app/services/signal_source_orchestration_service.py`(信号源 onboarding 规划与 worker 执行失败均 fail-fast,不再回退 heuristic/fallback 摘要) - 更新:`backend/app/services/project_knowledge_graph.py`(新增 `ai_model -> governance_policy -> interface` 治理图谱同步能力,增量任务新增 `model_guardrails` 阶段) - 移除:`backend/.env.example`(配置模板统一到根目录 `.env.example`) -- 新增:`backend/app/services/project_command_utils.py`(项目创建标题/描述提取与归一化辅助) +- 新增:`backend/app/utils/project_command_utils.py`(项目创建标题/描述提取与归一化辅助) - 新增:`backend/app/services/ai_pmo_intent_routing.py`(AI PMO 意图/路由常量与解析器收口,统一 `family.action` 路由映射) -- 新增:`backend/app/services/ai_pmo_workflow_runtime.py`(AI PMO `ContextAssembler` + `WorkflowRegistry/WorkflowHandler` 运行时骨架) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_workflow_runtime.py`(AI PMO `ContextAssembler` + `WorkflowRegistry/WorkflowHandler` 运行时骨架) - 新增:`backend/app/services/ai_pmo_decision_runtime.py`(AI PMO 决策脑层:`Strategic/Tactical/Simulation/ExecutionPolicy/DecisionEngine`) -- 新增:`backend/app/services/ai_pmo_reply_renderer.py`(AI PMO 回执渲染出口 `ReplyRenderer`) -- 新增:`backend/app/services/ai_pmo_typed_executor.py`(AI PMO typed 执行层组合入口) -- 新增:`backend/app/services/ai_pmo_typed_executor_common.py`(TypedExecutor 共享常量/依赖) -- 新增:`backend/app/services/ai_pmo_typed_executor_mixins_parse.py`(TypedExecutor 解析与批量分析逻辑) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_reply_renderer.py`(AI PMO 回执渲染出口 `ReplyRenderer`) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_typed_executor.py`(AI PMO typed 执行层组合入口) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_typed_executor_common.py`(TypedExecutor 共享常量/依赖) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_typed_executor_mixins_parse.py`(TypedExecutor 解析与批量分析逻辑) - 新增:`backend/app/services/ai_pmo_typed_executor_mixins_discovery.py`(TypedExecutor discover 候选上下文逻辑) - 新增:`backend/app/services/ai_pmo_typed_executor_mixins_execute.py`(TypedExecutor execute/create/source-onboard 落库逻辑) -- 新增:`backend/app/services/ai_pmo_kernel_runtime.py`(AI PMO kernel 组合入口) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_runtime.py`(AI PMO kernel 组合入口) - 新增:`backend/app/services/ai_pmo_kernel_common.py`(Kernel 共享常量/依赖) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_ingress.py`(Kernel ingress 组合入口) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_ingress.py`(Kernel ingress 组合入口) - 新增:`backend/app/services/ai_pmo_kernel_mixins_ingress_flow.py`(Kernel 入站主流程编排) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_ingress_storage.py`(Kernel 入站事件/工作项写入) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_ingress_render.py`(Kernel 入站结果组装与输出辅助) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_world_model.py`(Kernel world-model 组合入口) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_ingress_storage.py`(Kernel 入站事件/工作项写入) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_ingress_render.py`(Kernel 入站结果组装与输出辅助) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_world_model.py`(Kernel world-model 组合入口) - 新增:`backend/app/services/ai_pmo_kernel_mixins_world_model_core.py`(Kernel world-model 核心构建与缓存) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_world_model_session.py`(Kernel 会话继承与会话态维护) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_world_model_session.py`(Kernel 会话继承与会话态维护) - 新增:`backend/app/services/ai_pmo_kernel_mixins_world_model_aggregates.py`(Kernel 组合摘要构建器) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_intent.py`(Kernel intent 组合入口) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_intent_rules.py`(Kernel 规则意图与槽位守卫) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_intent_llm.py`(Kernel LLM 意图识别与仲裁) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_intent_resolve.py`(Kernel 最终意图解析入口) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_followup.py`(Kernel followup 组合入口) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_followup_records.py`(followup 决策/计划/回执写入) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_followup_routing.py`(followup 候选定位与恢复分发) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_followup_project_signal.py`(project_signal followup 组合入口) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_followup_project_signal_actions.py`(project_signal commit/refresh/cancel 动作执行) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_followup_project_signal_resume.py`(project_signal 目标工作项恢复闭环) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_followup_verification.py`(followup 执行校验与工具函数) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_closure.py`(Kernel closure 组合入口) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_closure_helpers.py`(Kernel 闭环通用归一化工具) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_closure_data.py`(Kernel 闭环历史上下文回放) -- 新增:`backend/app/services/ai_pmo_kernel_mixins_closure_payload.py`(Kernel 闭环语义与来源上下文组装) -- 更新:`backend/app/services/ai_pmo_kernel_service.py`(兼容入口层,仅导出 `AIPMOKernelService`) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent.py`(Kernel intent 组合入口) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent_rules.py`(Kernel 规则意图与槽位守卫) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent_llm.py`(Kernel LLM 意图识别与仲裁) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent_resolve.py`(Kernel 最终意图解析入口) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup.py`(Kernel followup 组合入口) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_records.py`(followup 决策/计划/回执写入) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_routing.py`(followup 候选定位与恢复分发) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_project_signal.py`(project_signal followup 组合入口) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_project_signal_actions.py`(project_signal commit/refresh/cancel 动作执行) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_project_signal_resume.py`(project_signal 目标工作项恢复闭环) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_verification.py`(followup 执行校验与工具函数) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure.py`(Kernel closure 组合入口) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure_helpers.py`(Kernel 闭环通用归一化工具) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure_data.py`(Kernel 闭环历史上下文回放) +- 新增:`backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure_payload.py`(Kernel 闭环语义与来源上下文组装) +- 移除:`backend/app/services/ai_pmo_kernel_service.py`(顶层兼容壳清理,统一改为 `backend/app/services/ai_pmo_kernel/` 子包) - 新增:`backend/app/services/feishu_signal_pipeline/`(飞书信号管道按职责拆分的服务包,所有子文件 <= 300 行) - 新增:`backend/app/services/feishu_signal_pipeline/service.py`(组合入口,按 mixin 聚合能力) - 新增:`backend/app/services/feishu_signal_pipeline/shared_core.py`、`shared_schema_utils.py`(共享常量/正则/Schema/工具函数拆分) @@ -151,11 +156,42 @@ backend/ - 新增:`backend/app/api/signals_api/`(signals 路由拆分为 list/create、ingest/fetch、feedback 子模块) - 新增:`backend/app/api/wecom_api/`(wecom 路由拆分为 config/webhook/messaging 子模块) - 新增:`backend/app/api/endpoints/skill_api/`(人员能力图谱路由拆分为 tags/bindings/workload/recommend 子模块) -- 新增:`backend/app/api/ai_logs_utils.py`、`backend/app/api/signal_sources_models.py`、`backend/app/api/signal_sources_utils.py`(API 共享序列化/Schema/项目解析工具) +- 更新:`backend/app/api/ai_logs.py`、`backend/app/api/ai_logs_utils.py` → `backend/app/api/ai_logs_api/routes.py`、`backend/app/api/ai_logs_api/helpers.py`(AI 日志 API 收敛到独立子包) +- 更新:`backend/app/api/signal_sources.py`、`backend/app/api/signal_sources_models.py`、`backend/app/api/signal_sources_utils.py` → `backend/app/api/signal_sources_api/routes.py`、`backend/app/api/signal_sources_api/schemas.py`、`backend/app/api/signal_sources_api/helpers.py`(信号源 API 收敛到独立子包) +- 更新:`backend/app/api/skill_tags.py`、`backend/app/api/skill_tags_contracts.py` → `backend/app/api/skill_tags_api/routes.py`、`backend/app/api/skill_tags_api/contracts.py`(技能标签 API 收敛到独立子包) +- 更新:`backend/app/api/router.py`、`backend/app/api/__init__.py`(直接引用 `*_api` 子模块路由,移除顶层兼容壳依赖) +- 移除:`backend/app/api/ai_pmo.py`、`backend/app/api/ai_steward.py`、`backend/app/api/model_capability.py`、`backend/app/api/projects.py`、`backend/app/api/rag.py`、`backend/app/api/sstc.py`、`backend/app/api/users.py`、`backend/app/api/feishu.py`、`backend/app/api/signals.py`、`backend/app/api/wecom.py`(顶层兼容壳清理) +- 更新:`backend/check_users.py`、`backend/seed_all.py`、`backend/init_db.py` → `backend/scripts/dev/check_users.py`、`backend/scripts/dev/seed_all.py`、`backend/scripts/legacy/init_db.py`(backend 根目录散落脚本归档) - 新增:`backend/app/config/operation_catalog_core/`(operation catalog 按模型/构造器/领域条目拆分) -- 新增:`backend/app/dispatcher_rules.py`、`backend/app/events_models.py`、`backend/app/seed_projects_helpers.py`(规则/事件模型/seed helper 拆分) -- 新增:`backend/app/main_db_guard.py`、`backend/app/main_feishu_outbox.py`、`backend/app/main_warmup.py`、`backend/app/main_model_probe.py`(main 启动职责拆分) +- 更新:`backend/app/dispatcher.py`、`backend/app/dispatcher_rules.py`(未被引用,按废弃文件移除) +- 更新:`backend/app/seed_projects.py`、`backend/app/seed_projects_helpers.py` → `backend/app/utils/seed_projects.py`、`backend/app/utils/seed_projects_helpers.py`(示例数据初始化脚本归并到 utils) +- 更新:`backend/app/database.py`、`backend/app/events.py`、`backend/app/events_models.py`、`backend/app/websocket.py` → `backend/app/core/database.py`、`backend/app/core/events.py`、`backend/app/core/events_models.py`、`backend/app/core/websocket.py`(核心基础设施归并到 core) +- 更新:`backend/app/main_db_guard.py`、`backend/app/main_feishu_outbox.py`、`backend/app/main_warmup.py`、`backend/app/main_model_probe.py` → `backend/app/core/startup/`(启动阶段职责归并) +- 更新:`backend/app/state.py`(无引用,按废弃文件移除) +- 新增:`backend/app/__init__.py`、`backend/app/deps.py`(根目录仅保留 `__init__.py / main.py / deps.py`) +- 更新:`backend/app/services/` 顶层兼容壳批量清理(如 `ai_service.py/llm.py/scheduler_center.py/signal_capture.py/...`),统一改为直接引用对应子包(`ai_service_core/llm_service/scheduler_center_core/signal_capture_service/...`) +- 更新:移除 `backend/app/services/alignment_orchestrator.py` 空文件(无引用) - 新增:`backend/app/services/ai_pmo_kernel_world_model_aggregates/`、`backend/app/services/ai_pmo_kernel_world_model_core/`、`backend/app/services/ai_pmo_kernel_common_core/`(kernel world-model/common 拆分) +- 更新:`backend/app/services/ai_pmo_kernel_runtime.py`、`backend/app/services/ai_agent_kernel.py`、`backend/app/services/ai_pmo_domain_workflow.py` 及 `backend/app/services/ai_pmo_kernel_mixins_*.py` → `backend/app/services/ai_pmo_kernel/`(AI PMO kernel 子包化,清理 services 根目录散落文件) +- 更新:`backend/app/services/ai_orchestration_run_service.py` → `backend/app/services/ai_orchestration_run/service.py`(编排运行账本服务子包化) +- 更新:`backend/app/services/ai_pmo_reply_renderer.py`、`backend/app/services/ai_pmo_review_service.py`、`backend/app/services/ai_pmo_typed_executor.py`、`backend/app/services/ai_pmo_typed_executor_common.py`、`backend/app/services/ai_pmo_typed_executor_mixins_parse.py`、`backend/app/services/ai_pmo_workflow_runtime.py` → `backend/app/services/ai_pmo_kernel/`(AI PMO 执行与回执运行时收敛到 kernel 子包) +- 更新:`backend/app/services/cost_optimization_service.py`、`backend/app/services/model_lifecycle_service.py` → `backend/app/services/model_capability/`(模型能力相关服务收敛) +- 更新:`backend/app/services/signal_strategic_analysis_service.py` → `backend/app/services/signal_planner/signal_strategic_analysis_service.py`(Signal Planner 分析写回服务归并) +- 移除:`backend/app/services/llm_client.py`(全仓库无引用,按废弃文件清理) +- 更新:`backend/app/services/analyzer.py`、`backend/app/services/fetcher.py` → `backend/app/services/signal_capture_service/impact_analyzer.py`、`backend/app/services/signal_capture_service/external_fetcher.py`(信号接入分析/抓取能力归并) +- 更新:`backend/app/services/plane.py` → `backend/app/services/integration_core/plane_service.py`(Plane 兼容服务归并到 integration_core) +- 更新:`backend/app/services/lark.py` → `backend/app/services/integration_core/lark_service.py`(Lark 兼容服务归并到 integration_core) +- 更新:`backend/app/services/workload_alert_service.py` → `backend/app/services/workload/workload_alert_service.py`(负载告警服务归并到 workload 子包) +- 更新:`backend/app/services/task_persistence.py`(兼容壳移除,统一直接引用 `backend/app/services/task_persistence_core/`) +- 更新:`backend/app/services/project_member_service.py` → `backend/app/services/project_member/service.py`(项目成员分配服务子包化) +- 更新:`backend/app/services/recipe_service.py` → `backend/app/services/recipe/service.py`(食谱服务子包化) +- 更新:`backend/app/services/model_routing_service.py` → `backend/app/services/model_routing/service.py`(模型路由服务子包化) +- 更新:`backend/app/services/prompt_profile_service.py` → `backend/app/services/prompt_profile/service.py`(Prompt 画像服务子包化) +- 更新:`backend/app/services/feishu_outbox_service.py` → `backend/app/services/feishu_outbox/service.py`(飞书 outbox 服务子包化) +- 更新:`backend/app/services/wecom_integration.py` → `backend/app/services/wecom/service.py`(企业微信集成服务子包化) +- 更新:`backend/app/services/skill_score_service.py` → `backend/app/services/skill/skill_score_service.py`(技能评分服务归并到 skill 子包) +- 更新:`backend/app/services/auth.py`、`backend/app/services/audit_query_service.py`、`backend/app/services/notification_service.py`、`backend/app/services/operation_catalog_service.py`、`backend/app/services/operation_log_service.py` → `backend/app/services/*/service.py`(同名服务子包化,`services` 根目录不再保留 `.py` 文件) +- 更新:`backend/app/services/` 根目录 `.py` 已清零(全部收敛到子包),仅保留目录化服务结构 ## 5. 前端结构(`frontend/`) ```text @@ -299,7 +335,7 @@ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 - 配置读取类接口:参考 `backend/app/api/llm_providers.py`(`GET /ai-steward/llm/providers`) - AI Steward 指挥规划接口已移除:`POST /ai-steward/command/dispatch` - 项目删除接口(`DELETE /projects/{project_id}`):参考 `backend/app/api/projects.py`,先清理强依赖外键、再置空弱依赖外键、最后删除主记录(单事务提交) -- 项目成员分配接口(`PUT /projects/{project_id}/members`):参考 `backend/app/api/projects.py` + `backend/app/services/project_member_service.py`,要求显式传入 `member_user_ids` 并写入 `user_projects` +- 项目成员分配接口(`PUT /projects/{project_id}/members`):参考 `backend/app/api/projects.py` + `backend/app/services/project_member/service.py`,要求显式传入 `member_user_ids` 并写入 `user_projects` - SSTC 总览接口(`GET /projects/{project_id}/sstc/overview`):`workload_health` 返回成员明细 `members[]`(姓名/角色/负载比例/状态)用于头部卡片展示 - AI PMO 审批接口(`POST /ai-pmo/work-items/{work_item_id}/decision`):显式 `approve/reject`,`reject` 必须落 `ignored`(失效)并同步 `decision_records.final_outcome` - AI PMO 审批接口补充:`approve + waiting_manual + project_id` 走“快速返回 + 后台继续执行”,避免前端长时间阻塞 diff --git a/backend/app/__init__.py b/backend/app/__init__.py new file mode 100644 index 00000000..2eac1506 --- /dev/null +++ b/backend/app/__init__.py @@ -0,0 +1,2 @@ +"""PMFlow app package.""" + diff --git a/backend/app/api/__init__.py b/backend/app/api/__init__.py index 97e47afc..8de3e614 100644 --- a/backend/app/api/__init__.py +++ b/backend/app/api/__init__.py @@ -4,20 +4,20 @@ API 路由模块 按业务域拆分路由,便于维护与扩展。 """ -from .signals import router as signals_router +from .signals_api import router as signals_router from .feedbacks import router as feedbacks_router from .experiments import router as experiments_router from .context import router as context_router from .tasks import router as tasks_router from .webhooks import router as webhooks_router from .auth import router as auth_router -from .users import router as users_router +from .users_api import router as users_router from .endpoints.skill import router as skill_router -from .sstc import router as sstc_router -from .ai_steward import router as ai_steward_router -from .feishu import router as feishu_router -from .wecom import router as wecom_router -from .model_capability import router as model_capability_router +from .sstc_api import router as sstc_router +from .ai_steward_api import router as ai_steward_router +from .feishu_api import router as feishu_router +from .wecom_api import router as wecom_router +from .model_capability_api import router as model_capability_router from .budget import router as budget_router from .scheduler import router as scheduler_router from .notifications import router as notifications_router @@ -26,7 +26,7 @@ from .llm_providers import router as llm_providers_router from .prompt_profiles import router as prompt_profiles_router from .knowledge_graph import router as knowledge_graph_router from .operation_catalog import router as operation_catalog_router -from .ai_pmo import router as ai_pmo_router +from .ai_pmo_api import router as ai_pmo_router __all__ = [ "signals_router", diff --git a/backend/app/api/rag.py b/backend/app/api/ai_logs_api/__init__.py similarity index 67% rename from backend/app/api/rag.py rename to backend/app/api/ai_logs_api/__init__.py index a0f0fb3a..8a2ebbc6 100644 --- a/backend/app/api/rag.py +++ b/backend/app/api/ai_logs_api/__init__.py @@ -1,5 +1,5 @@ from __future__ import annotations -from .rag_api import router +from .routes import router __all__ = ["router"] diff --git a/backend/app/api/ai_logs_utils.py b/backend/app/api/ai_logs_api/helpers.py similarity index 97% rename from backend/app/api/ai_logs_utils.py rename to backend/app/api/ai_logs_api/helpers.py index 73a33a4f..db82074e 100644 --- a/backend/app/api/ai_logs_utils.py +++ b/backend/app/api/ai_logs_api/helpers.py @@ -7,7 +7,7 @@ from typing import Any, Optional from sqlalchemy import and_, func, or_, select, union_all -from ..models import AIProcessingLog, FeishuItem, ProjectSignalLink, ProjectSuggestion, Signal, WorkItem +from ...models import AIProcessingLog, FeishuItem, ProjectSignalLink, ProjectSuggestion, Signal, WorkItem def normalize_bullets(value: Any) -> list[str]: diff --git a/backend/app/api/ai_logs.py b/backend/app/api/ai_logs_api/routes.py similarity index 96% rename from backend/app/api/ai_logs.py rename to backend/app/api/ai_logs_api/routes.py index eeb69e2d..4ceedfe7 100644 --- a/backend/app/api/ai_logs.py +++ b/backend/app/api/ai_logs_api/routes.py @@ -9,11 +9,11 @@ from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy import and_, case, func, select from sqlalchemy.ext.asyncio import AsyncSession -from ..core.response import success_response -from ..database import get_db -from ..dependencies.auth import get_current_user -from ..models import AIProcessingLog, User -from .ai_logs_utils import apply_project_filter, serialize_log_detail, serialize_log_row +from ...core.response import success_response +from ...core.database import get_db +from ...dependencies.auth import get_current_user +from ...models import AIProcessingLog, User +from .helpers import apply_project_filter, serialize_log_detail, serialize_log_row router = APIRouter(prefix="/ai-logs", tags=["AI Logs"]) diff --git a/backend/app/api/ai_pmo.py b/backend/app/api/ai_pmo.py deleted file mode 100644 index 450d33e2..00000000 --- a/backend/app/api/ai_pmo.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .ai_pmo_api import router - -__all__ = ["router"] diff --git a/backend/app/api/ai_pmo_api/shared.py b/backend/app/api/ai_pmo_api/shared.py index 732b3c5f..3885e1bf 100644 --- a/backend/app/api/ai_pmo_api/shared.py +++ b/backend/app/api/ai_pmo_api/shared.py @@ -12,12 +12,12 @@ from sqlalchemy.ext.asyncio import AsyncSession from ...core.logging import get_logger from ...core.response import success_response -from ...database import AsyncSessionLocal, get_db +from ...core.database import AsyncSessionLocal, get_db from ...dependencies.auth import get_current_user from ...dependencies.tenant import get_tenant_id from ...models import DecisionRecord, IngestEvent, PlanBundle, PortfolioSnapshot, Project, ReplyReceipt, User, WorkItem -from ...services.ai_pmo_cadence_service import AIPMOCadenceService -from ...services.ai_pmo_kernel_service import AIPMOKernelService +from ...services.ai_pmo_cadence import AIPMOCadenceService +from ...services.ai_pmo_kernel import AIPMOKernelService router = APIRouter(prefix="/ai-pmo", tags=["AI PMO"]) logger = get_logger(__name__) diff --git a/backend/app/api/ai_steward.py b/backend/app/api/ai_steward.py deleted file mode 100644 index 99f444df..00000000 --- a/backend/app/api/ai_steward.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .ai_steward_api import router - -__all__ = ["router"] diff --git a/backend/app/api/ai_steward_api/routes_brief_blockers.py b/backend/app/api/ai_steward_api/routes_brief_blockers.py index 19cb628f..c41e37bb 100644 --- a/backend/app/api/ai_steward_api/routes_brief_blockers.py +++ b/backend/app/api/ai_steward_api/routes_brief_blockers.py @@ -78,7 +78,7 @@ async def analyze_blocker( 当开发在代码注释中提到「这个接口达不到效果」时, AI 自动触发分析,推荐替代方案或生成代码片段 """ - from ..services.llm import LLMService + from ...services.llm_service import LLMService service = get_ai_steward_service(db) diff --git a/backend/app/api/ai_steward_api/routes_capture.py b/backend/app/api/ai_steward_api/routes_capture.py index 074f65fa..60e0e692 100644 --- a/backend/app/api/ai_steward_api/routes_capture.py +++ b/backend/app/api/ai_steward_api/routes_capture.py @@ -181,8 +181,8 @@ async def sync_external_signal( - GitHub commits/PRs - 浏览器标签页 """ - from ..models import Signal - from ..services.ai_steward import get_ai_steward_service + from ...models import Signal + from ...services.ai_steward_service import get_ai_steward_service service = get_ai_steward_service(db) @@ -200,7 +200,7 @@ async def sync_external_signal( 以 JSON 格式返回。""" try: - from ..services.llm import LLMService + from ...services.llm_service import LLMService llm = LLMService() response = await llm.generate( prompt, diff --git a/backend/app/api/ai_steward_api/routes_conflicts.py b/backend/app/api/ai_steward_api/routes_conflicts.py index 30761b2b..371588cb 100644 --- a/backend/app/api/ai_steward_api/routes_conflicts.py +++ b/backend/app/api/ai_steward_api/routes_conflicts.py @@ -18,7 +18,7 @@ async def get_cognitive_conflicts( - 产品说"用户留存提升10%",开发实现的是"DAU提升10%" - 双方没有争论,但目标不一致,AI 会主动识别并推送对齐提醒 """ - from ..models import CognitiveConflict, TruthNode + from ...models import CognitiveConflict, TruthNode from sqlalchemy.future import select query = select(CognitiveConflict).where( @@ -162,7 +162,7 @@ async def resolve_cognitive_conflict( AI 会生成解决方案建议,双方确认后标记为已解决 """ - from ..models import CognitiveConflict + from ...models import CognitiveConflict from sqlalchemy.future import select result = await db.execute( @@ -199,7 +199,7 @@ async def check_task_charter_mismatch( 2. 技术选型是否符合约束 3. 是否偏离项目方向 """ - from ..models import Task, TruthNode + from ...models import Task, TruthNode from sqlalchemy.future import select try: diff --git a/backend/app/api/ai_steward_api/routes_stats_config.py b/backend/app/api/ai_steward_api/routes_stats_config.py index 6b2df458..6e976ec6 100644 --- a/backend/app/api/ai_steward_api/routes_stats_config.py +++ b/backend/app/api/ai_steward_api/routes_stats_config.py @@ -18,7 +18,7 @@ async def get_ai_steward_stats( - 自动解决的阻塞数 - 节省的会议时间(小时) """ - from ..models import Signal, CognitiveConflict + from ...models import Signal, CognitiveConflict from sqlalchemy import func, text # 统计信号数量 @@ -75,7 +75,7 @@ async def get_ai_steward_stats( active_blockers = blocker_result.scalar() or 0 # 活跃项目数 - from ..models import Project + from ...models import Project project_result = await db.execute( select(func.count(Project.id)).where( Project.tenant_id == tenant_id, @@ -111,7 +111,7 @@ async def get_ai_config_suggestion( 根据团队现状,智能推荐应该优先配置哪些集成源 """ - from ..models import Integration, Project, Signal + from ...models import Integration, Project, Signal from sqlalchemy.future import select from sqlalchemy import func diff --git a/backend/app/api/ai_steward_api/routes_workflow.py b/backend/app/api/ai_steward_api/routes_workflow.py index 4a099787..05ea555d 100644 --- a/backend/app/api/ai_steward_api/routes_workflow.py +++ b/backend/app/api/ai_steward_api/routes_workflow.py @@ -56,7 +56,7 @@ async def trigger_signal_workflow( 检查信号的 impact_score,如果超过阈值(0.85), 自动触发工作流来调整相关项目的优先级 """ - from ..models import Signal + from ...models import Signal from sqlalchemy.future import select signal_result = await db.execute( @@ -98,7 +98,7 @@ async def get_workflow_status( 显示最近触发的工作流及其结果 """ - from ..models import AICallLog + from ...models import AICallLog from sqlalchemy.future import select # 获取最近的工作流记录 @@ -125,7 +125,7 @@ async def enable_auto_workflow( - 任务阻塞检测 - 认知冲突检测 """ - from ..models import Project + from ...models import Project from sqlalchemy.future import select project_result = await db.execute( diff --git a/backend/app/api/ai_steward_api/shared.py b/backend/app/api/ai_steward_api/shared.py index ad210dcf..8824a5ff 100644 --- a/backend/app/api/ai_steward_api/shared.py +++ b/backend/app/api/ai_steward_api/shared.py @@ -10,23 +10,23 @@ from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession from ...core.response import success_response -from ...database import get_db +from ...core.database import get_db from ...dependencies.auth import get_current_user from ...dependencies.permissions import require_manager_user from ...dependencies.tenant import get_tenant_id from ...models import ProjectSignalLink, Signal, User from ...schemas.rag import RAGAskRequest from ...services.adaptive_rag_service import AdaptiveRAGService -from ...services.ai_orchestration_run_service import AIOrchestrationRunService -from ...services.ai_steward import AIStewardService, get_ai_steward_service -from ...services.blocker_detection import get_blocker_detection_service -from ...services.cognitive_conflict import get_cognitive_conflict_service -from ...services.daily_briefing import get_daily_briefing_service -from ...services.event_workflow import WorkflowEventType, get_event_workflow_engine -from ...services.feishu_outbox_service import FeishuOutboxService -from ...services.signal_capture import ProactiveSignalCaptureService -from ...services.signal_source_orchestration_service import SignalSourceOrchestrationService -from ...services.signal_source_repair_service import ( +from ...services.ai_orchestration_run import AIOrchestrationRunService +from ...services.ai_steward_service import AIStewardService, get_ai_steward_service +from ...services.blocker_detection_core import get_blocker_detection_service +from ...services.cognitive_conflict_core import get_cognitive_conflict_service +from ...services.daily_briefing_core import get_daily_briefing_service +from ...services.event_workflow_core import WorkflowEventType, get_event_workflow_engine +from ...services.feishu_outbox import FeishuOutboxService +from ...services.signal_capture_service import ProactiveSignalCaptureService +from ...services.signal_source_orchestration import SignalSourceOrchestrationService +from ...services.signal_source_repair import ( SignalSourceRepairMissingSignalError, SignalSourceRepairService, SignalSourceRepairTimeoutError, diff --git a/backend/app/api/audit.py b/backend/app/api/audit.py index b659f157..9fb943f0 100644 --- a/backend/app/api/audit.py +++ b/backend/app/api/audit.py @@ -9,7 +9,7 @@ from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.ext.asyncio import AsyncSession from ..core.response import success_response -from ..database import get_db +from ..core.database import get_db from ..dependencies.auth import get_optional_current_user from ..dependencies.tenant import get_tenant_id from ..models import User diff --git a/backend/app/api/auth.py b/backend/app/api/auth.py index 4c708bcb..6b8541d0 100644 --- a/backend/app/api/auth.py +++ b/backend/app/api/auth.py @@ -5,7 +5,7 @@ from fastapi.security import OAuth2PasswordRequestForm from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select -from ..database import get_db +from ..core.database import get_db from ..models import User, UserStatus from ..schemas import UserLoginResponse from ..services.auth import AuthService diff --git a/backend/app/api/budget.py b/backend/app/api/budget.py index 74e439e0..5f8bd62d 100644 --- a/backend/app/api/budget.py +++ b/backend/app/api/budget.py @@ -9,7 +9,7 @@ from sqlalchemy import and_, desc, select from sqlalchemy.ext.asyncio import AsyncSession from ..core.response import ErrorCode, error_response, success_response -from ..database import get_db +from ..core.database import get_db from ..dependencies import get_tenant_id, get_current_user, require_roles from ..models import Budget, BudgetAlert, User from ..schemas.budget import ( @@ -18,7 +18,7 @@ from ..schemas.budget import ( BudgetOverrideRequest, BudgetUpdateRequest, ) -from ..services.budget_enforcement_service import BudgetEnforcementService +from ..services.budget_enforcement import BudgetEnforcementService from ..utils.timezone import now_cn_naive router = APIRouter(prefix="/budget", tags=["budget"]) diff --git a/backend/app/api/context.py b/backend/app/api/context.py index 2651bae9..166799af 100644 --- a/backend/app/api/context.py +++ b/backend/app/api/context.py @@ -4,11 +4,11 @@ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select -from ..database import get_db +from ..core.database import get_db from ..dependencies.tenant import get_tenant_id from ..models import ContextNode from ..schemas import ContextNodeCreate -from ..services.llm import llm_service +from ..services.llm_service import llm_service router = APIRouter(prefix="/context_nodes", tags=["context"]) diff --git a/backend/app/api/endpoints/skill_api/bindings.py b/backend/app/api/endpoints/skill_api/bindings.py index e526805a..b100a129 100644 --- a/backend/app/api/endpoints/skill_api/bindings.py +++ b/backend/app/api/endpoints/skill_api/bindings.py @@ -7,7 +7,7 @@ from typing import List from fastapi import APIRouter, Depends, Query from sqlalchemy.ext.asyncio import AsyncSession -from ....database import get_db +from ....core.database import get_db from ....dependencies import get_current_user, get_tenant_id from ....models import User from ....schemas.skill import ( @@ -16,7 +16,7 @@ from ....schemas.skill import ( UserSkillBindingBatchUpdate, UserSkillBindingResponse, ) -from ....services import skill_service +from ....services import skill as skill_service from .shared import ensure_self_or_admin router = APIRouter() diff --git a/backend/app/api/endpoints/skill_api/recommend.py b/backend/app/api/endpoints/skill_api/recommend.py index 080da1ab..e23da01a 100644 --- a/backend/app/api/endpoints/skill_api/recommend.py +++ b/backend/app/api/endpoints/skill_api/recommend.py @@ -7,14 +7,14 @@ from typing import Optional from fastapi import APIRouter, Depends, Query from sqlalchemy.ext.asyncio import AsyncSession -from ....database import get_db +from ....core.database import get_db from ....dependencies import get_current_user, get_tenant_id from ....models import User from ....schemas.skill import ( PersonnelRecommendationItem, PersonnelRecommendationResponse, ) -from ....services import skill_service +from ....services import skill as skill_service router = APIRouter() diff --git a/backend/app/api/endpoints/skill_api/tags.py b/backend/app/api/endpoints/skill_api/tags.py index ee59a346..648a1d3b 100644 --- a/backend/app/api/endpoints/skill_api/tags.py +++ b/backend/app/api/endpoints/skill_api/tags.py @@ -8,11 +8,11 @@ from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy.ext.asyncio import AsyncSession -from ....database import get_db +from ....core.database import get_db from ....dependencies import get_current_user, get_tenant_id, require_roles from ....models import User from ....schemas.skill import SkillTagCreate, SkillTagResponse, SkillTagUpdate -from ....services import skill_service +from ....services import skill as skill_service from .shared import skill_tag_to_response router = APIRouter() diff --git a/backend/app/api/endpoints/skill_api/workload.py b/backend/app/api/endpoints/skill_api/workload.py index ce7058d7..8ff60edc 100644 --- a/backend/app/api/endpoints/skill_api/workload.py +++ b/backend/app/api/endpoints/skill_api/workload.py @@ -5,10 +5,10 @@ from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession -from ....database import get_db +from ....core.database import get_db from ....dependencies import get_current_user, get_tenant_id from ....models import User -from ....services import workload_service +from ....services import workload as workload_service from .shared import ensure_self_or_admin router = APIRouter() diff --git a/backend/app/api/experiments.py b/backend/app/api/experiments.py index 3b6a484a..7eefe040 100644 --- a/backend/app/api/experiments.py +++ b/backend/app/api/experiments.py @@ -4,7 +4,7 @@ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select -from ..database import get_db +from ..core.database import get_db from ..models import Experiment from ..schemas import ExperimentCreate, ExperimentUpdate diff --git a/backend/app/api/feedbacks.py b/backend/app/api/feedbacks.py index 03224fee..0f87d191 100644 --- a/backend/app/api/feedbacks.py +++ b/backend/app/api/feedbacks.py @@ -4,7 +4,7 @@ from fastapi import APIRouter, Depends from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select -from ..database import get_db +from ..core.database import get_db from ..models import SignalFeedback router = APIRouter(prefix="/feedbacks", tags=["feedbacks"]) diff --git a/backend/app/api/feishu.py b/backend/app/api/feishu.py deleted file mode 100644 index 4234346d..00000000 --- a/backend/app/api/feishu.py +++ /dev/null @@ -1,7 +0,0 @@ -"""Feishu API router compatibility entrypoint.""" - -from __future__ import annotations - -from .feishu_api import router - -__all__ = ["router"] diff --git a/backend/app/api/feishu_api/config_routes.py b/backend/app/api/feishu_api/config_routes.py index 86f0641b..8a30281c 100644 --- a/backend/app/api/feishu_api/config_routes.py +++ b/backend/app/api/feishu_api/config_routes.py @@ -6,13 +6,13 @@ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select -from ...database import get_db +from ...core.database import get_db from ...dependencies.auth import get_current_user from ...dependencies.tenant import get_tenant_id from ...models import Integration, User from ...services.auth import has_any_role -from ...services.feishu_integration import get_feishu_service -from ...services.feishu_long_connection import get_feishu_long_connection_manager +from ...services.feishu_integration_service import get_feishu_service +from ...services.feishu_long_connection_core import get_feishu_long_connection_manager from .schemas import FeishuConfigRequest router = APIRouter() diff --git a/backend/app/api/feishu_api/long_connection_routes.py b/backend/app/api/feishu_api/long_connection_routes.py index 57b7c821..1221f730 100644 --- a/backend/app/api/feishu_api/long_connection_routes.py +++ b/backend/app/api/feishu_api/long_connection_routes.py @@ -7,7 +7,7 @@ from fastapi import APIRouter, Depends, HTTPException from ...dependencies.auth import get_current_user from ...models import User from ...services.auth import has_any_role -from ...services.feishu_long_connection import get_feishu_long_connection_manager +from ...services.feishu_long_connection_core import get_feishu_long_connection_manager router = APIRouter() diff --git a/backend/app/api/feishu_api/message_routes.py b/backend/app/api/feishu_api/message_routes.py index 841efe29..d5690b83 100644 --- a/backend/app/api/feishu_api/message_routes.py +++ b/backend/app/api/feishu_api/message_routes.py @@ -5,11 +5,11 @@ from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession -from ...database import get_db +from ...core.database import get_db from ...dependencies.auth import get_current_user from ...dependencies.tenant import get_tenant_id from ...models import User -from ...services.feishu_integration import get_feishu_service +from ...services.feishu_integration_service import get_feishu_service from .schemas import FeishuSendCardRequest, FeishuSendMessageRequest router = APIRouter() diff --git a/backend/app/api/feishu_api/test_routes.py b/backend/app/api/feishu_api/test_routes.py index e2aca228..44d9e315 100644 --- a/backend/app/api/feishu_api/test_routes.py +++ b/backend/app/api/feishu_api/test_routes.py @@ -5,12 +5,12 @@ from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession -from ...database import get_db +from ...core.database import get_db from ...dependencies.auth import get_current_user from ...dependencies.tenant import get_tenant_id from ...models import User -from ...services.feishu_integration import get_feishu_service -from ...services.feishu_long_connection import get_feishu_long_connection_manager +from ...services.feishu_integration_service import get_feishu_service +from ...services.feishu_long_connection_core import get_feishu_long_connection_manager from .helpers import build_long_connection_failure router = APIRouter() diff --git a/backend/app/api/knowledge_graph.py b/backend/app/api/knowledge_graph.py index 1a94ba20..19ec0317 100644 --- a/backend/app/api/knowledge_graph.py +++ b/backend/app/api/knowledge_graph.py @@ -10,13 +10,13 @@ from pydantic import BaseModel, Field from sqlalchemy.ext.asyncio import AsyncSession from ..core.response import success_response -from ..database import get_db +from ..core.database import get_db from ..dependencies.auth import get_current_user from ..dependencies.tenant import get_tenant_id from ..models import User from ..services.auth import has_any_role -from ..services.model_context_bundle_service import ModelContextBundleService -from ..services.project_knowledge_graph import ProjectKnowledgeGraphService +from ..services.model_context_bundle import ModelContextBundleService +from ..services.project_knowledge_graph_service import ProjectKnowledgeGraphService router = APIRouter(prefix="/ai-steward/knowledge-graph", tags=["AI Steward"]) diff --git a/backend/app/api/llm_engines.py b/backend/app/api/llm_engines.py index a76b4e1b..e4dffead 100644 --- a/backend/app/api/llm_engines.py +++ b/backend/app/api/llm_engines.py @@ -9,12 +9,12 @@ from pydantic import BaseModel, Field from sqlalchemy.ext.asyncio import AsyncSession from ..core.response import success_response -from ..database import get_db +from ..core.database import get_db from ..dependencies.auth import get_current_user from ..dependencies.tenant import get_tenant_id from ..models import User from ..services.auth import has_any_role -from ..services.llm import llm_service +from ..services.llm_service import llm_service router = APIRouter(prefix="/ai-steward/llm-engines", tags=["AI Steward"]) diff --git a/backend/app/api/model_capability.py b/backend/app/api/model_capability.py deleted file mode 100644 index eb3ed6db..00000000 --- a/backend/app/api/model_capability.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .model_capability_api import router - -__all__ = ["router"] diff --git a/backend/app/api/model_capability_api/shared.py b/backend/app/api/model_capability_api/shared.py index f2b9d88d..669d6d49 100644 --- a/backend/app/api/model_capability_api/shared.py +++ b/backend/app/api/model_capability_api/shared.py @@ -8,7 +8,7 @@ from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession from ...core.response import ErrorCode, error_response, success_response -from ...database import get_db +from ...core.database import get_db from ...dependencies import get_current_user, get_tenant_id from ...models import Experiment, TruthNode, User from ...schemas.model_capability import ( @@ -20,10 +20,10 @@ from ...schemas.model_capability import ( LifecycleImpactRequest, ValidateMatchRequest, ) -from ...services.ai_service import get_ai_service -from ...services.cost_optimization_service import CostOptimizationService -from ...services.experiment_sync_service import ExperimentSyncService -from ...services.model_capability_service import ModelCapabilityService -from ...services.model_lifecycle_service import ModelLifecycleService +from ...services.ai_service_core import get_ai_service +from ...services.model_capability.cost_optimization_service import CostOptimizationService +from ...services.experiment_sync import ExperimentSyncService +from ...services.model_capability import ModelCapabilityService +from ...services.model_capability.model_lifecycle_service import ModelLifecycleService router = APIRouter(prefix="/model-capability", tags=["model-capability"]) diff --git a/backend/app/api/model_routing.py b/backend/app/api/model_routing.py index a002d832..b7012125 100644 --- a/backend/app/api/model_routing.py +++ b/backend/app/api/model_routing.py @@ -10,11 +10,11 @@ from pydantic import BaseModel, Field from sqlalchemy.ext.asyncio import AsyncSession from ..core.response import error_response, success_response -from ..database import get_db +from ..core.database import get_db from ..dependencies import get_current_user from ..models import User from ..services.auth import has_any_role -from ..services.model_routing_service import ModelRoutingService +from ..services.model_routing import ModelRoutingService from ..services.operation_log_service import log_operation router = APIRouter(prefix="/model-routing", tags=["model_routing"]) diff --git a/backend/app/api/notifications.py b/backend/app/api/notifications.py index 9e44091e..be5182d6 100644 --- a/backend/app/api/notifications.py +++ b/backend/app/api/notifications.py @@ -10,7 +10,7 @@ from sqlalchemy import and_, desc, func, select from sqlalchemy.ext.asyncio import AsyncSession from ..core.response import success_response -from ..database import get_db +from ..core.database import get_db from ..dependencies import get_current_user, get_tenant_id from ..models import Notification, User diff --git a/backend/app/api/projects.py b/backend/app/api/projects.py deleted file mode 100644 index 5d23fbe3..00000000 --- a/backend/app/api/projects.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .projects_api import router - -__all__ = ["router"] diff --git a/backend/app/api/projects_api/shared.py b/backend/app/api/projects_api/shared.py index ba136145..e57fa2ce 100644 --- a/backend/app/api/projects_api/shared.py +++ b/backend/app/api/projects_api/shared.py @@ -9,7 +9,7 @@ from sqlalchemy import and_, delete, func, select, update from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.asyncio import AsyncSession -from ...database import get_db +from ...core.database import get_db from ...dependencies import get_current_user, get_tenant_id, require_roles from ...models import ( AIOrchestrationRun, @@ -29,10 +29,10 @@ from ...models import ( UserProject, WorkItem, ) -from ...services.ai_pmo_kernel_service import AIPMOKernelService -from ...services.context_cache import context_cache_service +from ...services.ai_pmo_kernel import AIPMOKernelService +from ...services.context_cache_service import context_cache_service from ...services.operation_log_service import log_operation -from ...services.project_member_service import ( +from ...services.project_member import ( ProjectMemberAssignmentError, notify_member_assignment_failure, replace_project_members, diff --git a/backend/app/api/prompt_profiles.py b/backend/app/api/prompt_profiles.py index 47e67cb4..38be13d9 100644 --- a/backend/app/api/prompt_profiles.py +++ b/backend/app/api/prompt_profiles.py @@ -9,12 +9,12 @@ from pydantic import BaseModel, Field from sqlalchemy.ext.asyncio import AsyncSession from ..core.response import success_response -from ..database import get_db +from ..core.database import get_db from ..dependencies.auth import get_current_user from ..dependencies.tenant import get_tenant_id from ..models import User from ..services.auth import has_any_role -from ..services.prompt_profile_service import prompt_profile_service +from ..services.prompt_profile import prompt_profile_service router = APIRouter(prefix="/ai-steward/prompt-profiles", tags=["AI Steward"]) diff --git a/backend/app/api/rag_api/shared.py b/backend/app/api/rag_api/shared.py index 27413048..ad9a96cf 100644 --- a/backend/app/api/rag_api/shared.py +++ b/backend/app/api/rag_api/shared.py @@ -9,7 +9,7 @@ from fastapi import APIRouter, Depends, File, Form, HTTPException, Query, Respon from sqlalchemy.ext.asyncio import AsyncSession from ...core.response import success_response -from ...database import get_db +from ...core.database import get_db from ...dependencies.auth import get_current_user, require_roles from ...dependencies.tenant import get_tenant_id from ...models import User @@ -28,6 +28,6 @@ from ...schemas.rag import ( SymbolSyncRequest, ) from ...services.adaptive_rag_service import AdaptiveRAGService -from ...services.symbol_index_service import SymbolIndexService +from ...services.symbol_index import SymbolIndexService router = APIRouter(prefix="/rag", tags=["Adaptive RAG"]) diff --git a/backend/app/api/recipes.py b/backend/app/api/recipes.py index e521e1a1..9ae356d5 100644 --- a/backend/app/api/recipes.py +++ b/backend/app/api/recipes.py @@ -4,7 +4,7 @@ from typing import Optional from fastapi import APIRouter, Depends, HTTPException, UploadFile, File from sqlalchemy.ext.asyncio import AsyncSession -from ..database import get_db +from ..core.database import get_db from ..dependencies.auth import get_current_tenant_id from ..schemas.recipe import ( RecipeCreate, @@ -13,7 +13,7 @@ from ..schemas.recipe import ( RecipeImageUploadRequest, RecipeAnalyzeCaloriesResponse, ) -from ..services.recipe_service import get_recipe_service +from ..services.recipe import get_recipe_service router = APIRouter(prefix="/recipes", tags=["食谱"]) diff --git a/backend/app/api/router.py b/backend/app/api/router.py index 82067b1e..3902219f 100644 --- a/backend/app/api/router.py +++ b/backend/app/api/router.py @@ -6,34 +6,34 @@ API 路由汇总 from fastapi import APIRouter -from .signals import router as signals_router +from .signals_api import router as signals_router from .feedbacks import router as feedbacks_router from .experiments import router as experiments_router from .context import router as context_router from .tasks import router as tasks_router from .webhooks import router as webhooks_router from .auth import router as auth_router -from .users import router as users_router +from .users_api import router as users_router from .endpoints.skill import router as skill_router from .workloads import router as workloads_router -from .skill_tags import router as skill_tags_router -from .sstc import router as sstc_router -from .projects import router as projects_router +from .skill_tags_api import router as skill_tags_router +from .sstc_api import router as sstc_router +from .projects_api import router as projects_router from .scheduler import router as scheduler_router -from .ai_steward import router as ai_steward_router -from .feishu import router as feishu_router -from .wecom import router as wecom_router +from .ai_steward_api import router as ai_steward_router +from .feishu_api import router as feishu_router +from .wecom_api import router as wecom_router from .notifications import router as notifications_router from .llm_engines import router as llm_engines_router from .llm_providers import router as llm_providers_router -from .ai_logs import router as ai_logs_router +from .ai_logs_api import router as ai_logs_router from .prompt_profiles import router as prompt_profiles_router -from .rag import router as rag_router +from .rag_api import router as rag_router from .knowledge_graph import router as knowledge_graph_router from .recipes import router as recipes_router -from .signal_sources import router as signal_sources_router +from .signal_sources_api import router as signal_sources_router from .operation_catalog import router as operation_catalog_router -from .ai_pmo import router as ai_pmo_router +from .ai_pmo_api import router as ai_pmo_router from .audit import router as audit_router from .model_routing import router as model_routing_router from .task_briefs import router as task_briefs_router diff --git a/backend/app/api/scheduler.py b/backend/app/api/scheduler.py index 1b6a9537..30aadb8f 100644 --- a/backend/app/api/scheduler.py +++ b/backend/app/api/scheduler.py @@ -6,14 +6,14 @@ from fastapi import APIRouter, Depends from sqlalchemy import and_, or_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..database import get_db +from ..core.database import get_db from ..dependencies import require_manager_user from ..models import KnowledgeBaseDoc, Project, User from ..services.adaptive_rag_service import AdaptiveRAGService -from ..services.ai_pmo_cadence_service import AIPMOCadenceService -from ..services.project_knowledge_graph import ProjectKnowledgeGraphService -from ..services.symbol_index_service import SymbolIndexService -from ..services import workload_service +from ..services.ai_pmo_cadence import AIPMOCadenceService +from ..services.project_knowledge_graph_service import ProjectKnowledgeGraphService +from ..services.symbol_index import SymbolIndexService +from ..services import workload as workload_service router = APIRouter(prefix="/scheduler", tags=["scheduler"]) diff --git a/backend/app/api/sstc.py b/backend/app/api/signal_sources_api/__init__.py similarity index 66% rename from backend/app/api/sstc.py rename to backend/app/api/signal_sources_api/__init__.py index 67ca293a..8a2ebbc6 100644 --- a/backend/app/api/sstc.py +++ b/backend/app/api/signal_sources_api/__init__.py @@ -1,5 +1,5 @@ from __future__ import annotations -from .sstc_api import router +from .routes import router __all__ = ["router"] diff --git a/backend/app/api/signal_sources_utils.py b/backend/app/api/signal_sources_api/helpers.py similarity index 98% rename from backend/app/api/signal_sources_utils.py rename to backend/app/api/signal_sources_api/helpers.py index e5fc7be9..cd29e868 100644 --- a/backend/app/api/signal_sources_utils.py +++ b/backend/app/api/signal_sources_api/helpers.py @@ -8,7 +8,7 @@ from fastapi import HTTPException from sqlalchemy import or_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..models import Project +from ...models import Project RECIPE_PROJECT_KEYWORDS = ("食谱", "recipe", "sstc") diff --git a/backend/app/api/signal_sources.py b/backend/app/api/signal_sources_api/routes.py similarity index 96% rename from backend/app/api/signal_sources.py rename to backend/app/api/signal_sources_api/routes.py index 1d5ebafc..83a4fa91 100644 --- a/backend/app/api/signal_sources.py +++ b/backend/app/api/signal_sources_api/routes.py @@ -9,12 +9,12 @@ from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession -from ..core.logging import get_logger -from ..database import get_db -from ..dependencies.tenant import get_tenant_id -from ..models import ProjectSignalLink, Signal -from .signal_sources_models import RecipeBatchRequest, RecipeRecognitionRequest, RecipeRecognitionResponse -from .signal_sources_utils import resolve_target_project_id +from ...core.logging import get_logger +from ...core.database import get_db +from ...dependencies.tenant import get_tenant_id +from ...models import ProjectSignalLink, Signal +from .schemas import RecipeBatchRequest, RecipeRecognitionRequest, RecipeRecognitionResponse +from .helpers import resolve_target_project_id router = APIRouter(prefix="/signal-sources", tags=["Signal Sources"]) logger = get_logger(__name__) diff --git a/backend/app/api/signal_sources_models.py b/backend/app/api/signal_sources_api/schemas.py similarity index 100% rename from backend/app/api/signal_sources_models.py rename to backend/app/api/signal_sources_api/schemas.py diff --git a/backend/app/api/signals.py b/backend/app/api/signals.py deleted file mode 100644 index 4c358a62..00000000 --- a/backend/app/api/signals.py +++ /dev/null @@ -1,7 +0,0 @@ -"""信号相关 API 路由。""" - -from __future__ import annotations - -from .signals_api import router - -__all__ = ["router"] diff --git a/backend/app/api/signals_api/feedback.py b/backend/app/api/signals_api/feedback.py index 55a3a35b..00d1d29e 100644 --- a/backend/app/api/signals_api/feedback.py +++ b/backend/app/api/signals_api/feedback.py @@ -9,7 +9,7 @@ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select -from ...database import get_db +from ...core.database import get_db from ...models import Signal, SignalFeedback from ...schemas import SignalFeedbackCreate, SignalFeedbackResponse diff --git a/backend/app/api/signals_api/ingest_fetch.py b/backend/app/api/signals_api/ingest_fetch.py index 71d5ae31..e9c3419b 100644 --- a/backend/app/api/signals_api/ingest_fetch.py +++ b/backend/app/api/signals_api/ingest_fetch.py @@ -8,15 +8,15 @@ from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select -from ...database import get_db +from ...core.database import get_db from ...dependencies.tenant import get_tenant_id from ...models import Signal from ...schemas import SignalCreate, SignalPriority, classify_signal_priority -from ...services.analyzer import analyze_impact -from ...services.fetcher import fetch_hn_stories -from ...services.lark import LarkService -from ...services.llm import llm_service -from ...services.plane import plane_service +from ...services.signal_capture_service.impact_analyzer import analyze_impact +from ...services.signal_capture_service.external_fetcher import fetch_hn_stories +from ...services.integration_core.lark_service import LarkService +from ...services.llm_service import llm_service +from ...services.integration_core.plane_service import plane_service router = APIRouter() lark_service = LarkService() diff --git a/backend/app/api/signals_api/list_create.py b/backend/app/api/signals_api/list_create.py index 901eca74..d89a35d6 100644 --- a/backend/app/api/signals_api/list_create.py +++ b/backend/app/api/signals_api/list_create.py @@ -9,7 +9,7 @@ from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select -from ...database import get_db +from ...core.database import get_db from ...models import Project, ProjectSignalLink, Signal from ...schemas import SignalCreate diff --git a/backend/app/api/users.py b/backend/app/api/skill_tags_api/__init__.py similarity index 65% rename from backend/app/api/users.py rename to backend/app/api/skill_tags_api/__init__.py index 27b6d0ce..8a2ebbc6 100644 --- a/backend/app/api/users.py +++ b/backend/app/api/skill_tags_api/__init__.py @@ -1,5 +1,5 @@ from __future__ import annotations -from .users_api import router +from .routes import router __all__ = ["router"] diff --git a/backend/app/api/skill_tags_contracts.py b/backend/app/api/skill_tags_api/contracts.py similarity index 97% rename from backend/app/api/skill_tags_contracts.py rename to backend/app/api/skill_tags_api/contracts.py index 937e09e0..2c8bf684 100644 --- a/backend/app/api/skill_tags_contracts.py +++ b/backend/app/api/skill_tags_api/contracts.py @@ -6,7 +6,7 @@ from typing import Optional from pydantic import BaseModel, Field -from ..models import SkillTag +from ...models import SkillTag class SkillTagCreateRequest(BaseModel): diff --git a/backend/app/api/skill_tags.py b/backend/app/api/skill_tags_api/routes.py similarity index 96% rename from backend/app/api/skill_tags.py rename to backend/app/api/skill_tags_api/routes.py index 713713b2..483d4e92 100644 --- a/backend/app/api/skill_tags.py +++ b/backend/app/api/skill_tags_api/routes.py @@ -6,14 +6,14 @@ from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy import and_, delete, func, select from sqlalchemy.ext.asyncio import AsyncSession -from ..database import get_db -from ..dependencies import get_current_user, get_tenant_id, require_roles -from ..models import SkillTag, User, UserSkillBinding -from ..services import skill_service -from ..services.ai_pmo_kernel_service import AIPMOKernelService -from ..services.auth import has_any_role -from ..utils.timezone import now_cn_naive -from .skill_tags_contracts import ( +from ...core.database import get_db +from ...dependencies import get_current_user, get_tenant_id, require_roles +from ...models import SkillTag, User, UserSkillBinding +from ...services import skill as skill_service +from ...services.ai_pmo_kernel import AIPMOKernelService +from ...services.auth import has_any_role +from ...utils.timezone import now_cn_naive +from .contracts import ( SkillTagCreateRequest, SkillTagUpdateRequest, UserSkillCreateRequest, diff --git a/backend/app/api/sstc_api/shared.py b/backend/app/api/sstc_api/shared.py index 52cc8a5b..8379d548 100644 --- a/backend/app/api/sstc_api/shared.py +++ b/backend/app/api/sstc_api/shared.py @@ -12,7 +12,7 @@ from sqlalchemy import and_, delete, select from sqlalchemy.ext.asyncio import AsyncSession from ...core.response import success_response -from ...database import get_db +from ...core.database import get_db from ...dependencies import get_current_user, require_project_member_or_manager from ...models import ( AICallLog, @@ -41,16 +41,17 @@ from ...schemas.sstc import ( TaskStatusPatchRequest, WorkloadOptimizeRequest, ) -from ...services import skill_score_service, workload_service -from ...services.ai_pmo_kernel_service import AIPMOKernelService -from ...services.ai_service import AIService +from ...services.skill import skill_score_service +from ...services import workload as workload_service +from ...services.ai_pmo_kernel import AIPMOKernelService +from ...services.ai_service_core import AIService from ...services.auth import has_any_role -from ...services.budget_enforcement_service import BudgetEnforcementService -from ...services.feishu_integration import get_feishu_service -from ...services.llm import llm_service +from ...services.budget_enforcement import BudgetEnforcementService +from ...services.feishu_integration_service import get_feishu_service +from ...services.llm_service import llm_service from ...services.operation_log_service import log_operation -from ...services.skill_service import recommend_personnel -from ...services.sstc_service import ALIGNED_STATUSES, DONE_STATUSES, RELEASE_VERIFIED_STATUSES, SSTCService -from ...services.task_persistence import build_task_create_draft, persist_task +from ...services.skill import recommend_personnel +from ...services.sstc_service_core import ALIGNED_STATUSES, DONE_STATUSES, RELEASE_VERIFIED_STATUSES, SSTCService +from ...services.task_persistence_core import build_task_create_draft, persist_task from ...utils.title import compact_title from ...utils.timezone import CN_TZ, now_cn_aware, now_cn_naive diff --git a/backend/app/api/task_briefs.py b/backend/app/api/task_briefs.py index f5fe252b..86195543 100644 --- a/backend/app/api/task_briefs.py +++ b/backend/app/api/task_briefs.py @@ -10,12 +10,12 @@ from pydantic import BaseModel, Field from sqlalchemy.ext.asyncio import AsyncSession from ..core.response import error_response, success_response -from ..database import get_db +from ..core.database import get_db from ..dependencies import get_current_user from ..models import User from ..services.auth import has_any_role from ..services.operation_log_service import log_operation -from ..services.task_brief_service import TaskBriefService +from ..services.task_brief import TaskBriefService router = APIRouter(prefix="/task-briefs", tags=["task_briefs"]) diff --git a/backend/app/api/tasks.py b/backend/app/api/tasks.py index d08a3211..6fb6d687 100644 --- a/backend/app/api/tasks.py +++ b/backend/app/api/tasks.py @@ -4,13 +4,13 @@ from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..database import get_db +from ..core.database import get_db from ..dependencies import get_current_user, require_manager_user from ..models import Task, User, UserProject from ..schemas import TaskBreakdownRequest, TaskBreakdownResponse -from ..services.llm import llm_service -from ..services.plane import plane_service -from ..services.skill_service import recommend_personnel +from ..services.llm_service import llm_service +from ..services.integration_core.plane_service import plane_service +from ..services.skill import recommend_personnel router = APIRouter(prefix="/tasks", tags=["tasks"]) diff --git a/backend/app/api/users_api/shared.py b/backend/app/api/users_api/shared.py index 4c1170aa..d5d260e1 100644 --- a/backend/app/api/users_api/shared.py +++ b/backend/app/api/users_api/shared.py @@ -11,7 +11,7 @@ from sqlalchemy import and_, delete, func, or_, select, update from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.asyncio import AsyncSession -from ...database import get_db +from ...core.database import get_db from ...dependencies import ( get_current_active_user, get_current_user, @@ -36,8 +36,8 @@ from ...schemas import ( UserStatusPatchRequest, UserUpdate, ) -from ...services import skill_service -from ...services.ai_pmo_kernel_service import AIPMOKernelService +from ...services import skill as skill_service +from ...services.ai_pmo_kernel import AIPMOKernelService from ...services.auth import AuthService from ...services.operation_log_service import log_operation from ...utils.timezone import now_cn_naive diff --git a/backend/app/api/webhooks.py b/backend/app/api/webhooks.py index e42eb5a6..15496e86 100644 --- a/backend/app/api/webhooks.py +++ b/backend/app/api/webhooks.py @@ -8,10 +8,10 @@ from fastapi import APIRouter, Depends from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select -from ..database import get_db +from ..core.database import get_db from ..models import Signal -from ..services.llm import llm_service -from ..services.plane import plane_service +from ..services.llm_service import llm_service +from ..services.integration_core.plane_service import plane_service from ..utils.timezone import now_cn_aware router = APIRouter(prefix="/webhooks", tags=["webhooks"]) diff --git a/backend/app/api/wecom.py b/backend/app/api/wecom.py deleted file mode 100644 index 65c05d38..00000000 --- a/backend/app/api/wecom.py +++ /dev/null @@ -1,7 +0,0 @@ -"""WeCom API compatibility module.""" - -from __future__ import annotations - -from .wecom_api import router - -__all__ = ["router"] diff --git a/backend/app/api/wecom_api/config.py b/backend/app/api/wecom_api/config.py index e099723b..033f4447 100644 --- a/backend/app/api/wecom_api/config.py +++ b/backend/app/api/wecom_api/config.py @@ -6,12 +6,12 @@ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select -from ...database import get_db +from ...core.database import get_db from ...dependencies.auth import get_current_user from ...dependencies.tenant import get_tenant_id from ...models import Integration, User from ...services.auth import has_any_role -from ...services.wecom_integration import get_wecom_service +from ...services.wecom import get_wecom_service from .schemas import WeComConfigRequest router = APIRouter() diff --git a/backend/app/api/wecom_api/messaging.py b/backend/app/api/wecom_api/messaging.py index 42c4cc9c..5f40aea1 100644 --- a/backend/app/api/wecom_api/messaging.py +++ b/backend/app/api/wecom_api/messaging.py @@ -5,11 +5,11 @@ from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession -from ...database import get_db +from ...core.database import get_db from ...dependencies.auth import get_current_user from ...dependencies.tenant import get_tenant_id from ...models import User -from ...services.wecom_integration import get_wecom_service +from ...services.wecom import get_wecom_service from .schemas import WeComSendMessageRequest router = APIRouter() diff --git a/backend/app/api/wecom_api/webhook.py b/backend/app/api/wecom_api/webhook.py index 2b5b89a0..4900645c 100644 --- a/backend/app/api/wecom_api/webhook.py +++ b/backend/app/api/wecom_api/webhook.py @@ -7,8 +7,8 @@ import json from fastapi import APIRouter, Depends, HTTPException, Request from sqlalchemy.ext.asyncio import AsyncSession -from ...database import get_db -from ...services.wecom_integration import get_wecom_service +from ...core.database import get_db +from ...services.wecom import get_wecom_service router = APIRouter() diff --git a/backend/app/api/workloads.py b/backend/app/api/workloads.py index d8ea4bfe..3d130510 100644 --- a/backend/app/api/workloads.py +++ b/backend/app/api/workloads.py @@ -8,7 +8,7 @@ from fastapi import APIRouter, Depends, HTTPException, Query from pydantic import BaseModel, Field from sqlalchemy.ext.asyncio import AsyncSession -from ..database import get_db +from ..core.database import get_db from ..dependencies import ( get_current_user, get_tenant_id, @@ -17,7 +17,7 @@ from ..dependencies import ( require_self_or_manager, ) from ..models import User -from ..services import workload_service +from ..services import workload as workload_service router = APIRouter(prefix="/workloads", tags=["workloads"]) diff --git a/backend/app/database.py b/backend/app/core/database.py similarity index 97% rename from backend/app/database.py rename to backend/app/core/database.py index 99fef2a9..749aa1a3 100644 --- a/backend/app/database.py +++ b/backend/app/core/database.py @@ -16,10 +16,10 @@ from sqlalchemy.ext.asyncio import ( ) from sqlalchemy.orm import Session -from .core.config import settings -from .core.logging import get_logger -from .models import OperationLog -from .utils.audited_write import get_audit_context +from .config import settings +from .logging import get_logger +from ..models import OperationLog +from ..utils.audited_write import get_audit_context DATABASE_URL = settings.database_url logger = get_logger(__name__) diff --git a/backend/app/events.py b/backend/app/core/events.py similarity index 100% rename from backend/app/events.py rename to backend/app/core/events.py diff --git a/backend/app/events_models.py b/backend/app/core/events_models.py similarity index 98% rename from backend/app/events_models.py rename to backend/app/core/events_models.py index 2cf5bb47..6380f32c 100644 --- a/backend/app/events_models.py +++ b/backend/app/core/events_models.py @@ -6,7 +6,7 @@ from dataclasses import dataclass, field from enum import Enum from typing import Any, Optional -from .utils.timezone import now_cn_aware +from ..utils.timezone import now_cn_aware class EventType(Enum): diff --git a/backend/app/main_db_guard.py b/backend/app/core/startup/db_guard.py similarity index 97% rename from backend/app/main_db_guard.py rename to backend/app/core/startup/db_guard.py index 29dbbd1c..334d35a3 100644 --- a/backend/app/main_db_guard.py +++ b/backend/app/core/startup/db_guard.py @@ -4,8 +4,8 @@ from __future__ import annotations import os -from .core.config import settings -from .core.logging import get_logger +from ..config import settings +from ..logging import get_logger logger = get_logger(__name__) diff --git a/backend/app/main_feishu_outbox.py b/backend/app/core/startup/feishu_outbox.py similarity index 94% rename from backend/app/main_feishu_outbox.py rename to backend/app/core/startup/feishu_outbox.py index ee99dacb..9d0f4de5 100644 --- a/backend/app/main_feishu_outbox.py +++ b/backend/app/core/startup/feishu_outbox.py @@ -7,10 +7,10 @@ from contextlib import suppress import sqlalchemy as sa -from .core.logging import get_logger -from .database import engine -from .services.feishu_integration import dispatch_pending_feishu_replies -from .main_db_guard import normalize_dialect +from ..logging import get_logger +from ..database import engine +from ...services.feishu_integration_service import dispatch_pending_feishu_replies +from .db_guard import normalize_dialect logger = get_logger(__name__) diff --git a/backend/app/main_model_probe.py b/backend/app/core/startup/model_probe.py similarity index 97% rename from backend/app/main_model_probe.py rename to backend/app/core/startup/model_probe.py index ae105fe3..a7a9c482 100644 --- a/backend/app/main_model_probe.py +++ b/backend/app/core/startup/model_probe.py @@ -6,7 +6,7 @@ import asyncio import os import time -from .core.logging import get_logger +from ..logging import get_logger logger = get_logger(__name__) @@ -16,7 +16,7 @@ def startup_log(message: str, **fields) -> None: async def probe_model_connectivity_on_startup() -> None: - from .services.llm import llm_service + from ...services.llm_service import llm_service low_provider = str(os.getenv("LLM_ROUTING_LOW_PROVIDER", os.getenv("LLM_PROVIDER", "glm")) or "").strip() or "glm" low_model = str(os.getenv("LLM_ROUTING_LOW_MODEL", os.getenv("GLM_MODEL", "GLM-4.7")) or "").strip() or "GLM-4.7" diff --git a/backend/app/main_warmup.py b/backend/app/core/startup/world_model_warmup.py similarity index 94% rename from backend/app/main_warmup.py rename to backend/app/core/startup/world_model_warmup.py index 9e7a32ad..2857e078 100644 --- a/backend/app/main_warmup.py +++ b/backend/app/core/startup/world_model_warmup.py @@ -8,12 +8,12 @@ from datetime import datetime, timedelta import sqlalchemy as sa from sqlalchemy.exc import OperationalError, ProgrammingError -from .core.logging import get_logger -from .database import AsyncSessionLocal -from .main_db_guard import is_missing_table_error -from .models import Project, WorkItem -from .services.ai_pmo_kernel_service import AIPMOKernelService -from .utils.timezone import now_cn_aware +from ..logging import get_logger +from ..database import AsyncSessionLocal +from .db_guard import is_missing_table_error +from ...models import Project, WorkItem +from ...services.ai_pmo_kernel import AIPMOKernelService +from ...utils.timezone import now_cn_aware logger = get_logger(__name__) ACTIVE_PROJECT_STATUSES = ("active", "planning", "todo", "doing") diff --git a/backend/app/websocket.py b/backend/app/core/websocket.py similarity index 99% rename from backend/app/websocket.py rename to backend/app/core/websocket.py index 12d298f4..8a42b518 100644 --- a/backend/app/websocket.py +++ b/backend/app/core/websocket.py @@ -11,7 +11,7 @@ import logging from fastapi import WebSocket, WebSocketDisconnect from enum import Enum -from .utils.timezone import now_cn_aware, now_cn_naive +from ..utils.timezone import now_cn_aware, now_cn_naive logger = logging.getLogger(__name__) diff --git a/backend/app/dependencies/auth.py b/backend/app/dependencies/auth.py index d4bfcc85..5ad48403 100644 --- a/backend/app/dependencies/auth.py +++ b/backend/app/dependencies/auth.py @@ -11,7 +11,7 @@ from fastapi.security import OAuth2PasswordBearer from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select -from ..database import get_db +from ..core.database import get_db from ..dependencies.tenant import get_tenant_id from ..models import User, UserStatus # noqa: E402 from ..services.auth import AuthService, has_any_role diff --git a/backend/app/dependencies/permissions.py b/backend/app/dependencies/permissions.py index cae33293..c93e70ee 100644 --- a/backend/app/dependencies/permissions.py +++ b/backend/app/dependencies/permissions.py @@ -8,7 +8,7 @@ from fastapi import Depends, HTTPException from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..database import get_db +from ..core.database import get_db from ..models import User, UserProject from ..services.auth import parse_role_values from .auth import get_current_user diff --git a/backend/app/deps.py b/backend/app/deps.py new file mode 100644 index 00000000..ce9f1771 --- /dev/null +++ b/backend/app/deps.py @@ -0,0 +1,5 @@ +"""Shared FastAPI dependencies exposed at app package root.""" + +from .core.database import AsyncSessionLocal, get_db + +__all__ = ["AsyncSessionLocal", "get_db"] diff --git a/backend/app/dispatcher.py b/backend/app/dispatcher.py deleted file mode 100644 index f5cb9d51..00000000 --- a/backend/app/dispatcher.py +++ /dev/null @@ -1,180 +0,0 @@ -"""Neural Sync - Role Dispatcher。""" - -from __future__ import annotations - -import logging -import re -from typing import Any, Optional - -from pydantic import BaseModel, Field - -from .dispatcher_rules import ROLE_RULES, TECH_KEYWORDS, Role, RoutingRule -from .utils.timezone import now_cn_aware - -logger = logging.getLogger(__name__) - - -class RoleRouter: - """角色路由引擎。""" - - ROLE_RULES: list[RoutingRule] = ROLE_RULES - TECH_KEYWORDS = TECH_KEYWORDS - - def __init__(self): - self._compiled_patterns: dict[Role, list[re.Pattern]] = {} - for rule in self.ROLE_RULES: - patterns = [re.compile(pattern, re.IGNORECASE) for pattern in rule.patterns] - self._compiled_patterns[rule.role] = patterns - - def route( - self, - signal_content: str, - analysis: Optional[dict[str, Any]] = None, - source: Optional[str] = None, - ) -> tuple[Role, float, dict[str, Any]]: - analysis = analysis or {} - details = { - "matched_rules": [], - "scores": {}, - "reasons": [], - } - - if self._should_escalate_to_boss(analysis): - details["reasons"].append("触发老板决策阈值") - details["matched_rules"].append("threshold_check") - return Role.BOSS, 1.0, details - - scores: dict[Role, float] = {rule.role: 0.0 for rule in self.ROLE_RULES} - - content_lower = signal_content.lower() - for rule in self.ROLE_RULES: - keyword_score = sum(1 for kw in rule.keywords if kw.lower() in content_lower) - if keyword_score > 0: - scores[rule.role] += keyword_score * 0.3 - details["scores"][f"{rule.role}_keywords"] = keyword_score - - for rule in self.ROLE_RULES: - if rule.role in self._compiled_patterns: - pattern_score = sum( - 1 - for pattern in self._compiled_patterns[rule.role] - if pattern.search(signal_content) - ) - if pattern_score > 0: - scores[rule.role] += pattern_score * 0.5 - details["scores"][f"{rule.role}_patterns"] = pattern_score - - for rule in self.ROLE_RULES: - trigger_score = sum(1 for trigger in rule.triggers if trigger.lower() in content_lower) - if trigger_score > 0: - scores[rule.role] += trigger_score * 0.7 - details["scores"][f"{rule.role}_triggers"] = trigger_score - - for rule in self.ROLE_RULES: - if scores[rule.role] > 0: - scores[rule.role] *= 1 + rule.priority * 0.01 - - max_role = Role.AI_ENGINEER - max_score = 0.0 - - for role, score in scores.items(): - if score > max_score: - max_score = score - max_role = role - elif score == max_score and score > 0: - role_priority = 0 - max_role_priority = 0 - for rule in self.ROLE_RULES: - if rule.role == role: - role_priority = rule.priority - if rule.role == max_role: - max_role_priority = rule.priority - if role_priority > max_role_priority: - max_role = role - - confidence = min(max_score / 3.0, 1.0) if max_score > 0 else 0.5 - - details["matched_rules"] = [ - rule.name - for rule in self.ROLE_RULES - if scores[rule.role] > 0 - ] - details["final_scores"] = {role.value: score for role, score in scores.items()} - details["reasons"].append("基于关键词和模式匹配") - - return max_role, confidence, details - - def _should_escalate_to_boss(self, analysis: dict[str, Any]) -> bool: - dev_days = analysis.get("resource_cost", {}).get("dev_days", 0) - if dev_days >= 5: - return True - - risk_level = analysis.get("risk_level", "") - if risk_level in ["CRITICAL", "HIGH"]: - return True - - is_architecture = analysis.get("is_architecture_change", False) - if is_architecture: - return True - - return False - - def get_role_info(self, role: Role) -> dict[str, Any]: - for rule in self.ROLE_RULES: - if rule.role == role: - return { - "role": role.value, - "name": rule.name, - "description": rule.description, - "keywords": rule.keywords, - "priority": rule.priority, - } - return {} - - def get_all_roles(self) -> list[dict[str, Any]]: - return [ - { - "role": rule.role.value, - "name": rule.name, - "description": rule.description, - "priority": rule.priority, - } - for rule in sorted(self.ROLE_RULES, key=lambda item: -item.priority) - ] - - -class RoutingResult(BaseModel): - """路由结果模型。""" - - role: str - confidence: float - details: dict[str, Any] - signal_id: Optional[str] = None - timestamp: float = Field(default_factory=lambda: now_cn_aware().timestamp()) - - -_global_router: Optional[RoleRouter] = None - - -def get_router() -> RoleRouter: - """获取全局路由器实例。""" - global _global_router - if _global_router is None: - _global_router = RoleRouter() - return _global_router - - -def route_signal( - signal_content: str, - analysis: Optional[dict[str, Any]] = None, - signal_id: Optional[str] = None, -) -> RoutingResult: - """路由信号到对应角色。""" - router = get_router() - role, confidence, details = router.route(signal_content, analysis) - return RoutingResult( - role=role.value, - confidence=confidence, - details=details, - signal_id=signal_id, - ) diff --git a/backend/app/dispatcher_rules.py b/backend/app/dispatcher_rules.py deleted file mode 100644 index e6a90b43..00000000 --- a/backend/app/dispatcher_rules.py +++ /dev/null @@ -1,179 +0,0 @@ -"""Static rule definitions for role dispatcher.""" - -from __future__ import annotations - -from dataclasses import dataclass, field -from enum import Enum -from typing import Any, Optional - - -class Role(str, Enum): - """系统角色定义""" - - BOSS = "boss" - AI_ENGINEER = "ai_engineer" - BACKEND = "backend" - FRONTEND = "frontend" - - -@dataclass -class RoutingRule: - """路由规则定义""" - - role: Role - name: str - description: str - triggers: list[str] = field(default_factory=list) - keywords: list[str] = field(default_factory=list) - patterns: list[str] = field(default_factory=list) - threshold: Optional[dict[str, Any]] = None - priority: int = 0 - - -ROLE_RULES: list[RoutingRule] = [ - RoutingRule( - role=Role.BOSS, - name="战略决策", - description="需要老板决策的高影响任务", - triggers=["cost_estimate", "architecture_change", "high_risk", "security"], - keywords=["预算", "架构", "安全", "风险", "审批", "决策"], - threshold={"dev_days": 5, "risk_level": ["CRITICAL", "HIGH"]}, - priority=100, - ), - RoutingRule( - role=Role.AI_ENGINEER, - name="AI 工程", - description="AI 模型和数据处理相关任务", - triggers=["prompt", "model", "embedding", "rag", "llm"], - keywords=[ - "ollama", - "openai", - "claude", - "prompt", - "embedding", - "rag", - "llm", - "向量", - "模型", - "训练", - "数据清洗", - "token", - "context", - ], - patterns=[r"(prompt|embedding|rag|llm|vector|model)", r"(ai|machine.?learning|ml)"], - priority=50, - ), - RoutingRule( - role=Role.BACKEND, - name="后端开发", - description="API、数据库、爬虫等后端任务", - triggers=["api", "database", "crawler", "performance", "docker"], - keywords=[ - "fastapi", - "sqlalchemy", - "postgres", - "sql", - "async", - "docker", - "kubernetes", - "redis", - "celery", - "爬虫", - "api", - "接口", - "数据库", - "后端", - "性能", - "缓存", - ], - patterns=[ - r"(api|endpoint|route)", - r"(sql|database|db)", - r"(docker|k8s|kubernetes)", - r"(async|await|celery)", - ], - priority=30, - ), - RoutingRule( - role=Role.FRONTEND, - name="前端开发", - description="UI、可视化、交互等前端任务", - triggers=["ui", "visualization", "interaction", "responsive", "chart"], - keywords=[ - "vue", - "react", - "typescript", - "component", - "chart", - "echarts", - "d3", - "可视化", - "ui", - "ux", - "样式", - "动画", - "响应式", - "组件", - "交互", - "页面", - "布局", - ], - patterns=[ - r"(vue|react|tsx?|jsx?)", - r"(css|scss|tailwind)", - r"(component|props|emit)", - r"(chart|graph|visualization)", - ], - priority=30, - ), -] - -TECH_KEYWORDS = { - "frontend": [ - "vue", - "react", - "typescript", - "javascript", - "css", - "scss", - "tailwind", - "component", - "props", - "emit", - "template", - "style", - ], - "backend": [ - "fastapi", - "flask", - "django", - "sqlalchemy", - "postgres", - "mysql", - "redis", - "celery", - "async", - "await", - "docker", - "kubernetes", - "k8s", - "api", - "endpoint", - "route", - ], - "ai": [ - "llm", - "ollama", - "openai", - "claude", - "prompt", - "embedding", - "rag", - "vector", - "model", - "training", - "inference", - "token", - "context", - ], -} diff --git a/backend/app/main.py b/backend/app/main.py index a7ac47c8..42bab875 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -13,22 +13,22 @@ from .api.router import api_router from .core.config import settings from .core.logging import configure_logging, get_logger from .core.response import success_response -from .database import AsyncSessionLocal, engine -from .main_db_guard import check_database_dialect_guard -from .main_feishu_outbox import feishu_outbox_drain_loop -from .main_model_probe import probe_model_connectivity_on_startup, startup_log -from .main_warmup import warmup_world_models +from .core.database import AsyncSessionLocal, engine +from .core.startup.db_guard import check_database_dialect_guard +from .core.startup.feishu_outbox import feishu_outbox_drain_loop +from .core.startup.model_probe import probe_model_connectivity_on_startup, startup_log +from .core.startup.world_model_warmup import warmup_world_models from .middleware import AuditContextMiddleware -from .services.ai_orchestration_run_service import AIOrchestrationRunService -from .services.context_cache import register_context_cache_invalidation_hooks -from .services.feishu_long_connection import init_feishu_long_connection_manager -from .services.scheduler_center import ( +from .services.ai_orchestration_run import AIOrchestrationRunService +from .services.context_cache_service import register_context_cache_invalidation_hooks +from .services.feishu_long_connection_core import init_feishu_long_connection_manager +from .services.scheduler_center_core import ( AIPMOCadenceScheduler, KnowledgeGraphIncrementalScheduler, KnowledgeUrlRefreshScheduler, WorkloadRecalcScheduler, ) -from .services.skill_service import init_system_skill_tags +from .services.skill import init_system_skill_tags configure_logging(settings.debug) logger = get_logger(__name__) diff --git a/backend/app/services/adaptive_rag_service.py b/backend/app/services/adaptive_rag_service.py deleted file mode 100644 index 9bc8a5c9..00000000 --- a/backend/app/services/adaptive_rag_service.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Adaptive RAG service compatibility module.""" - -from .adaptive_rag_service import AdaptiveRAGService - -__all__ = ["AdaptiveRAGService"] diff --git a/backend/app/services/adaptive_rag_service/shared_imports.py b/backend/app/services/adaptive_rag_service/shared_imports.py index 90f58275..c74473d2 100644 --- a/backend/app/services/adaptive_rag_service/shared_imports.py +++ b/backend/app/services/adaptive_rag_service/shared_imports.py @@ -27,9 +27,9 @@ import httpx from sqlalchemy import and_, bindparam, delete, func, or_, select, text from sqlalchemy.ext.asyncio import AsyncSession -from ..config.ai_prompts import PROMPT_RAG_ANSWER, PROMPT_RAG_DB_PROJECT_QA, PROMPT_RAG_INTENT_CLASSIFICATION -from ..database import AsyncSessionLocal -from ..models import ( +from ...config.ai_prompts import PROMPT_RAG_ANSWER, PROMPT_RAG_DB_PROJECT_QA, PROMPT_RAG_INTENT_CLASSIFICATION +from ...core.database import AsyncSessionLocal +from ...models import ( KnowledgeBaseChunk, KnowledgeBaseDoc, KGEvidence, @@ -48,10 +48,10 @@ from ..models import ( UserProject, UserWorkload, ) -from .context_cache import context_cache_service -from .llm import LLMService -from .signal_source_orchestration_service import SignalSourceOrchestrationService -from .symbol_index_service import SymbolIndexService +from ..context_cache_service import context_cache_service +from ..llm_service import LLMService +from ..signal_source_orchestration import SignalSourceOrchestrationService +from ..symbol_index import SymbolIndexService -from ..utils.timezone import CN_TZ, now_cn_aware, now_cn_naive +from ...utils.timezone import CN_TZ, now_cn_aware, now_cn_naive diff --git a/backend/app/services/ai_orchestration_run/__init__.py b/backend/app/services/ai_orchestration_run/__init__.py new file mode 100644 index 00000000..c8da9c04 --- /dev/null +++ b/backend/app/services/ai_orchestration_run/__init__.py @@ -0,0 +1,5 @@ +"""Public exports for AI orchestration run services.""" + +from .service import AIOrchestrationRunService + +__all__ = ["AIOrchestrationRunService"] diff --git a/backend/app/services/ai_orchestration_run_service.py b/backend/app/services/ai_orchestration_run/service.py similarity index 98% rename from backend/app/services/ai_orchestration_run_service.py rename to backend/app/services/ai_orchestration_run/service.py index faedd2d4..c6be4539 100644 --- a/backend/app/services/ai_orchestration_run_service.py +++ b/backend/app/services/ai_orchestration_run/service.py @@ -8,10 +8,10 @@ from typing import Any, Optional from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..models import AIOrchestrationRun +from ...models import AIOrchestrationRun -from ..utils.timezone import now_cn_naive +from ...utils.timezone import now_cn_naive def _utc_now_naive() -> datetime: return now_cn_naive() diff --git a/backend/app/services/ai_pmo_cadence_service.py b/backend/app/services/ai_pmo_cadence_service.py deleted file mode 100644 index b4cd5985..00000000 --- a/backend/app/services/ai_pmo_cadence_service.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Compatibility exports for AI PMO cadence service.""" - -from .ai_pmo_cadence import AIPMOCadenceService - -__all__ = ["AIPMOCadenceService"] diff --git a/backend/app/services/ai_pmo_decision/shared.py b/backend/app/services/ai_pmo_decision/shared.py index d7855a5b..66212919 100644 --- a/backend/app/services/ai_pmo_decision/shared.py +++ b/backend/app/services/ai_pmo_decision/shared.py @@ -5,7 +5,7 @@ from __future__ import annotations import re from typing import Any -from ..ai_pmo_intent_routing import ( +from ..ai_pmo_intent import ( INTENT_FOLLOWUP_CONFIRM, INTENT_FOLLOWUP_CONTINUE, INTENT_PROJECT_CREATE, diff --git a/backend/app/services/ai_pmo_decision_runtime.py b/backend/app/services/ai_pmo_decision_runtime.py deleted file mode 100644 index e49ca4d8..00000000 --- a/backend/app/services/ai_pmo_decision_runtime.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Compatibility exports for AI PMO decision runtime.""" - -from .ai_pmo_decision import ( - DecisionEngine, - ExecutionPolicyBrain, - SimulationEngine, - StrategicBrain, - TacticalBrain, - _normalize_workload_ratio, - _safe_int, -) - -__all__ = [ - "StrategicBrain", - "TacticalBrain", - "SimulationEngine", - "ExecutionPolicyBrain", - "DecisionEngine", - "_normalize_workload_ratio", - "_safe_int", -] diff --git a/backend/app/services/ai_pmo_intent/shared.py b/backend/app/services/ai_pmo_intent/shared.py index 528864e5..63732811 100644 --- a/backend/app/services/ai_pmo_intent/shared.py +++ b/backend/app/services/ai_pmo_intent/shared.py @@ -6,8 +6,8 @@ import re from dataclasses import dataclass from typing import Any, Optional -from .project_command_utils import extract_project_create_title -from .signal_source_orchestration_service import SignalSourceOrchestrationService +from ...utils.project_command_utils import extract_project_create_title +from ..signal_source_orchestration import SignalSourceOrchestrationService INTENT_QUERY = "query.read_only" INTENT_PROJECT_CREATE = "project.create" diff --git a/backend/app/services/ai_pmo_intent_routing.py b/backend/app/services/ai_pmo_intent_routing.py deleted file mode 100644 index f79dd324..00000000 --- a/backend/app/services/ai_pmo_intent_routing.py +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import annotations - -from .ai_pmo_intent import * diff --git a/backend/app/services/ai_pmo_kernel/__init__.py b/backend/app/services/ai_pmo_kernel/__init__.py new file mode 100644 index 00000000..ff2667aa --- /dev/null +++ b/backend/app/services/ai_pmo_kernel/__init__.py @@ -0,0 +1,19 @@ +"""Public exports for AI PMO kernel package.""" + +from .ai_agent_kernel import ( + build_decision_trace, + gate_execution, + resolve_correction, + select_intent_route, +) +from .ai_pmo_domain_workflow import SignalSourceDomainWorkflow +from .ai_pmo_kernel_runtime import AIPMOKernelService + +__all__ = [ + "AIPMOKernelService", + "SignalSourceDomainWorkflow", + "build_decision_trace", + "gate_execution", + "resolve_correction", + "select_intent_route", +] diff --git a/backend/app/services/ai_agent_kernel.py b/backend/app/services/ai_pmo_kernel/ai_agent_kernel.py similarity index 100% rename from backend/app/services/ai_agent_kernel.py rename to backend/app/services/ai_pmo_kernel/ai_agent_kernel.py diff --git a/backend/app/services/ai_pmo_domain_workflow.py b/backend/app/services/ai_pmo_kernel/ai_pmo_domain_workflow.py similarity index 98% rename from backend/app/services/ai_pmo_domain_workflow.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_domain_workflow.py index 5a8d73a1..6dc6bfee 100644 --- a/backend/app/services/ai_pmo_domain_workflow.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_domain_workflow.py @@ -6,7 +6,7 @@ from typing import Any, Optional from sqlalchemy.ext.asyncio import AsyncSession -from .signal_source_orchestration_service import SignalSourceOrchestrationService +from ..signal_source_orchestration import SignalSourceOrchestrationService class SignalSourceDomainWorkflow: diff --git a/backend/app/services/ai_pmo_kernel_mixins_closure.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure.py similarity index 100% rename from backend/app/services/ai_pmo_kernel_mixins_closure.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure.py diff --git a/backend/app/services/ai_pmo_kernel_mixins_closure_data.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure_data.py similarity index 99% rename from backend/app/services/ai_pmo_kernel_mixins_closure_data.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure_data.py index 178f8d38..34cf7b72 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_closure_data.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure_data.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_closure_helpers.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure_helpers.py similarity index 98% rename from backend/app/services/ai_pmo_kernel_mixins_closure_helpers.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure_helpers.py index 8a374db6..542cdc0d 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_closure_helpers.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure_helpers.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_closure_payload.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure_payload.py similarity index 99% rename from backend/app/services/ai_pmo_kernel_mixins_closure_payload.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure_payload.py index 0bd926f5..798a0beb 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_closure_payload.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_closure_payload.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_followup.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup.py similarity index 100% rename from backend/app/services/ai_pmo_kernel_mixins_followup.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup.py diff --git a/backend/app/services/ai_pmo_kernel_mixins_followup_project_signal.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_project_signal.py similarity index 100% rename from backend/app/services/ai_pmo_kernel_mixins_followup_project_signal.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_project_signal.py diff --git a/backend/app/services/ai_pmo_kernel_mixins_followup_project_signal_actions.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_project_signal_actions.py similarity index 99% rename from backend/app/services/ai_pmo_kernel_mixins_followup_project_signal_actions.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_project_signal_actions.py index dc0b6dc1..b48ad7d5 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_followup_project_signal_actions.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_project_signal_actions.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_followup_project_signal_resume.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_project_signal_resume.py similarity index 99% rename from backend/app/services/ai_pmo_kernel_mixins_followup_project_signal_resume.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_project_signal_resume.py index 73a118f9..ab367700 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_followup_project_signal_resume.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_project_signal_resume.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_followup_records.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_records.py similarity index 98% rename from backend/app/services/ai_pmo_kernel_mixins_followup_records.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_records.py index 117074ea..ded6b3c3 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_followup_records.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_records.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_followup_routing.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_routing.py similarity index 99% rename from backend/app/services/ai_pmo_kernel_mixins_followup_routing.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_routing.py index 7d1ed51d..98b9c92e 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_followup_routing.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_routing.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_followup_verification.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_verification.py similarity index 99% rename from backend/app/services/ai_pmo_kernel_mixins_followup_verification.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_verification.py index 4d34d36c..3a97429b 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_followup_verification.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_followup_verification.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_ingress.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_ingress.py similarity index 85% rename from backend/app/services/ai_pmo_kernel_mixins_ingress.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_ingress.py index f97e1f1f..0fc079fc 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_ingress.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_ingress.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .ai_pmo_kernel_mixins_ingress_flow import KernelIngressFlowMixin +from ..ai_pmo_kernel_ingress_flow import KernelIngressFlowMixin from .ai_pmo_kernel_mixins_ingress_render import KernelIngressRenderMixin from .ai_pmo_kernel_mixins_ingress_storage import KernelIngressStorageMixin diff --git a/backend/app/services/ai_pmo_kernel_mixins_ingress_render.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_ingress_render.py similarity index 99% rename from backend/app/services/ai_pmo_kernel_mixins_ingress_render.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_ingress_render.py index 0371b016..9950ee77 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_ingress_render.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_ingress_render.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_ingress_storage.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_ingress_storage.py similarity index 99% rename from backend/app/services/ai_pmo_kernel_mixins_ingress_storage.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_ingress_storage.py index 247d50a0..36055cbe 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_ingress_storage.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_ingress_storage.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_intent.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent.py similarity index 100% rename from backend/app/services/ai_pmo_kernel_mixins_intent.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent.py diff --git a/backend/app/services/ai_pmo_kernel_mixins_intent_llm.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent_llm.py similarity index 99% rename from backend/app/services/ai_pmo_kernel_mixins_intent_llm.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent_llm.py index d7d85830..6682a219 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_intent_llm.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent_llm.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_intent_resolve.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent_resolve.py similarity index 98% rename from backend/app/services/ai_pmo_kernel_mixins_intent_resolve.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent_resolve.py index e69c298c..5bebf3d4 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_intent_resolve.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent_resolve.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_intent_rules.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent_rules.py similarity index 99% rename from backend/app/services/ai_pmo_kernel_mixins_intent_rules.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent_rules.py index 78b3b427..273df9b0 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_intent_rules.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_intent_rules.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_world_model.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_world_model.py similarity index 69% rename from backend/app/services/ai_pmo_kernel_mixins_world_model.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_world_model.py index 40c6e920..306bc70f 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_world_model.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_world_model.py @@ -2,8 +2,8 @@ from __future__ import annotations -from .ai_pmo_kernel_mixins_world_model_aggregates import KernelWorldModelAggregatesMixin -from .ai_pmo_kernel_mixins_world_model_core import KernelWorldModelCoreMixin +from ..ai_pmo_kernel_world_model_aggregates import KernelWorldModelAggregatesMixin +from ..ai_pmo_kernel_world_model_core import KernelWorldModelCoreMixin from .ai_pmo_kernel_mixins_world_model_session import KernelWorldModelSessionMixin diff --git a/backend/app/services/ai_pmo_kernel_mixins_world_model_session.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_world_model_session.py similarity index 98% rename from backend/app/services/ai_pmo_kernel_mixins_world_model_session.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_world_model_session.py index 848ed1b3..d4d9de5c 100644 --- a/backend/app/services/ai_pmo_kernel_mixins_world_model_session.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_mixins_world_model_session.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_runtime.py b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_runtime.py similarity index 97% rename from backend/app/services/ai_pmo_kernel_runtime.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_kernel_runtime.py index 532301c4..dd1aecb7 100644 --- a/backend/app/services/ai_pmo_kernel_runtime.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_kernel_runtime.py @@ -2,7 +2,7 @@ from __future__ import annotations -from . import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_reply_renderer.py b/backend/app/services/ai_pmo_kernel/ai_pmo_reply_renderer.py similarity index 99% rename from backend/app/services/ai_pmo_reply_renderer.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_reply_renderer.py index 97882b0a..43410595 100644 --- a/backend/app/services/ai_pmo_reply_renderer.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_reply_renderer.py @@ -4,7 +4,7 @@ from __future__ import annotations from typing import Any, Optional -from .ai_pmo_intent_routing import ( +from ..ai_pmo_intent import ( INTENT_FOLLOWUP_CONFIRM, INTENT_FOLLOWUP_CONTINUE, INTENT_PROJECT_CREATE, diff --git a/backend/app/services/ai_pmo_review_service.py b/backend/app/services/ai_pmo_kernel/ai_pmo_review_service.py similarity index 98% rename from backend/app/services/ai_pmo_review_service.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_review_service.py index 40ca3396..1e70065e 100644 --- a/backend/app/services/ai_pmo_review_service.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_review_service.py @@ -7,7 +7,7 @@ from typing import Any from sqlalchemy import and_, func, select from sqlalchemy.ext.asyncio import AsyncSession -from ..models import PortfolioSnapshot, ProjectSignalLink, ReplyReceipt, SignalSourceRegistry, WorkItem +from ...models import PortfolioSnapshot, ProjectSignalLink, ReplyReceipt, SignalSourceRegistry, WorkItem def _safe_int(value: Any) -> int | None: diff --git a/backend/app/services/ai_pmo_typed_executor.py b/backend/app/services/ai_pmo_kernel/ai_pmo_typed_executor.py similarity index 81% rename from backend/app/services/ai_pmo_typed_executor.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_typed_executor.py index f9060073..70a0da85 100644 --- a/backend/app/services/ai_pmo_typed_executor.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_typed_executor.py @@ -8,8 +8,8 @@ for _name, _value in vars(_common).items(): if not _name.startswith("__"): globals()[_name] = _value -from .ai_pmo_typed_executor_mixins_discovery import TypedExecutorDiscoveryMixin -from .ai_pmo_typed_executor_mixins_execute import TypedExecutorExecuteMixin +from ..ai_pmo_typed_executor_discovery import TypedExecutorDiscoveryMixin +from ..ai_pmo_typed_executor_execute import TypedExecutorExecuteMixin from .ai_pmo_typed_executor_mixins_parse import TypedExecutorParseMixin diff --git a/backend/app/services/ai_pmo_typed_executor_common.py b/backend/app/services/ai_pmo_kernel/ai_pmo_typed_executor_common.py similarity index 82% rename from backend/app/services/ai_pmo_typed_executor_common.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_typed_executor_common.py index ef162c73..4193d2bc 100644 --- a/backend/app/services/ai_pmo_typed_executor_common.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_typed_executor_common.py @@ -11,9 +11,9 @@ from typing import Any, Optional from sqlalchemy import and_, or_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..config.ai_prompts import PROMPT_AI_PMO_SIGNAL_BATCH_ANALYSIS -from ..core.logging import get_logger -from ..models import ( +from ...config.ai_prompts import PROMPT_AI_PMO_SIGNAL_BATCH_ANALYSIS +from ...core.logging import get_logger +from ...models import ( Experiment, Project, ProjectSignalLink, @@ -23,10 +23,10 @@ from ..models import ( UserSkillBinding, UserWorkload, ) -from ..utils.timezone import now_cn_naive -from .adaptive_rag_service import AdaptiveRAGService +from ...utils.timezone import now_cn_naive +from ..adaptive_rag_service import AdaptiveRAGService from .ai_pmo_domain_workflow import SignalSourceDomainWorkflow -from .ai_pmo_intent_routing import ( +from ..ai_pmo_intent import ( INTENT_PROJECT_CREATE, INTENT_QUERY, INTENT_SIGNAL_CREATE, @@ -40,10 +40,10 @@ from .ai_pmo_intent_routing import ( IntentResolver, RouteResolver, ) -from .ai_steward import AIStewardService -from .llm import llm_service -from .model_context_bundle_service import ModelContextBundleService -from .signal_planner_service import SignalPlannerService +from ..ai_steward_service import AIStewardService +from ..llm_service import llm_service +from ..model_context_bundle import ModelContextBundleService +from ..signal_planner import SignalPlannerService logger = get_logger(__name__) diff --git a/backend/app/services/ai_pmo_typed_executor_mixins_parse.py b/backend/app/services/ai_pmo_kernel/ai_pmo_typed_executor_mixins_parse.py similarity index 100% rename from backend/app/services/ai_pmo_typed_executor_mixins_parse.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_typed_executor_mixins_parse.py diff --git a/backend/app/services/ai_pmo_workflow_runtime.py b/backend/app/services/ai_pmo_kernel/ai_pmo_workflow_runtime.py similarity index 97% rename from backend/app/services/ai_pmo_workflow_runtime.py rename to backend/app/services/ai_pmo_kernel/ai_pmo_workflow_runtime.py index 7c1de13c..12d54927 100644 --- a/backend/app/services/ai_pmo_workflow_runtime.py +++ b/backend/app/services/ai_pmo_kernel/ai_pmo_workflow_runtime.py @@ -4,9 +4,9 @@ from __future__ import annotations from typing import Optional, TYPE_CHECKING -from ..models import ConversationSession, IngestEvent, Project, WorkItem -from ..schemas.world_model import WorldModel -from .ai_pmo_intent_routing import ( +from ...models import ConversationSession, IngestEvent, Project, WorkItem +from ...schemas.world_model import WorldModel +from ..ai_pmo_intent import ( INTENT_FOLLOWUP_CONTINUE, ROUTE_ACTION_DISCOVER, ROUTE_FAMILY_FOLLOWUP, @@ -20,7 +20,7 @@ from .ai_pmo_intent_routing import ( ) if TYPE_CHECKING: - from .ai_pmo_kernel_service import AIPMOKernelService + from .ai_pmo_kernel_runtime import AIPMOKernelService class ContextAssembler: diff --git a/backend/app/services/ai_pmo_kernel_common.py b/backend/app/services/ai_pmo_kernel_common.py deleted file mode 100644 index 1bdcecdf..00000000 --- a/backend/app/services/ai_pmo_kernel_common.py +++ /dev/null @@ -1,5 +0,0 @@ -"""AI PMO 决策中枢内核服务。""" - -from __future__ import annotations - -from .ai_pmo_kernel_common_core import * # noqa: F401,F403 diff --git a/backend/app/services/ai_pmo_kernel_common_core/__init__.py b/backend/app/services/ai_pmo_kernel_common_core/__init__.py index 3da93b92..6d048715 100644 --- a/backend/app/services/ai_pmo_kernel_common_core/__init__.py +++ b/backend/app/services/ai_pmo_kernel_common_core/__init__.py @@ -1,5 +1,5 @@ """Public exports for AI PMO kernel common module.""" -from .constants import * # noqa: F401,F403 -from .helpers import * # noqa: F401,F403 -from .imports import * # noqa: F401,F403 +from .constants import * # noqa: F401, F403 +from .helpers import * # noqa: F401, F403 +from .imports import * # noqa: F401, F403 diff --git a/backend/app/services/ai_pmo_kernel_common_core/imports.py b/backend/app/services/ai_pmo_kernel_common_core/imports.py index 8f759ce6..0e3e7c78 100644 --- a/backend/app/services/ai_pmo_kernel_common_core/imports.py +++ b/backend/app/services/ai_pmo_kernel_common_core/imports.py @@ -63,16 +63,16 @@ from ...schemas.world_model import ( ) from ...utils.timezone import now_cn_naive from ..adaptive_rag_service import AdaptiveRAGService -from ..ai_agent_kernel import ( +from ..ai_pmo_kernel import ( build_decision_trace, gate_execution as kernel_gate_execution, resolve_correction as kernel_resolve_correction, select_intent_route, ) -from ..ai_pmo_cadence_service import AIPMOCadenceService -from ..ai_pmo_decision_runtime import DecisionEngine -from ..ai_pmo_domain_workflow import SignalSourceDomainWorkflow -from ..ai_pmo_intent_routing import ( +from ..ai_pmo_cadence import AIPMOCadenceService +from ..ai_pmo_decision import DecisionEngine +from ..ai_pmo_kernel import SignalSourceDomainWorkflow +from ..ai_pmo_intent import ( FOLLOWUP_TARGET_INTENTS, FOLLOWUP_WORK_ITEM_ID_RE, INTENT_CANDIDATES, @@ -119,15 +119,15 @@ from ..ai_pmo_intent_routing import ( RouteResolver, WorkflowRoute, ) -from ..ai_pmo_reply_renderer import ReplyRenderer -from ..ai_pmo_review_service import AIPMOReviewService -from ..ai_pmo_typed_executor import TypedExecutor -from ..ai_pmo_workflow_runtime import ContextAssembler, WorkflowRegistry -from ..ai_steward import AIStewardService -from ..context_cache import ContextCacheService -from ..llm import llm_service -from ..model_context_bundle_service import ModelContextBundleService +from ..ai_pmo_kernel.ai_pmo_reply_renderer import ReplyRenderer +from ..ai_pmo_kernel.ai_pmo_review_service import AIPMOReviewService +from ..ai_pmo_kernel.ai_pmo_typed_executor import TypedExecutor +from ..ai_pmo_kernel.ai_pmo_workflow_runtime import ContextAssembler, WorkflowRegistry +from ..ai_steward_service import AIStewardService +from ..context_cache_service import ContextCacheService +from ..llm_service import llm_service +from ..model_context_bundle import ModelContextBundleService from ..notification_service import NotificationService -from ..signal_planner_service import SignalPlannerService +from ..signal_planner import SignalPlannerService logger = get_logger(__name__) diff --git a/backend/app/services/ai_pmo_kernel_ingress_flow/shared.py b/backend/app/services/ai_pmo_kernel_ingress_flow/shared.py index 97800d2f..2b68a92a 100644 --- a/backend/app/services/ai_pmo_kernel_ingress_flow/shared.py +++ b/backend/app/services/ai_pmo_kernel_ingress_flow/shared.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .. import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_mixins_ingress_flow.py b/backend/app/services/ai_pmo_kernel_mixins_ingress_flow.py deleted file mode 100644 index d0b0f0e1..00000000 --- a/backend/app/services/ai_pmo_kernel_mixins_ingress_flow.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .ai_pmo_kernel_ingress_flow import KernelIngressFlowMixin - -__all__ = ["KernelIngressFlowMixin"] diff --git a/backend/app/services/ai_pmo_kernel_mixins_world_model_aggregates.py b/backend/app/services/ai_pmo_kernel_mixins_world_model_aggregates.py deleted file mode 100644 index 5a01ffe0..00000000 --- a/backend/app/services/ai_pmo_kernel_mixins_world_model_aggregates.py +++ /dev/null @@ -1,7 +0,0 @@ -"""AI PMO kernel world-model aggregates mixin.""" - -from __future__ import annotations - -from .ai_pmo_kernel_world_model_aggregates import KernelWorldModelAggregatesMixin - -__all__ = ["KernelWorldModelAggregatesMixin"] diff --git a/backend/app/services/ai_pmo_kernel_mixins_world_model_core.py b/backend/app/services/ai_pmo_kernel_mixins_world_model_core.py deleted file mode 100644 index a59f43c1..00000000 --- a/backend/app/services/ai_pmo_kernel_mixins_world_model_core.py +++ /dev/null @@ -1,7 +0,0 @@ -"""AI PMO kernel world-model core mixin.""" - -from __future__ import annotations - -from .ai_pmo_kernel_world_model_core import KernelWorldModelCoreMixin - -__all__ = ["KernelWorldModelCoreMixin"] diff --git a/backend/app/services/ai_pmo_kernel_service.py b/backend/app/services/ai_pmo_kernel_service.py deleted file mode 100644 index 3d169f43..00000000 --- a/backend/app/services/ai_pmo_kernel_service.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Backward-compatible AI PMO kernel service entrypoint.""" - -from .ai_pmo_kernel_runtime import AIPMOKernelService - -__all__ = ["AIPMOKernelService"] diff --git a/backend/app/services/ai_pmo_kernel_world_model_aggregates/mixin_basics.py b/backend/app/services/ai_pmo_kernel_world_model_aggregates/mixin_basics.py index c7ec0bdf..79c4106e 100644 --- a/backend/app/services/ai_pmo_kernel_world_model_aggregates/mixin_basics.py +++ b/backend/app/services/ai_pmo_kernel_world_model_aggregates/mixin_basics.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class KernelWorldModelAggregatesBasicsMixin: diff --git a/backend/app/services/ai_pmo_kernel_world_model_aggregates/mixin_project.py b/backend/app/services/ai_pmo_kernel_world_model_aggregates/mixin_project.py index 06ca3d2f..c4a4c261 100644 --- a/backend/app/services/ai_pmo_kernel_world_model_aggregates/mixin_project.py +++ b/backend/app/services/ai_pmo_kernel_world_model_aggregates/mixin_project.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class KernelWorldModelAggregatesProjectMixin: diff --git a/backend/app/services/ai_pmo_kernel_world_model_aggregates/shared.py b/backend/app/services/ai_pmo_kernel_world_model_aggregates/shared.py index e64a4d4b..90514154 100644 --- a/backend/app/services/ai_pmo_kernel_world_model_aggregates/shared.py +++ b/backend/app/services/ai_pmo_kernel_world_model_aggregates/shared.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .. import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_kernel_world_model_core/mixin_builder.py b/backend/app/services/ai_pmo_kernel_world_model_core/mixin_builder.py index 000f8f19..6e17aa4f 100644 --- a/backend/app/services/ai_pmo_kernel_world_model_core/mixin_builder.py +++ b/backend/app/services/ai_pmo_kernel_world_model_core/mixin_builder.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class KernelWorldModelCoreBuilderMixin: diff --git a/backend/app/services/ai_pmo_kernel_world_model_core/mixin_cache.py b/backend/app/services/ai_pmo_kernel_world_model_core/mixin_cache.py index 5ab5bef7..0c0874db 100644 --- a/backend/app/services/ai_pmo_kernel_world_model_core/mixin_cache.py +++ b/backend/app/services/ai_pmo_kernel_world_model_core/mixin_cache.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class KernelWorldModelCoreCacheMixin: diff --git a/backend/app/services/ai_pmo_kernel_world_model_core/mixin_project.py b/backend/app/services/ai_pmo_kernel_world_model_core/mixin_project.py index 94ec2207..8a661124 100644 --- a/backend/app/services/ai_pmo_kernel_world_model_core/mixin_project.py +++ b/backend/app/services/ai_pmo_kernel_world_model_core/mixin_project.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class KernelWorldModelCoreProjectMixin: diff --git a/backend/app/services/ai_pmo_kernel_world_model_core/shared.py b/backend/app/services/ai_pmo_kernel_world_model_core/shared.py index c2a3f782..e404b302 100644 --- a/backend/app/services/ai_pmo_kernel_world_model_core/shared.py +++ b/backend/app/services/ai_pmo_kernel_world_model_core/shared.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .. import ai_pmo_kernel_common as _common +from .. import ai_pmo_kernel_common_core as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_typed_executor_discovery/mixin_analysis.py b/backend/app/services/ai_pmo_typed_executor_discovery/mixin_analysis.py index 1163d363..529dd3ed 100644 --- a/backend/app/services/ai_pmo_typed_executor_discovery/mixin_analysis.py +++ b/backend/app/services/ai_pmo_typed_executor_discovery/mixin_analysis.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class DiscoveryAnalysisMixin: diff --git a/backend/app/services/ai_pmo_typed_executor_discovery/mixin_context.py b/backend/app/services/ai_pmo_typed_executor_discovery/mixin_context.py index 6caed7c3..7a460944 100644 --- a/backend/app/services/ai_pmo_typed_executor_discovery/mixin_context.py +++ b/backend/app/services/ai_pmo_typed_executor_discovery/mixin_context.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class DiscoveryContextMixin: diff --git a/backend/app/services/ai_pmo_typed_executor_discovery/mixin_discover.py b/backend/app/services/ai_pmo_typed_executor_discovery/mixin_discover.py index 0ac65bee..6f1ee170 100644 --- a/backend/app/services/ai_pmo_typed_executor_discovery/mixin_discover.py +++ b/backend/app/services/ai_pmo_typed_executor_discovery/mixin_discover.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class DiscoveryFlowMixin: diff --git a/backend/app/services/ai_pmo_typed_executor_discovery/shared.py b/backend/app/services/ai_pmo_typed_executor_discovery/shared.py index f5944df2..ae96110d 100644 --- a/backend/app/services/ai_pmo_typed_executor_discovery/shared.py +++ b/backend/app/services/ai_pmo_typed_executor_discovery/shared.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .. import ai_pmo_typed_executor_common as _common +from ..ai_pmo_kernel import ai_pmo_typed_executor_common as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_typed_executor_execute/mixin_execute_query_project.py b/backend/app/services/ai_pmo_typed_executor_execute/mixin_execute_query_project.py index 08c2996d..3c8e1791 100644 --- a/backend/app/services/ai_pmo_typed_executor_execute/mixin_execute_query_project.py +++ b/backend/app/services/ai_pmo_typed_executor_execute/mixin_execute_query_project.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class ExecuteQueryProjectMixin: diff --git a/backend/app/services/ai_pmo_typed_executor_execute/mixin_execute_signal_create.py b/backend/app/services/ai_pmo_typed_executor_execute/mixin_execute_signal_create.py index 08dddca0..b2590191 100644 --- a/backend/app/services/ai_pmo_typed_executor_execute/mixin_execute_signal_create.py +++ b/backend/app/services/ai_pmo_typed_executor_execute/mixin_execute_signal_create.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class ExecuteSignalCreateMixin: diff --git a/backend/app/services/ai_pmo_typed_executor_execute/mixin_execute_signal_source.py b/backend/app/services/ai_pmo_typed_executor_execute/mixin_execute_signal_source.py index c4988b56..3675f87c 100644 --- a/backend/app/services/ai_pmo_typed_executor_execute/mixin_execute_signal_source.py +++ b/backend/app/services/ai_pmo_typed_executor_execute/mixin_execute_signal_source.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class ExecuteSignalSourceMixin: diff --git a/backend/app/services/ai_pmo_typed_executor_execute/mixin_helpers.py b/backend/app/services/ai_pmo_typed_executor_execute/mixin_helpers.py index ddd7b8ef..f9f63a4c 100644 --- a/backend/app/services/ai_pmo_typed_executor_execute/mixin_helpers.py +++ b/backend/app/services/ai_pmo_typed_executor_execute/mixin_helpers.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class ExecuteHelpersMixin: diff --git a/backend/app/services/ai_pmo_typed_executor_execute/service.py b/backend/app/services/ai_pmo_typed_executor_execute/service.py index 0877babc..1d4f6354 100644 --- a/backend/app/services/ai_pmo_typed_executor_execute/service.py +++ b/backend/app/services/ai_pmo_typed_executor_execute/service.py @@ -6,7 +6,7 @@ from .mixin_execute_query_project import ExecuteQueryProjectMixin from .mixin_execute_signal_create import ExecuteSignalCreateMixin from .mixin_execute_signal_source import ExecuteSignalSourceMixin from .mixin_helpers import ExecuteHelpersMixin -from .shared import * # noqa: F401,F403 +from .shared import * # noqa: F401, F403 class TypedExecutorExecuteMixin( diff --git a/backend/app/services/ai_pmo_typed_executor_execute/shared.py b/backend/app/services/ai_pmo_typed_executor_execute/shared.py index 6d287d2c..1e68ffef 100644 --- a/backend/app/services/ai_pmo_typed_executor_execute/shared.py +++ b/backend/app/services/ai_pmo_typed_executor_execute/shared.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .. import ai_pmo_typed_executor_common as _common +from ..ai_pmo_kernel import ai_pmo_typed_executor_common as _common for _name, _value in vars(_common).items(): if not _name.startswith("__"): diff --git a/backend/app/services/ai_pmo_typed_executor_mixins_discovery.py b/backend/app/services/ai_pmo_typed_executor_mixins_discovery.py deleted file mode 100644 index 8f62e0bd..00000000 --- a/backend/app/services/ai_pmo_typed_executor_mixins_discovery.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Compatibility exports for typed executor discovery mixin.""" - -from .ai_pmo_typed_executor_discovery import TypedExecutorDiscoveryMixin - -__all__ = ["TypedExecutorDiscoveryMixin"] diff --git a/backend/app/services/ai_pmo_typed_executor_mixins_execute.py b/backend/app/services/ai_pmo_typed_executor_mixins_execute.py deleted file mode 100644 index a8a54191..00000000 --- a/backend/app/services/ai_pmo_typed_executor_mixins_execute.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Compatibility exports for typed executor execute mixin.""" - -from .ai_pmo_typed_executor_execute import TypedExecutorExecuteMixin - -__all__ = ["TypedExecutorExecuteMixin"] diff --git a/backend/app/services/ai_service.py b/backend/app/services/ai_service.py deleted file mode 100644 index 0b583ec2..00000000 --- a/backend/app/services/ai_service.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .ai_service_core import AIService, get_ai_service - -__all__ = ["AIService", "get_ai_service"] diff --git a/backend/app/services/ai_service_core/mixin_business_analysis.py b/backend/app/services/ai_service_core/mixin_business_analysis.py index 5e3e9ca2..d2e7af1b 100644 --- a/backend/app/services/ai_service_core/mixin_business_analysis.py +++ b/backend/app/services/ai_service_core/mixin_business_analysis.py @@ -15,7 +15,7 @@ class AIServiceBusinessAnalysisMixin: ) -> dict: """任务完成后,根据质量/效率评分更新相关人员技能分""" from sqlalchemy import select - from ..models import UserSkillBinding + from ...models import UserSkillBinding from uuid import UUID def to_uuid(v): @@ -77,9 +77,9 @@ class AIServiceBusinessAnalysisMixin: user_context: str = "", ) -> dict: """计算用户对真理节点的认知对齐度(0-100)""" - from ..config.ai_prompts import PROMPT_ALIGNMENT_SCORE + from ...config.ai_prompts import PROMPT_ALIGNMENT_SCORE from sqlalchemy import select - from ..models import TruthNode + from ...models import TruthNode tid = _t2s(tenant_id) if db and not truth_content: @@ -116,9 +116,9 @@ class AIServiceBusinessAnalysisMixin: user_viewpoints: str = "", ) -> dict: """识别真理节点下的隐性认知冲突""" - from ..config.ai_prompts import PROMPT_COGNITIVE_CONFLICTS + from ...config.ai_prompts import PROMPT_COGNITIVE_CONFLICTS from sqlalchemy import select - from ..models import TruthNode + from ...models import TruthNode tid = _t2s(tenant_id) if db and not truth_content: @@ -154,7 +154,7 @@ class AIServiceBusinessAnalysisMixin: model_info: str = "", ) -> dict: """评估需求与模型的匹配度""" - from ..config.ai_prompts import PROMPT_EVALUATE_MODEL_REQUIREMENT + from ...config.ai_prompts import PROMPT_EVALUATE_MODEL_REQUIREMENT tid = _t2s(tenant_id) prompt = PROMPT_EVALUATE_MODEL_REQUIREMENT.format( diff --git a/backend/app/services/ai_service_core/mixin_business_tasks.py b/backend/app/services/ai_service_core/mixin_business_tasks.py index ba2def40..91f129eb 100644 --- a/backend/app/services/ai_service_core/mixin_business_tasks.py +++ b/backend/app/services/ai_service_core/mixin_business_tasks.py @@ -10,7 +10,7 @@ class AIServiceBusinessTasksMixin: db=None, ) -> dict: """从市场/模型信号生成需求宪章草案""" - from ..config.ai_prompts import PROMPT_GENERATE_CHARTER + from ...config.ai_prompts import PROMPT_GENERATE_CHARTER tid = _t2s(tenant_id) prompt = PROMPT_GENERATE_CHARTER.format(signal_content=signal_content) @@ -27,7 +27,7 @@ class AIServiceBusinessTasksMixin: db=None, ) -> dict: """从宪章拆解任务,自动识别所需技能标签,返回带技能要求的任务列表""" - from ..config.ai_prompts import PROMPT_DECOMPOSE_TASKS + from ...config.ai_prompts import PROMPT_DECOMPOSE_TASKS tid = _t2s(tenant_id) prompt = PROMPT_DECOMPOSE_TASKS.format( @@ -49,7 +49,7 @@ class AIServiceBusinessTasksMixin: candidates_json: Optional[str] = None, ) -> dict: """基于人员能力图谱、负载、熟练度,推荐 Top3 人员""" - from ..config.ai_prompts import PROMPT_RECOMMEND_ASSIGNEES + from ...config.ai_prompts import PROMPT_RECOMMEND_ASSIGNEES tid = _t2s(tenant_id) candidates = candidates_json or "[]" diff --git a/backend/app/services/ai_service_core/mixin_runtime_prompt_retry.py b/backend/app/services/ai_service_core/mixin_runtime_prompt_retry.py index b9178f56..34a947a6 100644 --- a/backend/app/services/ai_service_core/mixin_runtime_prompt_retry.py +++ b/backend/app/services/ai_service_core/mixin_runtime_prompt_retry.py @@ -94,7 +94,7 @@ class AIServiceRuntimePromptRetryMixin: error_message: Optional[str] = None, ): try: - from ..models import AICallLog + from ...models import AICallLog total = prompt_tokens + completion_tokens cost = _estimate_cost(prompt_tokens, completion_tokens) @@ -136,7 +136,7 @@ class AIServiceRuntimePromptRetryMixin: # 预算前置检查(仅在有 db 会话时启用) if db is not None: try: - from .budget_enforcement_service import BudgetEnforcementService + from ..budget_enforcement import BudgetEnforcementService tenant_int = _tenant_to_int(tenant_id) # 预估:按 prompt 长度粗略估算,保守给定 completion 预算 @@ -185,7 +185,7 @@ class AIServiceRuntimePromptRetryMixin: ) # 按实际 token 成本累计预算 try: - from .budget_enforcement_service import BudgetEnforcementService + from ..budget_enforcement import BudgetEnforcementService actual_cost = _estimate_cost(prompt_tokens, completion_tokens) await BudgetEnforcementService(db).update_budget_usage_after_ai_call( diff --git a/backend/app/services/ai_service_core/shared.py b/backend/app/services/ai_service_core/shared.py index 3b659b54..8d3bd95f 100644 --- a/backend/app/services/ai_service_core/shared.py +++ b/backend/app/services/ai_service_core/shared.py @@ -45,7 +45,7 @@ DEFAULT_OPENAI_MODEL = "MiniMax-M2.5" DEFAULT_GLM_MODEL = "GLM-4.7" from ...config.ai_prompts import build_default_role_prompt_bundle -from ...database import AsyncSessionLocal +from ...core.database import AsyncSessionLocal from ...models import Integration diff --git a/backend/app/services/ai_steward.py b/backend/app/services/ai_steward.py deleted file mode 100644 index 5de53483..00000000 --- a/backend/app/services/ai_steward.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .ai_steward_service import AIStewardService, get_ai_steward_service - -__all__ = ["AIStewardService", "get_ai_steward_service"] diff --git a/backend/app/services/ai_steward_service/shared.py b/backend/app/services/ai_steward_service/shared.py index 6a4ac0a0..64427ae4 100644 --- a/backend/app/services/ai_steward_service/shared.py +++ b/backend/app/services/ai_steward_service/shared.py @@ -13,14 +13,14 @@ from typing import Any, Dict, List from sqlalchemy.ext.asyncio import AsyncSession from ...core.logging import get_logger -from ...database import get_db +from ...core.database import get_db from ...models import CognitiveConflict, Project, ProjectSignalLink, Signal, TruthNode from ...utils.project_members import ensure_project_default_members from ...utils.sequence import ensure_project_id_sequence from ...utils.title import compact_title from ..adaptive_rag_service import AdaptiveRAGService -from ..llm import LLMService -from ..task_persistence import ( +from ..llm_service import LLMService +from ..task_persistence_core import ( build_task_create_draft, normalize_skill_names, persist_task, diff --git a/backend/app/services/alignment_orchestrator.py b/backend/app/services/alignment_orchestrator.py deleted file mode 100644 index e69de29b..00000000 diff --git a/backend/app/services/audit_query_service/__init__.py b/backend/app/services/audit_query_service/__init__.py new file mode 100644 index 00000000..4f1e5894 --- /dev/null +++ b/backend/app/services/audit_query_service/__init__.py @@ -0,0 +1,5 @@ +"""Audit query service exports.""" + +from .service import AuditQueryService + +__all__ = ["AuditQueryService"] diff --git a/backend/app/services/audit_query_service.py b/backend/app/services/audit_query_service/service.py similarity index 95% rename from backend/app/services/audit_query_service.py rename to backend/app/services/audit_query_service/service.py index d82196d6..44ef41c7 100644 --- a/backend/app/services/audit_query_service.py +++ b/backend/app/services/audit_query_service/service.py @@ -8,9 +8,9 @@ from typing import Any, Optional from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..models import OperationLog -from ..utils.audited_write import format_beijing_datetime -from ..utils.timezone import CN_TZ +from ...models import OperationLog +from ...utils.audited_write import format_beijing_datetime +from ...utils.timezone import CN_TZ def _to_beijing_naive(value: Optional[datetime]) -> Optional[datetime]: diff --git a/backend/app/services/auditor.py b/backend/app/services/auditor.py deleted file mode 100644 index f6961e40..00000000 --- a/backend/app/services/auditor.py +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import annotations - -from .auditor_core import * diff --git a/backend/app/services/auth/__init__.py b/backend/app/services/auth/__init__.py new file mode 100644 index 00000000..88c294ba --- /dev/null +++ b/backend/app/services/auth/__init__.py @@ -0,0 +1,19 @@ +"""Authentication & authorization service exports.""" + +from .service import ( + AuthService, + can_assign_tasks, + can_manage_users, + has_any_role, + has_permission, + parse_role_values, +) + +__all__ = [ + "AuthService", + "has_permission", + "has_any_role", + "parse_role_values", + "can_manage_users", + "can_assign_tasks", +] diff --git a/backend/app/services/auth.py b/backend/app/services/auth/service.py similarity index 99% rename from backend/app/services/auth.py rename to backend/app/services/auth/service.py index 11798729..cde7736d 100644 --- a/backend/app/services/auth.py +++ b/backend/app/services/auth/service.py @@ -11,7 +11,7 @@ import hmac import os # Try to import passlib, fallback to simple hashing -from ..utils.timezone import now_cn_aware, now_cn_naive +from ...utils.timezone import now_cn_aware, now_cn_naive try: from passlib.context import CryptContext from jose import JWTError, jwt diff --git a/backend/app/services/auto_merger.py b/backend/app/services/auto_merger.py deleted file mode 100644 index bf51777b..00000000 --- a/backend/app/services/auto_merger.py +++ /dev/null @@ -1,19 +0,0 @@ -"""Compatibility exports for auto merge service.""" - -from .auto_merger_core import ( - AutoMergeService, - ConfirmationRequest, - MergeRequest, - MergeResponse, - MergeStatus, - get_auto_merger, -) - -__all__ = [ - "MergeStatus", - "MergeRequest", - "MergeResponse", - "ConfirmationRequest", - "AutoMergeService", - "get_auto_merger", -] diff --git a/backend/app/services/auto_merger_core/mixin_events_guard.py b/backend/app/services/auto_merger_core/mixin_events_guard.py index 80c5f2f3..49cce9fd 100644 --- a/backend/app/services/auto_merger_core/mixin_events_guard.py +++ b/backend/app/services/auto_merger_core/mixin_events_guard.py @@ -12,7 +12,7 @@ class AutoMergerEventsGuardMixin: async def _notify_confirmation_request(self, confirmation: ConfirmationRequest): """Publish merge confirmation request event.""" if self.event_bus: - from ..events import EventType + from ...core.events import EventType await self.event_bus.publish( Event( @@ -30,7 +30,7 @@ class AutoMergerEventsGuardMixin: async def _publish_merge_success_event(self, request: MergeRequest, merge_sha: str): """Publish successful merge event.""" if self.event_bus: - from ..events import EventType + from ...core.events import EventType await self.event_bus.publish( Event( @@ -48,7 +48,7 @@ class AutoMergerEventsGuardMixin: async def _publish_merge_failed_event(self, request: MergeRequest, error: str): """Publish failed merge event.""" if self.event_bus: - from ..events import EventType + from ...core.events import EventType await self.event_bus.publish( Event( diff --git a/backend/app/services/auto_merger_core/shared.py b/backend/app/services/auto_merger_core/shared.py index 90a5e955..dce5a93c 100644 --- a/backend/app/services/auto_merger_core/shared.py +++ b/backend/app/services/auto_merger_core/shared.py @@ -10,7 +10,7 @@ from typing import Any, Dict, List, Optional, Tuple from pydantic import BaseModel, Field -from ...events import Event, EventType +from ...core.events import Event, EventType from ...utils.timezone import now_cn_aware, now_cn_naive logger = logging.getLogger(__name__) diff --git a/backend/app/services/blocker_detection.py b/backend/app/services/blocker_detection.py deleted file mode 100644 index 8e63f1ef..00000000 --- a/backend/app/services/blocker_detection.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Compatibility exports for blocker detection service.""" - -from .blocker_detection_core import ( - BlockerDetectionService, - get_blocker_detection_service, -) - -__all__ = ["BlockerDetectionService", "get_blocker_detection_service"] diff --git a/backend/app/services/blocker_detection_core/shared.py b/backend/app/services/blocker_detection_core/shared.py index 85e0d539..2a70add0 100644 --- a/backend/app/services/blocker_detection_core/shared.py +++ b/backend/app/services/blocker_detection_core/shared.py @@ -14,7 +14,7 @@ from sqlalchemy.future import select from ...models import CognitiveConflict, Project, Signal, Task, TruthNode, User from ...utils.timezone import now_cn_naive -from ..llm import LLMService +from ..llm_service import LLMService BLOCKER_PATTERNS = [ r"等待.*接口", diff --git a/backend/app/services/budget_enforcement_service.py b/backend/app/services/budget_enforcement_service.py deleted file mode 100644 index c9769c73..00000000 --- a/backend/app/services/budget_enforcement_service.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Compatibility exports for budget enforcement service.""" - -from .budget_enforcement import BudgetEnforcementService - -__all__ = ["BudgetEnforcementService"] diff --git a/backend/app/services/codegen.py b/backend/app/services/codegen.py deleted file mode 100644 index e77a5c5f..00000000 --- a/backend/app/services/codegen.py +++ /dev/null @@ -1,19 +0,0 @@ -"""Compatibility exports for code draft generation service.""" - -from .codegen_core import ( - CodeDraftRequest, - CodeDraftResponse, - CodeDraftService, - FileInfo, - GeneratedFile, - get_codegen_service, -) - -__all__ = [ - "CodeDraftRequest", - "FileInfo", - "GeneratedFile", - "CodeDraftResponse", - "CodeDraftService", - "get_codegen_service", -] diff --git a/backend/app/services/cognitive_conflict.py b/backend/app/services/cognitive_conflict.py deleted file mode 100644 index a53eafb1..00000000 --- a/backend/app/services/cognitive_conflict.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Compatibility exports for cognitive conflict service.""" - -from .cognitive_conflict_core import ( - CognitiveConflictService, - get_cognitive_conflict_service, -) - -__all__ = ["CognitiveConflictService", "get_cognitive_conflict_service"] diff --git a/backend/app/services/cognitive_conflict_core/shared.py b/backend/app/services/cognitive_conflict_core/shared.py index 81db498a..42c8bb42 100644 --- a/backend/app/services/cognitive_conflict_core/shared.py +++ b/backend/app/services/cognitive_conflict_core/shared.py @@ -12,7 +12,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select from ...models import CognitiveConflict, Project, ProjectDomain, Task, TruthNode, User -from ..llm import LLMService +from ..llm_service import LLMService __all__ = [ "Any", diff --git a/backend/app/services/context_cache.py b/backend/app/services/context_cache.py deleted file mode 100644 index fc68eaad..00000000 --- a/backend/app/services/context_cache.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .context_cache_service import ContextCacheInvalidator, ContextCacheService, context_cache_service, register_context_cache_invalidation_hooks - -__all__ = ["ContextCacheInvalidator", "ContextCacheService", "context_cache_service", "register_context_cache_invalidation_hooks"] diff --git a/backend/app/services/daily_briefing.py b/backend/app/services/daily_briefing.py deleted file mode 100644 index a64cf5e3..00000000 --- a/backend/app/services/daily_briefing.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Compatibility exports for daily briefing service.""" - -from .daily_briefing_core import DailyBriefingService, get_daily_briefing_service - -__all__ = ["DailyBriefingService", "get_daily_briefing_service"] diff --git a/backend/app/services/daily_briefing_core/shared.py b/backend/app/services/daily_briefing_core/shared.py index b77b3faf..159e0e1a 100644 --- a/backend/app/services/daily_briefing_core/shared.py +++ b/backend/app/services/daily_briefing_core/shared.py @@ -22,7 +22,7 @@ from ...models import ( UserRole, ) from ...utils.timezone import now_cn_aware -from ..llm import LLMService +from ..llm_service import LLMService __all__ = [ "Any", diff --git a/backend/app/services/domain.py b/backend/app/services/domain.py deleted file mode 100644 index 97afa758..00000000 --- a/backend/app/services/domain.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Compatibility exports for project domain service.""" - -from .domain_core import ( - DomainConfig, - DomainSyncProgress, - ProjectDomainCreate, - ProjectDomainResponse, - ProjectDomainService, - ProjectDomainUpdate, - get_domain_service, -) - -__all__ = [ - "DomainConfig", - "ProjectDomainCreate", - "ProjectDomainUpdate", - "ProjectDomainResponse", - "DomainSyncProgress", - "ProjectDomainService", - "get_domain_service", -] diff --git a/backend/app/services/domain_core/mixin_crud.py b/backend/app/services/domain_core/mixin_crud.py index c9d93407..0acd55ba 100644 --- a/backend/app/services/domain_core/mixin_crud.py +++ b/backend/app/services/domain_core/mixin_crud.py @@ -35,7 +35,7 @@ class DomainCrudMixin: await self.db.refresh(domain) if self.event_bus: - from ...events import Event, EventType + from ...core.events import Event, EventType await self.event_bus.publish( Event( @@ -134,7 +134,7 @@ class DomainCrudMixin: await self.db.refresh(domain) if self.event_bus: - from ...events import Event, EventType + from ...core.events import Event, EventType await self.event_bus.publish( Event( @@ -172,7 +172,7 @@ class DomainCrudMixin: await self.db.commit() if self.event_bus: - from ...events import Event, EventType + from ...core.events import Event, EventType await self.event_bus.publish( Event( diff --git a/backend/app/services/domain_core/mixin_runtime_stats.py b/backend/app/services/domain_core/mixin_runtime_stats.py index 4bb74813..d2edbb14 100644 --- a/backend/app/services/domain_core/mixin_runtime_stats.py +++ b/backend/app/services/domain_core/mixin_runtime_stats.py @@ -34,7 +34,7 @@ class DomainRuntimeStatsMixin: self._active_domain_id = str(domain.id) if self.event_bus: - from ...events import Event, EventType + from ...core.events import Event, EventType await self.event_bus.publish( Event( diff --git a/backend/app/services/event_workflow.py b/backend/app/services/event_workflow.py deleted file mode 100644 index 2c650366..00000000 --- a/backend/app/services/event_workflow.py +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import annotations - -from .event_workflow_core import * diff --git a/backend/app/services/event_workflow_core/shared.py b/backend/app/services/event_workflow_core/shared.py index 13b761e6..aed3ead1 100644 --- a/backend/app/services/event_workflow_core/shared.py +++ b/backend/app/services/event_workflow_core/shared.py @@ -26,8 +26,8 @@ from ...models import ( User, Project, Task, Signal, CognitiveConflict, TruthNode, ProjectSignalLink, UserRole ) -from ..llm import LLMService -from ...events import EventType, Event, get_event_bus +from ..llm_service import LLMService +from ...core.events import EventType, Event, get_event_bus from ...utils.timezone import now_cn_aware diff --git a/backend/app/services/experiment_sync_service.py b/backend/app/services/experiment_sync_service.py deleted file mode 100644 index f002e63b..00000000 --- a/backend/app/services/experiment_sync_service.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Compatibility exports for experiment sync service.""" - -from .experiment_sync import ExperimentSyncService - -__all__ = ["ExperimentSyncService"] diff --git a/backend/app/services/feishu_integration.py b/backend/app/services/feishu_integration.py deleted file mode 100644 index 7c0629d3..00000000 --- a/backend/app/services/feishu_integration.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .feishu_integration_service import FeishuIntegrationService, dispatch_pending_feishu_replies, get_feishu_service - -__all__ = ["FeishuIntegrationService", "dispatch_pending_feishu_replies", "get_feishu_service"] diff --git a/backend/app/services/feishu_integration_service/shared.py b/backend/app/services/feishu_integration_service/shared.py index e42ba839..de2debec 100644 --- a/backend/app/services/feishu_integration_service/shared.py +++ b/backend/app/services/feishu_integration_service/shared.py @@ -37,11 +37,11 @@ from ...models import ( FeishuReplyOutbox, AIProcessingLog, ) -from ...database import AsyncSessionLocal +from ...core.database import AsyncSessionLocal from ...config.ai_prompts import PROMPT_FEISHU_HUMANIZED_REPLY from ..notification_service import NotificationService -from ..signal_capture import ProactiveSignalCaptureService -from ..llm import LLMService +from ..signal_capture_service import ProactiveSignalCaptureService +from ..llm_service import LLMService from ...utils.timezone import now_cn_naive CN_TZ = timezone(timedelta(hours=8)) diff --git a/backend/app/services/feishu_long_connection.py b/backend/app/services/feishu_long_connection.py deleted file mode 100644 index 74c4355c..00000000 --- a/backend/app/services/feishu_long_connection.py +++ /dev/null @@ -1,13 +0,0 @@ -"""Compatibility exports for Feishu long connection manager.""" - -from .feishu_long_connection_core import ( - FeishuLongConnectionManager, - get_feishu_long_connection_manager, - init_feishu_long_connection_manager, -) - -__all__ = [ - "FeishuLongConnectionManager", - "init_feishu_long_connection_manager", - "get_feishu_long_connection_manager", -] diff --git a/backend/app/services/feishu_long_connection_core/shared.py b/backend/app/services/feishu_long_connection_core/shared.py index bfce99f9..2b51ff21 100644 --- a/backend/app/services/feishu_long_connection_core/shared.py +++ b/backend/app/services/feishu_long_connection_core/shared.py @@ -17,7 +17,7 @@ from sqlalchemy.future import select from ...core.logging import get_logger from ...models import Integration from ...utils.timezone import CN_TZ, now_cn_aware -from ..feishu_integration import FeishuIntegrationService +from ..feishu_integration_service import FeishuIntegrationService logger = get_logger(__name__) diff --git a/backend/app/services/feishu_outbox/__init__.py b/backend/app/services/feishu_outbox/__init__.py new file mode 100644 index 00000000..dc04de93 --- /dev/null +++ b/backend/app/services/feishu_outbox/__init__.py @@ -0,0 +1,5 @@ +"""Feishu outbox service exports.""" + +from .service import FeishuOutboxService + +__all__ = ["FeishuOutboxService"] diff --git a/backend/app/services/feishu_outbox_service.py b/backend/app/services/feishu_outbox/service.py similarity index 98% rename from backend/app/services/feishu_outbox_service.py rename to backend/app/services/feishu_outbox/service.py index 5f808417..37d3a7a4 100644 --- a/backend/app/services/feishu_outbox_service.py +++ b/backend/app/services/feishu_outbox/service.py @@ -9,7 +9,7 @@ from sqlalchemy import and_, select from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.asyncio import AsyncSession -from ..models import FeishuReplyOutbox +from ...models import FeishuReplyOutbox class FeishuOutboxService: diff --git a/backend/app/services/feishu_signal_pipeline.py b/backend/app/services/feishu_signal_pipeline.py deleted file mode 100644 index ae10743c..00000000 --- a/backend/app/services/feishu_signal_pipeline.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Feishu signal pipeline compatibility module.""" - -from .feishu_signal_pipeline import FeishuSignalPipelineService - -__all__ = ["FeishuSignalPipelineService"] diff --git a/backend/app/services/feishu_signal_pipeline/shared_core.py b/backend/app/services/feishu_signal_pipeline/shared_core.py index eeb5ecdc..2e434a65 100644 --- a/backend/app/services/feishu_signal_pipeline/shared_core.py +++ b/backend/app/services/feishu_signal_pipeline/shared_core.py @@ -14,13 +14,13 @@ from sqlalchemy import and_, delete, func, or_, select, text from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.asyncio import AsyncSession -from ..config.ai_prompts import ( +from ...config.ai_prompts import ( PROMPT_FEISHU_LEVEL_CLASSIFICATION, PROMPT_FEISHU_PROJECT_PREFILL, PROMPT_FEISHU_SIGNAL_EXTRACTION, ) -from ..core.logging import get_logger -from ..models import ( +from ...core.logging import get_logger +from ...models import ( FeishuItem, AIProcessingLog, FeishuReplyOutbox, @@ -33,27 +33,27 @@ from ..models import ( TruthNode, User, ) -from .llm import LLMService -from .adaptive_rag_service import AdaptiveRAGService -from .ai_agent_kernel import ( +from ..llm_service import LLMService +from ..adaptive_rag_service import AdaptiveRAGService +from ..ai_pmo_kernel import ( build_decision_trace, gate_execution as kernel_gate_execution, resolve_correction as kernel_resolve_correction, ) -from .context_cache import context_cache_service -from .notification_service import NotificationService -from .operation_log_service import log_operation -from .project_command_utils import ( +from ..context_cache_service import context_cache_service +from ..notification_service import NotificationService +from ..operation_log_service import log_operation +from ...utils.project_command_utils import ( extract_project_create_description, extract_project_create_title, normalize_project_title_candidate, ) -from .sstc_service import ALIGNED_STATUSES -from .task_persistence import build_task_create_draft, persist_task -from ..utils.project_members import ensure_project_default_members -from ..utils.sequence import ensure_project_id_sequence +from ..sstc_service_core import ALIGNED_STATUSES +from ..task_persistence_core import build_task_create_draft, persist_task +from ...utils.project_members import ensure_project_default_members +from ...utils.sequence import ensure_project_id_sequence -from ..utils.timezone import CN_TZ, now_cn_aware +from ...utils.timezone import CN_TZ, now_cn_aware logger = get_logger(__name__) PROJECT_PRIORITY_ORDER = { diff --git a/backend/app/services/integration.py b/backend/app/services/integration.py deleted file mode 100644 index 687db3d9..00000000 --- a/backend/app/services/integration.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Compatibility exports for integration service.""" - -from .integration_core import ( - IntegrationConfig, - IntegrationHealth, - IntegrationService, - IntegrationStatus, - IntegrationType, - LarkConfig, - NotificationResult, - PlaneConfig, - TaskSyncResult, - get_integration_service, -) - -__all__ = [ - "IntegrationType", - "IntegrationStatus", - "PlaneConfig", - "LarkConfig", - "IntegrationHealth", - "IntegrationConfig", - "TaskSyncResult", - "NotificationResult", - "IntegrationService", - "get_integration_service", -] diff --git a/backend/app/services/lark.py b/backend/app/services/integration_core/lark_service.py similarity index 100% rename from backend/app/services/lark.py rename to backend/app/services/integration_core/lark_service.py diff --git a/backend/app/services/integration_core/mixin_clients.py b/backend/app/services/integration_core/mixin_clients.py index 6aead2cd..28732c1a 100644 --- a/backend/app/services/integration_core/mixin_clients.py +++ b/backend/app/services/integration_core/mixin_clients.py @@ -9,7 +9,7 @@ class IntegrationClientsMixin: async def _get_plane_service(self): """Get Plane service instance.""" if self._plane_service is None: - from ..plane import PlaneService + from .plane_service import PlaneService self._plane_service = PlaneService() if self.config.plane.api_url: @@ -26,7 +26,7 @@ class IntegrationClientsMixin: async def _get_lark_service(self): """Get Lark service instance.""" if self._lark_service is None: - from ..lark import LarkService + from .lark_service import LarkService self._lark_service = LarkService() if self.config.lark.app_id: diff --git a/backend/app/services/integration_core/mixin_sync.py b/backend/app/services/integration_core/mixin_sync.py index acbc1a43..ae524d50 100644 --- a/backend/app/services/integration_core/mixin_sync.py +++ b/backend/app/services/integration_core/mixin_sync.py @@ -89,7 +89,7 @@ class IntegrationSyncMixin: health.latency_ms = latency if self.event_bus: - from ...events import Event, EventType + from ...core.events import Event, EventType await self.event_bus.publish( Event( @@ -112,7 +112,7 @@ class IntegrationSyncMixin: await self._record_failure(integration_type, str(exc)) if self.event_bus: - from ...events import Event, EventType + from ...core.events import Event, EventType await self.event_bus.publish( Event( diff --git a/backend/app/services/plane.py b/backend/app/services/integration_core/plane_service.py similarity index 100% rename from backend/app/services/plane.py rename to backend/app/services/integration_core/plane_service.py diff --git a/backend/app/services/llm.py b/backend/app/services/llm.py deleted file mode 100644 index d08928b0..00000000 --- a/backend/app/services/llm.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .llm_service import ChatCompletionResult, LLMService, StructuredExtractionResult, llm_service - -__all__ = ["ChatCompletionResult", "StructuredExtractionResult", "LLMService", "llm_service"] diff --git a/backend/app/services/llm_client.py b/backend/app/services/llm_client.py deleted file mode 100644 index 5683e614..00000000 --- a/backend/app/services/llm_client.py +++ /dev/null @@ -1,184 +0,0 @@ -""" -统一 LLM 客户端 - 支持多种提供商 - -支持的提供商: -- ollama: 本地运行 (免费,但占用 CPU/内存) -- deepseek: 云端 API (便宜,¥1/百万 tokens) -- openai: 云端 API (GPT-4) -- qwen: 阿里云通义千问 (便宜,国内稳定) -""" - -import httpx -from typing import Dict, List, Optional, Any -import os -import json - - -class LLMClient: - """统一 LLM 客户端""" - - def __init__(self): - self.provider = os.getenv("LLM_PROVIDER", "deepseek").lower() - self.client = self._create_client() - - def _create_client(self) -> 'LLMProvider': - """根据配置创建对应的提供商客户端""" - if self.provider == "ollama": - return OllamaClient() - elif self.provider == "deepseek": - return OpenAICompatibleClient( - api_key=os.getenv("DEEPSEEK_API_KEY"), - base_url=os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com/v1"), - model=os.getenv("DEEPSEEK_MODEL", "deepseek-chat") - ) - elif self.provider == "openai": - return OpenAICompatibleClient( - api_key=os.getenv("OPENAI_API_KEY"), - base_url=os.getenv("OPENAI_BASE_URL", "https://api.edgefn.net/v1"), - model=os.getenv("OPENAI_MODEL", "MiniMax-M2.5") - ) - elif self.provider == "qwen": - return OpenAICompatibleClient( - api_key=os.getenv("QWEN_API_KEY"), - base_url=os.getenv("QWEN_BASE_URL", "https://dashscope.aliyuncs.com/compatible-mode/v1"), - model=os.getenv("QWEN_MODEL", "qwen-plus") - ) - else: - raise ValueError(f"不支持的 LLM 提供商: {self.provider}") - - def generate(self, prompt: str, **kwargs) -> str: - """生成文本""" - return self.client.generate(prompt, **kwargs) - - def generate_json(self, prompt: str, **kwargs) -> Dict: - """生成 JSON 格式响应""" - return self.client.generate_json(prompt, **kwargs) - - def get_embedding(self, text: str) -> List[float]: - """获取向量嵌入""" - return self.client.get_embedding(text) - - -class LLMProvider: - """LLM 提供商基类""" - def generate(self, prompt: str, **kwargs) -> str: - raise NotImplementedError - - def generate_json(self, prompt: str, **kwargs) -> Dict: - raise NotImplementedError - - def get_embedding(self, text: str) -> List[float]: - raise NotImplementedError - - -class OllamaClient(LLMProvider): - """Ollama 本地客户端""" - - def __init__(self): - self.host = os.getenv("OLLAMA_HOST", "http://127.0.0.1:11434").rstrip('/') - self.chat_model = os.getenv("OLLAMA_CHAT_MODEL", "llama3:8b") - self.embedding_model = os.getenv("OLLAMA_EMBEDDING_MODEL", "nomic-embed-text") - self.client = httpx.Client(base_url=self.host, timeout=300.0, trust_env=False) - - def generate(self, prompt: str, **kwargs) -> str: - response = self.client.post("/api/generate", json={ - "model": self.chat_model, - "prompt": prompt, - "stream": False, - **kwargs - }) - response.raise_for_status() - return response.json()["response"] - - def generate_json(self, prompt: str, **kwargs) -> Dict: - response = self.client.post("/api/generate", json={ - "model": self.chat_model, - "prompt": prompt, - "stream": False, - "format": "json", - **kwargs - }) - response.raise_for_status() - content = response.json()["response"] - # 清理 markdown 代码块 - if content.startswith("```json"): - content = content[7:] - if content.startswith("```"): - content = content[3:] - if content.endswith("```"): - content = content[:-3] - content = content.strip() - return json.loads(content) - - def get_embedding(self, text: str) -> List[float]: - response = self.client.post("/api/embeddings", json={ - "model": self.embedding_model, - "prompt": text - }) - response.raise_for_status() - return response.json().get("embedding", []) - - -class OpenAICompatibleClient(LLMProvider): - """OpenAI 兼容客户端 (适用于 DeepSeek, Qwen 等)""" - - def __init__(self, api_key: str, base_url: str, model: str): - self.model = model - self.base_url = base_url - self.api_key = api_key - # 延迟初始化客户端,在实际调用时才检查 API_KEY - self._client = None - - @property - def client(self): - """延迟初始化客户端""" - if self._client is None: - if not self.api_key: - raise ValueError(f"请设置 {self.base_url} 的 API_KEY") - self._client = httpx.Client( - base_url=self.base_url, - timeout=120.0, - headers={"Authorization": f"Bearer {self.api_key}"} - ) - return self._client - - def generate(self, prompt: str, **kwargs) -> str: - response = self.client.post("/chat/completions", json={ - "model": self.model, - "messages": [{"role": "user", "content": prompt}], - **kwargs - }) - response.raise_for_status() - return response.json()["choices"][0]["message"]["content"] - - def generate_json(self, prompt: str, **kwargs) -> Dict: - response = self.client.post("/chat/completions", json={ - "model": self.model, - "messages": [{"role": "user", "content": prompt}], - "response_format": {"type": "json_object"}, - **kwargs - }) - response.raise_for_status() - content = response.json()["choices"][0]["message"]["content"] - return json.loads(content) - - def get_embedding(self, text: str) -> List[float]: - # DeepSeek 不支持 embedding,使用替代方案或返回空 - if "deepseek" in self.base_url: - print("[WARNING] DeepSeek 不支持 embedding API,使用简化向量") - # 简化方案:基于文本内容生成伪向量(实际使用时应该用其他服务) - import hashlib - hash_obj = hashlib.md5(text.encode()) - # 生成 768 维伪向量(与 nomic-embed-text 维度一致) - return [float((hash_obj.digest()[i % 16] / 255.0) * 2 - 1) for _ in range(768)] - - response = self.client.post("/embeddings", json={ - "model": self.model, - "input": text - }) - response.raise_for_status() - return response.json()["data"][0]["embedding"] - - -# 单例实例 -llm_client = LLMClient() diff --git a/backend/app/services/llm_service/shared_part_01.py b/backend/app/services/llm_service/shared_part_01.py index 58b5a499..598502b7 100644 --- a/backend/app/services/llm_service/shared_part_01.py +++ b/backend/app/services/llm_service/shared_part_01.py @@ -28,9 +28,9 @@ from sqlalchemy.exc import OperationalError from sqlalchemy.ext.asyncio import AsyncSession from ...config.ai_prompts import build_default_role_prompt_bundle -from ...database import AsyncSessionLocal +from ...core.database import AsyncSessionLocal from ...models import AICallLog, Integration -from ..model_context_bundle_service import ModelContextBundleService +from ..model_context_bundle import ModelContextBundleService from ...utils.timezone import now_cn_aware try: diff --git a/backend/app/services/cost_optimization_service.py b/backend/app/services/model_capability/cost_optimization_service.py similarity index 98% rename from backend/app/services/cost_optimization_service.py rename to backend/app/services/model_capability/cost_optimization_service.py index 47ddc402..e2df0985 100644 --- a/backend/app/services/cost_optimization_service.py +++ b/backend/app/services/model_capability/cost_optimization_service.py @@ -5,7 +5,7 @@ from typing import Any, Dict, Optional from sqlalchemy import and_, func, select from sqlalchemy.ext.asyncio import AsyncSession -from ..models import AICallLog, CostTracking, ModelRequirementBinding, ModelVersion, TruthNode +from ...models import AICallLog, CostTracking, ModelRequirementBinding, ModelVersion, TruthNode class CostOptimizationService: diff --git a/backend/app/services/model_capability/mixin_cost_tracking.py b/backend/app/services/model_capability/mixin_cost_tracking.py index 5057217c..d9994392 100644 --- a/backend/app/services/model_capability/mixin_cost_tracking.py +++ b/backend/app/services/model_capability/mixin_cost_tracking.py @@ -198,7 +198,7 @@ class ModelCapabilityCostTrackingMixin: tenant_id: int, ) -> Dict[str, Any]: """AI 分析成本效益""" - from ..config.ai_prompts import PROMPT_ANALYZE_COST_ROI + from ...config.ai_prompts import PROMPT_ANALYZE_COST_ROI prompt = PROMPT_ANALYZE_COST_ROI.format( total_cost=f"${total_cost:.2f}", diff --git a/backend/app/services/model_lifecycle_service.py b/backend/app/services/model_capability/model_lifecycle_service.py similarity index 99% rename from backend/app/services/model_lifecycle_service.py rename to backend/app/services/model_capability/model_lifecycle_service.py index 0bdb99ef..1f0637f2 100644 --- a/backend/app/services/model_lifecycle_service.py +++ b/backend/app/services/model_capability/model_lifecycle_service.py @@ -5,7 +5,7 @@ from typing import Any, Dict, List, Optional from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..models import ( +from ...models import ( ModelRequirementBinding, ModelUpdateImpact, ModelVersion, diff --git a/backend/app/services/model_capability/shared.py b/backend/app/services/model_capability/shared.py index f1dc091c..15941ff1 100644 --- a/backend/app/services/model_capability/shared.py +++ b/backend/app/services/model_capability/shared.py @@ -23,7 +23,7 @@ from ...models import ( CostTracking, User, ) -from ..ai_service import AIService +from ..ai_service_core import AIService from ...utils.timezone import now_cn_naive diff --git a/backend/app/services/model_capability_service.py b/backend/app/services/model_capability_service.py deleted file mode 100644 index 511e1407..00000000 --- a/backend/app/services/model_capability_service.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .model_capability import ModelCapabilityService - -__all__ = ["ModelCapabilityService"] diff --git a/backend/app/services/model_context_bundle/mixin_build.py b/backend/app/services/model_context_bundle/mixin_build.py index d3e70204..c45d26bd 100644 --- a/backend/app/services/model_context_bundle/mixin_build.py +++ b/backend/app/services/model_context_bundle/mixin_build.py @@ -13,7 +13,7 @@ from .shared import ( datetime, timezone, ) -from ..project_knowledge_graph import ProjectKnowledgeGraphService +from ..project_knowledge_graph_service import ProjectKnowledgeGraphService class ModelContextBundleBuildMixin: diff --git a/backend/app/services/model_context_bundle/mixin_verify.py b/backend/app/services/model_context_bundle/mixin_verify.py index 2edfdfce..c80e9395 100644 --- a/backend/app/services/model_context_bundle/mixin_verify.py +++ b/backend/app/services/model_context_bundle/mixin_verify.py @@ -19,7 +19,7 @@ class ModelContextBundleVerifyMixin: ) -> dict[str, Any]: prompt = cls._canary_prompt_for_function(function_name=function_name, probe_id=probe_id) try: - from ..llm import llm_service + from ..llm_service import llm_service result = await llm_service.generate_structured_object( prompt, diff --git a/backend/app/services/model_context_bundle/shared.py b/backend/app/services/model_context_bundle/shared.py index da5748af..61f020d1 100644 --- a/backend/app/services/model_context_bundle/shared.py +++ b/backend/app/services/model_context_bundle/shared.py @@ -11,9 +11,9 @@ from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession from ...models import AICallLog -from ..model_routing_service import ModelRoutingService -from ..project_knowledge_graph import ProjectKnowledgeGraphService -from ..task_brief_service import ( +from ..model_routing import ModelRoutingService +from ..project_knowledge_graph_service import ProjectKnowledgeGraphService +from ..task_brief import ( HIGH_CONTRACT_TEMPLATE_ID, HIGH_TEMPLATE_ID, LOW_TEMPLATE_ID, diff --git a/backend/app/services/model_context_bundle_service.py b/backend/app/services/model_context_bundle_service.py deleted file mode 100644 index f71bbe8e..00000000 --- a/backend/app/services/model_context_bundle_service.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Compatibility exports for model context bundle service.""" - -from .model_context_bundle import ( - CONTEXT_BUNDLE_KEYS, - CONTEXT_BUNDLE_MARKER, - TARGET_FUNCTION_CONTEXT, - ModelContextBundleService, -) - -__all__ = [ - "CONTEXT_BUNDLE_MARKER", - "CONTEXT_BUNDLE_KEYS", - "TARGET_FUNCTION_CONTEXT", - "ModelContextBundleService", -] diff --git a/backend/app/services/model_routing/__init__.py b/backend/app/services/model_routing/__init__.py new file mode 100644 index 00000000..f0adc64f --- /dev/null +++ b/backend/app/services/model_routing/__init__.py @@ -0,0 +1,5 @@ +"""Model routing service exports.""" + +from .service import ModelRoutingService + +__all__ = ["ModelRoutingService"] diff --git a/backend/app/services/model_routing_service.py b/backend/app/services/model_routing/service.py similarity index 99% rename from backend/app/services/model_routing_service.py rename to backend/app/services/model_routing/service.py index 3420b072..5d58a568 100644 --- a/backend/app/services/model_routing_service.py +++ b/backend/app/services/model_routing/service.py @@ -8,8 +8,8 @@ from typing import Any from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..models import Integration -from ..utils.timezone import now_cn_naive +from ...models import Integration +from ...utils.timezone import now_cn_naive ALLOWED_PROVIDERS = {"openai", "glm", "deepseek", "ollama"} ALLOWED_TIERS = {"low", "high", "safety"} diff --git a/backend/app/services/notification_service/__init__.py b/backend/app/services/notification_service/__init__.py new file mode 100644 index 00000000..80835fe2 --- /dev/null +++ b/backend/app/services/notification_service/__init__.py @@ -0,0 +1,5 @@ +"""Notification service exports.""" + +from .service import NotificationService + +__all__ = ["NotificationService"] diff --git a/backend/app/services/notification_service.py b/backend/app/services/notification_service/service.py similarity index 99% rename from backend/app/services/notification_service.py rename to backend/app/services/notification_service/service.py index ff91d86e..4153fda0 100644 --- a/backend/app/services/notification_service.py +++ b/backend/app/services/notification_service/service.py @@ -7,10 +7,10 @@ from typing import Any, Iterable, Optional from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..models import Notification, User +from ...models import Notification, User -from ..utils.timezone import CN_TZ, now_cn_aware +from ...utils.timezone import CN_TZ, now_cn_aware class NotificationService: def __init__(self, db: AsyncSession): self.db = db diff --git a/backend/app/services/operation_catalog_service/__init__.py b/backend/app/services/operation_catalog_service/__init__.py new file mode 100644 index 00000000..674bf060 --- /dev/null +++ b/backend/app/services/operation_catalog_service/__init__.py @@ -0,0 +1,5 @@ +"""Operation catalog service exports.""" + +from .service import OperationCatalogService, operation_catalog_service + +__all__ = ["OperationCatalogService", "operation_catalog_service"] diff --git a/backend/app/services/operation_catalog_service.py b/backend/app/services/operation_catalog_service/service.py similarity index 97% rename from backend/app/services/operation_catalog_service.py rename to backend/app/services/operation_catalog_service/service.py index ab51847b..0e171a81 100644 --- a/backend/app/services/operation_catalog_service.py +++ b/backend/app/services/operation_catalog_service/service.py @@ -5,7 +5,7 @@ from __future__ import annotations from collections import Counter from typing import Any, Optional -from ..config.operation_catalog import OPERATION_CATALOG, OperationCatalogEntry +from ...config.operation_catalog import OPERATION_CATALOG, OperationCatalogEntry REQUIRED_OPERATION_CODES = { diff --git a/backend/app/services/operation_log_service/__init__.py b/backend/app/services/operation_log_service/__init__.py new file mode 100644 index 00000000..f4be78e5 --- /dev/null +++ b/backend/app/services/operation_log_service/__init__.py @@ -0,0 +1,5 @@ +"""Operation log service exports.""" + +from .service import log_operation + +__all__ = ["log_operation"] diff --git a/backend/app/services/operation_log_service.py b/backend/app/services/operation_log_service/service.py similarity index 93% rename from backend/app/services/operation_log_service.py rename to backend/app/services/operation_log_service/service.py index 8301a534..4d76c488 100644 --- a/backend/app/services/operation_log_service.py +++ b/backend/app/services/operation_log_service/service.py @@ -4,8 +4,8 @@ from typing import Optional from sqlalchemy.ext.asyncio import AsyncSession -from ..models import OperationLog -from ..utils.audited_write import get_audit_context, normalize_caller +from ...models import OperationLog +from ...utils.audited_write import get_audit_context, normalize_caller async def log_operation( diff --git a/backend/app/services/project_knowledge_graph.py b/backend/app/services/project_knowledge_graph.py deleted file mode 100644 index f9e8f2df..00000000 --- a/backend/app/services/project_knowledge_graph.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .project_knowledge_graph_service import ProjectKnowledgeGraphService - -__all__ = ["ProjectKnowledgeGraphService"] diff --git a/backend/app/services/project_knowledge_graph_service/shared.py b/backend/app/services/project_knowledge_graph_service/shared.py index de5cfd7d..bfbf1e17 100644 --- a/backend/app/services/project_knowledge_graph_service/shared.py +++ b/backend/app/services/project_knowledge_graph_service/shared.py @@ -34,8 +34,8 @@ from ...models import ( Task, User, ) -from ..context_cache import context_cache_service -from ..symbol_index_service import SymbolIndexService +from ..context_cache_service import context_cache_service +from ..symbol_index import SymbolIndexService from ...utils.timezone import now_cn_naive diff --git a/backend/app/services/project_member/__init__.py b/backend/app/services/project_member/__init__.py new file mode 100644 index 00000000..f032c994 --- /dev/null +++ b/backend/app/services/project_member/__init__.py @@ -0,0 +1,15 @@ +"""Project member assignment service exports.""" + +from .service import ( + ProjectMemberAssignmentError, + notify_member_assignment_failure, + replace_project_members, + resolve_project_member_ids, +) + +__all__ = [ + "ProjectMemberAssignmentError", + "resolve_project_member_ids", + "replace_project_members", + "notify_member_assignment_failure", +] diff --git a/backend/app/services/project_member_service.py b/backend/app/services/project_member/service.py similarity index 98% rename from backend/app/services/project_member_service.py rename to backend/app/services/project_member/service.py index 4c29d515..b240c4cc 100644 --- a/backend/app/services/project_member_service.py +++ b/backend/app/services/project_member/service.py @@ -8,8 +8,8 @@ from typing import Iterable, Sequence from sqlalchemy import and_, delete, select from sqlalchemy.ext.asyncio import AsyncSession -from ..models import User, UserProject -from .notification_service import NotificationService +from ...models import User, UserProject +from ..notification_service import NotificationService _ROLE_SPLIT_RE = re.compile(r"[,/|\s]+") _ROLE_ALIAS_MAP = { diff --git a/backend/app/services/prompt_profile/__init__.py b/backend/app/services/prompt_profile/__init__.py new file mode 100644 index 00000000..3713b82c --- /dev/null +++ b/backend/app/services/prompt_profile/__init__.py @@ -0,0 +1,5 @@ +"""Prompt profile service exports.""" + +from .service import PromptProfileService, prompt_profile_service + +__all__ = ["PromptProfileService", "prompt_profile_service"] diff --git a/backend/app/services/prompt_profile_service.py b/backend/app/services/prompt_profile/service.py similarity index 98% rename from backend/app/services/prompt_profile_service.py rename to backend/app/services/prompt_profile/service.py index f6eecd24..7d534e0a 100644 --- a/backend/app/services/prompt_profile_service.py +++ b/backend/app/services/prompt_profile/service.py @@ -10,10 +10,10 @@ from typing import Any, Optional from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..config.ai_prompts import build_default_role_prompt_bundle -from ..models import Integration +from ...config.ai_prompts import build_default_role_prompt_bundle +from ...models import Integration -from ..utils.timezone import now_cn_aware +from ...utils.timezone import now_cn_aware INTEGRATION_TYPE = "ai_prompt_profiles" ROLE_KEY_RE = re.compile(r"^[a-z0-9][a-z0-9_-]{1,31}$") MAX_ROLES = 12 diff --git a/backend/app/services/recipe/__init__.py b/backend/app/services/recipe/__init__.py new file mode 100644 index 00000000..9be1e193 --- /dev/null +++ b/backend/app/services/recipe/__init__.py @@ -0,0 +1,5 @@ +"""Recipe service exports.""" + +from .service import RecipeService, get_recipe_service + +__all__ = ["RecipeService", "get_recipe_service"] diff --git a/backend/app/services/recipe_service.py b/backend/app/services/recipe/service.py similarity index 96% rename from backend/app/services/recipe_service.py rename to backend/app/services/recipe/service.py index f437ba73..dd04e62a 100644 --- a/backend/app/services/recipe_service.py +++ b/backend/app/services/recipe/service.py @@ -6,10 +6,10 @@ from typing import Optional from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession -from ..models import Recipe -from ..schemas import RecipeCreate, RecipeUpdate, RecipeResponse -from .ai_service import AIService -from ..config.ai_prompts import PROMPT_ANALYZE_FOOD_CALORIES +from ...models import Recipe +from ...schemas import RecipeCreate, RecipeUpdate, RecipeResponse +from ..ai_service_core import AIService +from ...config.ai_prompts import PROMPT_ANALYZE_FOOD_CALORIES class RecipeService: @@ -261,6 +261,6 @@ def get_recipe_service() -> RecipeService: """获取食谱服务单例""" global _recipe_service if _recipe_service is None: - from .ai_service import get_ai_service + from ..ai_service_core import get_ai_service _recipe_service = RecipeService(ai_service=get_ai_service()) return _recipe_service diff --git a/backend/app/services/scheduler_center.py b/backend/app/services/scheduler_center.py deleted file mode 100644 index a0185b7c..00000000 --- a/backend/app/services/scheduler_center.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Compatibility exports for scheduler center.""" - -from .scheduler_center_core import ( - AIPMOCadenceScheduler, - KnowledgeGraphIncrementalScheduler, - KnowledgeUrlRefreshScheduler, - WorkloadRecalcScheduler, -) - -__all__ = [ - "WorkloadRecalcScheduler", - "KnowledgeUrlRefreshScheduler", - "KnowledgeGraphIncrementalScheduler", - "AIPMOCadenceScheduler", -] diff --git a/backend/app/services/scheduler_center_core/ai_pmo_cadence.py b/backend/app/services/scheduler_center_core/ai_pmo_cadence.py index 35d45761..5cdcb1ed 100644 --- a/backend/app/services/scheduler_center_core/ai_pmo_cadence.py +++ b/backend/app/services/scheduler_center_core/ai_pmo_cadence.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import AIPMOCadenceService, PortfolioSnapshot, Project, and_, async_sessionmaker, asyncio, datetime, logger, os, select, timedelta, workload_service +from .shared import AIPMOCadenceService, PortfolioSnapshot, Project, and_, async_sessionmaker, asyncio, datetime, logger, os, select, timedelta, workload as workload_service class AIPMOCadenceScheduler: diff --git a/backend/app/services/scheduler_center_core/knowledge_graph.py b/backend/app/services/scheduler_center_core/knowledge_graph.py index 18701f83..5b4f0b48 100644 --- a/backend/app/services/scheduler_center_core/knowledge_graph.py +++ b/backend/app/services/scheduler_center_core/knowledge_graph.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import ProjectKnowledgeGraphService, async_sessionmaker, asyncio, logger, os, workload_service +from .shared import ProjectKnowledgeGraphService, async_sessionmaker, asyncio, logger, os, workload as workload_service class KnowledgeGraphIncrementalScheduler: diff --git a/backend/app/services/scheduler_center_core/shared.py b/backend/app/services/scheduler_center_core/shared.py index d6f6a18e..626db119 100644 --- a/backend/app/services/scheduler_center_core/shared.py +++ b/backend/app/services/scheduler_center_core/shared.py @@ -12,10 +12,11 @@ from sqlalchemy.ext.asyncio import async_sessionmaker from ...core.logging import get_logger from ...models import KnowledgeBaseDoc, PortfolioSnapshot, Project -from .. import workload_alert_service, workload_service +from ..workload import workload_alert_service +from .. import workload as workload_service from ..adaptive_rag_service import AdaptiveRAGService -from ..ai_pmo_cadence_service import AIPMOCadenceService -from ..project_knowledge_graph import ProjectKnowledgeGraphService +from ..ai_pmo_cadence import AIPMOCadenceService +from ..project_knowledge_graph_service import ProjectKnowledgeGraphService logger = get_logger(__name__) diff --git a/backend/app/services/scheduler_center_core/workload.py b/backend/app/services/scheduler_center_core/workload.py index 022a6a7c..b3bd4212 100644 --- a/backend/app/services/scheduler_center_core/workload.py +++ b/backend/app/services/scheduler_center_core/workload.py @@ -2,7 +2,15 @@ from __future__ import annotations -from .shared import async_sessionmaker, asyncio, datetime, logger, timedelta, workload_alert_service, workload_service +from .shared import ( + async_sessionmaker, + asyncio, + datetime, + logger, + timedelta, + workload_alert_service, + workload_service, +) class WorkloadRecalcScheduler: diff --git a/backend/app/services/signal_capture.py b/backend/app/services/signal_capture.py deleted file mode 100644 index f00fc4b5..00000000 --- a/backend/app/services/signal_capture.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .signal_capture_service import ProactiveSignalCaptureService, get_signal_capture_service - -__all__ = ["ProactiveSignalCaptureService", "get_signal_capture_service"] diff --git a/backend/app/services/fetcher.py b/backend/app/services/signal_capture_service/external_fetcher.py similarity index 100% rename from backend/app/services/fetcher.py rename to backend/app/services/signal_capture_service/external_fetcher.py diff --git a/backend/app/services/analyzer.py b/backend/app/services/signal_capture_service/impact_analyzer.py similarity index 100% rename from backend/app/services/analyzer.py rename to backend/app/services/signal_capture_service/impact_analyzer.py diff --git a/backend/app/services/signal_capture_service/mixin_external_sources.py b/backend/app/services/signal_capture_service/mixin_external_sources.py index 72b4a067..bb85d4da 100644 --- a/backend/app/services/signal_capture_service/mixin_external_sources.py +++ b/backend/app/services/signal_capture_service/mixin_external_sources.py @@ -130,7 +130,7 @@ class SignalCaptureExternalSourcesMixin: while True: try: # 抓取 HackerNews 首页 - from .fetcher import fetch_hn_stories + from ..fetcher import fetch_hn_stories # 兼容三种实现: # 1) async def -> 直接 await # 2) sync def -> to_thread 防阻塞 diff --git a/backend/app/services/signal_capture_service/mixin_source_analyzers.py b/backend/app/services/signal_capture_service/mixin_source_analyzers.py index 6d666f44..5f3f37b0 100644 --- a/backend/app/services/signal_capture_service/mixin_source_analyzers.py +++ b/backend/app/services/signal_capture_service/mixin_source_analyzers.py @@ -191,7 +191,7 @@ URL: {url} {"project_id": project_id, "signal_id": signal_id}, ) if existing.first() is None: - from ..models import ProjectSignalLink + from ...models import ProjectSignalLink link = ProjectSignalLink( project_id=project_id, signal_id=signal_id, diff --git a/backend/app/services/signal_capture_service/shared.py b/backend/app/services/signal_capture_service/shared.py index 571e8fa7..11a7359b 100644 --- a/backend/app/services/signal_capture_service/shared.py +++ b/backend/app/services/signal_capture_service/shared.py @@ -27,7 +27,7 @@ from sqlalchemy.future import select from sqlalchemy import and_, text from ...core.logging import get_logger -from ...database import AsyncSessionLocal +from ...core.database import AsyncSessionLocal from ...models import ( Signal, Project, ProjectDomain, User, ProjectSignalLink, Task, TruthNode, @@ -37,13 +37,13 @@ from ...config.ai_prompts import ( PROMPT_FEISHU_PROJECT_SIGNAL_CLASSIFICATION, PROMPT_FEISHU_TASK_ORCHESTRATION, ) -from ..llm import LLMService +from ..llm_service import LLMService from ..notification_service import NotificationService -from .. import workload_service +from .. import workload as workload_service from ..adaptive_rag_service import AdaptiveRAGService -from ..context_cache import context_cache_service -from ..signal_source_orchestration_service import SignalSourceOrchestrationService -from ..ai_pmo_kernel_service import AIPMOKernelService +from ..context_cache_service import context_cache_service +from ..signal_source_orchestration import SignalSourceOrchestrationService +from ..ai_pmo_kernel import AIPMOKernelService from ...utils.project_members import ensure_project_default_members from ...utils.sequence import ensure_project_id_sequence, ensure_signal_id_sequence diff --git a/backend/app/services/signal_planner/shared.py b/backend/app/services/signal_planner/shared.py index ffd144ae..5dc2b4c9 100644 --- a/backend/app/services/signal_planner/shared.py +++ b/backend/app/services/signal_planner/shared.py @@ -11,7 +11,7 @@ from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker from ...config.ai_prompts import PROMPT_SIGNAL_PLANNER from ...core.logging import get_logger -from ...database import AsyncSessionLocal +from ...core.database import AsyncSessionLocal from ...models import ( Project, ProjectSignalLink, @@ -23,10 +23,10 @@ from ...models import ( UserWorkload, ) from ...utils.timezone import now_cn_naive -from ..feishu_outbox_service import FeishuOutboxService -from ..llm import llm_service -from ..model_routing_service import ModelRoutingService -from ..signal_strategic_analysis_service import SignalStrategicAnalysisService +from ..feishu_outbox import FeishuOutboxService +from ..llm_service import llm_service +from ..model_routing import ModelRoutingService +from .signal_strategic_analysis_service import SignalStrategicAnalysisService logger = get_logger(__name__) PLANNER_MAX_WAIT_SECONDS = 25.0 diff --git a/backend/app/services/signal_strategic_analysis_service.py b/backend/app/services/signal_planner/signal_strategic_analysis_service.py similarity index 97% rename from backend/app/services/signal_strategic_analysis_service.py rename to backend/app/services/signal_planner/signal_strategic_analysis_service.py index 6e07f959..65c6a04a 100644 --- a/backend/app/services/signal_strategic_analysis_service.py +++ b/backend/app/services/signal_planner/signal_strategic_analysis_service.py @@ -8,8 +8,8 @@ from typing import Any, Optional from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..models import Signal -from ..utils.timezone import now_cn_naive +from ...models import Signal +from ...utils.timezone import now_cn_naive class SignalStrategicAnalysisService: diff --git a/backend/app/services/signal_planner_service.py b/backend/app/services/signal_planner_service.py deleted file mode 100644 index d0a5c758..00000000 --- a/backend/app/services/signal_planner_service.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Compatibility exports for signal planner service.""" - -from .signal_planner import SignalPlannerService - -__all__ = ["SignalPlannerService"] diff --git a/backend/app/services/signal_source_orchestration/shared.py b/backend/app/services/signal_source_orchestration/shared.py index cf2c4ae1..19c22393 100644 --- a/backend/app/services/signal_source_orchestration/shared.py +++ b/backend/app/services/signal_source_orchestration/shared.py @@ -27,10 +27,10 @@ from ...models import ( SignalSourceRegistry, User, ) -from ...database import AsyncSessionLocal -from ..ai_orchestration_run_service import AIOrchestrationRunService -from ..prompt_profile_service import prompt_profile_service -from ..llm import llm_service +from ...core.database import AsyncSessionLocal +from ..ai_orchestration_run import AIOrchestrationRunService +from ..prompt_profile import prompt_profile_service +from ..llm_service import llm_service from ...utils.timezone import now_cn_naive SOURCE_ONBOARDING_ACTION_RE = re.compile( diff --git a/backend/app/services/signal_source_orchestration_service.py b/backend/app/services/signal_source_orchestration_service.py deleted file mode 100644 index a03fa1ff..00000000 --- a/backend/app/services/signal_source_orchestration_service.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .signal_source_orchestration import SignalSourceOrchestrationService - -__all__ = ["SignalSourceOrchestrationService"] diff --git a/backend/app/services/signal_source_repair/shared.py b/backend/app/services/signal_source_repair/shared.py index 47f069a8..2b349c5f 100644 --- a/backend/app/services/signal_source_repair/shared.py +++ b/backend/app/services/signal_source_repair/shared.py @@ -15,7 +15,7 @@ from ...utils.audited_write import get_audit_context from ...utils.timezone import now_cn_naive from ..notification_service import NotificationService from ..operation_log_service import log_operation -from ..signal_capture import ProactiveSignalCaptureService +from ..signal_capture_service import ProactiveSignalCaptureService __all__ = [ "Any", diff --git a/backend/app/services/signal_source_repair_service.py b/backend/app/services/signal_source_repair_service.py deleted file mode 100644 index fdb63440..00000000 --- a/backend/app/services/signal_source_repair_service.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Compatibility exports for signal source repair service.""" - -from .signal_source_repair import ( - SignalSourceRepairError, - SignalSourceRepairMissingSignalError, - SignalSourceRepairService, - SignalSourceRepairTimeoutError, -) - -__all__ = [ - "SignalSourceRepairError", - "SignalSourceRepairTimeoutError", - "SignalSourceRepairMissingSignalError", - "SignalSourceRepairService", -] diff --git a/backend/app/services/skill/shared.py b/backend/app/services/skill/shared.py index babc81e5..e7e6ef1a 100644 --- a/backend/app/services/skill/shared.py +++ b/backend/app/services/skill/shared.py @@ -15,7 +15,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload from ...models import SkillTag, UserSkillBinding, UserWorkload, User, UserStatus, Task -from ..ai_pmo_kernel_service import AIPMOKernelService +from ..ai_pmo_kernel import AIPMOKernelService # 系统预设 AI 开发专属技能标签 diff --git a/backend/app/services/skill_score_service.py b/backend/app/services/skill/skill_score_service.py similarity index 96% rename from backend/app/services/skill_score_service.py rename to backend/app/services/skill/skill_score_service.py index 2c27f1c1..8db130df 100644 --- a/backend/app/services/skill_score_service.py +++ b/backend/app/services/skill/skill_score_service.py @@ -9,12 +9,12 @@ from typing import Optional from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession -from ..config.ai_prompts import PROMPT_SKILL_SCORE_UPDATE -from ..database import AsyncSessionLocal -from ..models import AICallLog, Task, UserSkillBinding -from .llm import llm_service +from ...config.ai_prompts import PROMPT_SKILL_SCORE_UPDATE +from ...core.database import AsyncSessionLocal +from ...models import AICallLog, Task, UserSkillBinding +from ..llm_service import llm_service -from ..utils.timezone import now_cn_naive +from ...utils.timezone import now_cn_naive PRIORITY_WEIGHT = { "critical": 1.5, "high": 1.2, diff --git a/backend/app/services/skill_service.py b/backend/app/services/skill_service.py deleted file mode 100644 index d14f3746..00000000 --- a/backend/app/services/skill_service.py +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import annotations - -from .skill import * diff --git a/backend/app/services/sstc/shared.py b/backend/app/services/sstc/shared.py index 17963786..a950ccb1 100644 --- a/backend/app/services/sstc/shared.py +++ b/backend/app/services/sstc/shared.py @@ -18,7 +18,7 @@ from sqlalchemy import and_, delete, select from sqlalchemy.ext.asyncio import AsyncSession from ...core.response import error_response, success_response -from ...database import get_db +from ...core.database import get_db from ...models import ( AICallLog, AlignmentRecord, @@ -46,25 +46,25 @@ from ...schemas.sstc import ( WorkloadOptimizeRequest, TaskStatusPatchRequest, ) -from ...services.llm import llm_service -from ...services.ai_service import AIService -from ...services.ai_pmo_kernel_service import AIPMOKernelService +from ...services.llm_service import llm_service +from ...services.ai_service_core import AIService +from ...services.ai_pmo_kernel import AIPMOKernelService from ...services.operation_log_service import log_operation from ...services.auth import has_any_role -from ...services.skill_service import recommend_personnel -from ...services import skill_score_service -from ...services.sstc_service import ( +from ...services.skill import recommend_personnel +from ...services.skill import skill_score_service +from ...services.sstc_service_core import ( ALIGNED_STATUSES, DONE_STATUSES, RELEASE_VERIFIED_STATUSES, SSTCService, ) -from ...services import workload_service -from ...services.budget_enforcement_service import BudgetEnforcementService -from ...services.feishu_integration import get_feishu_service +from ...services import workload as workload_service +from ...services.budget_enforcement import BudgetEnforcementService +from ...services.feishu_integration_service import get_feishu_service from ...services.adaptive_rag_service import AdaptiveRAGService -from ...services.context_cache import context_cache_service -from ...services.task_persistence import build_task_create_draft, persist_task +from ...services.context_cache_service import context_cache_service +from ...services.task_persistence_core import build_task_create_draft, persist_task from ...dependencies import get_current_user, require_project_member_or_manager from ...utils.title import compact_title diff --git a/backend/app/services/sstc_service.py b/backend/app/services/sstc_service.py deleted file mode 100644 index 017315d0..00000000 --- a/backend/app/services/sstc_service.py +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import annotations - -from .sstc_service_core import * diff --git a/backend/app/services/symbol_index_service.py b/backend/app/services/symbol_index_service.py deleted file mode 100644 index 54bb2f88..00000000 --- a/backend/app/services/symbol_index_service.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .symbol_index import ParsedReference, ParsedSymbol, SymbolIndexService - -__all__ = ["ParsedReference", "ParsedSymbol", "SymbolIndexService"] diff --git a/backend/app/services/task_brief_service.py b/backend/app/services/task_brief_service.py deleted file mode 100644 index 4e116975..00000000 --- a/backend/app/services/task_brief_service.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .task_brief import TaskBriefService - -__all__ = ["TaskBriefService"] diff --git a/backend/app/services/task_persistence.py b/backend/app/services/task_persistence.py deleted file mode 100644 index b2d8f780..00000000 --- a/backend/app/services/task_persistence.py +++ /dev/null @@ -1,35 +0,0 @@ -"""Compatibility exports for task persistence helpers.""" - -from .task_persistence_core import ( - SUPPORTED_TASK_STATUSES, - TASK_PRIORITY_MAP, - TASK_STATUS_MAP, - SkillTagResolution, - TaskCreateDraft, - build_task_create_draft, - normalize_due_date, - normalize_estimated_hours, - normalize_int_list, - normalize_skill_names, - normalize_task_priority, - normalize_task_status, - persist_task, - resolve_skill_tag_ids_by_names, -) - -__all__ = [ - "TASK_PRIORITY_MAP", - "TASK_STATUS_MAP", - "SUPPORTED_TASK_STATUSES", - "SkillTagResolution", - "TaskCreateDraft", - "normalize_task_priority", - "normalize_task_status", - "normalize_estimated_hours", - "normalize_due_date", - "normalize_int_list", - "normalize_skill_names", - "build_task_create_draft", - "resolve_skill_tag_ids_by_names", - "persist_task", -] diff --git a/backend/app/services/task_persistence_core/persist.py b/backend/app/services/task_persistence_core/persist.py index 5e707f0a..518f858b 100644 --- a/backend/app/services/task_persistence_core/persist.py +++ b/backend/app/services/task_persistence_core/persist.py @@ -3,7 +3,7 @@ from __future__ import annotations from .models import TaskCreateDraft -from .shared import AsyncSession, Optional, Task, log_operation, workload_service +from .shared import AsyncSession, Optional, Task, log_operation, workload as workload_service async def persist_task( diff --git a/backend/app/services/task_persistence_core/shared.py b/backend/app/services/task_persistence_core/shared.py index 28bcc3b4..75a9aebe 100644 --- a/backend/app/services/task_persistence_core/shared.py +++ b/backend/app/services/task_persistence_core/shared.py @@ -12,7 +12,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from ...models import SkillTag, Task from ...utils.title import compact_title from ...utils.timezone import CN_TZ -from .. import workload_service +from .. import workload as workload_service from ..operation_log_service import log_operation TASK_PRIORITY_MAP = { diff --git a/backend/app/services/wecom/__init__.py b/backend/app/services/wecom/__init__.py new file mode 100644 index 00000000..8adcdb5a --- /dev/null +++ b/backend/app/services/wecom/__init__.py @@ -0,0 +1,5 @@ +"""WeCom integration service exports.""" + +from .service import WeChatWorkIntegrationService, get_wecom_service + +__all__ = ["WeChatWorkIntegrationService", "get_wecom_service"] diff --git a/backend/app/services/wecom_integration.py b/backend/app/services/wecom/service.py similarity index 98% rename from backend/app/services/wecom_integration.py rename to backend/app/services/wecom/service.py index 510e0dc6..62500eff 100644 --- a/backend/app/services/wecom_integration.py +++ b/backend/app/services/wecom/service.py @@ -20,10 +20,10 @@ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select from sqlalchemy import text -from ..models import ( +from ...models import ( Signal, Project, Integration ) -from .signal_capture import ProactiveSignalCaptureService +from ..signal_capture_service import ProactiveSignalCaptureService class WeChatWorkIntegrationService: diff --git a/backend/app/services/workload/shared.py b/backend/app/services/workload/shared.py index 39de2872..b658dbe1 100644 --- a/backend/app/services/workload/shared.py +++ b/backend/app/services/workload/shared.py @@ -11,7 +11,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from ...config.ai_prompts import PROMPT_WORKLOAD_OPTIMIZATION from ...models import AICallLog, Task, User, UserProject, UserSkillBinding, UserWorkload -from ..llm import llm_service +from ..llm_service import llm_service from ...utils.timezone import now_cn_naive LEVEL_HOURS_MULTIPLIER = { diff --git a/backend/app/services/workload_alert_service.py b/backend/app/services/workload/workload_alert_service.py similarity index 99% rename from backend/app/services/workload_alert_service.py rename to backend/app/services/workload/workload_alert_service.py index 42ce766c..e8e586c0 100644 --- a/backend/app/services/workload_alert_service.py +++ b/backend/app/services/workload/workload_alert_service.py @@ -9,7 +9,7 @@ from sqlalchemy import and_, func, select from sqlalchemy.ext.asyncio import AsyncSession from ..models import OperationLog, Task, User, UserProject, UserWorkload -from .lark import lark_service +from ..integration_core.lark_service import lark_service from ..utils.timezone import now_cn_naive DONE_STATUSES = {"done", "completed", "closed", "resolved", "archived"} diff --git a/backend/app/services/workload_service.py b/backend/app/services/workload_service.py deleted file mode 100644 index 7efd6cbd..00000000 --- a/backend/app/services/workload_service.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import annotations - -from .workload import * - -__all__ = [ - "remaining_workdays_this_week", - "calculate_workload_ratio", - "ensure_user_workload", - "recalculate_user_workload_ratio", - "recalculate_all_users_workload_ratio", - "list_tenant_ids", - "get_team_workload_board", - "get_user_personal_workload", - "update_user_max_weekly_hours", - "list_user_assigned_tasks", - "get_user_workload_trend", - "refresh_user_assigned_hours_from_tasks", - "build_ai_optimize_preview", - "apply_ai_optimize_plan", -] diff --git a/backend/app/state.py b/backend/app/state.py deleted file mode 100644 index 6870f7d5..00000000 --- a/backend/app/state.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -应用级全局状态 - -event_bus、ws_manager 等由 main.py startup 设置,各 router 通过 `from app import state` 使用。 -""" - -event_bus = None -ws_manager = None - - -def set_event_bus(eb): - global event_bus - event_bus = eb - - -def set_ws_manager(wm): - global ws_manager - ws_manager = wm diff --git a/backend/app/services/project_command_utils.py b/backend/app/utils/project_command_utils.py similarity index 100% rename from backend/app/services/project_command_utils.py rename to backend/app/utils/project_command_utils.py diff --git a/backend/app/utils/project_members.py b/backend/app/utils/project_members.py index d24786e6..f1490560 100644 --- a/backend/app/utils/project_members.py +++ b/backend/app/utils/project_members.py @@ -4,7 +4,7 @@ from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession from ..models import UserProject -from ..services.project_member_service import resolve_project_member_ids +from ..services.project_member import resolve_project_member_ids async def ensure_project_default_members( diff --git a/backend/app/seed_projects.py b/backend/app/utils/seed_projects.py similarity index 97% rename from backend/app/seed_projects.py rename to backend/app/utils/seed_projects.py index 2b6696f5..3ebd560e 100644 --- a/backend/app/seed_projects.py +++ b/backend/app/utils/seed_projects.py @@ -10,7 +10,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import sessionmaker from app.models import Project, ProjectSignalLink, Signal, TruthNode -from app.seed_projects_helpers import ( +from app.utils.seed_projects_helpers import ( build_ai_signal, build_pixelle_signals, create_pixelle_charter_and_tasks, @@ -23,7 +23,7 @@ PIXELLE_NAME = "Pixelle-Video 集成" async def seed_pixelle_project(db: Optional[AsyncSession] = None): """创建或恢复 Pixelle-Video 示例项目与 SSTC 数据。""" - from app.database import engine + from app.core.database import engine if db is None: async_session_maker = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) @@ -179,7 +179,7 @@ async def _seed_projects(session: AsyncSession): async def main(): print("开始初始化示例数据...") - from app.database import engine + from app.core.database import engine from app.models import Base async with engine.begin() as conn: diff --git a/backend/app/seed_projects_helpers.py b/backend/app/utils/seed_projects_helpers.py similarity index 100% rename from backend/app/seed_projects_helpers.py rename to backend/app/utils/seed_projects_helpers.py diff --git a/backend/evals/feishu_replay_eval.py b/backend/evals/feishu_replay_eval.py index e040f226..5e6d3b21 100644 --- a/backend/evals/feishu_replay_eval.py +++ b/backend/evals/feishu_replay_eval.py @@ -22,7 +22,7 @@ from typing import Any, Optional from sqlalchemy import and_, delete, func, select from sqlalchemy.ext.asyncio import AsyncSession -from app.database import AsyncSessionLocal +from app.core.database import AsyncSessionLocal from app.models import ( AIProcessingLog, FeishuItem, @@ -34,7 +34,7 @@ from app.models import ( User, ) from app.services.adaptive_rag_service import AdaptiveRAGService -from app.services.feishu_integration import FeishuIntegrationService +from app.services.feishu_integration_service import FeishuIntegrationService from app.services.feishu_signal_pipeline import FeishuSignalPipelineService CURRENT_CASE_ID: contextvars.ContextVar[str | None] = contextvars.ContextVar( diff --git a/backend/evals/rag_project_understanding_eval.py b/backend/evals/rag_project_understanding_eval.py index ac95b55b..a5fc82ff 100644 --- a/backend/evals/rag_project_understanding_eval.py +++ b/backend/evals/rag_project_understanding_eval.py @@ -24,7 +24,7 @@ def _bootstrap_path() -> None: _bootstrap_path() -from app.database import AsyncSessionLocal # noqa: E402 +from app.core.database import AsyncSessionLocal # noqa: E402 from app.services.adaptive_rag_service import AdaptiveRAGService # noqa: E402 diff --git a/backend/scripts/backfill_orphan_signal_links.py b/backend/scripts/backfill_orphan_signal_links.py index f8dc4386..d4ae7d1c 100644 --- a/backend/scripts/backfill_orphan_signal_links.py +++ b/backend/scripts/backfill_orphan_signal_links.py @@ -8,7 +8,7 @@ import asyncio from sqlalchemy import and_, select -from app.database import AsyncSessionLocal +from app.core.database import AsyncSessionLocal from app.models import ProjectSignalLink, Signal diff --git a/backend/check_users.py b/backend/scripts/dev/check_users.py similarity index 83% rename from backend/check_users.py rename to backend/scripts/dev/check_users.py index f5b57c38..769dcf37 100644 --- a/backend/check_users.py +++ b/backend/scripts/dev/check_users.py @@ -1,12 +1,12 @@ - import asyncio import sys from pathlib import Path # Add backend directory to sys.path -sys.path.append(str(Path(__file__).parent.absolute())) +BACKEND_ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(BACKEND_ROOT)) -from app.database import AsyncSessionLocal +from app.core.database import AsyncSessionLocal from app.models.user import User from sqlalchemy import select, func diff --git a/backend/seed_all.py b/backend/scripts/dev/seed_all.py similarity index 97% rename from backend/seed_all.py rename to backend/scripts/dev/seed_all.py index 8195cb37..4189300e 100644 --- a/backend/seed_all.py +++ b/backend/scripts/dev/seed_all.py @@ -4,9 +4,16 @@ Comprehensive seed script for PMFlow/Neural Sync. Creates users, domains, and initial data. """ import asyncio +import sys +from pathlib import Path + from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select -from app.database import AsyncSessionLocal + +BACKEND_ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(BACKEND_ROOT)) + +from app.core.database import AsyncSessionLocal from app.models import User, ProjectDomain, Project from app.services.auth import AuthService diff --git a/backend/init_db.py b/backend/scripts/legacy/init_db.py similarity index 79% rename from backend/init_db.py rename to backend/scripts/legacy/init_db.py index ba13404d..592f0df4 100644 --- a/backend/init_db.py +++ b/backend/scripts/legacy/init_db.py @@ -1,16 +1,21 @@ #!/usr/bin/env python3 -"""Initialize database metadata for PostgreSQL environments.""" +"""Legacy DB bootstrap utility. + +WARNING: runtime DDL is forbidden in PMFlow production flow. +Use Alembic migrations instead of create_all. +""" import asyncio import sys from pathlib import Path -# Add parent directory to path for imports -sys.path.insert(0, str(Path(__file__).parent.parent)) +# Add backend directory to path for imports +BACKEND_ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(BACKEND_ROOT)) from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker -from backend.app.models import Base -from backend.app.database import DATABASE_URL +from app.models import Base +from app.core.database import DATABASE_URL from sqlalchemy import text