Repository navigation
Expand file tree
/
Copy pathprofile.py
More file actions
56 lines (43 loc) · 1.72 KB
/
Copy pathprofile.py
File metadata and controls
56 lines (43 loc) · 1.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# Copyright © 2026 MIH AI B.V.
# Licensed under the Apache License, Version 2.0
# See LICENSE file in the project root
"""Backend profile model — validated configuration loaded from YAML."""
from __future__ import annotations
from pathlib import Path
from typing import Any, Literal
import yaml
from pydantic import BaseModel, Field, field_validator
from compass.eval.pricing import ModelPricing
class BackendProfile(BaseModel):
"""Validated backend configuration loaded from YAML."""
model: str
provider: Literal["anthropic", "openai", "bedrock", "mock_echo"] = "anthropic"
pricing: ModelPricing | None = None
api_key_env: str | None = None
api_base: str | None = None
requests_per_minute: int
tokens_per_minute: int
max_tokens: int | None = None
temperature: float | None = None
reasoning_level: Literal["low", "medium", "high"] | None = None
extra_params: dict[str, Any] = Field(default_factory=dict)
provider_params: dict[str, Any] = Field(default_factory=dict)
@field_validator("model")
@classmethod
def model_must_be_non_empty(cls, v: str) -> str:
if not v.strip():
raise ValueError("model must be non-empty")
return v.strip()
@field_validator("requests_per_minute", "tokens_per_minute")
@classmethod
def rate_limits_must_be_positive(cls, v: int) -> int:
if v < 1:
raise ValueError("must be >= 1")
return v
@classmethod
def from_yaml(cls, path: str | Path) -> BackendProfile:
with open(path) as f:
data = yaml.safe_load(f)
if not isinstance(data, dict):
raise ValueError(f"Expected a YAML mapping in {path}, got {type(data).__name__}")
return cls(**data)