# DO NOT EDIT — generated by _gen/ from the OpenAPI spec.
# Regenerate with: ./client_gen.sh
from __future__ import annotations

from typing import Any

import httpx

from goodmem._base import _op_meta, _expand_label_filters
from goodmem._base import _op_meta, _prepare_create_payload
from goodmem.errors import raise_for_status
from goodmem.models.create_llm_response import CreateLLMResponse
from goodmem.models.endpoint_authentication import EndpointAuthentication
from goodmem.models.list_llms_response import ListLLMsResponse
from goodmem.models.llm_capabilities import LLMCapabilities
from goodmem.models.llm_creation_request import LLMCreationRequest
from goodmem.models.llm_provider_type import LLMProviderType
from goodmem.models.llm_response import LLMResponse
from goodmem.models.llm_sampling_params import LLMSamplingParams
from goodmem.models.llm_update_request import LLMUpdateRequest


class LlmsAPIBase:
    """Llms API — auto-generated structural base.

    Auto-generated structural base. Do not edit.
    Override in goodmem/api/llms.py to add domain-specific logic.
    """

    _create_model = LLMCreationRequest
    _rest_metadata: dict = {'create': {'http_method': 'POST', 'path': '/v1/llms', 'input_shape': 'kwargs_body', 'summary': 'Create a new LLM', 'description': "Creates a new LLM configuration for text generation services. LLMs represent connections to different language model API services (like OpenAI, vLLM, etc.) and include all the necessary configuration to use them for text generation. DUPLICATE DETECTION: Returns HTTP 409 Conflict (ALREADY_EXISTS) if another LLM exists with identical {ownerId, providerType, endpointUrl, apiPath, modelIdentifier, credentialsFingerprint} after URL canonicalization. Uniqueness is enforced per-owner. Credentials are hashed (SHA-256) for uniqueness while remaining encrypted. The apiPath field defaults to '/chat/completions' if omitted. Requires CREATE_LLM_OWN permission (or CREATE_LLM_ANY for admin users).", 'response': 'CreateLLMResponse', 'params': [{'name': 'display_name', 'type': 'str', 'source': 'body', 'required': True, 'alias': 'displayName', 'description': 'User-facing name of the LLM'}, {'name': 'description', 'type': 'str', 'source': 'body', 'required': False, 'description': 'Description of the LLM'}, {'name': 'provider_type', 'type': 'LLMProviderType', 'source': 'body', 'required': True, 'alias': 'providerType', 'description': 'Type of LLM provider'}, {'name': 'endpoint_url', 'type': 'str', 'source': 'body', 'required': True, 'alias': 'endpointUrl', 'description': 'API endpoint base URL (OpenAI-compatible base, typically ends with /v1)'}, {'name': 'api_path', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'apiPath', 'description': 'API path for chat/completions request (defaults to /chat/completions if not provided)', 'default': '/chat/completions'}, {'name': 'model_identifier', 'type': 'str', 'source': 'body', 'required': True, 'alias': 'modelIdentifier', 'description': 'Model identifier'}, {'name': 'supported_modalities', 'type': 'list[Modality]', 'source': 'body', 'required': False, 'alias': 'supportedModalities', 'description': 'Supported content modalities (defaults to TEXT if not provided)', 'default': ['TEXT']}, {'name': 'credentials', 'type': 'EndpointAuthentication', 'source': 'body', 'required': False, 'description': 'Structured credential payload describing how to authenticate with the provider. Omit for deployments that do not require credentials.'}, {'name': 'labels', 'type': 'dict', 'source': 'body', 'required': False, 'description': 'User-defined labels for categorization'}, {'name': 'version', 'type': 'str', 'source': 'body', 'required': False, 'description': 'Version information'}, {'name': 'monitoring_endpoint', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'monitoringEndpoint', 'description': 'Monitoring endpoint URL'}, {'name': 'capabilities', 'type': 'LLMCapabilities', 'source': 'body', 'required': False, 'description': 'LLM capabilities defining supported features and modes. Optional - server infers capabilities from model identifier if not provided.'}, {'name': 'default_sampling_params', 'type': 'LLMSamplingParams', 'source': 'body', 'required': False, 'alias': 'defaultSamplingParams', 'description': 'Default sampling parameters for generation requests'}, {'name': 'max_context_length', 'type': 'int', 'source': 'body', 'required': False, 'alias': 'maxContextLength', 'description': 'Maximum context window size in tokens'}, {'name': 'client_config', 'type': 'dict', 'source': 'body', 'required': False, 'alias': 'clientConfig', 'description': 'Provider-specific client configuration as flexible JSON structure'}, {'name': 'owner_id', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'ownerId', 'description': 'Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_LLM_ANY permission if specified.'}, {'name': 'llm_id', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'llmId', 'description': 'Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.'}], 'body_model': 'LLMCreationRequest', 'body_expr': 'LLMCreationRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json']}, 'get': {'http_method': 'GET', 'path': '/v1/llms/{id}', 'input_shape': 'path_query', 'summary': 'Get an LLM by ID', 'description': "Retrieves the details of a specific LLM configuration by its unique identifier. Requires READ_LLM_OWN permission for LLMs you own (or READ_LLM_ANY for admin users to view any user's LLMs). This is a read-only operation with no side effects.", 'response': 'LLMResponse', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the LLM to retrieve'}]}, 'list': {'http_method': 'GET', 'path': '/v1/llms', 'input_shape': 'query_only', 'summary': 'List LLMs', 'description': 'Retrieves a list of LLM configurations accessible to the caller, with optional filtering. LABEL FILTERS: Supply dynamic query parameters in the form label.<key>=<value> (for example, label.environment=production). PERMISSION-BASED FILTERING: With LIST_LLM_OWN permission, you can only see your own LLMs (ownerId filter is ignored if set to another user). With LIST_LLM_ANY permission, you can see all LLMs or filter by any ownerId. This is a read-only operation with no side effects.', 'response': 'ListLLMsResponse', 'query_params': ['owner_id', 'provider_type', 'label.*'], 'params': [{'name': 'owner_id', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'ownerId', 'description': 'Filter LLMs by owner ID. With LIST_LLM_ANY permission, omitting this shows all accessible LLMs; providing it filters by that owner. With LIST_LLM_OWN permission, only your own LLMs are shown regardless of this parameter.'}, {'name': 'provider_type', 'type': 'LLMProviderType', 'source': 'query', 'required': False, 'alias': 'providerType', 'description': 'Filter LLMs by provider type. Allowed values match the LLMProviderType schema.'}, {'name': 'label.*', 'type': 'str', 'source': 'query', 'required': False, 'description': 'Filter by label value. Multiple label filters can be specified (e.g., ?label.environment=production&label.team=ai)'}], 'supports_label_wildcard': True}, 'update': {'http_method': 'PUT', 'path': '/v1/llms/{id}', 'input_shape': 'typed_request', 'summary': 'Update an LLM', 'description': 'Updates an existing LLM configuration including display information, endpoint configuration, model parameters, credentials, and labels. All fields are optional - only specified fields will be updated. IMPORTANT: providerType is IMMUTABLE after creation and cannot be changed. Requires UPDATE_LLM_OWN permission for LLMs you own (or UPDATE_LLM_ANY for admin users).', 'response': 'LLMResponse', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the LLM to update'}, {'name': 'display_name', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'displayName', 'description': 'Update display name'}, {'name': 'description', 'type': 'str', 'source': 'body', 'required': False, 'description': 'Update description'}, {'name': 'endpoint_url', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'endpointUrl', 'description': 'Update endpoint base URL (OpenAI-compatible base, typically ends with /v1)'}, {'name': 'api_path', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'apiPath', 'description': 'Update API path'}, {'name': 'model_identifier', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'modelIdentifier', 'description': 'Update model identifier (cannot be empty)'}, {'name': 'supported_modalities', 'type': 'list[Modality]', 'source': 'body', 'required': False, 'alias': 'supportedModalities', 'description': 'Update supported modalities (if array contains ≥1 elements, replaces stored set; if empty or omitted, no change)'}, {'name': 'credentials', 'type': 'EndpointAuthentication', 'source': 'body', 'required': False, 'description': 'Update credentials'}, {'name': 'version', 'type': 'str', 'source': 'body', 'required': False, 'description': 'Update version information'}, {'name': 'monitoring_endpoint', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'monitoringEndpoint', 'description': 'Update monitoring endpoint URL'}, {'name': 'capabilities', 'type': 'LLMCapabilities', 'source': 'body', 'required': False, 'description': 'Update LLM capabilities (replaces entire capability set; clients MUST send all flags)'}, {'name': 'default_sampling_params', 'type': 'LLMSamplingParams', 'source': 'body', 'required': False, 'alias': 'defaultSamplingParams', 'description': 'Update default sampling parameters'}, {'name': 'max_context_length', 'type': 'int', 'source': 'body', 'required': False, 'alias': 'maxContextLength', 'description': 'Update maximum context window size in tokens'}, {'name': 'client_config', 'type': 'dict', 'source': 'body', 'required': False, 'alias': 'clientConfig', 'description': 'Update provider-specific client configuration (replaces entire config; no merging)'}, {'name': 'replace_labels', 'type': 'dict', 'source': 'body', 'required': False, 'alias': 'replaceLabels', 'description': 'Replace all existing labels with this set. Empty map clears all labels. Cannot be used with mergeLabels.'}, {'name': 'merge_labels', 'type': 'dict', 'source': 'body', 'required': False, 'alias': 'mergeLabels', 'description': 'Merge with existing labels: upserts with overwrite. Labels not mentioned are preserved. Cannot be used with replaceLabels.'}], 'body_model': 'LLMUpdateRequest', 'body_expr': 'LLMUpdateRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json']}, 'delete': {'http_method': 'DELETE', 'path': '/v1/llms/{id}', 'input_shape': 'path_query', 'summary': 'Delete an LLM', 'description': 'Permanently deletes an LLM configuration. This operation cannot be undone and removes the LLM record and securely deletes stored credentials. IMPORTANT: This does NOT invalidate or delete any previously generated content using this LLM - existing generations remain accessible. Requires DELETE_LLM_OWN permission for LLMs you own (or DELETE_LLM_ANY for admin users).', 'response': 'None', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the LLM to delete'}]}}

    def __init__(self, http: httpx.Client, headers: dict[str, str]) -> None:
        self._http = http
        self._headers = headers

    def create(self, *, display_name: str | None=None, description: str | None=None, provider_type: LLMProviderType | None=None, endpoint_url: str | None=None, api_path: str | None='/chat/completions', model_identifier: str | None=None, supported_modalities: list | None=('TEXT',), credentials: EndpointAuthentication | None=None, labels: dict | None=None, version: str | None=None, monitoring_endpoint: str | None=None, capabilities: LLMCapabilities | None=None, default_sampling_params: LLMSamplingParams | None=None, max_context_length: int | None=None, client_config: dict | None=None, owner_id: str | None=None, llm_id: str | None=None) -> CreateLLMResponse:
        """Create a new LLM

        Creates a new LLM configuration for text generation services. LLMs represent connections to different language model API services (like OpenAI, vLLM, etc.) and include all the necessary configuration to use them for text generation. DUPLICATE DETECTION: Returns HTTP 409 Conflict (ALREADY_EXISTS) if another LLM exists with identical {owner_id, provider_type, endpoint_url, api_path, model_identifier, credentials_fingerprint} after URL canonicalization. Uniqueness is enforced per-owner. Credentials are hashed (SHA-256) for uniqueness while remaining encrypted. The api_path field defaults to '/chat/completions' if omitted. Requires CREATE_LLM_OWN permission (or CREATE_LLM_ANY for admin users).

        Args:
            display_name (str): User-facing name of the LLM
            description (str, optional): Description of the LLM
            provider_type (LLMProviderType): Type of LLM provider
            endpoint_url (str): API endpoint base URL (OpenAI-compatible base, typically ends with /v1)
            api_path (str, optional, default='/chat/completions'): API path for chat/completions request (defaults to /chat/completions if not provided)
            model_identifier (str): Model identifier
            supported_modalities (list, optional, default=['TEXT']): Supported content modalities (defaults to TEXT if not provided)
            credentials (EndpointAuthentication, optional): Structured credential payload describing how to authenticate with the provider. Omit for deployments that do not require credentials.
            labels (dict, optional): User-defined labels for categorization
            version (str, optional): Version information
            monitoring_endpoint (str, optional): Monitoring endpoint URL
            capabilities (LLMCapabilities, optional): LLM capabilities defining supported features and modes. Optional - server infers capabilities from model identifier if not provided.
            default_sampling_params (LLMSamplingParams, optional): Default sampling parameters for generation requests
            max_context_length (int, optional): Maximum context window size in tokens
            client_config (dict, optional): Provider-specific client configuration as flexible JSON structure
            owner_id (str, optional): Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_LLM_ANY permission if specified.
            llm_id (str, optional): Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.

        Returns:
            CreateLLMResponse
        """
        op = _op_meta(self, 'create')
        _params: dict = {}
        if display_name is not None:
            _params['display_name'] = display_name
        if description is not None:
            _params['description'] = description
        if provider_type is not None:
            _params['provider_type'] = provider_type
        if endpoint_url is not None:
            _params['endpoint_url'] = endpoint_url
        _params['api_path'] = api_path
        if model_identifier is not None:
            _params['model_identifier'] = model_identifier
        _params['supported_modalities'] = supported_modalities
        if credentials is not None:
            _params['credentials'] = credentials
        if labels is not None:
            _params['labels'] = labels
        if version is not None:
            _params['version'] = version
        if monitoring_endpoint is not None:
            _params['monitoring_endpoint'] = monitoring_endpoint
        if capabilities is not None:
            _params['capabilities'] = capabilities
        if default_sampling_params is not None:
            _params['default_sampling_params'] = default_sampling_params
        if max_context_length is not None:
            _params['max_context_length'] = max_context_length
        if client_config is not None:
            _params['client_config'] = client_config
        if owner_id is not None:
            _params['owner_id'] = owner_id
        if llm_id is not None:
            _params['llm_id'] = llm_id
        json_payload, data_payload, files_payload = _prepare_create_payload(
            create_model=LLMCreationRequest, op=op, kwargs=_params,
        )
        resp = self._http.post(
            "/v1/llms",
            json=json_payload,
            data=data_payload,
            files=files_payload,
            headers=self._headers,
        )
        raise_for_status(resp)
        return CreateLLMResponse.model_validate(resp.json())

    def list(self, *, labels: dict[str, str] | None = None, owner_id: str | None=None, provider_type: LLMProviderType | None=None) -> list[LLMResponse]:
        """List LLMs

        Retrieves a list of LLM configurations accessible to the caller, with optional filtering. LABEL FILTERS: Supply dynamic query parameters in the form label.<key>=<value> (for example, label.environment=production). PERMISSION-BASED FILTERING: With LIST_LLM_OWN permission, you can only see your own LLMs (owner_id filter is ignored if set to another user). With LIST_LLM_ANY permission, you can see all LLMs or filter by any owner_id. This is a read-only operation with no side effects.

        Args:
            owner_id (str, optional): Filter LLMs by owner ID. With LIST_LLM_ANY permission, omitting this shows all accessible LLMs; providing it filters by that owner. With LIST_LLM_OWN permission, only your own LLMs are shown regardless of this parameter.
            provider_type (LLMProviderType, optional): Filter LLMs by provider type. Allowed values match the LLMProviderType schema.
            label.* (str, optional): Filter by label value. Multiple label filters can be specified (e.g., ?label.environment=production&label.team=ai)

        Returns:
            list[LLMResponse]
        """
        op = _op_meta(self, 'list')
        _params: dict = {}
        if owner_id is not None:
            _params['owner_id'] = owner_id
        if provider_type is not None:
            _params['provider_type'] = provider_type
        params = _expand_label_filters(op=op, labels=labels, params=_params)
        resp = self._http.get(
            "/v1/llms",
            params=params or None,
            headers=self._headers,
        )
        raise_for_status(resp)
        wrapper = ListLLMsResponse.model_validate(resp.json())
        return getattr(wrapper, 'llms', [])

    def get(self, *, id: str) -> LLMResponse:
        """Get an LLM by ID

        Retrieves the details of a specific LLM configuration by its unique identifier. Requires READ_LLM_OWN permission for LLMs you own (or READ_LLM_ANY for admin users to view any user's LLMs). This is a read-only operation with no side effects.

        Args:
            id (str): The unique identifier of the LLM to retrieve

        Returns:
            LLMResponse
        """
        resp = self._http.get(
            f"/v1/llms/{id}",
            headers=self._headers,
        )
        raise_for_status(resp)
        return LLMResponse.model_validate(resp.json())

    def update(self, *, id: str, request: LLMUpdateRequest | dict) -> LLMResponse:
        """Update an LLM

        Updates an existing LLM configuration including display information, endpoint configuration, model parameters, credentials, and labels. All fields are optional - only specified fields will be updated. IMPORTANT: provider_type is IMMUTABLE after creation and cannot be changed. Requires UPDATE_LLM_OWN permission for LLMs you own (or UPDATE_LLM_ANY for admin users).

        Args:
            id (str): The unique identifier of the llm to update.
            request (LLMUpdateRequest | dict): The update payload. Accepts a LLMUpdateRequest instance or a plain dict with the same fields. Only specified fields will be modified.

        Returns:
            LLMResponse
        """
        if isinstance(request, dict):
            request = LLMUpdateRequest.model_validate(request)
        resp = self._http.put(
            f"/v1/llms/{id}",
            json=request.model_dump(by_alias=True, exclude_unset=True),
            headers=self._headers,
        )
        raise_for_status(resp)
        return LLMResponse.model_validate(resp.json())

    def delete(self, *, id: str) -> None:
        """Delete an LLM

        Permanently deletes an LLM configuration. This operation cannot be undone and removes the LLM record and securely deletes stored credentials. IMPORTANT: This does NOT invalidate or delete any previously generated content using this LLM - existing generations remain accessible. Requires DELETE_LLM_OWN permission for LLMs you own (or DELETE_LLM_ANY for admin users).

        Args:
            id (str): The unique identifier of the LLM to delete
        """
        resp = self._http.delete(
            f"/v1/llms/{id}",
            headers=self._headers,
        )
        raise_for_status(resp)


class AsyncLlmsAPIBase:
    """Async Llms API — auto-generated structural base.

    Auto-generated structural base. Do not edit.
    Override in goodmem/api/llms.py to add domain-specific logic.
    """

    _create_model = LLMCreationRequest
    _rest_metadata: dict = {'create': {'http_method': 'POST', 'path': '/v1/llms', 'input_shape': 'kwargs_body', 'summary': 'Create a new LLM', 'description': "Creates a new LLM configuration for text generation services. LLMs represent connections to different language model API services (like OpenAI, vLLM, etc.) and include all the necessary configuration to use them for text generation. DUPLICATE DETECTION: Returns HTTP 409 Conflict (ALREADY_EXISTS) if another LLM exists with identical {ownerId, providerType, endpointUrl, apiPath, modelIdentifier, credentialsFingerprint} after URL canonicalization. Uniqueness is enforced per-owner. Credentials are hashed (SHA-256) for uniqueness while remaining encrypted. The apiPath field defaults to '/chat/completions' if omitted. Requires CREATE_LLM_OWN permission (or CREATE_LLM_ANY for admin users).", 'response': 'CreateLLMResponse', 'params': [{'name': 'display_name', 'type': 'str', 'source': 'body', 'required': True, 'alias': 'displayName', 'description': 'User-facing name of the LLM'}, {'name': 'description', 'type': 'str', 'source': 'body', 'required': False, 'description': 'Description of the LLM'}, {'name': 'provider_type', 'type': 'LLMProviderType', 'source': 'body', 'required': True, 'alias': 'providerType', 'description': 'Type of LLM provider'}, {'name': 'endpoint_url', 'type': 'str', 'source': 'body', 'required': True, 'alias': 'endpointUrl', 'description': 'API endpoint base URL (OpenAI-compatible base, typically ends with /v1)'}, {'name': 'api_path', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'apiPath', 'description': 'API path for chat/completions request (defaults to /chat/completions if not provided)', 'default': '/chat/completions'}, {'name': 'model_identifier', 'type': 'str', 'source': 'body', 'required': True, 'alias': 'modelIdentifier', 'description': 'Model identifier'}, {'name': 'supported_modalities', 'type': 'list[Modality]', 'source': 'body', 'required': False, 'alias': 'supportedModalities', 'description': 'Supported content modalities (defaults to TEXT if not provided)', 'default': ['TEXT']}, {'name': 'credentials', 'type': 'EndpointAuthentication', 'source': 'body', 'required': False, 'description': 'Structured credential payload describing how to authenticate with the provider. Omit for deployments that do not require credentials.'}, {'name': 'labels', 'type': 'dict', 'source': 'body', 'required': False, 'description': 'User-defined labels for categorization'}, {'name': 'version', 'type': 'str', 'source': 'body', 'required': False, 'description': 'Version information'}, {'name': 'monitoring_endpoint', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'monitoringEndpoint', 'description': 'Monitoring endpoint URL'}, {'name': 'capabilities', 'type': 'LLMCapabilities', 'source': 'body', 'required': False, 'description': 'LLM capabilities defining supported features and modes. Optional - server infers capabilities from model identifier if not provided.'}, {'name': 'default_sampling_params', 'type': 'LLMSamplingParams', 'source': 'body', 'required': False, 'alias': 'defaultSamplingParams', 'description': 'Default sampling parameters for generation requests'}, {'name': 'max_context_length', 'type': 'int', 'source': 'body', 'required': False, 'alias': 'maxContextLength', 'description': 'Maximum context window size in tokens'}, {'name': 'client_config', 'type': 'dict', 'source': 'body', 'required': False, 'alias': 'clientConfig', 'description': 'Provider-specific client configuration as flexible JSON structure'}, {'name': 'owner_id', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'ownerId', 'description': 'Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_LLM_ANY permission if specified.'}, {'name': 'llm_id', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'llmId', 'description': 'Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.'}], 'body_model': 'LLMCreationRequest', 'body_expr': 'LLMCreationRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json']}, 'get': {'http_method': 'GET', 'path': '/v1/llms/{id}', 'input_shape': 'path_query', 'summary': 'Get an LLM by ID', 'description': "Retrieves the details of a specific LLM configuration by its unique identifier. Requires READ_LLM_OWN permission for LLMs you own (or READ_LLM_ANY for admin users to view any user's LLMs). This is a read-only operation with no side effects.", 'response': 'LLMResponse', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the LLM to retrieve'}]}, 'list': {'http_method': 'GET', 'path': '/v1/llms', 'input_shape': 'query_only', 'summary': 'List LLMs', 'description': 'Retrieves a list of LLM configurations accessible to the caller, with optional filtering. LABEL FILTERS: Supply dynamic query parameters in the form label.<key>=<value> (for example, label.environment=production). PERMISSION-BASED FILTERING: With LIST_LLM_OWN permission, you can only see your own LLMs (ownerId filter is ignored if set to another user). With LIST_LLM_ANY permission, you can see all LLMs or filter by any ownerId. This is a read-only operation with no side effects.', 'response': 'ListLLMsResponse', 'query_params': ['owner_id', 'provider_type', 'label.*'], 'params': [{'name': 'owner_id', 'type': 'str', 'source': 'query', 'required': False, 'alias': 'ownerId', 'description': 'Filter LLMs by owner ID. With LIST_LLM_ANY permission, omitting this shows all accessible LLMs; providing it filters by that owner. With LIST_LLM_OWN permission, only your own LLMs are shown regardless of this parameter.'}, {'name': 'provider_type', 'type': 'LLMProviderType', 'source': 'query', 'required': False, 'alias': 'providerType', 'description': 'Filter LLMs by provider type. Allowed values match the LLMProviderType schema.'}, {'name': 'label.*', 'type': 'str', 'source': 'query', 'required': False, 'description': 'Filter by label value. Multiple label filters can be specified (e.g., ?label.environment=production&label.team=ai)'}], 'supports_label_wildcard': True}, 'update': {'http_method': 'PUT', 'path': '/v1/llms/{id}', 'input_shape': 'typed_request', 'summary': 'Update an LLM', 'description': 'Updates an existing LLM configuration including display information, endpoint configuration, model parameters, credentials, and labels. All fields are optional - only specified fields will be updated. IMPORTANT: providerType is IMMUTABLE after creation and cannot be changed. Requires UPDATE_LLM_OWN permission for LLMs you own (or UPDATE_LLM_ANY for admin users).', 'response': 'LLMResponse', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the LLM to update'}, {'name': 'display_name', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'displayName', 'description': 'Update display name'}, {'name': 'description', 'type': 'str', 'source': 'body', 'required': False, 'description': 'Update description'}, {'name': 'endpoint_url', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'endpointUrl', 'description': 'Update endpoint base URL (OpenAI-compatible base, typically ends with /v1)'}, {'name': 'api_path', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'apiPath', 'description': 'Update API path'}, {'name': 'model_identifier', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'modelIdentifier', 'description': 'Update model identifier (cannot be empty)'}, {'name': 'supported_modalities', 'type': 'list[Modality]', 'source': 'body', 'required': False, 'alias': 'supportedModalities', 'description': 'Update supported modalities (if array contains ≥1 elements, replaces stored set; if empty or omitted, no change)'}, {'name': 'credentials', 'type': 'EndpointAuthentication', 'source': 'body', 'required': False, 'description': 'Update credentials'}, {'name': 'version', 'type': 'str', 'source': 'body', 'required': False, 'description': 'Update version information'}, {'name': 'monitoring_endpoint', 'type': 'str', 'source': 'body', 'required': False, 'alias': 'monitoringEndpoint', 'description': 'Update monitoring endpoint URL'}, {'name': 'capabilities', 'type': 'LLMCapabilities', 'source': 'body', 'required': False, 'description': 'Update LLM capabilities (replaces entire capability set; clients MUST send all flags)'}, {'name': 'default_sampling_params', 'type': 'LLMSamplingParams', 'source': 'body', 'required': False, 'alias': 'defaultSamplingParams', 'description': 'Update default sampling parameters'}, {'name': 'max_context_length', 'type': 'int', 'source': 'body', 'required': False, 'alias': 'maxContextLength', 'description': 'Update maximum context window size in tokens'}, {'name': 'client_config', 'type': 'dict', 'source': 'body', 'required': False, 'alias': 'clientConfig', 'description': 'Update provider-specific client configuration (replaces entire config; no merging)'}, {'name': 'replace_labels', 'type': 'dict', 'source': 'body', 'required': False, 'alias': 'replaceLabels', 'description': 'Replace all existing labels with this set. Empty map clears all labels. Cannot be used with mergeLabels.'}, {'name': 'merge_labels', 'type': 'dict', 'source': 'body', 'required': False, 'alias': 'mergeLabels', 'description': 'Merge with existing labels: upserts with overwrite. Labels not mentioned are preserved. Cannot be used with replaceLabels.'}], 'body_model': 'LLMUpdateRequest', 'body_expr': 'LLMUpdateRequest(**kwargs)', 'body_kind': 'json', 'body_kinds': ['application/json']}, 'delete': {'http_method': 'DELETE', 'path': '/v1/llms/{id}', 'input_shape': 'path_query', 'summary': 'Delete an LLM', 'description': 'Permanently deletes an LLM configuration. This operation cannot be undone and removes the LLM record and securely deletes stored credentials. IMPORTANT: This does NOT invalidate or delete any previously generated content using this LLM - existing generations remain accessible. Requires DELETE_LLM_OWN permission for LLMs you own (or DELETE_LLM_ANY for admin users).', 'response': 'None', 'query_params': ['id'], 'params': [{'name': 'id', 'type': 'str', 'source': 'path', 'required': True, 'description': 'The unique identifier of the LLM to delete'}]}}

    def __init__(self, http: httpx.AsyncClient, headers: dict[str, str]) -> None:
        self._http = http
        self._headers = headers

    async def create(self, *, display_name: str | None=None, description: str | None=None, provider_type: LLMProviderType | None=None, endpoint_url: str | None=None, api_path: str | None='/chat/completions', model_identifier: str | None=None, supported_modalities: list | None=('TEXT',), credentials: EndpointAuthentication | None=None, labels: dict | None=None, version: str | None=None, monitoring_endpoint: str | None=None, capabilities: LLMCapabilities | None=None, default_sampling_params: LLMSamplingParams | None=None, max_context_length: int | None=None, client_config: dict | None=None, owner_id: str | None=None, llm_id: str | None=None) -> CreateLLMResponse:
        """Create a new LLM

        Creates a new LLM configuration for text generation services. LLMs represent connections to different language model API services (like OpenAI, vLLM, etc.) and include all the necessary configuration to use them for text generation. DUPLICATE DETECTION: Returns HTTP 409 Conflict (ALREADY_EXISTS) if another LLM exists with identical {owner_id, provider_type, endpoint_url, api_path, model_identifier, credentials_fingerprint} after URL canonicalization. Uniqueness is enforced per-owner. Credentials are hashed (SHA-256) for uniqueness while remaining encrypted. The api_path field defaults to '/chat/completions' if omitted. Requires CREATE_LLM_OWN permission (or CREATE_LLM_ANY for admin users).

        Args:
            display_name (str): User-facing name of the LLM
            description (str, optional): Description of the LLM
            provider_type (LLMProviderType): Type of LLM provider
            endpoint_url (str): API endpoint base URL (OpenAI-compatible base, typically ends with /v1)
            api_path (str, optional, default='/chat/completions'): API path for chat/completions request (defaults to /chat/completions if not provided)
            model_identifier (str): Model identifier
            supported_modalities (list, optional, default=['TEXT']): Supported content modalities (defaults to TEXT if not provided)
            credentials (EndpointAuthentication, optional): Structured credential payload describing how to authenticate with the provider. Omit for deployments that do not require credentials.
            labels (dict, optional): User-defined labels for categorization
            version (str, optional): Version information
            monitoring_endpoint (str, optional): Monitoring endpoint URL
            capabilities (LLMCapabilities, optional): LLM capabilities defining supported features and modes. Optional - server infers capabilities from model identifier if not provided.
            default_sampling_params (LLMSamplingParams, optional): Default sampling parameters for generation requests
            max_context_length (int, optional): Maximum context window size in tokens
            client_config (dict, optional): Provider-specific client configuration as flexible JSON structure
            owner_id (str, optional): Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_LLM_ANY permission if specified.
            llm_id (str, optional): Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.

        Returns:
            CreateLLMResponse
        """
        op = _op_meta(self, 'create')
        _params: dict = {}
        if display_name is not None:
            _params['display_name'] = display_name
        if description is not None:
            _params['description'] = description
        if provider_type is not None:
            _params['provider_type'] = provider_type
        if endpoint_url is not None:
            _params['endpoint_url'] = endpoint_url
        _params['api_path'] = api_path
        if model_identifier is not None:
            _params['model_identifier'] = model_identifier
        _params['supported_modalities'] = supported_modalities
        if credentials is not None:
            _params['credentials'] = credentials
        if labels is not None:
            _params['labels'] = labels
        if version is not None:
            _params['version'] = version
        if monitoring_endpoint is not None:
            _params['monitoring_endpoint'] = monitoring_endpoint
        if capabilities is not None:
            _params['capabilities'] = capabilities
        if default_sampling_params is not None:
            _params['default_sampling_params'] = default_sampling_params
        if max_context_length is not None:
            _params['max_context_length'] = max_context_length
        if client_config is not None:
            _params['client_config'] = client_config
        if owner_id is not None:
            _params['owner_id'] = owner_id
        if llm_id is not None:
            _params['llm_id'] = llm_id
        json_payload, data_payload, files_payload = _prepare_create_payload(
            create_model=LLMCreationRequest, op=op, kwargs=_params,
        )
        resp = await self._http.post(
            "/v1/llms",
            json=json_payload,
            data=data_payload,
            files=files_payload,
            headers=self._headers,
        )
        raise_for_status(resp)
        return CreateLLMResponse.model_validate(resp.json())

    async def list(self, *, labels: dict[str, str] | None = None, owner_id: str | None=None, provider_type: LLMProviderType | None=None) -> list[LLMResponse]:
        """List LLMs

        Retrieves a list of LLM configurations accessible to the caller, with optional filtering. LABEL FILTERS: Supply dynamic query parameters in the form label.<key>=<value> (for example, label.environment=production). PERMISSION-BASED FILTERING: With LIST_LLM_OWN permission, you can only see your own LLMs (owner_id filter is ignored if set to another user). With LIST_LLM_ANY permission, you can see all LLMs or filter by any owner_id. This is a read-only operation with no side effects.

        Args:
            owner_id (str, optional): Filter LLMs by owner ID. With LIST_LLM_ANY permission, omitting this shows all accessible LLMs; providing it filters by that owner. With LIST_LLM_OWN permission, only your own LLMs are shown regardless of this parameter.
            provider_type (LLMProviderType, optional): Filter LLMs by provider type. Allowed values match the LLMProviderType schema.
            label.* (str, optional): Filter by label value. Multiple label filters can be specified (e.g., ?label.environment=production&label.team=ai)

        Returns:
            list[LLMResponse]
        """
        op = _op_meta(self, 'list')
        _params: dict = {}
        if owner_id is not None:
            _params['owner_id'] = owner_id
        if provider_type is not None:
            _params['provider_type'] = provider_type
        params = _expand_label_filters(op=op, labels=labels, params=_params)
        resp = await self._http.get(
            "/v1/llms",
            params=params or None,
            headers=self._headers,
        )
        raise_for_status(resp)
        wrapper = ListLLMsResponse.model_validate(resp.json())
        return getattr(wrapper, 'llms', [])

    async def get(self, *, id: str) -> LLMResponse:
        """Get an LLM by ID

        Retrieves the details of a specific LLM configuration by its unique identifier. Requires READ_LLM_OWN permission for LLMs you own (or READ_LLM_ANY for admin users to view any user's LLMs). This is a read-only operation with no side effects.

        Args:
            id (str): The unique identifier of the LLM to retrieve

        Returns:
            LLMResponse
        """
        resp = await self._http.get(
            f"/v1/llms/{id}",
            headers=self._headers,
        )
        raise_for_status(resp)
        return LLMResponse.model_validate(resp.json())

    async def update(self, *, id: str, request: LLMUpdateRequest | dict) -> LLMResponse:
        """Update an LLM

        Updates an existing LLM configuration including display information, endpoint configuration, model parameters, credentials, and labels. All fields are optional - only specified fields will be updated. IMPORTANT: provider_type is IMMUTABLE after creation and cannot be changed. Requires UPDATE_LLM_OWN permission for LLMs you own (or UPDATE_LLM_ANY for admin users).

        Args:
            id (str): The unique identifier of the llm to update.
            request (LLMUpdateRequest | dict): The update payload. Accepts a LLMUpdateRequest instance or a plain dict with the same fields. Only specified fields will be modified.

        Returns:
            LLMResponse
        """
        if isinstance(request, dict):
            request = LLMUpdateRequest.model_validate(request)
        resp = await self._http.put(
            f"/v1/llms/{id}",
            json=request.model_dump(by_alias=True, exclude_unset=True),
            headers=self._headers,
        )
        raise_for_status(resp)
        return LLMResponse.model_validate(resp.json())

    async def delete(self, *, id: str) -> None:
        """Delete an LLM

        Permanently deletes an LLM configuration. This operation cannot be undone and removes the LLM record and securely deletes stored credentials. IMPORTANT: This does NOT invalidate or delete any previously generated content using this LLM - existing generations remain accessible. Requires DELETE_LLM_OWN permission for LLMs you own (or DELETE_LLM_ANY for admin users).

        Args:
            id (str): The unique identifier of the LLM to delete
        """
        resp = await self._http.delete(
            f"/v1/llms/{id}",
            headers=self._headers,
        )
        raise_for_status(resp)

