Files
Aether/_deprecated_py_src/services/billing/schema.py

113 lines
3.4 KiB
Python
Raw Normal View History

"""
Billing schema (stable contracts)
These dataclasses are meant to be stored in `Usage.request_metadata` / `Task.request_metadata`
for auditability. They are internal-only and MUST NOT be exposed to end users without sanitizing.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Literal
BILLING_SNAPSHOT_SCHEMA_VERSION = "2.0"
BillingSnapshotStatus = Literal["complete", "incomplete", "no_rule", "legacy"]
@dataclass(frozen=True)
class BillingSnapshot:
"""
Stable billing snapshot for audit.
v2.0 semantics:
- resolved_dimensions: final dimension values used (tokens, request_count, etc.)
- resolved_variables: final variables used (prices, tier-resolved values, etc.)
- cost_breakdown: itemized costs (quantized)
- total_cost: quantized total cost (equals sum(cost_breakdown) when breakdown present)
Backward compatibility:
- dimensions_used aliases resolved_dimensions
- cost aliases total_cost
"""
schema_version: str = BILLING_SNAPSHOT_SCHEMA_VERSION
# Rule info (optional for legacy/no_rule)
rule_id: str | None = None
rule_name: str | None = None
scope: str | None = None
# Rule expression (internal, do not expose to clients)
expression: str | None = None
# v2: resolved inputs
resolved_dimensions: dict[str, Any] = field(default_factory=dict)
resolved_variables: dict[str, Any] = field(default_factory=dict)
# v2: breakdown and totals
cost_breakdown: dict[str, float] = field(default_factory=dict)
total_cost: float = 0.0
# Tier info (optional)
tier_index: int | None = None
tier_info: dict[str, Any] | None = None
# Missing dims
missing_required: list[str] = field(default_factory=list)
# Result status
status: BillingSnapshotStatus = "no_rule"
# Audit
calculated_at: str = "" # ISO 8601
engine_version: str = "2.0"
# ---------------------------------------------------------------------
# Backward-compatible aliases (v1 fields)
# ---------------------------------------------------------------------
@property
def dimensions_used(self) -> dict[str, Any]:
return self.resolved_dimensions
@property
def cost(self) -> float:
return self.total_cost
def to_dict(self) -> dict[str, Any]:
"""
Serialize snapshot.
Includes both v2 keys and v1-compatible keys for safer rollouts.
"""
return {
"schema_version": self.schema_version,
"rule_id": self.rule_id,
"rule_name": self.rule_name,
"scope": self.scope,
"expression": self.expression,
# v2
"resolved_dimensions": self.resolved_dimensions,
"resolved_variables": self.resolved_variables,
"cost_breakdown": self.cost_breakdown,
"total_cost": self.total_cost,
"tier_index": self.tier_index,
"tier_info": self.tier_info,
"missing_required": self.missing_required,
"status": self.status,
"calculated_at": self.calculated_at,
"engine_version": self.engine_version,
# v1 compat
"dimensions_used": self.resolved_dimensions,
"cost": self.total_cost,
}
@dataclass(frozen=True)
class CostResult:
"""Billing calculation output."""
cost: float
status: BillingSnapshotStatus
snapshot: BillingSnapshot