Skip to content

TDR-004: OrchestrationService Pre-Builds Dependencies the Factory Could Own

Description

OrchestrationService receives conversation_context_repository and builds domain_agent_registry in its __init__, then passes both to create_global_supervisor(). These dependencies are only used for building the supervisor — no other method in OrchestrationService references them.

The create_global_supervisor factory accepts either pre-built dependencies OR raw services (memory_service, rag_service) and builds them internally. This "either/or" interface exists because OrchestrationService does prework the factory could do itself.

Current State

FastAPI DI → builds conversation_context_repository
           → passes to OrchestrationService
           → OrchestrationService stores it
           → OrchestrationService passes it to factory
           → factory passes it to supervisor constructor

Ideal State

FastAPI DI → passes memory_service + rag_service to OrchestrationService
           → OrchestrationService passes raw services to factory
           → factory builds conversation_context_repository + domain_agent_registry
           → factory passes them to supervisor constructor

Why It Matters

  • Duplicated wiring logic — the factory knows how to build these dependencies, but OrchestrationService does it too
  • Factory's "either/or" interface is confusing — it accepts pre-built OR raw services, which is unusual
  • DI layer complexityget_conversation_context_repository dependency in FastAPI exists only to pass through to the supervisor

Why We Deferred

  • Changing OrchestrationService.__init__ signature requires updating the FastAPI DI layer (services_deps.py) and the voice event handler (voice_event_handler.py)
  • The current approach works correctly — the toggle works, production uses the factory
  • The v2 evolution will likely simplify OrchestrationService significantly, making this cleanup natural

Cleanup Plan

When evolving the v2 supervisor (PR 2+): 1. Remove conversation_context_repository from OrchestrationService.__init__ params 2. Add memory_service param instead (or get it from DI) 3. Remove domain_agent_registry construction from __init__ 4. Pass memory_service + rag_service to the factory (raw services path) 5. Remove the "either/or" from the factory — only accept raw services 6. Update services_deps.py and voice_event_handler.py

Impact

  • Low risk — no behavioral change
  • ~30 lines changed across 3 files
  • Cleaner separation: factory owns ALL supervisor construction, OrchestrationService owns orchestration

Files Affected

  • swisper/services/orchestration.py — remove pre-built deps, pass raw services
  • swisper/services/global_supervisor_factory.py — simplify to raw services only
  • swisper/services/services_deps.py — remove get_conversation_context_repository dep, add get_memory_service
  • swisper/services/voice/voice_event_handler.py — same change