qfa.domain.models#
Domain models for the feedback analysis backend.
All models are immutable (frozen) Pydantic models per ADR-001.
Classes
|
The result of summarizing multiple feedback records as a single aggregate. |
|
A request to analyze one or more feedback records. |
|
The result of a feedback analysis. |
|
A single leaf code assigned to a feedback record. |
|
Per-call context propagated via ContextVar from orchestrator to tracker. |
|
Outcome of a single LLM call attempt. |
|
Coding output for one feedback record. |
|
A request to assign hierarchical codes to feedback records. |
|
The result of assigning codes to multiple feedback records. |
|
Statistical distribution summary. |
|
A single feedback record submitted for analysis. |
|
Summary output for a single feedback record. |
|
A single recorded LLM call attempt for usage and cost tracking. |
|
Raw response from an LLM provider. |
|
Orchestrator operations that produce LLM calls. |
|
A request to summarize one or more feedback records individually. |
|
The result of summarizing multiple feedback records individually. |
|
An API key associated with a tenant. |
|
Token distribution summary with a total count. |
|
Aggregated usage statistics for a tenant or grand total. |
- class qfa.domain.models.FeedbackRecordModel(*, id: str, text: ~typing.Annotated[str, ~annotated_types.MinLen(min_length=1), ~annotated_types.MaxLen(max_length=100000)], metadata: dict[str, str | int | float | bool] = <factory>)[source]#
Bases:
BaseModelA single feedback record submitted for analysis.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class qfa.domain.models.AnalysisRequestModel(*, feedback_records: Annotated[tuple[FeedbackRecordModel, ...], MinLen(min_length=1)], prompt: Annotated[str, MinLen(min_length=1), MaxLen(max_length=4000)], tenant_id: str)[source]#
Bases:
BaseModelA request to analyze one or more feedback records.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- feedback_records: tuple[FeedbackRecordModel, ...]#
- class qfa.domain.models.AnalysisResultModel(*, result: str)[source]#
Bases:
BaseModelThe result of a feedback analysis.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class qfa.domain.models.SummaryRequestModel(*, feedback_records: Annotated[tuple[FeedbackRecordModel, ...], MinLen(min_length=1)], output_language: str | None = None, prompt: Annotated[str | None, MaxLen(max_length=4000)] = None, tenant_id: str)[source]#
Bases:
BaseModelA request to summarize one or more feedback records individually.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- feedback_records: tuple[FeedbackRecordModel, ...]#
- class qfa.domain.models.FeedbackRecordSummaryModel(*, id: str, title: str, summary: str, quality_score: float)[source]#
Bases:
BaseModelSummary output for a single feedback record.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class qfa.domain.models.SummaryResultModel(*, feedback_record_summaries: tuple[FeedbackRecordSummaryModel, ...])[source]#
Bases:
BaseModelThe result of summarizing multiple feedback records individually.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- feedback_record_summaries: tuple[FeedbackRecordSummaryModel, ...]#
- class qfa.domain.models.AggregateSummaryResultModel(*, ids: tuple[str, ...], title: str, summary: str, quality_score: float)[source]#
Bases:
BaseModelThe result of summarizing multiple feedback records as a single aggregate.
# TODO come up with nice solution for non-mutable quality-score, so this can be a frozen class.
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 = {}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class qfa.domain.models.CodingAssignmentRequestModel(*, feedback_records: Annotated[tuple[FeedbackRecordModel, ...], MinLen(min_length=1)], coding_framework: dict[str, Any], max_codes: Annotated[int, Ge(ge=1), Le(le=50)], confidence_threshold: Annotated[float | None, Ge(ge=0.0), Le(le=1.0)] = None, tenant_id: str)[source]#
Bases:
BaseModelA request to assign hierarchical codes to feedback records.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- feedback_records: tuple[FeedbackRecordModel, ...]#
- class qfa.domain.models.AssignedCodeModel(*, code_id: str, code_label: str, confidence_type: float, confidence_category: float, confidence_code: float, confidence_aggregate: float, explanation: str)[source]#
Bases:
BaseModelA single leaf code assigned to a feedback record.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class qfa.domain.models.CodedFeedbackRecordModel(*, feedback_record_id: str, assigned_codes: tuple[AssignedCodeModel, ...])[source]#
Bases:
BaseModelCoding output for one feedback record.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- assigned_codes: tuple[AssignedCodeModel, ...]#
- class qfa.domain.models.CodingAssignmentResultModel(*, coded_feedback_records: tuple[CodedFeedbackRecordModel, ...])[source]#
Bases:
BaseModelThe result of assigning codes to multiple feedback records.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- coded_feedback_records: tuple[CodedFeedbackRecordModel, ...]#
- class qfa.domain.models.LLMResponse(*, structured: T_Response, model: str, prompt_tokens: int, completion_tokens: int, cost: float)[source]#
Bases:
BaseModel,Generic[T_Response]Raw response from an LLM provider.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- structured: T_Response#
- class qfa.domain.models.TenantApiKey(*, key_id: str, name: str, key: SecretStr, tenant_id: str, is_superuser: bool = False)[source]#
Bases:
BaseModelAn API key associated with a tenant.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- key: SecretStr#
- class qfa.domain.models.Operation(*values)[source]#
Bases:
StrEnumOrchestrator operations that produce LLM calls.
Stored as plain strings in the database; new members can be added without a DB migration.
UNKNOWNis a sentinel for backfilled rows from before per-operation tracking was introduced and must never be removed (removal would orphan historical rows).- ANALYZE = 'analyze'#
- SUMMARIZE = 'summarize'#
- SUMMARIZE_AGGREGATE = 'summarize_aggregate'#
- ASSIGN_CODES = 'assign_codes'#
- UNKNOWN = 'unknown'#
- class qfa.domain.models.CallStatus(*values)[source]#
Bases:
StrEnumOutcome of a single LLM call attempt.
- OK = 'ok'#
- ERROR = 'error'#
- class qfa.domain.models.CallContext(*, tenant_id: str, operation: Operation)[source]#
Bases:
BaseModelPer-call context propagated via ContextVar from orchestrator to tracker.
- Variables:
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class qfa.domain.models.LLMCallRecord(*, tenant_id: str, operation: Operation, timestamp: datetime, call_duration_ms: int, model: str, input_tokens: int = 0, output_tokens: int = 0, cost_usd: Decimal = Decimal('0'), status: CallStatus, error_class: str | None = None)[source]#
Bases:
BaseModelA single recorded LLM call attempt for usage and cost tracking.
Recorded once per LLM-call attempt — success or failure.
cost_usdand token counts are populated only for successful attempts; failures record zeros pluserror_class.- Variables:
tenant_id (str) – Tenant that made the call.
operation (Operation) – Public orchestrator operation that issued the call.
timestamp (datetime) – UTC wall-clock when the call started.
call_duration_ms (int) – Wall-clock duration of the call in milliseconds.
model (str) – The LLM model used.
input_tokens (int) – Number of input (prompt) tokens; 0 on failure.
output_tokens (int) – Number of output (completion) tokens; 0 on failure.
cost_usd (Decimal) – Estimated cost in USD; 0 on failure.
status (CallStatus) – Outcome of the attempt.
error_class (str | None) –
type(exc).__name__whenstatus == CallStatus.ERROR;Noneotherwise. Enforced bymodel_validator.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- status: CallStatus#
- class qfa.domain.models.DistributionStats(*, avg: float, min: float, max: float, p5: float, p95: float)[source]#
Bases:
BaseModelStatistical distribution summary.
- Variables:
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class qfa.domain.models.TokenStats(*, avg: float, min: float, max: float, p5: float, p95: float, total: int)[source]#
Bases:
DistributionStatsToken distribution summary with a total count.
- Variables:
total (int) – Total number of tokens.
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class qfa.domain.models.UsageStats(*, tenant_id: str | None = None, total_calls: int, failed_calls: int = 0, total_cost_usd: Decimal = Decimal('0'), call_duration: DistributionStats, input_tokens: TokenStats, output_tokens: TokenStats)[source]#
Bases:
BaseModelAggregated usage statistics for a tenant or grand total.
The token and duration distributions and
total_cost_usdare scoped tostatus='ok'rows.total_callsandfailed_callscount all attempts including failures (policy “alpha”).- Variables:
tenant_id (str | None) – Tenant identifier, or None for grand total.
total_calls (int) – Total attempts (successful + failed).
failed_calls (int) – Attempts with
status='error'.total_cost_usd (Decimal) – Sum of cost over successful attempts only.
call_duration (DistributionStats) – Call duration distribution in milliseconds (successful attempts only).
input_tokens (TokenStats) – Input token distribution (successful attempts only).
output_tokens (TokenStats) – Output token distribution (successful attempts only).
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}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- call_duration: DistributionStats#
- input_tokens: TokenStats#
- output_tokens: TokenStats#