# Generated by `cargo run -p tl-codegen` from docs/openapi.yaml.
# Do not hand-edit.

# generated by datamodel-codegen:
#   filename:  openapi.yaml

from __future__ import annotations

from enum import Enum
from typing import Any, Literal
from uuid import UUID

from pydantic import BaseModel, Field, RootModel, conint


class AgentAuthority(BaseModel):
    can_promise: list[str] | None = None
    cannot_promise: list[str] | None = None


class AgentScope(BaseModel):
    in_scope: list[str] | None = None
    out_of_scope: list[str] | None = None


class AgentTone(BaseModel):
    forbidden: list[str] | None = None
    target: str


class ApiErrorCode(Enum):
    invalid = 'invalid'
    unauthorized = 'unauthorized'
    forbidden = 'forbidden'
    not_found = 'not_found'
    gone = 'gone'
    unprocessable = 'unprocessable'
    rate_limited = 'rate_limited'
    internal = 'internal'
    unavailable = 'unavailable'


class ApiKeyBatchRevokeRequest(BaseModel):
    ids: list[str]


class AuthRequest(BaseModel):
    password: str = Field(
        ..., description="SHA-256-hex of the user's plaintext password."
    )
    username: str = Field(
        ...,
        description='Account identifier. Stored as-given, matched case-insensitively.',
    )


class AuthResponse(BaseModel):
    jwt: str | None = Field(
        None,
        description='Signed bearer token (HS256) issued by `tl-server` on successful\nsignup or login. The web dashboard stashes this in the\nNextAuth session and forwards it on every Rust API call as\n`Authorization: Bearer <jwt>`. Absent when the server runs\nwithout `TL_JWT_SECRET` configured (memory-only dev mode).',
    )
    user_id: str
    username: str


class ChangePasswordRequest(BaseModel):
    current_password: str = Field(
        ..., description="SHA-256-hex of the user's current password."
    )
    new_password: str = Field(
        ..., description='SHA-256-hex of the new password to store.'
    )
    username: str


class Channel(Enum):
    voice = 'voice'
    chat = 'chat'
    email = 'email'


class CreateApiKeyRequest(BaseModel):
    name: str


class Kind(Enum):
    added = 'added'


class Kind1(Enum):
    invited = 'invited'


class CreateWorkspaceRequest(BaseModel):
    name: str


class DashboardApiKey(BaseModel):
    created_at: str = Field(..., description='RFC 3339 timestamp.')
    created_by: str | None = None
    id: str
    last_used_at: str | None = Field(None, description='RFC 3339 timestamp.')
    name: str
    prefix: str
    status: str


class DashboardKnowledgeSourceKind(Enum):
    url = 'url'
    file = 'file'
    note = 'note'


class HumanReviewAnalyticsSummary(BaseModel):
    automated_intervention_count: int
    false_positive_rate: float
    human_intervention_count: int
    human_intervention_rate: float
    human_review_count: int
    trace_count: int


class HumanReviewGroupRow(BaseModel):
    group: str
    human_intervention_count: int
    human_review_count: int


class HumanReviewOutcome(Enum):
    accepted = 'accepted'
    corrected = 'corrected'
    rejected = 'rejected'
    false_positive = 'false_positive'
    missed_issue = 'missed_issue'
    ignored = 'ignored'


class HumanReviewOutcomeCounts(BaseModel):
    accepted_count: int
    corrected_count: int
    false_positive_count: int
    ignored_count: int
    missed_issue_count: int
    rejected_count: int


class HumanReviewPolicyRow(BaseModel):
    corrected_count: int
    escalation_count: int
    false_positive_count: int
    policy_id: str


class HumanReviewReasonRow(BaseModel):
    count: int
    reason_code: str


class HumanReviewWorkflowStepRow(BaseModel):
    corrected_count: int
    false_positive_count: int
    human_review_count: int
    rejected_count: int
    workflow_step: str


class InviteStatus(Enum):
    pending = 'pending'
    accepted = 'accepted'
    revoked = 'revoked'
    expired = 'expired'


class KnowledgeFileInput(BaseModel):
    data_base64: str
    file_name: str
    media_type: str


class KnowledgeFileMetadata(BaseModel):
    byte_size: int
    checksum_sha256: str
    file_name: str
    media_type: str


class KnowledgeSourceFileResponse(BaseModel):
    byte_size: int
    data_base64: str
    file_name: str
    media_type: str


class KnowledgeSourceKind(Enum):
    local = 'local'
    web = 'web'


class KnowledgeSourceStatus(Enum):
    draft = 'draft'
    indexing = 'indexing'
    ready = 'ready'
    failed = 'failed'


class PolicyAction(Enum):
    block = 'block'
    rewrite = 'rewrite'
    escalate = 'escalate'


class PolicyBatchSetEnabledRequest(BaseModel):
    enabled: bool
    ids: list[str]


class PolicyDraftRequest(BaseModel):
    prompt: str


class PolicyMatchType(Enum):
    literal = 'literal'
    regex = 'regex'


class PolicySetEnabledRequest(BaseModel):
    enabled: bool


class PolicyValidationIssue(BaseModel):
    message: str
    path: str


class RunEventKind(Enum):
    user_turn = 'user_turn'
    assistant_turn = 'assistant_turn'
    tool_call = 'tool_call'
    workflow_step = 'workflow_step'
    interruption = 'interruption'
    retry = 'retry'
    system_event = 'system_event'
    other = 'other'


class RunEventSummary(BaseModel):
    created_at: str = Field(..., description='RFC 3339 timestamp.')
    id: str
    input_summary: str | None = None
    kind: RunEventKind
    label: str | None = None
    metadata: Any
    occurred_at: str = Field(..., description='RFC 3339 timestamp.')
    output_summary: str | None = None
    run_id: str
    sequence: int
    workspace_id: str


class RunKind(Enum):
    chat_session = 'chat_session'
    live_call = 'live_call'
    workflow = 'workflow'
    job = 'job'
    other = 'other'


class RunStatus(Enum):
    warming = 'warming'
    running = 'running'
    completed = 'completed'
    failed = 'failed'
    canceled = 'canceled'


class RunSummary(BaseModel):
    agent_id: str
    blocked_count: int
    created_at: str = Field(..., description='RFC 3339 timestamp.')
    ended_at: str | None = Field(None, description='RFC 3339 timestamp.')
    escalated_count: int
    external_id: str | None = None
    id: str
    kind: RunKind
    metadata: Any
    p95_latency_ms: int | None = None
    rewritten_count: int
    started_at: str = Field(..., description='RFC 3339 timestamp.')
    status: RunStatus
    trace_count: int
    updated_at: str = Field(..., description='RFC 3339 timestamp.')
    workspace_id: str


class Severity(Enum):
    low = 'low'
    medium = 'medium'
    high = 'high'
    critical = 'critical'


class TraceSummary(BaseModel):
    created_at: str = Field(..., description='RFC 3339 timestamp.')
    decision: str
    domain: str
    elapsed_ms: int
    latest_review_outcome: HumanReviewOutcome | None = None
    latest_reviewed_at: str | None = None
    payload: Any
    run_event_id: str | None = None
    run_id: str | None = None
    trace_id: str


class TriggeredPolicy(BaseModel):
    id: str
    reason: str
    severity: Severity


class UpdateRunRequest(BaseModel):
    ended_at: str | None = Field(
        None,
        description='RFC 3339 timestamp. Defaults to now when completing/failing/canceling\na run without an explicit timestamp.',
    )
    metadata: Any | None = None
    status: RunStatus | None = None


class Verdict(Enum):
    allow = 'allow'
    block = 'block'
    rewrite = 'rewrite'
    escalate = 'escalate'


class WorkspaceRole(Enum):
    owner = 'owner'
    admin = 'admin'
    editor = 'editor'
    viewer = 'viewer'


class DataHandlingMode(RootModel[Any]):
    root: Any


class RedactionInfo(RootModel[Any]):
    root: Any


class TierResult(RootModel[Any]):
    root: Any


class ApiError(BaseModel):
    code: ApiErrorCode
    details: Any | None = Field(
        None,
        description='Opaque structured details (e.g. validation field path).\nDefaults to `null`; servers may add fields without breaking SDKs.',
    )
    message: str
    retriable: bool = Field(
        ...,
        description='Whether the caller may retry the same request without modification.\nSDKs honor `Retry-After` when present in addition to this flag.',
    )


class ApiKeyBatchRevokeResponse(BaseModel):
    api_keys: list[DashboardApiKey]


class ApiKeyListResponse(BaseModel):
    api_keys: list[DashboardApiKey]


class CreateApiKeyResponse(BaseModel):
    api_key: DashboardApiKey
    plaintext_key: str = Field(
        ..., description='Full bearer key. Returned only once at creation time.'
    )


class CreateHumanReviewEventRequest(BaseModel):
    metadata: Any | None = None
    note: str | None = None
    outcome: HumanReviewOutcome
    reason_codes: list[str] | None = None


class CreateInviteRequest(BaseModel):
    email: str
    role: WorkspaceRole


class CreateKnowledgeSourceRequest(BaseModel):
    file: KnowledgeFileInput | None = None
    kind: DashboardKnowledgeSourceKind
    location: str | None = None
    notes: str | None = None
    title: str


class CreateRunEventRequest(BaseModel):
    input_summary: str | None = None
    kind: RunEventKind
    label: str | None = None
    metadata: Any | None = None
    occurred_at: str | None = Field(
        None, description='RFC 3339 timestamp. Defaults to now when omitted.'
    )
    output_summary: str | None = None
    sequence: int | None = None


class CreateRunRequest(BaseModel):
    agent_id: str
    external_id: str | None = None
    kind: RunKind
    metadata: Any | None = None
    status: RunStatus | None = None


class Decision(BaseModel):
    latency_ms: conint(ge=0)
    reason: str
    redaction: RedactionInfo | None = None
    safe_output: str | None = None
    tier_results: list[TierResult] | None = Field(
        None,
        description='Per-tier breakdown produced by the parallel-cancel orchestrator.\nEmpty for callers that only ran the synchronous `Engine::check`\npath; populated when `Engine::check_async` is used.',
    )
    trace_id: str
    triggered_policies: list[TriggeredPolicy]
    verdict: Verdict


class HumanReviewAnalyticsResponse(BaseModel):
    by_agent: list[HumanReviewGroupRow]
    by_policy: list[HumanReviewPolicyRow]
    by_run_kind: list[HumanReviewGroupRow]
    by_workflow_step: list[HumanReviewWorkflowStepRow]
    outcomes: HumanReviewOutcomeCounts
    summary: HumanReviewAnalyticsSummary
    top_reasons: list[HumanReviewReasonRow]


class HumanReviewEvent(BaseModel):
    created_at: str = Field(..., description='RFC 3339 timestamp.')
    id: str
    metadata: Any
    note: str | None = None
    outcome: HumanReviewOutcome
    reason_codes: list[str] | None = None
    reviewer_id: str | None = None
    run_event_id: str | None = None
    run_id: str | None = None
    trace_id: str
    workspace_id: str


class HumanReviewEventListResponse(BaseModel):
    review_events: list[HumanReviewEvent]


class KnowledgeSource(BaseModel):
    description: str | None = None
    kb_id: str
    kind: KnowledgeSourceKind | None = None
    url: str | None = None


class KnowledgeSourceDocument(BaseModel):
    created_at: str = Field(..., description='RFC 3339 timestamp.')
    id: str
    kind: DashboardKnowledgeSourceKind
    last_indexed_at: str | None = Field(None, description='RFC 3339 timestamp.')
    location: str | None = None
    metadata: Any
    status: KnowledgeSourceStatus
    title: str
    updated_at: str = Field(..., description='RFC 3339 timestamp.')


class KnowledgeSourceListResponse(BaseModel):
    knowledge_sources: list[KnowledgeSourceDocument]


class MyWorkspace(BaseModel):
    id: str
    name: str
    organization_id: str
    role: WorkspaceRole
    slug: str


class MyWorkspacesResponse(BaseModel):
    workspaces: list[MyWorkspace]


class PolicyDocument(BaseModel):
    description: str | None = None
    enabled: bool
    id: str
    severity: Severity
    source_yaml: str


class PolicyDraft(BaseModel):
    action: PolicyAction
    description: str
    id: str
    match_type: PolicyMatchType
    match_value: str
    rewrite: str | None = None
    severity: Severity


class PolicyDraftResponse(BaseModel):
    draft: PolicyDraft


class PolicySummary(BaseModel):
    action: str | None = None
    description: str | None = None
    enabled: bool
    id: str
    owner_agent_id: str | None = None
    severity: Severity


class PolicyValidateResponse(BaseModel):
    errors: list[PolicyValidationIssue]
    policy_id: str | None = None
    valid: bool


class RunDetail(BaseModel):
    events: list[RunEventSummary]
    run: RunSummary
    traces: list[TraceSummary]


class RunEventListResponse(BaseModel):
    events: list[RunEventSummary]


class RunListResponse(BaseModel):
    runs: list[RunSummary]


class TraceListResponse(BaseModel):
    traces: list[TraceSummary]


class WorkspaceInvite(BaseModel):
    created_at: str = Field(..., description='RFC3339 timestamps.')
    email: str
    expires_at: str
    id: str
    invited_by_user_id: str | None = None
    role: WorkspaceRole
    status: InviteStatus
    workspace_id: str


class WorkspaceMember(BaseModel):
    joined_at: str = Field(..., description='RFC3339 timestamp.')
    role: WorkspaceRole
    user_id: str
    username: str


class WorkspaceSettings(BaseModel):
    config: Any
    data_handling_mode: DataHandlingMode | None = None
    default_action: str
    escalation_webhook_url: str | None = None
    retention_days: str
    telemetry_enabled: bool
    updated_at: str | None = Field(None, description='RFC 3339 timestamp.')


class AgentProfile(BaseModel):
    agent_id: str
    authority: AgentAuthority
    display_name: str
    escalation_triggers: list[str] | None = None
    knowledge_sources: list[KnowledgeSource] | None = None
    scope: AgentScope
    system_prompt: str | None = Field(
        None,
        description='Raw system prompt the customer ships to their LLM. Source of truth\nfor auto-generating guardrails: `POST /v1/agents/{id}/guardrails:generate`\nreads this and asks an LLM to derive a policy set tailored to it.\nOptional at the type level so existing profiles keep deserializing;\nthe generate endpoint enforces presence at call time.',
    )
    tone: AgentTone


class CheckRequest(BaseModel):
    agent_id: str
    channel: Channel
    context: Any | None = None
    domain: str | None = Field(
        None,
        description='Optional domain selector for the dispatcher. Defaults to\n`customer_support` server-side when absent. Reserved for future\n`voice_agent` / `coding_agent` handlers.',
    )
    input: str
    policies: list[str] | None = None
    proposed_output: str
    redaction: RedactionInfo | None = None
    run_event: CreateRunEventRequest | None = None
    run_event_id: UUID | None = None
    run_id: UUID | None = None
    trace_id: str | None = None
    workspace_id: str | None = None


class CreateInviteResponse1(BaseModel):
    kind: Literal['added']
    member: WorkspaceMember


class CreateInviteResponse2(BaseModel):
    invite: WorkspaceInvite
    kind: Literal['invited']


class CreateInviteResponse(RootModel[CreateInviteResponse1 | CreateInviteResponse2]):
    root: CreateInviteResponse1 | CreateInviteResponse2 = Field(
        ...,
        description="POST `/v1/team/invites` outcome. Discriminated by `kind`:\n- `added` — the email matched an existing user; they're now a\nworkspace member. No accept step needed.\n- `invited` — no account exists for that email yet; we recorded\na pending membership intent. When the user signs up with this\nemail (any time, anywhere), they're auto-joined on their next\npage load via the `accept_pending_invites_for_email` path.",
        discriminator='kind',
    )


class GuardrailGenerateResponse(BaseModel):
    generated: list[PolicyDocument]


class GuardrailListResponse(BaseModel):
    policies: list[PolicySummary]


class InviteListResponse(BaseModel):
    invites: list[WorkspaceInvite]


class MemberListResponse(BaseModel):
    members: list[WorkspaceMember]


class PolicyBatchSetEnabledResponse(BaseModel):
    policies: list[PolicySummary]


class PolicyListResponse(BaseModel):
    policies: list[PolicySummary]


class AgentListResponse(BaseModel):
    agents: list[AgentProfile]
