SebAustin's picture
deploy: routing-agent demo dashboard
5299d9a verified
Raw
History Blame Contribute Delete
2.45 kB
"""Pydantic data types shared across the routing agent.
These types are the stable boundary between the (unknown) scoring harness and
the rest of the system. `Task` tolerantly accepts several historically-common
field name variants so that `adapter.py` can stay thin; every other module
only ever sees the normalized shape.
"""
from __future__ import annotations
from typing import Any
from pydantic import BaseModel, ConfigDict, Field, model_validator
# Field names harnesses have been observed to use for the task's primary text.
_PROMPT_ALIASES = ("prompt", "input", "question", "text")
class Task(BaseModel):
"""A single unit of work to route and solve.
`prompt` is populated from whichever of `prompt`/`input`/`question`/`text`
is present in the source payload (first match wins). `type` is an optional
harness-supplied hint; when absent the classifier infers it.
"""
model_config = ConfigDict(extra="allow")
id: str
prompt: str
type: str | None = None
metadata: dict[str, Any] = Field(default_factory=dict)
@model_validator(mode="before")
@classmethod
def _populate_prompt_from_aliases(cls, data: Any) -> Any:
if not isinstance(data, dict):
return data
if data.get("prompt"):
return data
normalized = dict(data)
for alias in _PROMPT_ALIASES:
value = data.get(alias)
if isinstance(value, str) and value.strip():
normalized["prompt"] = value
break
return normalized
class RouteDecision(BaseModel):
"""Records which tier/model resolved a task, for logging and eval analysis."""
tier: int
model: str | None = None
task_type: str
confident: bool = True
retried: bool = False
escalated: bool = False
class Result(BaseModel):
"""The output for a single task plus routing metadata (never serialized to
the harness-facing results.json — adapter strips metadata before writing).
"""
id: str
output: str
route: RouteDecision | None = None
class CallRecord(BaseModel):
"""A single Fireworks API call, as recorded by the TokenLedger."""
model: str
prompt_tokens: int
completion_tokens: int
cached_tokens: int = 0
latency_ms: float = 0.0
route: str = ""
retry: bool = False
@property
def total_tokens(self) -> int:
return self.prompt_tokens + self.completion_tokens