Tasks: US6 — Unified Embedding Provider via LiteLLM¶
User Story: A platform user has vectorstore/hierarchical_document tools and wants embeddings to work consistently regardless of backend. LiteLLM replaces SK embedding classes as the unified embedding provider, supporting 20+ providers.
Branch: 023-choose-your-backend
Depends on: BackendEnum from US1 setup (for embedding_provider validator); otherwise independent of US1/US2.
Phase 1: Setup — Add LiteLLM Core Dependency¶
- T6-01 P1 [US6] Add
litellmas a core dependency inpyproject.toml(dependencieslist, not optional) - Pin to a stable minor range (e.g.,
litellm>=1.40.0,<2.0.0) - Run
uv lockto verify resolution with existing deps - Confirm no conflicts with existing
openai,anthropic,ollamapackages
Phase 2: Foundational — EmbeddingService Protocol¶
- T6-02 P0 [US6] Create
src/holodeck/lib/embedding_protocol.pywithEmbeddingServiceprotocol - Define
@runtime_checkableProtocol class with:async def embed_batch(self, texts: list[str]) -> list[list[float]]@property dimensions -> int@property model_id -> str
-
Include docstrings per project style (Google Python Style Guide)
-
T6-03 P0 [US6] Implement
LiteLLMEmbeddingAdapterinsrc/holodeck/lib/embedding_protocol.py - Fields:
_model_id: str,_api_key: str | None,_api_base: str | None,_dimensions: int embed_batch()callslitellm.aembedding()with the mapped model string- Implement provider mapping logic:
openai+text-embedding-3-small->"text-embedding-3-small"azure_openai+my-deployment->"azure/my-deployment"ollama+nomic-embed-text->"ollama/nomic-embed-text"google+text-embedding-004->"gemini/text-embedding-004"
- Add
@classmethod from_embedding_provider(cls, provider_config: LLMProvider) -> LiteLLMEmbeddingAdapterfactory method -
Handle
api_key,api_base(fromendpointfield), andapi_versionmapping to LiteLLM kwargs -
T6-04 P1 [US6] Add provider-to-LiteLLM model string mapping helper in
embedding_protocol.py - Function:
def _map_provider_model(provider: ProviderEnum, name: str) -> str - Mapping rules per data-model.md section 5
- Raise clear error for unsupported providers (e.g.,
anthropichas no embedding models)
Phase 3: Integration — Refactor tool_initializer.py¶
- T6-05 P0 [US6] Replace
create_embedding_service()insrc/holodeck/lib/tool_initializer.pyto useLiteLLMEmbeddingAdapter - Remove SK embedding imports:
OpenAITextEmbedding,AzureTextEmbedding,OllamaTextEmbedding - Remove the
from semantic_kernel.connectors.ai.open_ai import AzureTextEmbedding, OpenAITextEmbeddingblock (line ~100-103) - Remove the
from semantic_kernel.connectors.ai.ollama import OllamaTextEmbeddinglazy import (line ~130) - Replace entire
create_embedding_service()body with:- Call
_resolve_embedding_provider()and_resolve_embedding_model_config()(keep these helpers) - Instantiate
LiteLLMEmbeddingAdapter.from_embedding_provider(model_config)or equivalent
- Call
- Return type annotation: change from
AnytoEmbeddingService -
Update module docstring to remove "uses SK TextEmbedding classes" reference
-
T6-06 P1 [US6] Update
_resolve_embedding_provider()intool_initializer.pyto handlegoogleprovider - Currently only checks for
ProviderEnum.ANTHROPIC; must also check forGOOGLE(new provider from US1) - All non-SK providers (anthropic, google) require
embedding_providerto be set -
Error message should list all providers that need
embedding_provider -
T6-07 P1 [US6] Update type annotations in
tool_initializer.py - Change
embedding_service: Anyparameters in_initialize_vectorstore_tools()andinitialize_hierarchical_doc_tools()toembedding_service: EmbeddingService - Add import of
EmbeddingServicefromembedding_protocol - Update docstrings referencing "SK TextEmbedding service" to "EmbeddingService"
Phase 4: Validation — embedding_provider Model Validator¶
- T6-08 P0 [US6] Add
@model_validator(mode='after')toAgentmodel insrc/holodeck/models/agent.py - Validator enforces: when resolved backend is
claude,google_adk, oragent_frameworkAND agent has vectorstore or hierarchical_document tools ->embedding_providerMUST be set - Backend resolution: use
backendfield if set, otherwise use default routing frommodel.provider - Import
BackendEnumfrommodels.llm(depends on T1-XX from US1 that adds BackendEnum) - Import tool types for isinstance checks:
VectorstoreTool,HierarchicalDocumentToolConfig - Error message: "Backend '{backend}' does not provide native embeddings. Configure 'embedding_provider' in agent.yaml for vectorstore/hierarchical_document tools."
-
This is a NEW validator, not a modification of an existing one
-
T6-09 P1 [US6] Handle the
semantic_kernelbackend case in embedding_provider validator - SK backend has its own embedding classes (functional when
backend: semantic_kernelis explicitly set) - When resolved backend is
semantic_kernel, embedding_provider is NOT required (SK handles it internally) - Note:
provider: openainow defaults toagent_frameworkbackend; onlybackend: semantic_kerneltriggers the SK path - Document this distinction in the validator docstring
Phase 5: Tests¶
- T6-10 P0 [US6] Create
tests/unit/lib/test_embedding_protocol.py - Test
EmbeddingServiceprotocol compliance: verifyLiteLLMEmbeddingAdaptersatisfiesisinstance()check - Test provider mapping function:
openai+text-embedding-3-small->"text-embedding-3-small"azure_openai+my-deployment->"azure/my-deployment"ollama+nomic-embed-text->"ollama/nomic-embed-text"google+text-embedding-004->"gemini/text-embedding-004"
- Test
from_embedding_provider()factory with mock LLMProvider configs for each supported provider - Test
embed_batch()with mockedlitellm.aembeddingresponse - Test error on unsupported provider (e.g., anthropic as embedding provider)
- Test
dimensionsandmodel_idproperties -
Use
@pytest.mark.unitand@pytest.mark.asyncio -
T6-11 P0 [US6] Add/update tests in
tests/unit/lib/test_tool_initializer.pyfor LiteLLM integration - Test
create_embedding_service()returnsLiteLLMEmbeddingAdapter(not SK types) - Test with
provider: openai+ vectorstore tools -> LiteLLM adapter created - Test with
provider: anthropic+embedding_provider-> LiteLLM adapter created - Test with
provider: google+embedding_provider-> LiteLLM adapter created (acceptance scenario 2) - Test with
provider: ollama+embedding_provider: { provider: ollama, endpoint: http://localhost:11434 }-> endpoint mapped (acceptance scenario 4) -
Verify NO SK embedding imports are used (mock check or import inspection)
-
T6-12 P0 [US6] Add tests for embedding_provider validator in
tests/unit/models/test_agent.py - Test:
provider: anthropic+ vectorstore tools + NO embedding_provider ->ValidationError(acceptance scenario 5) - Test:
provider: google+ vectorstore tools + NO embedding_provider ->ValidationError(acceptance scenario 5) - Test:
provider: openai+ backend:agent_framework+ vectorstore tools + NO embedding_provider ->ValidationError - Test:
provider: openai+ backend:semantic_kernel+ vectorstore tools + NO embedding_provider -> PASSES (SK handles it) - Test:
provider: openai+ vectorstore tools + embedding_provider set -> PASSES (acceptance scenario 3) - Test: agent with NO vectorstore/hierarchical_document tools -> validator is no-op regardless of backend
Phase 6: Polish¶
- T6-13 P2 [US6] Update
src/holodeck/lib/embedding_protocol.pyexports in__init__.pyfiles - Add
EmbeddingServiceandLiteLLMEmbeddingAdaptertosrc/holodeck/lib/__init__.pyif one exists -
Ensure public API is importable as
from holodeck.lib.embedding_protocol import EmbeddingService -
T6-14 P2 [US6] Run full code quality pipeline and fix issues
make format(Black + Ruff)make lint(Ruff + Bandit)make type-check(MyPy — verify EmbeddingService protocol type-checks correctly)-
make test-unit -n auto(all unit tests pass, including new ones) -
T6-15 P2 [US6] Verify embedding behavior under new default routing:
provider: openainow defaults toagent_frameworkbackend - The YAML schema for
embedding_provideris NOT modified provider: openaiwith vectorstore tools now requiresembedding_provider(since default backend isagent_framework, not SK)provider: openai+backend: semantic_kernel+ vectorstore tools continues to work withoutembedding_provider(SK handles it internally)- Existing tests that exercise vectorstore tool initialization must be updated to either set
embedding_provideror explicitly setbackend: semantic_kernel
Dependency Graph¶
T6-01 (litellm dep)
└──> T6-02 (protocol) + T6-03 (adapter) + T6-04 (mapping)
└──> T6-05 (tool_initializer refactor)
│ └──> T6-06 (google provider handling)
│ └──> T6-07 (type annotations)
└──> T6-08 (validator) ──> requires BackendEnum from US1
│ └──> T6-09 (SK backend case)
└──> T6-10 (protocol tests)
└──> T6-11 (tool_init tests) ──> after T6-05
└──> T6-12 (validator tests) ──> after T6-08
└──> T6-13 + T6-14 + T6-15 (polish)
Acceptance Criteria Traceability¶
| Scenario | Covered By |
|---|---|
1. provider: openai + vectorstore + embedding_provider: openai -> LiteLLM |
T6-05, T6-11 |
2. provider: google + vectorstore + embedding_provider -> LiteLLM (no SK dep) |
T6-06, T6-11 |
3. provider: openai + vectorstore + embedding_provider -> embeddings via LiteLLM, backend auto-detected to agent_framework |
T6-05, T6-11, T6-15 |
4. embedding_provider: { provider: ollama, endpoint: ... } -> mapped to LiteLLM |
T6-03, T6-04, T6-10, T6-11 |
5. provider: anthropic/google + vectorstore + NO embedding_provider -> error |
T6-08, T6-12 |