# generated by datamodel-codegen:
#   filename:  dograh-openapi-XXXXXX.json.eTS9nKh73G
#   timestamp: 2026-09-12T00:37:42+00:00

from __future__ import annotations

from enum import Enum
from typing import Annotated, Any, Literal

from pydantic import AwareDatetime, BaseModel, ConfigDict, Field, RootModel


class AmbientNoiseConfigurationDefaults(BaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    enabled: Annotated[bool | None, Field(title='Enabled')] = False
    volume: Annotated[float | None, Field(title='Volume')] = 0.3


class CalculatorToolDefinition(BaseModel):
    """
    Tool definition for Calculator tools.
    """

    schema_version: Annotated[int | None, Field(title='Schema Version')] = 1
    """
    Schema version.
    """
    type: Annotated[Literal['calculator'], Field(title='Type')]
    """
    Tool type.
    """


class CallDispositionCodes(BaseModel):
    disposition_codes: Annotated[list[str] | None, Field(title='Disposition Codes')] = (
        []
    )


class CallDispositionOption(BaseModel):
    """
    One business outcome the terminal classifier may select.
    """

    code: Annotated[
        str,
        Field(
            max_length=64,
            min_length=1,
            pattern='^[A-Za-z][A-Za-z0-9_-]*$',
            title='Code',
        ),
    ]
    """
    Stable code recorded when this outcome is selected.
    """
    description: Annotated[
        str, Field(max_length=1000, min_length=1, title='Description')
    ]
    """
    Business criteria for selecting this disposition.
    """


class FallbackDestination(RootModel[str]):
    root: Annotated[str, Field(max_length=255, title='Fallback Destination')]
    """
    Optional provider-native destination or context template used when no rule matched.
    """


class ContextDestinationRoute(BaseModel):
    """
    Map one context value to a transfer destination.
    """

    context_value: Annotated[
        str, Field(max_length=255, min_length=1, title='Context Value')
    ]
    """
    Context value that selects this destination.
    """
    destination: Annotated[
        str, Field(max_length=255, min_length=1, title='Destination')
    ]
    """
    VICIdial in-group, SIP endpoint, E.164 phone number, or context template used when this route matches.
    """


class ContextDestinationRule(BaseModel):
    """
    One context lookup with its value-to-destination routes.
    """

    context_path: Annotated[
        str, Field(max_length=255, min_length=1, title='Context Path')
    ]
    """
    Context path used for routing. An unprefixed path checks gathered context first, then initial context; use initial_context.* or gathered_context.* to select one explicitly.
    """
    routes: Annotated[
        list[ContextDestinationRoute],
        Field(max_length=100, min_length=1, title='Routes'),
    ]


class Category(Enum):
    """
    Tool category. Must match definition.type.
    """

    http_api = 'http_api'
    end_call = 'end_call'
    transfer_call = 'transfer_call'
    calculator = 'calculator'
    native = 'native'
    integration = 'integration'
    mcp = 'mcp'


class Icon(RootModel[str]):
    root: Annotated[str, Field(max_length=50, title='Icon')] = 'globe'
    """
    Lucide icon identifier.
    """


class IconColor(RootModel[str]):
    root: Annotated[str, Field(max_length=7, title='Icon Color')] = '#3B82F6'
    """
    Hex color for the tool icon.
    """


class CreateWorkflowRequest(BaseModel):
    name: Annotated[str, Field(title='Name')]
    workflow_definition: Annotated[dict[str, Any], Field(title='Workflow Definition')]


class CreatedByResponse(BaseModel):
    """
    Response schema for the user who created a tool.
    """

    id: Annotated[int, Field(title='Id')]
    provider_id: Annotated[str, Field(title='Provider Id')]


class CredentialResponse(BaseModel):
    """
    Response schema for a webhook credential (never includes sensitive data).
    """

    uuid: Annotated[str, Field(title='Uuid')]
    name: Annotated[str, Field(title='Name')]
    description: Annotated[str | None, Field(title='Description')]
    credential_type: Annotated[str, Field(title='Credential Type')]
    created_at: Annotated[AwareDatetime, Field(title='Created At')]
    updated_at: Annotated[AwareDatetime | None, Field(title='Updated At')]


class DisplayOptions(BaseModel):
    """
    Conditional visibility rules.

    `show` keys are AND-combined: this property is visible only when EVERY
    referenced field's value matches one of the listed values.

    `hide` keys are OR-combined: this property is hidden when ANY referenced
    field's value matches one of the listed values.

    Example:
        DisplayOptions(show={"extraction_enabled": [True]})
        DisplayOptions(show={"greeting_type": ["audio"]})
    """

    model_config = ConfigDict(
        extra='forbid',
    )
    show: Annotated[dict[str, list[Any]] | None, Field(title='Show')] = None
    hide: Annotated[dict[str, list[Any]] | None, Field(title='Hide')] = None


class DocumentResponseSchema(BaseModel):
    """
    Response schema for document metadata.
    """

    id: Annotated[int, Field(title='Id')]
    document_uuid: Annotated[str, Field(title='Document Uuid')]
    filename: Annotated[str, Field(title='Filename')]
    file_size_bytes: Annotated[int, Field(title='File Size Bytes')]
    file_hash: Annotated[str, Field(title='File Hash')]
    mime_type: Annotated[str, Field(title='Mime Type')]
    processing_status: Annotated[str, Field(title='Processing Status')]
    processing_error: Annotated[str | None, Field(title='Processing Error')] = None
    total_chunks: Annotated[int, Field(title='Total Chunks')]
    retrieval_mode: Annotated[str | None, Field(title='Retrieval Mode')] = 'chunked'
    custom_metadata: Annotated[dict[str, Any], Field(title='Custom Metadata')]
    docling_metadata: Annotated[dict[str, Any], Field(title='Docling Metadata')]
    source_url: Annotated[str | None, Field(title='Source Url')] = None
    created_at: Annotated[AwareDatetime, Field(title='Created At')]
    updated_at: Annotated[AwareDatetime, Field(title='Updated At')]
    organization_id: Annotated[int, Field(title='Organization Id')]
    created_by: Annotated[int, Field(title='Created By')]
    is_active: Annotated[bool, Field(title='Is Active')]


class MessageType(Enum):
    """
    Type of goodbye message.
    """

    none = 'none'
    custom = 'custom'
    audio = 'audio'


class EndCallConfig(BaseModel):
    """
    Configuration for End Call tools.
    """

    messageType: Annotated[MessageType | None, Field(title='Messagetype')] = 'none'
    """
    Type of goodbye message.
    """
    customMessage: Annotated[str | None, Field(title='Custommessage')] = None
    """
    Custom message to play before ending the call.
    """
    audioRecordingId: Annotated[str | None, Field(title='Audiorecordingid')] = None
    """
    Recording ID for audio goodbye message.
    """
    endCallReason: Annotated[bool | None, Field(title='Endcallreason')] = False
    """
    When enabled, the model must provide a reason for ending the call. The reason is set as call disposition and added to call tags.
    """
    endCallReasonDescription: Annotated[
        str | None, Field(title='Endcallreasondescription')
    ] = None
    """
    Description shown to the model for the reason parameter. Used only when endCallReason is enabled.
    """


class EndCallToolDefinition(BaseModel):
    """
    Tool definition for End Call tools.
    """

    schema_version: Annotated[int | None, Field(title='Schema Version')] = 1
    """
    Schema version.
    """
    type: Annotated[Literal['end_call'], Field(title='Type')]
    """
    Tool type.
    """
    config: EndCallConfig
    """
    End Call configuration.
    """


class ExternalPBXFieldMapping(BaseModel):
    """
    Map one gathered-context value to a provider-native field.
    """

    context_path: Annotated[
        str, Field(max_length=255, min_length=1, title='Context Path')
    ]
    destination_field: Annotated[
        str, Field(pattern='^[A-Za-z][A-Za-z0-9_]{0,63}$', title='Destination Field')
    ]


class GraphConstraints(BaseModel):
    """
    Per-node-type graph rules. WorkflowGraph enforces these at validation.
    """

    model_config = ConfigDict(
        extra='forbid',
    )
    min_incoming: Annotated[int | None, Field(title='Min Incoming')] = None
    max_incoming: Annotated[int | None, Field(title='Max Incoming')] = None
    min_outgoing: Annotated[int | None, Field(title='Min Outgoing')] = None
    max_outgoing: Annotated[int | None, Field(title='Max Outgoing')] = None
    min_instances: Annotated[int | None, Field(title='Min Instances')] = None
    max_instances: Annotated[int | None, Field(title='Max Instances')] = None


class Method(Enum):
    """
    HTTP method to use for the request.
    """

    GET = 'GET'
    POST = 'POST'
    PUT = 'PUT'
    PATCH = 'PATCH'
    DELETE = 'DELETE'


class TimeoutMs(RootModel[int]):
    root: Annotated[int, Field(ge=1, title='Timeout Ms')] = 5000
    """
    Request timeout in milliseconds.
    """


class CustomMessageType(Enum):
    """
    Type of custom message.
    """

    text = 'text'
    audio = 'audio'


class InitiateCallRequest(BaseModel):
    workflow_id: Annotated[int, Field(title='Workflow Id')]
    workflow_run_id: Annotated[int | None, Field(title='Workflow Run Id')] = None
    phone_number: Annotated[str | None, Field(title='Phone Number')] = None
    telephony_configuration_id: Annotated[
        int | None, Field(title='Telephony Configuration Id')
    ] = None
    from_phone_number_id: Annotated[int | None, Field(title='From Phone Number Id')] = (
        None
    )


class McpToolConfig(BaseModel):
    """
    Configuration for a customer MCP server tool definition.
    """

    transport: Annotated[Literal['streamable_http'], Field(title='Transport')] = (
        'streamable_http'
    )
    """
    MCP transport protocol.
    """
    url: Annotated[str, Field(title='Url')]
    """
    MCP server URL. Must use http:// or https://.
    """
    credential_uuid: Annotated[str | None, Field(title='Credential Uuid')] = None
    """
    Reference to an external credential for MCP server auth.
    """
    tools_filter: Annotated[list[str] | None, Field(title='Tools Filter')] = None
    """
    Allowlist of MCP tool names to expose. Empty exposes all tools.
    """
    timeout_secs: Annotated[int | None, Field(ge=0, title='Timeout Secs')] = 30
    """
    Connection timeout in seconds.
    """
    sse_read_timeout_secs: Annotated[
        int | None, Field(ge=0, title='Sse Read Timeout Secs')
    ] = 300
    """
    SSE read timeout in seconds.
    """
    discovered_tools: Annotated[
        list[dict[str, Any]] | None, Field(title='Discovered Tools')
    ] = None
    """
    Server-managed cache of the MCP server's tool catalog [{name, description}]. Populated best-effort by the backend.
    """


class McpToolDefinition(BaseModel):
    """
    Persisted MCP tool definition.
    """

    schema_version: Annotated[int | None, Field(title='Schema Version')] = 1
    """
    Schema version.
    """
    type: Annotated[Literal['mcp'], Field(title='Type')]
    """
    Tool type.
    """
    config: McpToolConfig
    """
    MCP server configuration.
    """


class NodeCategory(Enum):
    """
    Drives grouping in the AddNodePanel UI.
    """

    call_node = 'call_node'
    global_node = 'global_node'
    trigger = 'trigger'
    integration = 'integration'


class NodeExample(BaseModel):
    """
    A worked example LLMs can pattern-match. Keep small and realistic.
    """

    model_config = ConfigDict(
        extra='forbid',
    )
    name: Annotated[str, Field(title='Name')]
    description: Annotated[str | None, Field(title='Description')] = None
    data: Annotated[dict[str, Any], Field(title='Data')]


class NumberInputOptions(BaseModel):
    """
    Renderer hints for numeric inputs.
    """

    model_config = ConfigDict(
        extra='forbid',
    )
    fractional: Annotated[bool | None, Field(title='Fractional')] = False
    """
    Allow arbitrary fractional values via step='any'.
    """


class Type(Enum):
    """
    JSON type for the resolved value.
    """

    string = 'string'
    number = 'number'
    boolean = 'boolean'
    object = 'object'
    array = 'array'


class PresetToolParameter(BaseModel):
    """
    A parameter injected by Dograh at runtime.
    """

    name: Annotated[str, Field(title='Name')]
    """
    Parameter name used as a key in the request body.
    """
    type: Annotated[Type, Field(title='Type')]
    """
    JSON type for the resolved value.
    """
    value_template: Annotated[str, Field(title='Value Template')]
    """
    Fixed value or template, e.g. {{initial_context.phone_number}}.
    """
    required: Annotated[bool | None, Field(title='Required')] = True
    """
    Whether the parameter must resolve to a non-empty value.
    """


class ColumnSpan(RootModel[int]):
    root: Annotated[int, Field(ge=1, le=12, title='Column Span')]
    """
    Number of columns to occupy in the editor's 12-column grid.
    """


class PropertyLayoutOptions(BaseModel):
    """
    Renderer layout hints for a property in the node editor.
    """

    model_config = ConfigDict(
        extra='forbid',
    )
    column_span: Annotated[ColumnSpan | None, Field(title='Column Span')] = None
    """
    Number of columns to occupy in the editor's 12-column grid.
    """


class PropertyOption(BaseModel):
    """
    An option in an `options` or `multi_options` dropdown.
    """

    model_config = ConfigDict(
        extra='forbid',
    )
    value: Annotated[str | int | bool | float, Field(title='Value')]
    label: Annotated[str, Field(title='Label')]
    description: Annotated[str | None, Field(title='Description')] = None


class PropertyRendererOptions(BaseModel):
    """
    Typed renderer metadata for node properties.

    Add new renderer behavior here instead of using free-form property metadata.
    """

    model_config = ConfigDict(
        extra='forbid',
    )
    layout: PropertyLayoutOptions | None = None
    number_input: NumberInputOptions | None = None


class PropertyType(Enum):
    """
    Bounded vocabulary of property types the renderer dispatches on.

    Adding a value here requires a matching arm in the frontend
    `<PropertyInput>` switch and (where relevant) the SDK codegen template.
    """

    string = 'string'
    number = 'number'
    boolean = 'boolean'
    options = 'options'
    multi_options = 'multi_options'
    fixed_collection = 'fixed_collection'
    json = 'json'
    tool_refs = 'tool_refs'
    document_refs = 'document_refs'
    recording_ref = 'recording_ref'
    credential_ref = 'credential_ref'
    mention_textarea = 'mention_textarea'
    url = 'url'


class RecordingResponseSchema(BaseModel):
    """
    Response schema for a single recording.
    """

    id: Annotated[int, Field(title='Id')]
    recording_id: Annotated[str, Field(title='Recording Id')]
    workflow_id: Annotated[int | None, Field(title='Workflow Id')] = None
    organization_id: Annotated[int, Field(title='Organization Id')]
    tts_provider: Annotated[str | None, Field(title='Tts Provider')] = None
    tts_model: Annotated[str | None, Field(title='Tts Model')] = None
    tts_voice_id: Annotated[str | None, Field(title='Tts Voice Id')] = None
    transcript: Annotated[str, Field(title='Transcript')]
    storage_key: Annotated[str, Field(title='Storage Key')]
    storage_backend: Annotated[str, Field(title='Storage Backend')]
    metadata: Annotated[dict[str, Any], Field(title='Metadata')]
    created_by: Annotated[int, Field(title='Created By')]
    created_at: Annotated[AwareDatetime, Field(title='Created At')]
    is_active: Annotated[bool, Field(title='Is Active')]


class Type1(Enum):
    """
    JSON type for the parameter value.
    """

    string = 'string'
    number = 'number'
    boolean = 'boolean'
    object = 'object'
    array = 'array'


class ToolParameter(BaseModel):
    """
    A parameter that the tool accepts from the model at call time.
    """

    name: Annotated[str, Field(title='Name')]
    """
    Parameter name used as a key in the tool request body.
    """
    type: Annotated[Type1, Field(title='Type')]
    """
    JSON type for the parameter value.
    """
    description: Annotated[str, Field(title='Description')]
    """
    Description shown to the model for this parameter.
    """
    required: Annotated[bool | None, Field(title='Required')] = True
    """
    Whether this parameter is required when the tool is called.
    """


class ToolResponse(BaseModel):
    """
    Response schema for a reusable tool.
    """

    id: Annotated[int, Field(title='Id')]
    tool_uuid: Annotated[str, Field(title='Tool Uuid')]
    name: Annotated[str, Field(title='Name')]
    description: Annotated[str | None, Field(title='Description')]
    category: Annotated[str, Field(title='Category')]
    icon: Annotated[str | None, Field(title='Icon')]
    icon_color: Annotated[str | None, Field(title='Icon Color')]
    status: Annotated[str, Field(title='Status')]
    definition: Annotated[dict[str, Any], Field(title='Definition')]
    created_at: Annotated[AwareDatetime, Field(title='Created At')]
    updated_at: Annotated[AwareDatetime | None, Field(title='Updated At')]
    created_by: CreatedByResponse | None = None


class DestinationSource(Enum):
    """
    Whether the destination is static/template, resolved by HTTP, or selected by ordered gathered/initial-context mapping rules.
    """

    static = 'static'
    dynamic = 'dynamic'
    context_mapping = 'context_mapping'


class MessageType1(Enum):
    """
    Type of message to play before transfer.
    """

    none = 'none'
    custom = 'custom'
    audio = 'audio'


class CallDisposition(RootModel[str]):
    root: Annotated[str, Field(max_length=64, title='Call Disposition')]
    """
    Optional disposition to record after a successful transfer. When omitted, Dograh records its provider-specific transfer default.
    """


class ValidationError(BaseModel):
    loc: Annotated[list[str | int], Field(title='Location')]
    msg: Annotated[str, Field(title='Message')]
    type: Annotated[str, Field(title='Error Type')]
    input: Annotated[Any | None, Field(title='Input')] = None
    ctx: Annotated[dict[str, Any] | None, Field(title='Context')] = None


class TurnStartStrategy(Enum):
    default = 'default'
    min_words = 'min_words'
    provisional_vad = 'provisional_vad'


class TurnStopStrategy(Enum):
    transcription = 'transcription'
    turn_analyzer = 'turn_analyzer'


class ExternalPbxLeadHeader(RootModel[str]):
    root: Annotated[str, Field(pattern='^[A-Za-z][A-Za-z0-9_]{0,63}$')]


class WorkflowConfigurationDefaults(BaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    ambient_noise_configuration: AmbientNoiseConfigurationDefaults | None = None
    max_call_duration: Annotated[
        int | None, Field(gt=0, le=1200, title='Max Call Duration')
    ] = 300
    max_user_idle_timeout: Annotated[
        float | None, Field(title='Max User Idle Timeout')
    ] = 10.0
    smart_turn_stop_secs: Annotated[
        float | None, Field(title='Smart Turn Stop Secs')
    ] = 2.0
    turn_start_strategy: Annotated[
        TurnStartStrategy | None, Field(title='Turn Start Strategy')
    ] = 'default'
    turn_start_min_words: Annotated[int | None, Field(title='Turn Start Min Words')] = 3
    provisional_vad_pause_secs: Annotated[
        float | None, Field(title='Provisional Vad Pause Secs')
    ] = 1.5
    turn_stop_strategy: Annotated[
        TurnStopStrategy | None, Field(title='Turn Stop Strategy')
    ] = 'transcription'
    dictionary: Annotated[str | None, Field(title='Dictionary')] = ''
    context_compaction_enabled: Annotated[
        bool | None, Field(title='Context Compaction Enabled')
    ] = False
    call_dispositions: Annotated[
        list[CallDispositionOption] | None,
        Field(max_length=50, title='Call Dispositions'),
    ] = None
    """
    Allowed business outcomes for terminal call classification. Each entry defines the exact stored code and the criteria for selecting it.
    """
    text_chat_inactivity_timeout_seconds: Annotated[
        int | None, Field(ge=60, le=10500, title='Text Chat Inactivity Timeout Seconds')
    ] = 1800
    external_pbx_field_mappings: Annotated[
        list[ExternalPBXFieldMapping] | None,
        Field(max_length=100, title='External Pbx Field Mappings'),
    ] = None
    external_pbx_lead_headers: Annotated[
        list[ExternalPbxLeadHeader] | None,
        Field(max_length=50, title='External Pbx Lead Headers'),
    ] = None


class WorkflowListResponse(BaseModel):
    """
    Lightweight response for workflow listings (excludes large fields).
    """

    id: Annotated[int, Field(title='Id')]
    name: Annotated[str, Field(title='Name')]
    status: Annotated[str, Field(title='Status')]
    created_at: Annotated[AwareDatetime, Field(title='Created At')]
    total_runs: Annotated[int, Field(title='Total Runs')]
    folder_id: Annotated[int | None, Field(title='Folder Id')] = None
    workflow_uuid: Annotated[str | None, Field(title='Workflow Uuid')] = None


class WorkflowResponse(BaseModel):
    id: Annotated[int, Field(title='Id')]
    name: Annotated[str, Field(title='Name')]
    status: Annotated[str, Field(title='Status')]
    created_at: Annotated[AwareDatetime, Field(title='Created At')]
    workflow_definition: Annotated[dict[str, Any], Field(title='Workflow Definition')]
    current_definition_id: Annotated[int | None, Field(title='Current Definition Id')]
    template_context_variables: Annotated[
        dict[str, Any] | None, Field(title='Template Context Variables')
    ] = None
    call_disposition_codes: CallDispositionCodes | None = None
    total_runs: Annotated[int | None, Field(title='Total Runs')] = None
    workflow_configurations: Annotated[
        dict[str, Any] | None, Field(title='Workflow Configurations')
    ] = None
    version_number: Annotated[int | None, Field(title='Version Number')] = None
    version_status: Annotated[str | None, Field(title='Version Status')] = None
    workflow_uuid: Annotated[str | None, Field(title='Workflow Uuid')] = None


class ContextDestinationMappingConfig(BaseModel):
    """
    Resolve a transfer destination from gathered or initial context.

    Rules are evaluated in order. The first rule whose context value matches
    one of its routes wins; ``fallback_destination`` applies only when no rule
    matched. Destinations may be provider-native values or context templates.
    """

    rules: Annotated[list[ContextDestinationRule] | None, Field(title='Rules')] = None
    """
    Ordered routing rules evaluated top to bottom; first match wins.
    """
    context_path: Annotated[str | None, Field(title='Context Path')] = None
    """
    Deprecated single-rule context path. Use rules instead; accepted for backward compatibility.
    """
    routes: Annotated[list[ContextDestinationRoute] | None, Field(title='Routes')] = (
        None
    )
    """
    Deprecated single-rule routes. Use rules instead; accepted for backward compatibility.
    """
    fallback_destination: Annotated[
        FallbackDestination | None, Field(title='Fallback Destination')
    ] = None
    """
    Optional provider-native destination or context template used when no rule matched.
    """


class DocumentListResponseSchema(BaseModel):
    """
    Response schema for list of documents.
    """

    documents: Annotated[list[DocumentResponseSchema], Field(title='Documents')]
    total: Annotated[int, Field(title='Total')]
    limit: Annotated[int, Field(title='Limit')]
    offset: Annotated[int, Field(title='Offset')]


class HTTPValidationError(BaseModel):
    detail: Annotated[list[ValidationError] | None, Field(title='Detail')] = None


class HttpApiConfig(BaseModel):
    """
    Configuration for HTTP API tools.
    """

    method: Annotated[Method, Field(title='Method')]
    """
    HTTP method to use for the request.
    """
    url: Annotated[str, Field(title='Url')]
    """
    Target HTTP or HTTPS URL.
    """
    headers: Annotated[dict[str, str] | None, Field(title='Headers')] = None
    """
    Static headers to include with every request.
    """
    credential_uuid: Annotated[str | None, Field(title='Credential Uuid')] = None
    """
    Reference to an external credential for request authentication.
    """
    parameters: Annotated[list[ToolParameter] | None, Field(title='Parameters')] = None
    """
    Parameters the model must provide when calling this tool.
    """
    preset_parameters: Annotated[
        list[PresetToolParameter] | None, Field(title='Preset Parameters')
    ] = None
    """
    Parameters injected by Dograh from fixed values or workflow context templates.
    """
    timeout_ms: Annotated[
        TimeoutMs | None, Field(title='Timeout Ms', validate_default=True)
    ] = 5000
    """
    Request timeout in milliseconds.
    """
    customMessage: Annotated[str | None, Field(title='Custommessage')] = None
    """
    Custom message to play after tool execution.
    """
    customMessageType: Annotated[
        CustomMessageType | None, Field(title='Custommessagetype')
    ] = None
    """
    Type of custom message.
    """
    customMessageRecordingId: Annotated[
        str | None, Field(title='Custommessagerecordingid')
    ] = None
    """
    Recording ID for an audio custom message.
    """
    body_template: Annotated[dict[str, Any] | None, Field(title='Body Template')] = None
    """
    Optional JSON body template for POST, PUT, and PATCH requests.
    """


class HttpApiToolDefinition(BaseModel):
    """
    Tool definition for HTTP API tools.
    """

    schema_version: Annotated[int | None, Field(title='Schema Version')] = 1
    """
    Schema version.
    """
    type: Annotated[Literal['http_api'], Field(title='Type')]
    """
    Tool type.
    """
    config: HttpApiConfig
    """
    HTTP API configuration.
    """


class HttpTransferResolverConfig(BaseModel):
    """
    HTTP endpoint used to resolve transfer destination at call time.
    """

    type: Annotated[Literal['http'], Field(title='Type')] = 'http'
    """
    Resolver type.
    """
    url: Annotated[str, Field(title='Url')]
    """
    HTTP or HTTPS endpoint for transfer resolution.
    """
    headers: Annotated[dict[str, str] | None, Field(title='Headers')] = None
    """
    Static headers to include with every resolver request.
    """
    credential_uuid: Annotated[str | None, Field(title='Credential Uuid')] = None
    """
    Reference to an external credential for resolver authentication.
    """
    timeout_ms: Annotated[int | None, Field(ge=500, le=5000, title='Timeout Ms')] = 3000
    """
    Resolver request timeout in milliseconds.
    """
    wait_message: Annotated[str | None, Field(title='Wait Message')] = None
    """
    Optional short message played while Dograh resolves routing.
    """
    parameters: Annotated[list[ToolParameter] | None, Field(title='Parameters')] = None
    """
    Parameters the model may provide when calling this transfer tool.
    """
    preset_parameters: Annotated[
        list[PresetToolParameter] | None, Field(title='Preset Parameters')
    ] = None
    """
    Parameters injected by Dograh from fixed values or workflow context templates.
    """


class PropertySpec(BaseModel):
    """
    Single field on a node.

    `description` is HUMAN-FACING — shown under the field in the edit
    dialog. Keep it concise and explain what the field does.

    `llm_hint` is LLM-FACING — appears only in the `get_node_type` MCP
    response and in SDK schema output. Use it for catalog tool references
    (e.g., "Use `list_recordings`"), array shape, expected value idioms,
    or anything that would be noise in the UI. Optional; omit when the
    `description` already suffices for both audiences.
    """

    model_config = ConfigDict(
        extra='forbid',
    )
    name: Annotated[str, Field(title='Name')]
    type: PropertyType
    display_name: Annotated[str, Field(title='Display Name')]
    description: Annotated[str, Field(min_length=1, title='Description')]
    """
    Human-facing explanation shown in the UI.
    """
    llm_hint: Annotated[str | None, Field(title='Llm Hint')] = None
    """
    LLM-only guidance; omitted from the UI.
    """
    default: Annotated[Any | None, Field(title='Default')] = None
    required: Annotated[bool | None, Field(title='Required')] = False
    placeholder: Annotated[str | None, Field(title='Placeholder')] = None
    display_options: DisplayOptions | None = None
    options: Annotated[list[PropertyOption] | None, Field(title='Options')] = None
    properties: Annotated[list[PropertySpec] | None, Field(title='Properties')] = None
    min_value: Annotated[float | None, Field(title='Min Value')] = None
    max_value: Annotated[float | None, Field(title='Max Value')] = None
    min_length: Annotated[int | None, Field(title='Min Length')] = None
    max_length: Annotated[int | None, Field(title='Max Length')] = None
    pattern: Annotated[str | None, Field(title='Pattern')] = None
    editor: Annotated[str | None, Field(title='Editor')] = None
    renderer_options: PropertyRendererOptions | None = None


class RecordingListResponseSchema(BaseModel):
    """
    Response schema for list of recordings.
    """

    recordings: Annotated[list[RecordingResponseSchema], Field(title='Recordings')]
    total: Annotated[int, Field(title='Total')]


class TransferCallConfig(BaseModel):
    """
    Configuration for Transfer Call tools.
    """

    destination_source: Annotated[
        DestinationSource | None, Field(title='Destination Source')
    ] = 'static'
    """
    Whether the destination is static/template, resolved by HTTP, or selected by ordered gathered/initial-context mapping rules.
    """
    destination: Annotated[str | None, Field(title='Destination')] = ''
    """
    Phone number, SIP endpoint, or template to transfer the call to, e.g. +1234567890, PJSIP/1234, or {{initial_context.transfer_destination}}.
    """
    messageType: Annotated[MessageType1 | None, Field(title='Messagetype')] = 'none'
    """
    Type of message to play before transfer.
    """
    customMessage: Annotated[str | None, Field(title='Custommessage')] = None
    """
    Custom message to play before transferring.
    """
    audioRecordingId: Annotated[str | None, Field(title='Audiorecordingid')] = None
    """
    Recording ID for audio message before transfer.
    """
    timeout: Annotated[int | None, Field(ge=5, le=120, title='Timeout')] = 30
    """
    Maximum seconds to wait for the destination to answer.
    """
    call_disposition: Annotated[
        CallDisposition | None, Field(title='Call Disposition')
    ] = None
    """
    Optional disposition to record after a successful transfer. When omitted, Dograh records its provider-specific transfer default.
    """
    parameters: Annotated[list[ToolParameter] | None, Field(title='Parameters')] = None
    """
    Parameters the model may provide when calling this transfer tool, for example state, department, or transfer reason.
    """
    resolver: HttpTransferResolverConfig | None = None
    """
    Optional resolver that determines transfer routing at call time.
    """
    context_mapping: ContextDestinationMappingConfig | None = None
    """
    Optional ordered context-to-destination routing rules.
    """


class TransferCallToolDefinition(BaseModel):
    """
    Tool definition for Transfer Call tools.
    """

    schema_version: Annotated[int | None, Field(title='Schema Version')] = 1
    """
    Schema version.
    """
    type: Annotated[Literal['transfer_call'], Field(title='Type')]
    """
    Tool type.
    """
    config: TransferCallConfig
    """
    Transfer Call configuration.
    """


class UpdateWorkflowRequest(BaseModel):
    name: Annotated[str | None, Field(title='Name')] = None
    workflow_definition: Annotated[
        dict[str, Any] | None, Field(title='Workflow Definition')
    ] = None
    template_context_variables: Annotated[
        dict[str, Any] | None, Field(title='Template Context Variables')
    ] = None
    workflow_configurations: WorkflowConfigurationDefaults | None = None


class CreateToolRequest(BaseModel):
    """
    Request schema for creating a reusable tool.
    """

    name: Annotated[str, Field(max_length=255, title='Name')]
    """
    Display name for the tool.
    """
    description: Annotated[str | None, Field(title='Description')] = None
    """
    Description shown to the agent when deciding whether to call it.
    """
    category: Annotated[Category | None, Field(title='Category')] = 'http_api'
    """
    Tool category. Must match definition.type.
    """
    icon: Annotated[Icon | None, Field(title='Icon', validate_default=True)] = 'globe'
    """
    Lucide icon identifier.
    """
    icon_color: Annotated[
        IconColor | None, Field(title='Icon Color', validate_default=True)
    ] = '#3B82F6'
    """
    Hex color for the tool icon.
    """
    definition: Annotated[
        HttpApiToolDefinition
        | EndCallToolDefinition
        | TransferCallToolDefinition
        | CalculatorToolDefinition
        | McpToolDefinition,
        Field(discriminator='type', title='Definition'),
    ]
    """
    Typed tool definition.
    """


class NodeSpec(BaseModel):
    """
    Single source of truth for a node type.
    """

    model_config = ConfigDict(
        extra='forbid',
    )
    name: Annotated[str, Field(title='Name')]
    display_name: Annotated[str, Field(title='Display Name')]
    description: Annotated[str, Field(min_length=1, title='Description')]
    """
    Human-facing explanation shown in AddNodePanel.
    """
    llm_hint: Annotated[str | None, Field(title='Llm Hint')] = None
    """
    LLM-only guidance; omitted from the UI.
    """
    docs_url: Annotated[str | None, Field(title='Docs Url')] = None
    """
    Documentation URL shown in the node editor.
    """
    category: NodeCategory
    icon: Annotated[str, Field(title='Icon')]
    version: Annotated[str | None, Field(title='Version')] = '1.0.0'
    properties: Annotated[list[PropertySpec], Field(title='Properties')]
    examples: Annotated[list[NodeExample] | None, Field(title='Examples')] = None
    graph_constraints: GraphConstraints | None = None


class NodeTypesResponse(BaseModel):
    spec_version: Annotated[str, Field(title='Spec Version')]
    node_types: Annotated[list[NodeSpec], Field(title='Node Types')]


PropertySpec.model_rebuild()
