Skip to content

router

router

Backward-compat shim — canonical location is learning.router.

Classes

DefaultQueryAnalyzer

Bases: QueryAnalyzer

Default query analyzer wrapping the heuristic build_routing_context function.

HeuristicRouter

HeuristicRouter(available_models: List[str] | None = None, *, default_model: str = '', fallback_model: str = '')

Bases: RouterPolicy

Rule-based model router.

Rules (applied in order): 1. Code detected → prefer model with "code"/"coder" in name 2. Math detected → prefer larger model 3. Low complexity (score < 0.20) → prefer smaller/faster model 4. High complexity (score >= 0.55 OR reasoning keywords) → prefer larger model 5. High urgency (>0.8) → override to smaller model 6. Default fallback → default_model → fallback_model → first available

Source code in src/openjarvis/learning/routing/router.py
def __init__(
    self,
    available_models: List[str] | None = None,
    *,
    default_model: str = "",
    fallback_model: str = "",
) -> None:
    self._available = available_models or []
    self._default = default_model
    self._fallback = fallback_model

Functions

build_routing_context

build_routing_context(query: str, *, urgency: float = 0.5, model: str | None = None) -> RoutingContext

Populate a RoutingContext from a raw query string.

When model is provided, the suggested token budget is adjusted for thinking models that need extra headroom.

Source code in src/openjarvis/learning/routing/router.py
def build_routing_context(
    query: str, *, urgency: float = 0.5, model: str | None = None
) -> RoutingContext:
    """Populate a ``RoutingContext`` from a raw query string.

    When *model* is provided, the suggested token budget is adjusted
    for thinking models that need extra headroom.
    """
    from openjarvis.learning.routing.complexity import (
        adjust_tokens_for_model,
        score_complexity,
    )

    result = score_complexity(query)
    tokens = adjust_tokens_for_model(result.suggested_max_tokens, model)

    return RoutingContext(
        query=query,
        query_length=len(query),
        has_code=result.signals.get("has_code", False),
        has_math=result.signals.get("has_math", False),
        has_reasoning=result.signals.get("has_reasoning", False),
        urgency=urgency,
        complexity_score=result.score,
        suggested_max_tokens=tokens,
        metadata={"complexity_tier": result.tier, "signals": result.signals},
    )