How OpenMontage Selector Tools Transparently Route to Providers

OpenMontage selector tools like tts_selector and video_selector transparently route to providers by automatically discovering capable backends through the ToolRegistry, scoring them against normalized task contexts, and delegating requests while enriching results with selection metadata.

OpenMontage abstracts concrete provider implementations behind capability-level selectors, enabling agents to request high-level functions like text-to-speech or video generation without hardcoding specific APIs. The selector tools handle the complex logic of provider discovery, ranking, and adaptation internally, presenting a unified interface that routes requests to the most appropriate available backend. This architecture ensures that selector tools transparently route to providers based on real-time availability, task requirements, and user preferences.

Automatic Provider Discovery via ToolRegistry

The routing process begins with automatic discovery in the selector's _providers() method. Located in tools/audio/tts_selector.py, this method queries the global ToolRegistry at runtime to locate any BaseTool instance whose capability field matches the selector's designated capability—"tts" for audio generation or "video" for video generation.

This discovery mechanism requires no manual registration. When developers add new providers to the system, they automatically become available to the selector provided they implement the correct capability constant, ensuring the routing pool expands dynamically as the ecosystem grows.

Dynamic Provider Matrix Construction

Each discovered provider contributes a row to the internal provider_matrix, a data structure that records the provider name alongside its "strength" rating. The strength value derives from the provider's best_for field, which describes optimal use cases and performance characteristics.

This matrix serves dual purposes: it drives the scoring algorithm that determines routing decisions, and it provides UI-side explanations for why specific providers were selected for particular tasks.

Task-Context Normalization and Preparation

Before scoring occurs, the selector prepares a normalized task-context dictionary from user inputs such as text, language, voice, or prompt. This normalization happens via lib.scoring.normalize_task_context, which standardizes parameters across different provider APIs to ensure fair comparison.

By passing the same structured context to every candidate provider, the system eliminates interface discrepancies that could skew routing decisions, creating a level playing field for the ranking engine.

Scored Ranking with Operation Modes

The core routing logic resides in lib.scoring.rank_providers, which evaluates candidates against the normalized context and returns ScoreItem objects containing suitability scores. The tts_selector and video_selector support two distinct operation modes controlled by the operation parameter:

  • operation="rank" — Returns the full ranked provider list without invoking any backend. This mode is useful for UI inspection, debugging provider selection logic, or presenting options to users before committing resources.
  • operation="generate" (default) — Selects the highest-scoring available provider and executes the actual generation task, handling all delegation transparently.

When users specify preferred_provider or allowed_providers in the request, the selector filters the candidate list before scoring, ensuring explicit preferences override automatic selection when provided.

Fallback Handling and Availability Management

If no providers are available for the requested capability, the selector returns ToolStatus.UNAVAILABLE along with a failure result. The fallback_tools property dynamically mirrors the names of all discovered providers, allowing downstream components to present alternative options when primary choices fail or constraints eliminate all high-scoring candidates.

This design ensures graceful degradation while maintaining transparency about available alternatives.

Input Adaptation for Provider APIs

Before delegating to the concrete provider, the selector performs input adaptation to match provider-specific requirements. For example, it might convert generic parameters like speaking_rate to Azure's specific rate parameter, or normalize output_format values to match individual provider expectations.

This translation layer prevents provider-specific quirks from leaking into the high-level selector interface, maintaining the abstraction that selector tools transparently route to providers regardless of backend differences.

Result Enrichment and Transparency Metadata

After the chosen provider completes execution, the selector augments the ToolResult object with metadata fields defined in tools/audio/tts_selector.py:

  • selected_tool: The concrete provider implementation used
  • selected_provider: The provider identifier string
  • selection_reason: Human-readable explanation of the ranking logic
  • alternatives_considered: List of other providers evaluated during selection

These fields provide full visibility into routing decisions, supporting debugging and enabling user interfaces to explain why specific backends were chosen.

Practical Implementation Examples

The following examples demonstrate how to use the selectors with different routing configurations.

Using tts_selector with an explicit provider preference:

result = registry.get("tts_selector").execute({
    "text": "Hello, world!",
    "preferred_provider": "elevenlabs",   # Force ElevenLabs if available

    "voice": "Rachel",
    "operation": "generate"
})
print(result.data["selected_provider"])   # → "elevenlabs"

print(result.data["selection_reason"])    # Explanation of why it was chosen

Ranking providers without generating audio:

rankings = registry.get("tts_selector").execute({
    "text": "Testing ranking mode",
    "operation": "rank"
})
for entry in rankings.data["rankings"]:
    print(f"{entry['provider']}: {entry['score']:.2f}")

Using video_selector in the same way:

video_result = registry.get("video_selector").execute({
    "prompt": "A futuristic cityscape at sunrise",
    "preferred_provider": "runway",
    "operation": "generate"
})
print(video_result.data["selected_tool"])   # e.g., "runway_video"

Summary

  • Automatic Discovery: Selectors query ToolRegistry for BaseTool instances matching their capability ("tts" or "video") through the _providers() method without requiring manual registration.
  • Dynamic Ranking: The provider_matrix and lib.scoring.rank_providers evaluate candidates based on task context and best_for strengths to determine optimal routing.
  • Flexible Operations: Support for operation="rank" (inspection) and operation="generate" (execution) modes adapts to different workflow requirements.
  • User Preferences: The preferred_provider and allowed_providers parameters allow explicit override of automatic selection logic.
  • Transparent Metadata: Results include selected_provider, selection_reason, and alternatives_considered for full routing visibility.
  • Provider-Agnostic Interface: Input adaptation and result enrichment hide provider-specific complexity behind unified capability selectors in tools/audio/tts_selector.py and tools/video/video_selector.py.

Frequently Asked Questions

How does the selector choose between multiple available providers?

The selector uses lib.scoring.rank_providers to evaluate each candidate against a normalized task context created by lib.scoring.normalize_task_context. Each provider's best_for characteristics are compared against task requirements to generate relevance scores, with the highest-scoring available provider selected by default. Users can override this behavior by setting the preferred_provider parameter in the request.

What happens if my preferred provider is unavailable?

If the specified preferred_provider is not found or unavailable, the selector filters it from the candidate list and proceeds to rank remaining providers according to the provider_matrix. If no providers remain available, the selector returns ToolStatus.UNAVAILABLE and populates fallback_tools with the names of all discovered alternatives, allowing your application to suggest other options or retry with different constraints.

Can I inspect provider rankings without triggering a generation?

Yes. Set operation="rank" when calling tts_selector or video_selector. This mode returns the full ranked list of providers and their scores through the rankings field without invoking any actual provider execution, making it ideal for debugging or presenting options to end users before committing to a generation task.

Where is the provider routing logic implemented in the codebase?

The routing implementation spans several key files: tools/audio/tts_selector.py and tools/video/video_selector.py contain the selector implementations with _providers() and result enrichment logic; lib/scoring.py houses the rank_providers and normalize_task_context functions; tools/tool_registry.py manages provider discovery; and tools/base_tool.py defines the interface shared by all providers and selectors. Architectural documentation is available in docs/ARCHITECTURE.md.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →