| 111 | |
| 112 | @dataclass(frozen=True, slots=True) |
| 113 | class RoutingFeatures: |
| 114 | step_type: str = "general" |
| 115 | tool_names: tuple[str, ...] = () |
| 116 | has_tool_results: bool = False |
| 117 | streaming: bool = False |
| 118 | needs_tool_calling: bool = False |
| 119 | needs_vision: bool = False |
| 120 | needs_structured_output: bool = False |
| 121 | response_format: str | None = None |
| 122 | step_risk: str = "normal" |
| 123 | is_agentic: bool = False |
| 124 | is_coding: bool = False |
| 125 | prefers_reasoning: bool = False |
| 126 | requested_max_output_tokens: int | None = None |
| 127 | tier_floor: Tier | None = None |
| 128 | tier_cap: Tier | None = None |
| 129 | tier_cap_reason: str = "" |
| 130 | session_present: bool = False |
| 131 | agent_step_count: int = 0 |
| 132 | agent_pressure: float = 0.0 |
| 133 | capability_lane: CapabilityLane | None = None |
| 134 | previous_served_quality: ServedQuality | None = None |
| 135 | continuity_quality_floor: ServedQuality | None = None |
| 136 | verification_failed: bool = False |
| 137 | failure_kind: str = "" |
| 138 | |
| 139 | @property |
| 140 | def tool_count(self) -> int: |
| 141 | return len(self.tool_names) |
| 142 | |
| 143 | def request_requirements(self) -> RequestRequirements: |
| 144 | return RequestRequirements( |
| 145 | needs_tool_calling=self.needs_tool_calling, |
| 146 | needs_vision=self.needs_vision, |
| 147 | prefers_reasoning=self.prefers_reasoning, |
| 148 | ) |
| 149 | |
| 150 | def workload_hints(self) -> WorkloadHints: |
| 151 | return WorkloadHints( |
| 152 | is_agentic=self.is_agentic, |
| 153 | is_coding=self.is_coding, |
| 154 | needs_structured_output=self.needs_structured_output, |
| 155 | ) |
| 156 | |
| 157 | def tags(self) -> tuple[str, ...]: |
| 158 | labels: list[str] = [] |
| 159 | if self.step_type != "general": |
| 160 | labels.append(f"step:{self.step_type}") |
| 161 | if self.tool_names: |
| 162 | labels.append(f"tools:{len(self.tool_names)}") |
| 163 | if self.has_tool_results: |
| 164 | labels.append("tool-results") |
| 165 | if self.step_risk != "normal": |
| 166 | labels.append(f"risk:{self.step_risk}") |
| 167 | if self.needs_vision: |
| 168 | labels.append("vision") |
| 169 | if self.needs_structured_output: |
| 170 | labels.append("structured-output") |
no outgoing calls