-
Notifications
You must be signed in to change notification settings - Fork 1
feat: implement model routing engine #99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
78f4bff
7618335
99fa913
b17601b
50c17a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,49 +22,49 @@ | |
| SeniorityInfo( | ||
| level=SeniorityLevel.JUNIOR, | ||
| authority_scope="Execute assigned tasks only", | ||
| typical_model_tier="haiku", | ||
| typical_model_tier="small", | ||
| cost_tier=CostTier.LOW, | ||
| ), | ||
|
Comment on lines
21
to
27
|
||
| SeniorityInfo( | ||
| level=SeniorityLevel.MID, | ||
| authority_scope="Execute and suggest improvements", | ||
| typical_model_tier="sonnet", | ||
| typical_model_tier="medium", | ||
| cost_tier=CostTier.MEDIUM, | ||
| ), | ||
| SeniorityInfo( | ||
| level=SeniorityLevel.SENIOR, | ||
| authority_scope="Execute, design, and review others", | ||
| typical_model_tier="sonnet", | ||
| typical_model_tier="medium", | ||
| cost_tier=CostTier.HIGH, | ||
| ), | ||
| SeniorityInfo( | ||
| level=SeniorityLevel.LEAD, | ||
| authority_scope="All above plus approve and delegate", | ||
| typical_model_tier="opus", | ||
| typical_model_tier="large", | ||
| cost_tier=CostTier.HIGH, | ||
| ), | ||
| SeniorityInfo( | ||
| level=SeniorityLevel.PRINCIPAL, | ||
| authority_scope="All above plus architectural decisions", | ||
| typical_model_tier="opus", | ||
| typical_model_tier="large", | ||
| cost_tier=CostTier.PREMIUM, | ||
| ), | ||
| SeniorityInfo( | ||
| level=SeniorityLevel.DIRECTOR, | ||
| authority_scope="Strategic decisions and budget authority", | ||
| typical_model_tier="opus", | ||
| typical_model_tier="large", | ||
| cost_tier=CostTier.PREMIUM, | ||
| ), | ||
| SeniorityInfo( | ||
| level=SeniorityLevel.VP, | ||
| authority_scope="Department-wide authority", | ||
| typical_model_tier="opus", | ||
| typical_model_tier="large", | ||
| cost_tier=CostTier.PREMIUM, | ||
| ), | ||
| SeniorityInfo( | ||
| level=SeniorityLevel.C_SUITE, | ||
| authority_scope="Company-wide authority and final approvals", | ||
| typical_model_tier="opus", | ||
| typical_model_tier="large", | ||
| cost_tier=CostTier.PREMIUM, | ||
| ), | ||
| ) | ||
|
|
@@ -440,6 +440,11 @@ def get_seniority_info(level: SeniorityLevel) -> SeniorityInfo: | |
| """ | ||
| info = _SENIORITY_INFO_BY_LEVEL.get(level) | ||
| if info is None: | ||
| logger.warning( | ||
| ROLE_LOOKUP_MISS, | ||
| level=level.value, | ||
| reason="no seniority info in catalog", | ||
| ) | ||
| msg = f"No seniority info for level {level!r}; catalog may be incomplete" | ||
| raise LookupError(msg) | ||
| return info | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| """Model routing engine — strategy-based LLM model selection. | ||
|
|
||
| Exports the router, resolver, domain models, errors, strategies, | ||
| and the ``RoutingStrategy`` protocol. | ||
| """ | ||
|
|
||
| from .errors import ( | ||
| ModelResolutionError, | ||
| NoAvailableModelError, | ||
| RoutingError, | ||
| UnknownStrategyError, | ||
| ) | ||
| from .models import ResolvedModel, RoutingDecision, RoutingRequest | ||
| from .resolver import ModelResolver | ||
| from .router import ModelRouter | ||
| from .strategies import ( | ||
| STRATEGY_MAP, | ||
| STRATEGY_NAME_CHEAPEST, | ||
| STRATEGY_NAME_COST_AWARE, | ||
| STRATEGY_NAME_MANUAL, | ||
| STRATEGY_NAME_ROLE_BASED, | ||
| STRATEGY_NAME_SMART, | ||
| CostAwareStrategy, | ||
| ManualStrategy, | ||
| RoleBasedStrategy, | ||
| RoutingStrategy, | ||
| SmartStrategy, | ||
| ) | ||
|
|
||
| __all__ = [ | ||
| "STRATEGY_MAP", | ||
| "STRATEGY_NAME_CHEAPEST", | ||
| "STRATEGY_NAME_COST_AWARE", | ||
| "STRATEGY_NAME_MANUAL", | ||
| "STRATEGY_NAME_ROLE_BASED", | ||
| "STRATEGY_NAME_SMART", | ||
| "CostAwareStrategy", | ||
| "ManualStrategy", | ||
| "ModelResolutionError", | ||
| "ModelResolver", | ||
| "ModelRouter", | ||
| "NoAvailableModelError", | ||
| "ResolvedModel", | ||
| "RoleBasedStrategy", | ||
| "RoutingDecision", | ||
| "RoutingError", | ||
| "RoutingRequest", | ||
| "RoutingStrategy", | ||
| "SmartStrategy", | ||
| "UnknownStrategyError", | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| """Routing error hierarchy. | ||
|
|
||
| All routing errors extend ``ProviderError`` so the entire provider | ||
| layer shares a single exception tree. | ||
| """ | ||
|
|
||
| from ai_company.providers.errors import ProviderError | ||
|
|
||
|
|
||
| class RoutingError(ProviderError): | ||
| """Base exception for all model-routing errors.""" | ||
|
|
||
| is_retryable = False | ||
|
|
||
|
|
||
| class ModelResolutionError(RoutingError): | ||
| """Model alias or ID could not be found in any provider.""" | ||
|
|
||
| is_retryable = False | ||
|
|
||
|
|
||
| class NoAvailableModelError(RoutingError): | ||
| """All candidate models exhausted (primary + fallbacks).""" | ||
|
|
||
| is_retryable = False | ||
|
|
||
|
|
||
| class UnknownStrategyError(RoutingError): | ||
| """Configured strategy name is not recognized.""" | ||
|
|
||
| is_retryable = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider restarting list numbering for the soft rules section.
The static analysis tool flagged that items 7-10 should restart from 1 after the new "Logging coverage suggestions" header, per MD029. However, if the cross-section numbering (1-6 for hard rules, 7-10 for soft rules) is intentional for easier reference in triage discussions, you may suppress this warning. Otherwise, consider restarting from 1.
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 111-111: Ordered list item prefix
Expected: 1; Actual: 7; Style: 1/2/3
(MD029, ol-prefix)
[warning] 112-112: Ordered list item prefix
Expected: 2; Actual: 8; Style: 1/2/3
(MD029, ol-prefix)
[warning] 113-113: Ordered list item prefix
Expected: 3; Actual: 9; Style: 1/2/3
(MD029, ol-prefix)
[warning] 114-114: Ordered list item prefix
Expected: 4; Actual: 10; Style: 1/2/3
(MD029, ol-prefix)
🤖 Prompt for AI Agents