qfa.api.schemas_usage#

HTTP-layer wrappers over the domain usage stats.

ADR-007 keeps API and domain models separate where the API needs to hide internal fields or reshape the wire format. The usage endpoints don’t need either — the domain TenantUsageStats is the aggregate the consumer wants. The only HTTP-specific addition is the echoed from/to query window, so this module holds two thin wrappers that add those fields and nothing else.

Classes

AllUsageByOperationResponse(*[, from_, to])

Per-operation + grand total usage with optional echoed time window.

AllUsageStatsResponse(*[, from_, to])

Per-tenant + grand total usage with optional echoed time window.

UsageStatsResponse(*, total_calls[, ...])

Domain TenantUsageStats plus echoed from/to query bounds.

class qfa.api.schemas_usage.UsageStatsResponse(*, total_calls: int, failed_calls: int = 0, total_cost_usd: Decimal = Decimal('0'), call_duration: DistributionStats, input_tokens: DistributionStats, output_tokens: DistributionStats, tenant_id: str | None = None, llm_call_stats: UsageMetrics, operations: tuple[OperationStats, ...] = (), from_: datetime | None = None, to: datetime | None = None)[source]#

Bases: TenantUsageStats

Domain TenantUsageStats plus echoed from/to query bounds.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

from_: datetime | None#
to: datetime | None#
class qfa.api.schemas_usage.AllUsageStatsResponse(*, from_: datetime | None = None, to: datetime | None = None, tenants: list[TenantUsageStats], total: TenantUsageStats)[source]#

Bases: BaseModel

Per-tenant + grand total usage with optional echoed time window.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

from_: datetime | None#
to: datetime | None#
tenants: list[TenantUsageStats]#
total: TenantUsageStats#
class qfa.api.schemas_usage.AllUsageByOperationResponse(*, from_: datetime | None = None, to: datetime | None = None, operations: list[OperationUsageStats], total: OperationUsageStats)[source]#

Bases: BaseModel

Per-operation + grand total usage with optional echoed time window.

Inverse hierarchy of AllUsageStatsResponse: operations is the list of per-operation blocks (each with a nested tenants breakdown), and total is the cross-operation grand total (operation is null).

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

from_: datetime | None#
to: datetime | None#
operations: list[OperationUsageStats]#
total: OperationUsageStats#