Tasks: US5 - Cross-Provider Backend Selection¶
User Story: A platform user wants to run an agent on a specific backend runtime while using a model from a different provider (e.g., Google ADK with OpenAI model, Agent Framework with Anthropic model).
Dependencies: US1 (ADK backend), US2 (AF backend) must be functional before US5 implementation.
Spec References: FR-030 (compatibility validation), Research R1, R5, R8
Phase 2: Foundational — Compatibility Matrix Definition¶
- US5-01 P1 [US5] EXTRACT inline backend/provider compatibility logic from US1 T007's
BackendSelectorcode into a named constantBACKEND_PROVIDER_COMPATIBILITYinsrc/holodeck/lib/backends/selector.py— adict[BackendEnum, set[ProviderEnum]]encoding the compatibility matrix:semantic_kernel: {openai, azure_openai, ollama},claude: {anthropic},google_adk: {google, openai, azure_openai, anthropic, ollama},agent_framework: {openai, azure_openai, anthropic, ollama} - US5-02 P1 [US5] EXTRACT inline default-routing logic from US1 T007's
BackendSelectorcode into a named constantPROVIDER_DEFAULT_BACKENDinsrc/holodeck/lib/backends/selector.py— adict[ProviderEnum, BackendEnum]encoding the default routing table:openai->agent_framework,azure_openai->agent_framework,anthropic->claude,ollama->claude,google->google_adk
Phase 3: US5 — Compatibility Validation and Cross-Provider Routing¶
Compatibility Validation (FR-030)¶
- US5-03 P1 [US5] EXTEND the existing
@model_validator(mode='after')created by US1 T010 inAgent(src/holodeck/models/agent.py) to also validatebackend/providercompatibility whenbackendis explicitly set — raiseValueErrorwith message listing the compatible providers for the requested backend (e.g., "Backend 'claude' only supports providers: anthropic. Got: openai") - US5-04 P1 [US5] REFACTOR the existing
BackendSelector.select()(already modified by US1 T007/US2) insrc/holodeck/lib/backends/selector.pyto resolve the effective backend using the extracted constants: ifagent.backendis set, use it directly (compatibility already validated by model); ifNone, look upPROVIDER_DEFAULT_BACKEND[agent.model.provider] - US5-05 P1 [US5] REFACTOR the existing
BackendSelector.select()to route by resolvedBackendEnumvalue instead ofProviderEnum— use a dispatch dict or match statement mapping eachBackendEnumto its backend class instantiation logic, replacing the inline routing already present from US1/US2
Cross-Provider Model Name Construction (ADK)¶
- US5-06 P1 [US5] In
src/holodeck/lib/backends/adk_backend.py, implement LiteLLM model name construction in the initialization path: ifagent.model.providerisgoogle, passagent.model.namedirectly (e.g.,"gemini-2.5-flash"); otherwise construct"{provider}/{name}"(e.g.,"openai/gpt-4o") per ADK's LiteLLM integration (research R1) - US5-07 P2 [US5] Handle
azure_openaiprovider prefix mapping inadk_backend.py— Azure models use"azure/{deployment_name}"format for LiteLLM, and may requireapi_baseandapi_versionenvironment variables
Cross-Provider Client Selection (AF)¶
- US5-08 P1 [US5] In
src/holodeck/lib/backends/af_backend.py, implement provider-to-client dispatch:openai->OpenAIChatClient,azure_openai->AzureOpenAIChatClient,anthropic->AnthropicClient,ollama->OllamaChatClient(research R5). Ensure the client is selected based onagent.model.providerand receives appropriate auth/endpoint config
Note: FR-031 (SK deprecation warning) was removed per design decision. Default routing breaks cleanly to AF/Claude. Users add backend: semantic_kernel explicitly if needed.
Error Messages¶
- US5-11 P1 [US5] Ensure the
BackendInitErrorraised for unsupported backend/provider combos inselector.pyincludes: the requested backend name, the requested provider name, and the full list of compatible providers for that backend (e.g., "Backend 'agent_framework' does not support provider 'google'. Compatible providers: openai, azure_openai, anthropic, ollama") - US5-12 P2 [US5] Add a fallback error in
BackendSelector.select()for unknownBackendEnumvalues (defensive programming — should not occur if enum is validated, but protects against future enum additions without dispatch updates)
Phase 3: US5 — Tests¶
- US5-13 P1 [US5] Add unit tests in
tests/unit/lib/backends/test_selector.pyfor compatibility validation: test thatbackend: google_adk+provider: openairesolves to ADK backend (acceptance scenario 1) - US5-14 P1 [US5] Add unit test:
backend: agent_framework+provider: anthropicresolves to AF backend with AnthropicClient (acceptance scenario 2) - US5-15 P1 [US5] Add unit test:
backend: claude+provider: openairaises clear error listing compatible providers (acceptance scenario 3) - US5-16 P1 [US5] Add unit tests for all valid backend/provider combinations from the compatibility matrix — parameterize across all 13 valid combos (SK:3 + Claude:1 + ADK:5 + AF:4) to verify each resolves without error
- US5-17 P1 [US5] Add unit tests for all invalid backend/provider combinations — parameterize across invalid combos (e.g.,
semantic_kernel+anthropic,claude+openai,agent_framework+google) to verify each raisesBackendInitErrorwith descriptive message - US5-18 P1 [US5] Add unit tests in
tests/unit/models/for theAgentmodel validator: verify that constructing anAgentwith incompatiblebackend/providerraisesValidationError - US5-19 P1 [US5] Add unit test for default backend auto-detection: verify each provider resolves to its expected default backend when
backendis omitted - US5-20 P2 [US5] Add unit test for ADK LiteLLM model name construction:
provider: google+name: gemini-2.5-flash->"gemini-2.5-flash",provider: openai+name: gpt-4o->"openai/gpt-4o",provider: azure_openai+name: my-deployment->"azure/my-deployment" - US5-21 P2 [US5] Add unit test for AF client selection: verify each supported provider maps to the correct client class
Phase 4: Polish¶
- US5-23 P2 [US5] Run
make format && make lint && make type-check— fix any issues introduced by US5 changes - US5-24 P2 [US5] Run full test suite
make testto verify no regressions from selector refactoring - US5-25 P3 [US5] Review error messages for consistency: all backend/provider validation errors should follow the same format pattern across model validator and selector
Summary¶
| Phase | Task Count | P1 | P2 | P3 |
|---|---|---|---|---|
| Phase 2: Foundational | 2 | 2 | 0 | 0 |
| Phase 3: Implementation | 7 | 5 | 2 | 0 |
| Phase 3: Tests | 9 | 7 | 2 | 0 |
| Phase 4: Polish | 3 | 0 | 2 | 1 |
| Total | 21 | 14 | 6 | 1 |