Skip to content

[ENHANCEMENT] Add provider routing selection for OpenRouter embeddings #9144

@SannidhyaSah

Description

@SannidhyaSah

Problem (one or two sentences)

Users configuring OpenRouter embeddings for code indexing cannot select specific routing providers, forcing them to accept OpenRouter's automatic routing which may select providers with significantly higher costs (up to 4-5x price difference).

Context (who is affected and when)

Anyone using OpenRouter's embedding models for code indexing. The pricing disparity becomes critical when processing large codebases - some OpenRouter embedding providers cost 400-500% more than others for the same embedding model. This affects:

  • Users on budget constraints who need cost-effective embedding providers
  • Teams processing large repositories where embedding costs accumulate
  • Users wanting consistency with their chat completion provider choice (which already has routing selection)

Desired behavior (conceptual, not technical)

When configuring OpenRouter embeddings in code indexing settings, users should be able to select a specific routing provider (similar to how they can select providers for chat completions). The system should respect this choice when creating embeddings, ensuring predictable costs and consistent provider selection.

Constraints / preferences (optional)

  • Must maintain backwards compatibility with existing configurations (default to automatic routing if not specified)
  • Should follow the same pattern as chat completion provider routing for consistency
  • UI/UX should match the existing OpenRouter provider selector in chat settings
  • No breaking changes to existing embedder API contracts

Request checklist

  • I've searched existing Issues and Discussions for duplicates
  • This describes a specific problem with clear context and impact

Roo Code Task Links (optional)

N/A

Acceptance criteria (optional)

Given a user has OpenRouter configured as their embedding provider
When they open code indexing settings
Then they should see a "Routing Provider" dropdown/selector (similar to chat completion settings)
And selecting a specific provider should pass that provider preference to the OpenRouter embedding API
And leaving it as "[default]" should maintain current behavior (automatic routing)
But existing configurations without this setting should continue working unchanged

Proposed approach (optional)

Following the existing pattern from chat completions:

  1. Reuse existing configuration flow:

    • Similar to how openRouterSpecificProvider works for chat (src/api/providers/openrouter.ts:154-161), add optional provider parameter to OpenRouterEmbedder constructor (src/services/code-index/embedders/openrouter.ts:58-82)
    • Currently only takes (apiKey, modelId?, maxItemTokens?) - extend to include optional provider
  2. Configuration chain updates:

    • CodeIndexConfigManager (src/services/code-index/config-manager.ts:136) loads openRouterOptions = { apiKey } - extend to include provider
    • CodeIndexServiceFactory (src/services/code-index/service-factory.ts:87) passes provider to embedder constructor
  3. Embedder implementation:

    • Mirror the provider routing logic from chat completion (lines 154-161 in openrouter.ts)
    • Add provider object with order, only, and allow_fallbacks to embedding API calls
  4. UI/Settings:

    • Add new setting field for OpenRouter embedding provider selection
    • Reuse existing provider endpoint fetching if applicable
  5. Testing:

    • Extend existing tests in src/services/code-index/embedders/tests/openrouter.spec.ts
    • Test with provider specified
    • Test backwards compatibility (undefined provider)

Trade-offs / risks (optional)

Backwards Compatibility: Fully maintained - optional parameter defaults to undefined, preserving current auto-routing behavior

Risks: Minimal. Potential for users to select providers that don't support their chosen embedding model, but this is the same risk that exists for chat completions.

Alternative Considered: Could implement provider filtering/validation, but that adds complexity. Better to match chat completion's approach and let OpenRouter's API handle invalid combinations.


🔍 Comprehensive Issue Scoping

Implementation Target

Enable provider routing for OpenRouter embeddings by extending the existing configuration chain to pass an optional provider preference through to the OpenRouter API, mirroring the proven pattern from chat completions.

Affected Components

Primary Files:

  • src/services/code-index/embedders/openrouter.ts (lines 58-82) - Constructor and embedding creation method
  • src/services/code-index/config-manager.ts (lines 23-136) - Configuration loading
  • src/services/code-index/service-factory.ts (lines 83-88) - Embedder instantiation
  • Settings UI component (location TBD) - Provider selection dropdown

Secondary Impact:

  • src/services/code-index/embedders/__tests__/openrouter.spec.ts - Test coverage
  • src/services/code-index/interfaces/config.ts (lines 7-23) - Type definitions
  • Package.json settings schema - New setting definition

Current Implementation Analysis

Chat Completion (HAS provider routing):

// src/api/providers/openrouter.ts:154-161
...(this.options.openRouterSpecificProvider &&
  this.options.openRouterSpecificProvider !== OPENROUTER_DEFAULT_PROVIDER_NAME && {
    provider: {
      order: [this.options.openRouterSpecificProvider],
      only: [this.options.openRouterSpecificProvider],
      allow_fallbacks: false,
    }
})

Embeddings (LACKS provider routing):

// src/services/code-index/embedders/openrouter.ts:58-82
constructor(apiKey: string, modelId?: string, maxItemTokens?: number) {
  // Only accepts apiKey, modelId, maxItemTokens
  // No provider parameter
}

// src/services/code-index/config-manager.ts:136
this.openRouterOptions = openRouterApiKey ? { apiKey: openRouterApiKey } : undefined
// Only stores apiKey

// src/services/code-index/service-factory.ts:87
return new OpenRouterEmbedder(config.openRouterOptions.apiKey, config.modelId)
// Only passes apiKey and modelId

The pattern from chat completions shows exactly how to implement this. The chat handler passes the provider parameter through to the API request, setting provider.order and provider.only arrays with the specific provider when configured.

Proposed Implementation

Step 1: Extend OpenRouterEmbedder constructor

  • File: src/services/code-index/embedders/openrouter.ts
  • Changes: Add optional specificProvider?: string parameter to constructor (line 58)
  • Rationale: Mirror chat completion pattern, maintain backwards compatibility

Step 2: Store provider in instance variable

  • File: src/services/code-index/embedders/openrouter.ts
  • Changes: Add private readonly specificProvider?: string property, set in constructor
  • Rationale: Need to access provider value in embedding creation methods

Step 3: Apply provider routing in API calls

  • File: src/services/code-index/embedders/openrouter.ts
  • Changes: In _embedBatchWithRetries method (lines 183-190), add provider object conditionally (mirror lines 154-161 from chat)
  • Rationale: This is where the actual API call happens

Step 4: Update configuration interface

  • File: src/services/code-index/interfaces/config.ts
  • Changes: Extend CodeIndexConfig.openRouterOptions from { apiKey: string } to { apiKey: string; specificProvider?: string }
  • Rationale: Type safety for configuration chain

Step 5: Update config manager to load provider

  • File: src/services/code-index/config-manager.ts
  • Changes: Line 136 - load provider from settings and include in openRouterOptions
  • Rationale: Configuration chain needs to pass provider through

Step 6: Update service factory

  • File: src/services/code-index/service-factory.ts
  • Changes: Line 87 - pass provider to OpenRouterEmbedder constructor
  • Rationale: Connect configuration to embedder instantiation

Step 7: Add UI setting

  • File: Package.json and settings UI (exact location TBD)
  • Changes: Add codebaseIndexOpenRouterSpecificProvider setting (similar to chat's openRouterSpecificProvider)
  • Rationale: User needs way to configure provider

Step 8: Add tests

  • File: src/services/code-index/embedders/__tests__/openrouter.spec.ts
  • Changes: Test cases for provider specified and undefined (backwards compat)
  • Rationale: Ensure feature works and doesn't break existing functionality

Code Architecture Considerations

  • Follow existing OpenRouter chat completion pattern exactly
  • Maintain full backwards compatibility (optional parameter)
  • No changes to public embedder interface (IEmbedder)
  • Reuse existing configuration architecture

Testing Requirements

  • Unit Tests:

    • Test OpenRouterEmbedder with provider specified
    • Test OpenRouterEmbedder without provider (backwards compat)
    • Test provider=[default] behavior
    • Test provider value flows through config chain
  • Integration Tests:

    • Verify embedding API calls include provider object when configured
    • Verify embedding API calls exclude provider object when not configured
  • Edge Cases:

    • Provider string validation (empty string handling)
    • Invalid provider names (let OpenRouter API handle)
    • Config migration from old to new format

Performance Impact

  • Expected change: Neutral
  • Benchmarking: No - only adds optional parameter
  • Optimization: None needed

Security Considerations

  • No authentication/authorization changes
  • No new data exposure risks
  • Provider value is user-controlled string - validated by OpenRouter API

Migration Strategy

Fully backwards compatible - no migration needed:

  • Existing configs continue working (provider parameter optional/undefined)
  • New configs can opt into provider routing
  • Default behavior unchanged

Rollback Plan

If issues arise:

  1. Remove provider parameter from embedder calls
  2. Revert configuration chain changes
  3. No database/storage changes to roll back

Dependencies and Breaking Changes

External Dependencies: None - uses existing OpenAI SDK patterns
API Contract Changes: None - purely additive (optional parameter)
Breaking Changes: None - fully backwards compatible

Metadata

Metadata

Assignees

No one assigned

    Labels

    EnhancementNew feature or requestIssue/PR - TriageNew issue. Needs quick review to confirm validity and assign labels.

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions