"""Public wire records shared by HTTP, SSE and generated frontend types. Optional metadata stays absent when unavailable. Additional provenance/tool fields are retained for compatibility; required response and citation fields are validated. These contracts describe shape, not legal support or authenticity. """ from typing import Any, Literal, NotRequired, Required from pydantic import ConfigDict, TypeAdapter, ValidationError from typing_extensions import TypedDict CONTRACT_VERSION = "2.0" class PublicRecord(TypedDict, total=False): __pydantic_config__ = ConfigDict(extra="allow", strict=True) class FeedbackContext(PublicRecord): question: Required[str] answer: Required[str] source_ids: Required[list[str]] class FeedbackReport(PublicRecord): category: Required[Literal["answer", "sources", "coverage", "interface", "signin", "other"]] details: Required[str] consent: Required[bool] share_context: Required[bool] context: Required[FeedbackContext | None] class FeedbackReceipt(PublicRecord): id: Required[str] created_at: Required[str] status: Required[Literal["received", "withdrawn"]] already_received: Required[bool] retention_days: Required[int] class SubmittedFeedback(FeedbackReceipt): report: Required[FeedbackReport] class FeedbackList(PublicRecord): reports: Required[list[SubmittedFeedback]] class Evaluation(PublicRecord, total=False): passed: bool notes: list[str] class KeyQuote(PublicRecord, total=False): quote: str text: str offset: int class SummaryProvenance(PublicRecord, total=False): summarized_from: str parent_id: str class Summary(PublicRecord, total=False): variant: str case_name: str | None facts: str | None facts_llm: str issues: str | None holding: str | None sections: dict[str, str] key_quotes: list[KeyQuote] llm_status: str llm_windows: int provenance: SummaryProvenance class Outcome(PublicRecord, total=False): action: str question: str document: str note: str review_notice: str class Source(PublicRecord, total=False): title: str source_id: str court: str year: int | str text: str score: float citation: str decision_date: str document_type: str edition_as_of: str article_number: str provision_status: str source_section: str chunk_index: int parent_id: str case_id: str case_number: str case_number_status: str case_number_original: str proceeding_id: str | None proceeding_basis: Literal["source_reported_docket", "pdf_checked_docket"] collection: str source_url: str source_origin: Literal["web"] provider: str fetched_at: str extraction_kind: Literal["provider_excerpts", "provider_full_content"] original_pdf_url: str page_start: int page_end: int paragraph_start: int paragraph_end: int paragraph_locator_kind: str section_heading: str passage_role: str opinion_role: str metadata_date_status: str pdf_header_date: str source_pdf_path: str context_kind: str text_start: int chunk_offset: int document_id: str pdf_sha256: str retrieval_signals: list[Literal["semantic", "bm25", "exact"]] retrieval_ranks: dict[Literal["semantic", "bm25", "exact"], int] candidate_reservations: list[Literal["semantic", "bm25", "exact"]] class Judgment(Source, total=False): parent_id: Required[str] text: Required[str] characters: Required[int] judge: str class ReviewPrompt(PublicRecord, total=False): note: str task: str approval_id: str expires_at: str class ApprovalReceipt(PublicRecord): approval_id: Required[str] approved: Required[bool] status: Required[Literal["accepted", "completed", "uncertain"]] created_at: Required[str] settled_at: Required[str | None] expires_at: Required[str] retention_days: Required[int] class DecisionDocument(Source, total=False): document_id: Required[str] parent_id: Required[str] title: Required[str] decision_date: Required[str] class DecisionScope(TypedDict): __pydantic_config__ = ConfigDict(extra="forbid", strict=True) start: str | None end: str | None court: str | None class DecisionPage(PublicRecord, total=False): kind: Literal["decision_list"] documents: Required[list[DecisionDocument]] total: Required[int] limit: Required[int] offset: Required[int] next_offset: Required[int | None] scope: Required[DecisionScope] date_basis: Required[Literal["source_reported_decision_date"]] date_status_counts: Required[dict[str, int]] conflicting_dates_excluded: Required[int] unknown_dates_excluded: Required[int] complete_court_inventory: Required[Literal[False]] class Citation(PublicRecord, total=False): id: Required[int] quote: Required[str] chunk_offset: Required[int] document_offset: int class AnswerParagraph(PublicRecord, total=False): heading: str text: Required[str] citations: Required[list[Citation]] class EvidencePassage(Source, total=False): id: Required[int] source_id: Required[str] parent_id: Required[str] title: Required[str] citation: Required[str] text: Required[str] chunk_offset: Required[int] locator_scope: Literal["source_chunk"] class EvidenceContext(PublicRecord, total=False): status: Required[str] documents_requested: int documents_read: int candidate_passages: int included_passages: int focused_passages: int requested_facets: list[str] selected_facets: list[str] bounded_scan_truncated: list[str] note: str class Claim(PublicRecord, total=False): claim_id: Required[int] paragraph_index: Required[int] text: Required[str] evidence_ids: Required[list[int]] consequential: Required[bool] status: Required[ Literal["references_checked", "rejected", "model_supported", "unsupported", "uncertain"] ] reason: Required[str] review_evidence_ids: list[int] paragraph_text: str standalone: bool class ClaimCheck(PublicRecord, total=False): status: Required[ Literal["not_run", "references_checked", "model_reviewed", "review_unavailable"] ] review_calls: Required[int] omitted_paragraphs: int partially_retained_paragraphs: int verification_scope: Required[str] claims: Required[list[Claim]] failure_reason: str | None repair: dict[str, Any] class TreatmentFinding(PublicRecord, total=False): statement: Required[Literal["overruled", "affirmed", "distinguished", "followed"]] identity_basis: Required[str] quote: Required[str] source: Required[Source] evidence_id: int class TreatmentCheck(PublicRecord, total=False): target_title: Required[str] target_citation: str status: Required[Literal["explicit_statement_found", "unknown"]] reason: Required[str] findings: Required[list[TreatmentFinding]] class TreatmentCoverage(PublicRecord, total=False): year_start: int | None year_end: int | None class Treatment(PublicRecord, total=False): status: Required[str] current_status: Required[Literal["unknown"]] coverage: Required[TreatmentCoverage] note: Required[str] checks: Required[list[TreatmentCheck]] class ResearchAnswer(PublicRecord, total=False): message: str kind: Literal["decision_list"] documents: list[DecisionDocument] mode: Required[Literal["synthesis", "excerpts", "insufficient_evidence"]] llm_status: Required[str] paragraphs: Required[list[AnswerParagraph]] evidence: Required[list[EvidencePassage]] gaps: Required[list[str]] evidence_context: EvidenceContext claim_check: ClaimCheck treatment: Treatment citation_validation: dict[str, Any] class WebResearch(PublicRecord, total=False): provider: Required[Literal["parallel_mcp"]] status: Required[str] searched: Required[bool] documents_fetched: Required[int] requests: Required[int] queries: list[str] note: Required[str] class ToolResult(PublicRecord, total=False): tool: str summary: Summary outcome: Outcome answer: ResearchAnswer discovery: "DecisionPage | CaseResolution" web_research: WebResearch sources: list[Source] class ChatResult(PublicRecord, total=False): # Optional to preserve readable previously saved transcripts; new server # responses always include this version. contract_version: Literal["2.0"] interrupted: Required[bool] thread_id: Required[str] routed_to: str | None evaluation: Evaluation | None result: ToolResult sources: list[Source] | None review: ReviewPrompt class RecoverySettings(PublicRecord): enabled: Required[bool] generation: Required[str | None] threads: Required[int] bytes: Required[int] retention_hours: Required[int] max_threads: Required[int] max_bytes: Required[int] max_thread_bytes: Required[int] class RecoveryThread(PublicRecord): thread_id: Required[str] updated_at: Required[str] expires_at: Required[str] class RecoveryThreads(PublicRecord): threads: Required[list[RecoveryThread]] class RecoveryExport(PublicRecord): version: Required[int] encoding: Required[str] retention_hours: Required[int] checkpoints: Required[list[dict[str, Any]]] class RecoveryTurn(PublicRecord): role: Required[Literal["user", "assistant"]] content: Required[str] class RecoveryConversation(PublicRecord): thread_id: Required[str] request: Required[str] status: Required[Literal["completed", "review_required", "review_expired", "decision_consumed", "interrupted"]] history: Required[list[RecoveryTurn]] result: Required[ChatResult | None] class HealthReport(TypedDict): status: str llm: str web_fallback: str backend: str index: str lexical_index: str class ReadinessComponent(TypedDict, total=False): name: Required[str] status: Required[Literal["ready", "failed", "disabled", "configured", "missing_credentials"]] code: str probe_ms: float class ReadinessResources(TypedDict, total=False): process_peak_rss_bytes: int runtime_filesystem_free_bytes: int container_memory_limit_bytes: int container_memory_used_bytes: int class ReadinessReport(TypedDict): status: Literal["ready", "retrieval_only", "warming", "degraded", "unavailable"] detail: str checked_at: str | None components: list[ReadinessComponent] generation: Literal["configured", "disabled", "missing_credentials", "not_probed"] verification_scope: str resources: NotRequired[ReadinessResources] class HistoryTurn(PublicRecord, total=False): role: Required[Literal["user", "assistant"]] content: Required[str] class HistoryResponse(PublicRecord, total=False): thread_id: Required[str] history: Required[list[HistoryTurn]] status: str | None class SupervisorResponse(PublicRecord, total=False): sources: list[Source] summary: Summary evaluation: Evaluation class CancelResponse(TypedDict): stopped: bool class UsageReport(PublicRecord, total=False): calls: Required[int] failed_calls: Required[int] prompt_tokens: Required[int] completion_tokens: Required[int] total_tokens: Required[int] cost_usd_estimate: Required[float] by_model: dict[str, Any] class LimitWindow(PublicRecord, total=False): limit: Required[int] remaining: Required[int] used: Required[int] window_seconds: Required[int] next_expiry_at: str | None retry_after: int class ProviderMinuteLimits(TypedDict): __pydantic_config__ = ConfigDict(extra="forbid", strict=True) model_provider_calls: LimitWindow model_provider_tokens: LimitWindow class ProviderWindow(TypedDict): provider: str model: str limits: ProviderMinuteLimits class ServiceLimitsReport(PublicRecord, total=False): persistence: Required[Literal["disabled", "memory", "postgres"]] counted_at: str limits: Required[dict[str, LimitWindow]] provider_windows: list[ProviderWindow] class CoverageSource(PublicRecord, total=False): provider: Required[str] url: Required[str] license: str attribution: str class CoverageReport(PublicRecord, total=False): snapshot_id: Required[str] documents: Required[int] built_at: Required[str] decision_year_counts: Required[dict[str, int]] court_counts: Required[dict[str, int]] date_status_counts: Required[dict[str, int]] document_kind_counts: Required[dict[str, int]] limitations: Required[list[str]] sources: Required[list[CoverageSource]] class CaseResolution(PublicRecord, total=False): kind: Literal["case_resolution"] status: Required[Literal["resolved", "ambiguous", "no_match"]] match_kind: Required[Literal["identity", "party_fragment", "none"]] documents: Required[list[Source]] class HistorySettings(TypedDict): enabled: bool threads: int bytes: int max_threads: int max_bytes: int max_thread_bytes: int retention_days: int class IdentityResponse(TypedDict): id: str persistence: Literal["postgres"] class SavedThread(PublicRecord, total=False): id: Required[str] title: Required[str] createdAt: Required[int] updatedAt: Required[int] messages: Required[list[dict[str, Any]]] revision: Required[int] class SavedThreads(TypedDict): threads: list[SavedThread] class HistoryExport(SavedThreads): version: Literal[1] class StreamNode(TypedDict): event: Literal["node"] name: str class StreamDone(ChatResult, total=False): event: Required[Literal["done"]] class StreamError(TypedDict): event: Literal["error"] code: str detail: str class ErrorResponse(PublicRecord, total=False): detail: Required[str | list[dict[str, Any]]] code: str category: str StreamEvent = StreamNode | StreamDone | StreamError chat_adapter = TypeAdapter(ChatResult) stream_adapter = TypeAdapter(StreamEvent) limits_adapter = TypeAdapter(ServiceLimitsReport) class ContractError(RuntimeError): """Sanitized failure; never include a private prompt or source payload.""" def _validate(adapter: TypeAdapter, payload: Any): try: return adapter.validate_python(payload) except ValidationError: raise ContractError("The research response was incomplete. Please try again.") from None def public_chat(payload: dict[str, Any]) -> ChatResult: return _validate(chat_adapter, {**payload, "contract_version": CONTRACT_VERSION}) def public_limits(payload: dict[str, Any]) -> ServiceLimitsReport: return _validate(limits_adapter, payload) def stream_frame(payload: dict[str, Any]) -> str: checked = _validate(stream_adapter, payload) return f"data: {stream_adapter.dump_json(checked).decode()}\n\n"