fix(providers): add OpenRouter support to _create_provider_llm #10950

Merged
HAL9000 merged 1 commits from bugfix/m3-openrouter-create-llm into master 2026-05-03 01:37:50 +00:00
Member

Summary

  • Adds a ProviderType.OPENROUTER branch to ProviderRegistry._create_provider_llm() so that create_llm("openrouter") returns a configured ChatOpenAI instance instead of raising ValueError: Unsupported provider type: openrouter
  • Fixes agents actor run openrouter/<model> failures caused by SimpleLLMAgent._resolve_llm() calling create_llm() rather than create_ai_provider()
  • Adds comprehensive BDD scenarios covering the new branch: basic client construction, header sanitization, create_llm() delegation, organization headers, default model fallback, empty headers, extra kwargs forwarding, and empty API key validation

Motivation

create_ai_provider("openrouter") correctly instantiated OpenRouterChatProvider, but create_llm("openrouter") — used by SimpleLLMAgent in the reactive stream router — fell through the provider dispatch chain to raise ValueError(f"Unsupported provider type: {provider_type}"). All seven other providers (OpenAI, Anthropic, Google/Gemini, Azure, Groq, Together, Cohere) had branches; OpenRouter was the only one missing.

Approach

src/cleveragents/providers/registry.py: Added OPENROUTER branch in _create_provider_llm():

  • Creates ChatOpenAI with openai_api_base="https://openrouter.ai/api/v1" and openai_api_key from settings
  • Handles optional default_headers kwarg — sanitizes mapping to dict[str, str] via inline comprehension (avoids ruff import-order violation from importing OpenRouterChatProvider._sanitize_headers)
  • New (review fix M1): Reads openrouter_organization from settings and injects HTTP-Referer and X-Title headers, matching OpenRouterChatProvider.__init__() behavior
  • New (review fix m1): Explicit ValueError guard when openrouter_api_key is empty/missing, consistent with OpenRouterChatProvider
  • Follows the existing single-import-per-branch pattern used by all other providers

features/provider_registry_coverage.feature: Nine @unit @providers @registry scenarios (expanded from three):

  1. _create_provider_llm builds OpenRouter client with ChatOpenAI — verifies model, openai_api_base, and openai_api_key (M2 fix)
  2. _create_provider_llm builds OpenRouter client with sanitized default headers — verifies numeric keys/values are coerced to strings, original integer key 123 is absent (m7 fix), and openai_api_key is passed (m8 fix)
  3. create_llm succeeds for OpenRouter and delegates to _create_provider_llm — verifies the dispatch chain
  4. _create_provider_llm adds organization headers for OpenRouter — verifies HTTP-Referer and X-Title are injected from openrouter_organization setting (M1 fix)
  5. _create_provider_llm uses default model for OpenRouter when model_id is None — verifies fallback anthropic/claude-sonnet-4-20250514 (m2 fix)
  6. _create_provider_llm treats empty default_headers as None for OpenRouter — verifies default_headers={} results in no default_headers key passed to ChatOpenAI (m4 fix)
  7. _create_provider_llm forwards extra kwargs to ChatOpenAI for OpenRouter — verifies temperature=0.7 is forwarded via kwargs (m5 fix)
  8. _create_provider_llm raises error when OpenRouter API key is empty — verifies explicit ValueError with OPENROUTER_API_KEY mention (m1 + m6 fix)

features/steps/provider_registry_steps.py: Added step definitions for new scenarios (no-model call, empty headers, temperature kwarg, negative header assertion, no-default-headers assertion, numeric value comparison in stubbed argument check).

CHANGELOG.md: Entry added to ### Fixed section.

Quality Gates

Gate Result
nox -s lint Pass
nox -s typecheck Pass (0 errors)
nox -s unit_tests Pass (15,702 scenarios)
nox -s integration_tests Pass (2,001 tests)
nox -s coverage_report Pass (97.0% ≥ 97% threshold)
nox -s e2e_tests ⚠️ 2 pre-existing M6 failures (rc=-9 SIGKILL — resource/memory issue unrelated to provider changes) + WF12 placeholder not yet implemented

Closes #10948

## Summary - Adds a `ProviderType.OPENROUTER` branch to `ProviderRegistry._create_provider_llm()` so that `create_llm("openrouter")` returns a configured `ChatOpenAI` instance instead of raising `ValueError: Unsupported provider type: openrouter` - Fixes `agents actor run openrouter/<model>` failures caused by `SimpleLLMAgent._resolve_llm()` calling `create_llm()` rather than `create_ai_provider()` - Adds comprehensive BDD scenarios covering the new branch: basic client construction, header sanitization, `create_llm()` delegation, organization headers, default model fallback, empty headers, extra kwargs forwarding, and empty API key validation ## Motivation `create_ai_provider("openrouter")` correctly instantiated `OpenRouterChatProvider`, but `create_llm("openrouter")` — used by `SimpleLLMAgent` in the reactive stream router — fell through the provider dispatch chain to `raise ValueError(f"Unsupported provider type: {provider_type}")`. All seven other providers (OpenAI, Anthropic, Google/Gemini, Azure, Groq, Together, Cohere) had branches; OpenRouter was the only one missing. ## Approach **`src/cleveragents/providers/registry.py`**: Added OPENROUTER branch in `_create_provider_llm()`: - Creates `ChatOpenAI` with `openai_api_base="https://openrouter.ai/api/v1"` and `openai_api_key` from settings - Handles optional `default_headers` kwarg — sanitizes mapping to `dict[str, str]` via inline comprehension (avoids ruff import-order violation from importing `OpenRouterChatProvider._sanitize_headers`) - **New (review fix M1)**: Reads `openrouter_organization` from settings and injects `HTTP-Referer` and `X-Title` headers, matching `OpenRouterChatProvider.__init__()` behavior - **New (review fix m1)**: Explicit `ValueError` guard when `openrouter_api_key` is empty/missing, consistent with `OpenRouterChatProvider` - Follows the existing single-import-per-branch pattern used by all other providers **`features/provider_registry_coverage.feature`**: Nine `@unit @providers @registry` scenarios (expanded from three): 1. `_create_provider_llm builds OpenRouter client with ChatOpenAI` — verifies `model`, `openai_api_base`, **and `openai_api_key`** (M2 fix) 2. `_create_provider_llm builds OpenRouter client with sanitized default headers` — verifies numeric keys/values are coerced to strings, **original integer key `123` is absent** (m7 fix), and **`openai_api_key` is passed** (m8 fix) 3. `create_llm succeeds for OpenRouter and delegates to _create_provider_llm` — verifies the dispatch chain 4. `_create_provider_llm adds organization headers for OpenRouter` — verifies `HTTP-Referer` and `X-Title` are injected from `openrouter_organization` setting (M1 fix) 5. `_create_provider_llm uses default model for OpenRouter when model_id is None` — verifies fallback `anthropic/claude-sonnet-4-20250514` (m2 fix) 6. `_create_provider_llm treats empty default_headers as None for OpenRouter` — verifies `default_headers={}` results in no `default_headers` key passed to `ChatOpenAI` (m4 fix) 7. `_create_provider_llm forwards extra kwargs to ChatOpenAI for OpenRouter` — verifies `temperature=0.7` is forwarded via kwargs (m5 fix) 8. `_create_provider_llm raises error when OpenRouter API key is empty` — verifies explicit `ValueError` with `OPENROUTER_API_KEY` mention (m1 + m6 fix) **`features/steps/provider_registry_steps.py`**: Added step definitions for new scenarios (no-model call, empty headers, temperature kwarg, negative header assertion, no-default-headers assertion, numeric value comparison in stubbed argument check). **`CHANGELOG.md`**: Entry added to `### Fixed` section. ## Quality Gates | Gate | Result | |------|--------| | `nox -s lint` | ✅ Pass | | `nox -s typecheck` | ✅ Pass (0 errors) | | `nox -s unit_tests` | ✅ Pass (15,702 scenarios) | | `nox -s integration_tests` | ✅ Pass (2,001 tests) | | `nox -s coverage_report` | ✅ Pass (97.0% ≥ 97% threshold) | | `nox -s e2e_tests` | ⚠️ 2 pre-existing M6 failures (`rc=-9` SIGKILL — resource/memory issue unrelated to provider changes) + WF12 placeholder not yet implemented | Closes #10948
hurui200320 added this to the v3.2.0 milestone 2026-05-01 07:12:07 +00:00
hurui200320 added the
Type
Bug
label 2026-05-01 07:12:10 +00:00
hurui200320 marked the pull request as work in progress 2026-05-01 07:40:55 +00:00
hurui200320 force-pushed bugfix/m3-openrouter-create-llm from a0671eb47a to 766845ba40 2026-05-01 09:58:29 +00:00 Compare
hurui200320 force-pushed bugfix/m3-openrouter-create-llm from 766845ba40 to fdbc9a3471 2026-05-01 10:03:20 +00:00 Compare
hurui200320 marked the pull request as ready for review 2026-05-01 10:22:18 +00:00
hurui200320 requested review from HAL9000 2026-05-01 13:23:33 +00:00
hurui200320 requested review from HAL9001 2026-05-01 13:23:33 +00:00
HAL9001 reviewed 2026-05-02 11:17:59 +00:00
HAL9001 left a comment
Owner

PR Review: Add OpenRouter Support to _create_provider_llm

Summary

This PR adds OpenRouter support to the _create_provider_llm method in src/cleveragents/providers/registry.py.

Changes

  • Added ProviderType.OPENROUTER case (lines 477-484) that creates a ChatOpenAI instance with openai_api_base="https://openrouter.ai/api/v1"
  • Follows the same pattern as other providers in the method

Review Checklist

  1. CORRECTNESS: Fix is correct - OpenRouter now supported in _create_provider_llm
  2. SPECIFICATION ALIGNMENT: OpenRouter already defined in enum and DEFAULT_MODELS
  3. TEST QUALITY: ⚠️ No test exists for _create_provider_llm with OpenRouter in the Scenario Outline (suggest adding)
  4. TYPE SAFETY: All type annotations correct
  5. READABILITY: Follows established patterns
  6. PERFORMANCE: No impact
  7. SECURITY: No secrets or credentials introduced
  8. CODE STYLE: Follows ruff conventions
  9. DOCUMENTATION: ⚠️ Consider updating CHANGELOG.md
  10. COMMIT AND PR QUALITY: Title follows Conventional Changelog format, CI is passing

Conclusion

Status: COMMENT - No blocking issues. The fix is correct and complete.

Suggestions (non-blocking):

  1. Add OpenRouter to the _create_provider_llm test scenario outline in features/provider_registry_coverage.feature
  2. Update CHANGELOG.md to document this fix

Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker

## PR Review: Add OpenRouter Support to _create_provider_llm ### Summary This PR adds OpenRouter support to the `_create_provider_llm` method in `src/cleveragents/providers/registry.py`. ### Changes - Added `ProviderType.OPENROUTER` case (lines 477-484) that creates a `ChatOpenAI` instance with `openai_api_base="https://openrouter.ai/api/v1"` - Follows the same pattern as other providers in the method ### Review Checklist 1. **CORRECTNESS**: ✅ Fix is correct - OpenRouter now supported in `_create_provider_llm` 2. **SPECIFICATION ALIGNMENT**: ✅ OpenRouter already defined in enum and DEFAULT_MODELS 3. **TEST QUALITY**: ⚠️ No test exists for `_create_provider_llm` with OpenRouter in the Scenario Outline (suggest adding) 4. **TYPE SAFETY**: ✅ All type annotations correct 5. **READABILITY**: ✅ Follows established patterns 6. **PERFORMANCE**: ✅ No impact 7. **SECURITY**: ✅ No secrets or credentials introduced 8. **CODE STYLE**: ✅ Follows ruff conventions 9. **DOCUMENTATION**: ⚠️ Consider updating CHANGELOG.md 10. **COMMIT AND PR QUALITY**: ✅ Title follows Conventional Changelog format, CI is passing ### Conclusion **Status: COMMENT** - No blocking issues. The fix is correct and complete. **Suggestions (non-blocking):** 1. Add OpenRouter to the `_create_provider_llm` test scenario outline in `features/provider_registry_coverage.feature` 2. Update CHANGELOG.md to document this fix --- Automated by CleverAgents Bot Supervisor: PR Review | Agent: pr-review-worker
Owner

Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker

--- Automated by CleverAgents Bot Supervisor: PR Review | Agent: pr-review-worker
HAL9001 approved these changes 2026-05-02 20:58:32 +00:00
HAL9001 left a comment
Owner

This PR adds comprehensive support for OpenRouter in ProviderRegistry._create_provider_llm(), including: API key validation, header sanitization, organization header injection, default model fallback, and forwarding extra kwargs. Comprehensive BDD scenarios and step definitions cover all new behavior, and the CHANGELOG has been updated accordingly. All Quality Gates pass and CI is green. No blocking issues were found.

Suggestions: consider refactoring header sanitization and organization header logic into a shared helper for consistency across providers, and verify import paths for ChatOpenAI match other provider branches for uniformity.

Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker

This PR adds comprehensive support for OpenRouter in ProviderRegistry._create_provider_llm(), including: API key validation, header sanitization, organization header injection, default model fallback, and forwarding extra kwargs. Comprehensive BDD scenarios and step definitions cover all new behavior, and the CHANGELOG has been updated accordingly. All Quality Gates pass and CI is green. No blocking issues were found. Suggestions: consider refactoring header sanitization and organization header logic into a shared helper for consistency across providers, and verify import paths for ChatOpenAI match other provider branches for uniformity. --- Automated by CleverAgents Bot Supervisor: PR Review | Agent: pr-review-worker
HAL9000 force-pushed bugfix/m3-openrouter-create-llm from fdbc9a3471 to 507c4a2c51 2026-05-02 21:19:29 +00:00 Compare
HAL9000 scheduled this pull request to auto merge when all checks succeed 2026-05-02 21:19:30 +00:00
HAL9000 force-pushed bugfix/m3-openrouter-create-llm from 507c4a2c51 to cfd4e987ca 2026-05-02 22:03:12 +00:00 Compare
HAL9000 force-pushed bugfix/m3-openrouter-create-llm from cfd4e987ca to cf078c2c53 2026-05-03 01:12:12 +00:00 Compare
HAL9000 merged commit 9b7a0543d0 into master 2026-05-03 01:37:50 +00:00
Sign in to join this conversation.
No Reviewers
No Label
Type
Bug
3 Participants
Notifications
Due Date
No due date set.
Reference: cleveragents/cleveragents-core#10950