| # P2 Architectural: BYOK Gaps in Non-Critical Paths | |
| **Date**: 2025-12-03 | |
| **Status**: β RESOLVED | |
| **Severity**: P2 (Architectural Debt) | |
| **Component**: LLM Routing / BYOK Support | |
| **Resolution**: Fixed end-to-end BYOK support in this PR | |
| --- | |
| ## Summary | |
| Two code paths do NOT support BYOK (Bring Your Own Key) from Gradio: | |
| 1. **HierarchicalOrchestrator** - Doesn't receive `api_key` parameter | |
| 2. **get_model() (PydanticAI)** - Only checks env vars, no BYOK | |
| These are **latent bugs** - they don't affect the main user flow currently. | |
| --- | |
| ## Bug 1: HierarchicalOrchestrator Missing api_key | |
| **Location**: `src/orchestrators/factory.py:61-64` | |
| ```python | |
| if effective_mode == "hierarchical": | |
| from src.orchestrators.hierarchical import HierarchicalOrchestrator | |
| return HierarchicalOrchestrator(config=effective_config, domain=domain) | |
| # BUG: api_key is NOT passed to HierarchicalOrchestrator | |
| ``` | |
| **Impact**: If hierarchical mode were exposed in UI, BYOK would not work. | |
| **Current State**: Hierarchical mode is NOT exposed in Gradio UI, so this is latent. | |
| **Fix**: Pass `api_key` to HierarchicalOrchestrator when instantiating. | |
| --- | |
| ## Bug 2: get_model() Doesn't Support BYOK | |
| **Location**: `src/agent_factory/judges.py:62-91` (function `get_model()`) | |
| ```python | |
| def get_model() -> Any: | |
| # Priority 1: OpenAI | |
| if settings.has_openai_key: # Only checks ENV VAR | |
| ... | |
| # Priority 2: Anthropic | |
| if settings.has_anthropic_key: # Only checks ENV VAR | |
| ... | |
| # Priority 3: HuggingFace | |
| if settings.has_huggingface_key: # Only checks ENV VAR | |
| ... | |
| ``` | |
| **Impact**: PydanticAI-based components (judges, statistical analyzer) cannot use BYOK keys. | |
| **Current State**: The main Advanced mode flow uses `get_chat_client()` (Microsoft Agent Framework), NOT `get_model()`. So this is latent. | |
| **Fix**: Either: | |
| 1. Add `api_key` parameter to `get_model()` | |
| 2. Or deprecate `get_model()` in favor of `get_chat_client()` everywhere | |
| --- | |
| ## Architecture Notes | |
| The codebase has **TWO separate LLM routing systems**: | |
| | System | Function | BYOK Support | Used By | | |
| |--------|----------|--------------|---------| | |
| | Microsoft Agent Framework | `get_chat_client()` | **YES** (key prefix detection) | Advanced mode (main flow) | | |
| | PydanticAI | `get_model()` | **NO** (env vars only) | Judges, statistical analyzer | | |
| This dual-system architecture creates confusion and maintenance burden. | |
| --- | |
| ## Recommendation | |
| **Short-term**: Leave as-is (latent, not blocking) | |
| **Long-term**: Unify on `get_chat_client()` and deprecate `get_model()` (see P3_REMOVE_ANTHROPIC_PARTIAL_WIRING.md for related cleanup) | |
| --- | |
| ## Test Results | |
| - All 310 unit tests pass | |
| - Main user flow (Gradio β Advanced) works with BYOK | |
| --- | |
| ## Related Documents | |
| - `P3_REMOVE_ANTHROPIC_PARTIAL_WIRING.md` - Related architecture cleanup | |
| - `src/clients/factory.py` - BYOK-capable factory (correct implementation) | |
| - `src/agent_factory/judges.py` - Non-BYOK factory (needs fix) | |