"""
Generated API resources for Maniac SDK.

DO NOT EDIT - This file is generated by scripts/generate.py
"""

from __future__ import annotations

from pathlib import Path
from typing import Any, BinaryIO, Generator, AsyncGenerator, Mapping, TYPE_CHECKING

if TYPE_CHECKING:
    from ._base import SyncAPIClient, AsyncAPIClient
    from .types import (
        ChatCompletion,
        ChatCompletionList,
        ChatCompletionRelaxed,
        ContainerCreateResponse,
        ContainerDeleteResponse,
        ContainerList,
        Dataset,
        DatasetCreateResponse,
        DatasetList,
        EvaluationRun,
        EvaluationRunList,
        EvaluatorDeleteResponse,
        EvaluatorList,
        FileDeleteResponse,
        FileList,
        FileObject,
        ModelAddResponse,
        ModelList,
        OptimizationRunCreateResponse,
        RegisterResponse,
    )


# =============================================================================
# SYNC RESOURCES
# =============================================================================


class SyncChatResource:
    """chat resource (sync)."""

    def __init__(self, client: SyncAPIClient) -> None:
        self._client = client
        self.completions = SyncCompletionsResource(client)


class SyncCompletionsResource:
    """chat.completions resource (sync)."""

    def __init__(self, client: SyncAPIClient) -> None:
        self._client = client

    def list(
        self,
        limit: int = 20,
        offset: int = 0,
        model: str | None = None,
        container: str | None = None,
        order: str = "desc",
        metadata: dict[str, Any] | None = None,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> ChatCompletionList:
        """
        List chat completions

        List chat completions captured in telemetry, scoped to the authenticated project.

        Args:
            limit: The limit.
            offset: The offset.
            model: The model.
            container: The container.
            order: The order.
        """
        params: dict[str, Any] = {}
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        if model is not None:
            params["model"] = model
        if container is not None:
            params["container"] = container
        if order is not None:
            params["order"] = order
        if metadata:
            return self._client._request(
                "GET",
                "/api/v1/chat/completions",
                params=params,
                json=metadata,
                headers=extra_headers,
            ).json()
        return self._client.get(
            "/api/v1/chat/completions", params=params, headers=extra_headers
        )

    def create(
        self,
        *,
        messages: list[dict[str, Any]],
        frequency_penalty: float | None = None,
        logit_bias: dict[str, Any] | None = None,
        logprobs: bool | None = None,
        max_completion_tokens: float | None = None,
        max_tokens: float | None = None,
        metadata: dict[str, Any] | None = None,
        model: str | None = None,
        models: list[str] | None = None,
        presence_penalty: float | None = None,
        reasoning: dict[str, Any] | None = None,
        response_format: dict[str, Any] | None = None,
        seed: int | None = None,
        stop: str | None = None,
        store: bool | None = True,
        stream: bool | None = False,
        stream_options: dict[str, Any] | None = None,
        tags: list[str] | None = None,
        temperature: float | None = None,
        tool_choice: str | None = None,
        tools: list[dict[str, Any]] | None = None,
        top_logprobs: float | None = None,
        top_p: float | None = None,
        extra_headers: Mapping[str, str] | None = None,
        **kwargs: Any,
    ) -> ChatCompletion | Generator[str, None, None]:
        """
        Create a chat completion

        Create a chat completion using the specified model.

        Supports both streaming and non-streaming responses and is compatible with
        OpenAI's chat completions API. Use a container slug (`maniac:<container>`) or
        an external slug (e.g. `openai/gpt-4o`).

        Args:
            messages: Conversation messages.
            frequency_penalty: Frequency penalty.
            logit_bias: Logit bias.
            logprobs: Include logprobs.
            max_completion_tokens: Max completion tokens.
            max_tokens: Max tokens.
            metadata: Arbitrary key/value metadata to attach to the request.
            model: Model slug to use. Supports global slugs or project slugs...
            models: Fallback models.
            presence_penalty: Presence penalty.
            reasoning: Reasoning config.
            response_format: Response format.
            seed: Random seed.
            stop: Stop sequences.
            store: Whether to store the completion in the database.
            stream: Stream response.
            stream_options: Stream options.
            tags: Optional tags for tracking.
            temperature: Temperature.
            tool_choice: Tool choice.
            tools: Tools.
            top_logprobs: Top logprobs.
            top_p: Top p.
        """
        body: dict[str, Any] = {}
        body["messages"] = messages
        if frequency_penalty is not None:
            body["frequency_penalty"] = frequency_penalty
        if logit_bias is not None:
            body["logit_bias"] = logit_bias
        if logprobs is not None:
            body["logprobs"] = logprobs
        if max_completion_tokens is not None:
            body["max_completion_tokens"] = max_completion_tokens
        if max_tokens is not None:
            body["max_tokens"] = max_tokens
        if metadata is not None:
            body["metadata"] = metadata
        if model is not None:
            body["model"] = model
        if models is not None:
            body["models"] = models
        if presence_penalty is not None:
            body["presence_penalty"] = presence_penalty
        if reasoning is not None:
            body["reasoning"] = reasoning
        if response_format is not None:
            body["response_format"] = response_format
        if seed is not None:
            body["seed"] = seed
        if stop is not None:
            body["stop"] = stop
        if store is not None:
            body["store"] = store
        if stream is not None:
            body["stream"] = stream
        if stream_options is not None:
            body["stream_options"] = stream_options
        if tags is not None:
            body["tags"] = tags
        if temperature is not None:
            body["temperature"] = temperature
        if tool_choice is not None:
            body["tool_choice"] = tool_choice
        if tools is not None:
            body["tools"] = tools
        if top_logprobs is not None:
            body["top_logprobs"] = top_logprobs
        if top_p is not None:
            body["top_p"] = top_p
        body.update(kwargs)
        if body.get("stream"):
            return self._client.post_stream(
                "/api/v1/chat/completions", json=body, extra_headers=extra_headers
            )
        return self._client.post(
            "/api/v1/chat/completions", json=body, headers=extra_headers
        )

    def retrieve(
        self, completion_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> ChatCompletionRelaxed:
        """
        Get a chat completion

        Fetch a single chat completion by id within the authenticated project.

        Args:
            completion_id: The completion_id.
        """
        return self._client.get(
            f"/api/v1/chat/completions/{completion_id}", headers=extra_headers
        )

    def register(
        self,
        *,
        container: str,
        items: list[dict[str, Any]],
        extra_headers: Mapping[str, str] | None = None,
    ) -> RegisterResponse:
        """
        Register chat completion examples

        Register completed chat examples for evaluation and analytics.

        This endpoint accepts input/output pairs and stores them for later analysis,
        while aggregating usage metrics for reporting.

        Args:
            container: Container label to associate these examples with.
            items: List of chat input/output examples.
        """
        body: dict[str, Any] = {}
        body["container"] = container
        body["items"] = items
        return self._client.post(
            "/api/v1/chat/completions/register", json=body, headers=extra_headers
        )


class SyncContainersResource:
    """containers resource (sync)."""

    def __init__(self, client: SyncAPIClient) -> None:
        self._client = client

    def list(
        self,
        limit: int = 20,
        offset: int = 0,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> ContainerList:
        """
        List containers

        List containers owned by the authenticated project.

        Args:
            limit: The limit.
            offset: The offset.
        """
        params: dict[str, Any] = {}
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        return self._client.get(
            "/api/v1/containers", params=params, headers=extra_headers
        )

    def create(
        self,
        *,
        initial_model: str,
        label: str,
        api: str = "chat.completions",
        default_parameters: dict[str, Any] | None = None,
        default_system_prompt: str | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> ContainerCreateResponse:
        """
        Create a container

        Create a new container. Containers represent one task in your codebase. Each container utilizes separate models, routing, and evaluations, and collects data separately.

        Args:
            initial_model: Initial model slug.
            label: Container label.
            api: API type.
            default_parameters: Default inference parameters.
            default_system_prompt: Default system prompt.
        """
        body: dict[str, Any] = {}
        body["initial_model"] = initial_model
        body["label"] = label
        if api is not None:
            body["api"] = api
        if default_parameters is not None:
            body["default_parameters"] = default_parameters
        if default_system_prompt is not None:
            body["default_system_prompt"] = default_system_prompt
        return self._client.post("/api/v1/containers", json=body, headers=extra_headers)

    def retrieve(
        self, label: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> ContainerCreateResponse:
        """
        Get a container

        Fetch a single container by label within the authenticated project.

        Args:
            label: The label.
        """
        return self._client.get(f"/api/v1/containers/{label}", headers=extra_headers)

    def delete(
        self, label: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> ContainerDeleteResponse:
        """
        Delete a container

        Soft-delete a container by label within the authenticated project.

        Args:
            label: The label.
        """
        return self._client.delete(f"/api/v1/containers/{label}", headers=extra_headers)


class SyncDatasetsResource:
    """datasets resource (sync)."""

    def __init__(self, client: SyncAPIClient) -> None:
        self._client = client

    def list(
        self,
        limit: int = 100,
        offset: int = 0,
        container: str | None = None,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> DatasetList:
        """
        List datasets

        List datasets owned by the authenticated project. Optionally filter by container.

        Args:
            limit: Max number of datasets.
            offset: Number of datasets to skip.
            container: Container ID or label to filter datasets by.
        """
        params: dict[str, Any] = {}
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        if container is not None:
            params["container"] = container
        return self._client.get(
            "/api/v1/datasets", params=params, headers=extra_headers
        )

    def create(
        self,
        *,
        container: str,
        name: str,
        size: int,
        description: str | None = None,
        filters: list[dict[str, Any]] | None = None,
        metadata: dict[str, Any] | None = None,
        tags: list[str] | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> DatasetCreateResponse:
        """
        Create a dataset

        Create a dataset for a container using telemetry filters.

        Args:
            container: Container id or label for source data.
            name: Dataset name.
            size: Requested dataset size.
            description: Dataset description.
            filters: Filter conditions.
            metadata: Arbitrary metadata.
            tags: Optional dataset tags.
        """
        body: dict[str, Any] = {}
        body["container"] = container
        body["name"] = name
        body["size"] = size
        if description is not None:
            body["description"] = description
        if filters is not None:
            body["filters"] = filters
        if metadata is not None:
            body["metadata"] = metadata
        if tags is not None:
            body["tags"] = tags
        return self._client.post("/api/v1/datasets", json=body, headers=extra_headers)

    def retrieve(
        self, dataset_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> Dataset:
        """
        Get a dataset

        Fetch a dataset by id within the authenticated project.

        Args:
            dataset_id: The dataset_id.
        """
        return self._client.get(f"/api/v1/datasets/{dataset_id}", headers=extra_headers)


class SyncEvaluationResource:
    """evaluation resource (sync)."""

    def __init__(self, client: SyncAPIClient) -> None:
        self._client = client
        self.runs = SyncEvaluationRunsResource(client)


class SyncEvaluationRunsResource:
    """evaluation.runs resource (sync)."""

    def __init__(self, client: SyncAPIClient) -> None:
        self._client = client

    def list(
        self,
        container: str | None = None,
        status: str | None = None,
        limit: int = 20,
        offset: int = 0,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> EvaluationRunList:
        """
        List evaluation runs

        List evaluation runs for the authenticated project. Optionally filter by container and status.

        Args:
            container: Container ID or label to filter by.
            status: Filter by run status (e.g. 'running', 'completed', 'error').
            limit: The limit.
            offset: The offset.
        """
        params: dict[str, Any] = {}
        if container is not None:
            params["container"] = container
        if status is not None:
            params["status"] = status
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        return self._client.get(
            "/api/v1/evaluation/runs", params=params, headers=extra_headers
        )

    def create(
        self,
        *,
        container: str,
        evaluators: list[str],
        environment: str | None = "main",
        ground_truth: dict[str, Any] | None = None,
        metadata: dict[str, Any] | None = None,
        sample: dict[str, Any] | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> EvaluationRun:
        """
        Create an evaluation run

        Launch a standalone evaluation run. Validates access to the specified container, evaluators, data sources, and models, then dispatches the evaluation to the Modal backend.

        Args:
            container: Container id or label.
            evaluators: Evaluator ids or labels.
            environment: Execution environment name (maps to Modal app suffix).
            ground_truth: Ground-truth-side data source. Omit to default to the con...
            metadata: Optional metadata.
            sample: Sample-side data source. Omit to default to the container...
        """
        body: dict[str, Any] = {}
        body["container"] = container
        body["evaluators"] = evaluators
        if environment is not None:
            body["environment"] = environment
        if ground_truth is not None:
            body["ground_truth"] = ground_truth
        if metadata is not None:
            body["metadata"] = metadata
        if sample is not None:
            body["sample"] = sample
        return self._client.post(
            "/api/v1/evaluation/runs", json=body, headers=extra_headers
        )

    def retrieve(
        self, run_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> EvaluationRun:
        """
        Get an evaluation run

        Retrieve a single evaluation run by ID within the authenticated project.

        Args:
            run_id: The run_id.
        """
        return self._client.get(
            f"/api/v1/evaluation/runs/{run_id}", headers=extra_headers
        )


class SyncEvaluatorsResource:
    """evaluators resource (sync)."""

    def __init__(self, client: SyncAPIClient) -> None:
        self._client = client

    def list(
        self,
        container: str | None = None,
        limit: int = 20,
        offset: int = 0,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> EvaluatorList:
        """
        List evaluators

        List evaluators for the authenticated project, optionally filtered by container.

        Args:
            container: The container.
            limit: The limit.
            offset: The offset.
        """
        params: dict[str, Any] = {}
        if container is not None:
            params["container"] = container
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        return self._client.get(
            "/api/v1/evaluators", params=params, headers=extra_headers
        )

    def create(
        self,
        *,
        type: str,
        api: str | None = None,
        container: str | None = None,
        description: str | None = None,
        inference_parameters: dict[str, Any] | None = None,
        metadata: dict[str, Any] | None = None,
        model: str | None = None,
        name: str | None = None,
        pass_threshold: float | None = None,
        prompt: str | None = None,
        requirements: list[str] | None = None,
        source: str | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> dict[str, Any]:
        """
        Create an evaluator

        Create a new evaluator scoped to a project or container.

        Args:
            type: Evaluator type.
            api: API type.
            container: Container label.
            description: Evaluator description.
            inference_parameters: Optional inference parameters for judge evaluators (e.g. ...
            metadata: Optional metadata.
            model: Judge model slug.
            name: Evaluator name.
            pass_threshold: Optional pass threshold.
            prompt: Judge prompt.
            requirements: Optional requirements list.
            source: Code evaluator source.
        """
        body: dict[str, Any] = {}
        body["type"] = type
        if api is not None:
            body["api"] = api
        if container is not None:
            body["container"] = container
        if description is not None:
            body["description"] = description
        if inference_parameters is not None:
            body["inference_parameters"] = inference_parameters
        if metadata is not None:
            body["metadata"] = metadata
        if model is not None:
            body["model"] = model
        if name is not None:
            body["name"] = name
        if pass_threshold is not None:
            body["pass_threshold"] = pass_threshold
        if prompt is not None:
            body["prompt"] = prompt
        if requirements is not None:
            body["requirements"] = requirements
        if source is not None:
            body["source"] = source
        return self._client.post("/api/v1/evaluators", json=body, headers=extra_headers)

    def retrieve(
        self, evaluator: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> dict[str, Any]:
        """
        Get an evaluator

        Fetch a single evaluator by id or name within the authenticated project.

        Args:
            evaluator: The evaluator.
        """
        return self._client.get(
            f"/api/v1/evaluators/{evaluator}", headers=extra_headers
        )

    def update(
        self,
        evaluator: str,
        *,
        api: str | None = None,
        container: str | None = None,
        description: str | None = None,
        inference_parameters: dict[str, Any] | None = None,
        metadata: dict[str, Any] | None = None,
        model: str | None = None,
        name: str | None = None,
        pass_threshold: float | None = None,
        prompt: str | None = None,
        requirements: list[str] | None = None,
        source: str | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> dict[str, Any]:
        """
        Update an evaluator

        Update an existing evaluator by id or name.

        Args:
            evaluator: The evaluator.
            api: API type.
            container: Container label.
            description: Evaluator description.
            inference_parameters: Optional inference parameters for judge evaluators (e.g. ...
            metadata: Optional metadata.
            model: Judge model slug.
            name: Evaluator name.
            pass_threshold: Optional pass threshold.
            prompt: Judge prompt.
            requirements: Optional requirements list.
            source: Code evaluator source.
        """
        body: dict[str, Any] = {}
        if api is not None:
            body["api"] = api
        if container is not None:
            body["container"] = container
        if description is not None:
            body["description"] = description
        if inference_parameters is not None:
            body["inference_parameters"] = inference_parameters
        if metadata is not None:
            body["metadata"] = metadata
        if model is not None:
            body["model"] = model
        if name is not None:
            body["name"] = name
        if pass_threshold is not None:
            body["pass_threshold"] = pass_threshold
        if prompt is not None:
            body["prompt"] = prompt
        if requirements is not None:
            body["requirements"] = requirements
        if source is not None:
            body["source"] = source
        return self._client.patch(
            f"/api/v1/evaluators/{evaluator}", json=body, headers=extra_headers
        )

    def delete(
        self, evaluator_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> EvaluatorDeleteResponse:
        """
        Delete an evaluator

        Delete an evaluator by id.

        Args:
            evaluator_id: The evaluator_id.
        """
        return self._client.delete(
            f"/api/v1/evaluators/{evaluator_id}", headers=extra_headers
        )


class SyncFilesResource:
    """files resource (sync)."""

    def __init__(self, client: SyncAPIClient) -> None:
        self._client = client

    def list(
        self,
        purpose: str | None = None,
        limit: int = 100,
        offset: int = 0,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> FileList:
        """
        List files (OpenAI-compatible)

        List files owned by the authenticated project, optionally filtered by purpose.

        Args:
            purpose: Filter by purpose
            limit: Max number of files.
            offset: Number of files to skip.
        """
        params: dict[str, Any] = {}
        if purpose is not None:
            params["purpose"] = purpose
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        return self._client.get("/api/v1/files", params=params, headers=extra_headers)

    def create(
        self,
        file: BinaryIO | Path | str,
        purpose: str,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> FileObject:
        """
        Upload a file

        Upload a file to the platform. This endpoint accepts a file and a purpose, and uploads the file to the platform, for later use in training or evaluation.
        """
        if isinstance(file, (str, Path)):
            file = open(file, "rb")
            should_close = True
        else:
            should_close = False

        try:
            filename = getattr(file, "name", "file")
            if isinstance(filename, (str, Path)):
                filename = Path(filename).name

            data: dict[str, Any] = {"purpose": purpose}
            files = {"file": (filename, file)}
            return self._client.post(
                "/api/v1/files", data=data, files=files, headers=extra_headers
            )
        finally:
            if should_close:
                file.close()

    def retrieve(
        self, file_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> FileObject:
        """
        Retrieve file metadata

        Fetch metadata for a single file by id within the authenticated project.

        Args:
            file_id: File id (UUID)
        """
        return self._client.get(f"/api/v1/files/{file_id}", headers=extra_headers)

    def delete(
        self, file_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> FileDeleteResponse:
        """
        Delete a file (OpenAI-compatible)

        Soft-delete a file by id within the authenticated project.

        Args:
            file_id: File id (UUID)
        """
        return self._client.delete(f"/api/v1/files/{file_id}", headers=extra_headers)

    def content(
        self, file_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> bytes:
        """
        Retrieve file content (OpenAI-compatible)

        Download the raw contents of a file by id within the authenticated project.

        Args:
            file_id: File id (UUID)
        """
        return self._client.get_raw(
            f"/api/v1/files/{file_id}/content", headers=extra_headers
        )


class SyncModelsResource:
    """models resource (sync)."""

    def __init__(self, client: SyncAPIClient) -> None:
        self._client = client

    def list(
        self,
        limit: int = 100,
        offset: int = 0,
        container: str | None = None,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> ModelList:
        """
        List available models

        List models available to the authenticated project. Optionally filter by container.

        Args:
            limit: Max number of models.
            offset: Number of models to skip.
            container: Container ID or label to filter models by.
        """
        params: dict[str, Any] = {}
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        if container is not None:
            params["container"] = container
        return self._client.get("/api/v1/models", params=params, headers=extra_headers)

    def add(
        self,
        *,
        container: str,
        model: str,
        slug: str,
        default_parameters: dict[str, Any] | None = None,
        default_system_prompt: str | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> ModelAddResponse:
        """
        Add a model to a container

        Attach a model to a container as a submodel with optional defaults.

        Args:
            container: Container id or label.
            model: Model slug to add.
            slug: User specified submodel slug.
            default_parameters: Default inference parameters.
            default_system_prompt: Default system prompt.
        """
        body: dict[str, Any] = {}
        body["container"] = container
        body["model"] = model
        body["slug"] = slug
        if default_parameters is not None:
            body["default_parameters"] = default_parameters
        if default_system_prompt is not None:
            body["default_system_prompt"] = default_system_prompt
        return self._client.post("/api/v1/models", json=body, headers=extra_headers)


class SyncOptimizationResource:
    """optimization resource (sync)."""

    def __init__(self, client: SyncAPIClient) -> None:
        self._client = client
        self.runs = SyncOptimizationRunsResource(client)


class SyncOptimizationRunsResource:
    """optimization.runs resource (sync)."""

    def __init__(self, client: SyncAPIClient) -> None:
        self._client = client

    def create(
        self,
        *,
        base_models: list[str],
        container: str,
        evals: list[str],
        methods: list[dict[str, Any] | dict[str, Any]],
        data_source: dict[str, Any] | None = None,
        environment: str | None = "main",
        metadata: dict[str, Any] | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> OptimizationRunCreateResponse:
        """
        Create an optimization run

        Create a new optimization run for a container using specified base models
        and evaluation criteria.

        Args:
            base_models: Base model ids or labels.
            container: Container id or label.
            evals: Evaluator ids or labels.
            methods: Optimization methods to run.
            data_source: Optional data source override.
            environment: Execution environment name.
            metadata: Optional metadata.
        """
        body: dict[str, Any] = {}
        body["base_models"] = base_models
        body["container"] = container
        body["evals"] = evals
        body["methods"] = methods
        if data_source is not None:
            body["data_source"] = data_source
        if environment is not None:
            body["environment"] = environment
        if metadata is not None:
            body["metadata"] = metadata
        return self._client.post(
            "/api/v1/optimization/runs", json=body, headers=extra_headers
        )


# =============================================================================
# ASYNC RESOURCES
# =============================================================================


class AsyncChatResource:
    """chat resource (async)."""

    def __init__(self, client: AsyncAPIClient) -> None:
        self._client = client
        self.completions = AsyncCompletionsResource(client)


class AsyncCompletionsResource:
    """chat.completions resource (async)."""

    def __init__(self, client: AsyncAPIClient) -> None:
        self._client = client

    async def list(
        self,
        limit: int = 20,
        offset: int = 0,
        model: str | None = None,
        container: str | None = None,
        order: str = "desc",
        metadata: dict[str, Any] | None = None,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> ChatCompletionList:
        """
        List chat completions

        List chat completions captured in telemetry, scoped to the authenticated project.

        Args:
            limit: The limit.
            offset: The offset.
            model: The model.
            container: The container.
            order: The order.
        """
        params: dict[str, Any] = {}
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        if model is not None:
            params["model"] = model
        if container is not None:
            params["container"] = container
        if order is not None:
            params["order"] = order
        if metadata:
            response = await self._client._request(
                "GET",
                "/api/v1/chat/completions",
                params=params,
                json=metadata,
                headers=extra_headers,
            )
            return response.json()
        return await self._client.get(
            "/api/v1/chat/completions", params=params, headers=extra_headers
        )

    async def create(
        self,
        *,
        messages: list[dict[str, Any]],
        frequency_penalty: float | None = None,
        logit_bias: dict[str, Any] | None = None,
        logprobs: bool | None = None,
        max_completion_tokens: float | None = None,
        max_tokens: float | None = None,
        metadata: dict[str, Any] | None = None,
        model: str | None = None,
        models: list[str] | None = None,
        presence_penalty: float | None = None,
        reasoning: dict[str, Any] | None = None,
        response_format: dict[str, Any] | None = None,
        seed: int | None = None,
        stop: str | None = None,
        store: bool | None = True,
        stream: bool | None = False,
        stream_options: dict[str, Any] | None = None,
        tags: list[str] | None = None,
        temperature: float | None = None,
        tool_choice: str | None = None,
        tools: list[dict[str, Any]] | None = None,
        top_logprobs: float | None = None,
        top_p: float | None = None,
        extra_headers: Mapping[str, str] | None = None,
        **kwargs: Any,
    ) -> ChatCompletion | AsyncGenerator[str, None]:
        """
        Create a chat completion

        Create a chat completion using the specified model.

        Supports both streaming and non-streaming responses and is compatible with
        OpenAI's chat completions API. Use a container slug (`maniac:<container>`) or
        an external slug (e.g. `openai/gpt-4o`).

        Args:
            messages: Conversation messages.
            frequency_penalty: Frequency penalty.
            logit_bias: Logit bias.
            logprobs: Include logprobs.
            max_completion_tokens: Max completion tokens.
            max_tokens: Max tokens.
            metadata: Arbitrary key/value metadata to attach to the request.
            model: Model slug to use. Supports global slugs or project slugs...
            models: Fallback models.
            presence_penalty: Presence penalty.
            reasoning: Reasoning config.
            response_format: Response format.
            seed: Random seed.
            stop: Stop sequences.
            store: Whether to store the completion in the database.
            stream: Stream response.
            stream_options: Stream options.
            tags: Optional tags for tracking.
            temperature: Temperature.
            tool_choice: Tool choice.
            tools: Tools.
            top_logprobs: Top logprobs.
            top_p: Top p.
        """
        body: dict[str, Any] = {}
        body["messages"] = messages
        if frequency_penalty is not None:
            body["frequency_penalty"] = frequency_penalty
        if logit_bias is not None:
            body["logit_bias"] = logit_bias
        if logprobs is not None:
            body["logprobs"] = logprobs
        if max_completion_tokens is not None:
            body["max_completion_tokens"] = max_completion_tokens
        if max_tokens is not None:
            body["max_tokens"] = max_tokens
        if metadata is not None:
            body["metadata"] = metadata
        if model is not None:
            body["model"] = model
        if models is not None:
            body["models"] = models
        if presence_penalty is not None:
            body["presence_penalty"] = presence_penalty
        if reasoning is not None:
            body["reasoning"] = reasoning
        if response_format is not None:
            body["response_format"] = response_format
        if seed is not None:
            body["seed"] = seed
        if stop is not None:
            body["stop"] = stop
        if store is not None:
            body["store"] = store
        if stream is not None:
            body["stream"] = stream
        if stream_options is not None:
            body["stream_options"] = stream_options
        if tags is not None:
            body["tags"] = tags
        if temperature is not None:
            body["temperature"] = temperature
        if tool_choice is not None:
            body["tool_choice"] = tool_choice
        if tools is not None:
            body["tools"] = tools
        if top_logprobs is not None:
            body["top_logprobs"] = top_logprobs
        if top_p is not None:
            body["top_p"] = top_p
        body.update(kwargs)
        if body.get("stream"):
            return self._client.post_stream(
                "/api/v1/chat/completions", json=body, extra_headers=extra_headers
            )
        return await self._client.post(
            "/api/v1/chat/completions", json=body, headers=extra_headers
        )

    async def retrieve(
        self, completion_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> ChatCompletionRelaxed:
        """
        Get a chat completion

        Fetch a single chat completion by id within the authenticated project.

        Args:
            completion_id: The completion_id.
        """
        return await self._client.get(
            f"/api/v1/chat/completions/{completion_id}", headers=extra_headers
        )

    async def register(
        self,
        *,
        container: str,
        items: list[dict[str, Any]],
        extra_headers: Mapping[str, str] | None = None,
    ) -> RegisterResponse:
        """
        Register chat completion examples

        Register completed chat examples for evaluation and analytics.

        This endpoint accepts input/output pairs and stores them for later analysis,
        while aggregating usage metrics for reporting.

        Args:
            container: Container label to associate these examples with.
            items: List of chat input/output examples.
        """
        body: dict[str, Any] = {}
        body["container"] = container
        body["items"] = items
        return await self._client.post(
            "/api/v1/chat/completions/register", json=body, headers=extra_headers
        )


class AsyncContainersResource:
    """containers resource (async)."""

    def __init__(self, client: AsyncAPIClient) -> None:
        self._client = client

    async def list(
        self,
        limit: int = 20,
        offset: int = 0,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> ContainerList:
        """
        List containers

        List containers owned by the authenticated project.

        Args:
            limit: The limit.
            offset: The offset.
        """
        params: dict[str, Any] = {}
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        return await self._client.get(
            "/api/v1/containers", params=params, headers=extra_headers
        )

    async def create(
        self,
        *,
        initial_model: str,
        label: str,
        api: str = "chat.completions",
        default_parameters: dict[str, Any] | None = None,
        default_system_prompt: str | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> ContainerCreateResponse:
        """
        Create a container

        Create a new container. Containers represent one task in your codebase. Each container utilizes separate models, routing, and evaluations, and collects data separately.

        Args:
            initial_model: Initial model slug.
            label: Container label.
            api: API type.
            default_parameters: Default inference parameters.
            default_system_prompt: Default system prompt.
        """
        body: dict[str, Any] = {}
        body["initial_model"] = initial_model
        body["label"] = label
        if api is not None:
            body["api"] = api
        if default_parameters is not None:
            body["default_parameters"] = default_parameters
        if default_system_prompt is not None:
            body["default_system_prompt"] = default_system_prompt
        return await self._client.post(
            "/api/v1/containers", json=body, headers=extra_headers
        )

    async def retrieve(
        self, label: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> ContainerCreateResponse:
        """
        Get a container

        Fetch a single container by label within the authenticated project.

        Args:
            label: The label.
        """
        return await self._client.get(
            f"/api/v1/containers/{label}", headers=extra_headers
        )

    async def delete(
        self, label: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> ContainerDeleteResponse:
        """
        Delete a container

        Soft-delete a container by label within the authenticated project.

        Args:
            label: The label.
        """
        return await self._client.delete(
            f"/api/v1/containers/{label}", headers=extra_headers
        )


class AsyncDatasetsResource:
    """datasets resource (async)."""

    def __init__(self, client: AsyncAPIClient) -> None:
        self._client = client

    async def list(
        self,
        limit: int = 100,
        offset: int = 0,
        container: str | None = None,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> DatasetList:
        """
        List datasets

        List datasets owned by the authenticated project. Optionally filter by container.

        Args:
            limit: Max number of datasets.
            offset: Number of datasets to skip.
            container: Container ID or label to filter datasets by.
        """
        params: dict[str, Any] = {}
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        if container is not None:
            params["container"] = container
        return await self._client.get(
            "/api/v1/datasets", params=params, headers=extra_headers
        )

    async def create(
        self,
        *,
        container: str,
        name: str,
        size: int,
        description: str | None = None,
        filters: list[dict[str, Any]] | None = None,
        metadata: dict[str, Any] | None = None,
        tags: list[str] | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> DatasetCreateResponse:
        """
        Create a dataset

        Create a dataset for a container using telemetry filters.

        Args:
            container: Container id or label for source data.
            name: Dataset name.
            size: Requested dataset size.
            description: Dataset description.
            filters: Filter conditions.
            metadata: Arbitrary metadata.
            tags: Optional dataset tags.
        """
        body: dict[str, Any] = {}
        body["container"] = container
        body["name"] = name
        body["size"] = size
        if description is not None:
            body["description"] = description
        if filters is not None:
            body["filters"] = filters
        if metadata is not None:
            body["metadata"] = metadata
        if tags is not None:
            body["tags"] = tags
        return await self._client.post(
            "/api/v1/datasets", json=body, headers=extra_headers
        )

    async def retrieve(
        self, dataset_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> Dataset:
        """
        Get a dataset

        Fetch a dataset by id within the authenticated project.

        Args:
            dataset_id: The dataset_id.
        """
        return await self._client.get(
            f"/api/v1/datasets/{dataset_id}", headers=extra_headers
        )


class AsyncEvaluationResource:
    """evaluation resource (async)."""

    def __init__(self, client: AsyncAPIClient) -> None:
        self._client = client
        self.runs = AsyncEvaluationRunsResource(client)


class AsyncEvaluationRunsResource:
    """evaluation.runs resource (async)."""

    def __init__(self, client: AsyncAPIClient) -> None:
        self._client = client

    async def list(
        self,
        container: str | None = None,
        status: str | None = None,
        limit: int = 20,
        offset: int = 0,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> EvaluationRunList:
        """
        List evaluation runs

        List evaluation runs for the authenticated project. Optionally filter by container and status.

        Args:
            container: Container ID or label to filter by.
            status: Filter by run status (e.g. 'running', 'completed', 'error').
            limit: The limit.
            offset: The offset.
        """
        params: dict[str, Any] = {}
        if container is not None:
            params["container"] = container
        if status is not None:
            params["status"] = status
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        return await self._client.get(
            "/api/v1/evaluation/runs", params=params, headers=extra_headers
        )

    async def create(
        self,
        *,
        container: str,
        evaluators: list[str],
        environment: str | None = "main",
        ground_truth: dict[str, Any] | None = None,
        metadata: dict[str, Any] | None = None,
        sample: dict[str, Any] | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> EvaluationRun:
        """
        Create an evaluation run

        Launch a standalone evaluation run. Validates access to the specified container, evaluators, data sources, and models, then dispatches the evaluation to the Modal backend.

        Args:
            container: Container id or label.
            evaluators: Evaluator ids or labels.
            environment: Execution environment name (maps to Modal app suffix).
            ground_truth: Ground-truth-side data source. Omit to default to the con...
            metadata: Optional metadata.
            sample: Sample-side data source. Omit to default to the container...
        """
        body: dict[str, Any] = {}
        body["container"] = container
        body["evaluators"] = evaluators
        if environment is not None:
            body["environment"] = environment
        if ground_truth is not None:
            body["ground_truth"] = ground_truth
        if metadata is not None:
            body["metadata"] = metadata
        if sample is not None:
            body["sample"] = sample
        return await self._client.post(
            "/api/v1/evaluation/runs", json=body, headers=extra_headers
        )

    async def retrieve(
        self, run_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> EvaluationRun:
        """
        Get an evaluation run

        Retrieve a single evaluation run by ID within the authenticated project.

        Args:
            run_id: The run_id.
        """
        return await self._client.get(
            f"/api/v1/evaluation/runs/{run_id}", headers=extra_headers
        )


class AsyncEvaluatorsResource:
    """evaluators resource (async)."""

    def __init__(self, client: AsyncAPIClient) -> None:
        self._client = client

    async def list(
        self,
        container: str | None = None,
        limit: int = 20,
        offset: int = 0,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> EvaluatorList:
        """
        List evaluators

        List evaluators for the authenticated project, optionally filtered by container.

        Args:
            container: The container.
            limit: The limit.
            offset: The offset.
        """
        params: dict[str, Any] = {}
        if container is not None:
            params["container"] = container
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        return await self._client.get(
            "/api/v1/evaluators", params=params, headers=extra_headers
        )

    async def create(
        self,
        *,
        type: str,
        api: str | None = None,
        container: str | None = None,
        description: str | None = None,
        inference_parameters: dict[str, Any] | None = None,
        metadata: dict[str, Any] | None = None,
        model: str | None = None,
        name: str | None = None,
        pass_threshold: float | None = None,
        prompt: str | None = None,
        requirements: list[str] | None = None,
        source: str | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> dict[str, Any]:
        """
        Create an evaluator

        Create a new evaluator scoped to a project or container.

        Args:
            type: Evaluator type.
            api: API type.
            container: Container label.
            description: Evaluator description.
            inference_parameters: Optional inference parameters for judge evaluators (e.g. ...
            metadata: Optional metadata.
            model: Judge model slug.
            name: Evaluator name.
            pass_threshold: Optional pass threshold.
            prompt: Judge prompt.
            requirements: Optional requirements list.
            source: Code evaluator source.
        """
        body: dict[str, Any] = {}
        body["type"] = type
        if api is not None:
            body["api"] = api
        if container is not None:
            body["container"] = container
        if description is not None:
            body["description"] = description
        if inference_parameters is not None:
            body["inference_parameters"] = inference_parameters
        if metadata is not None:
            body["metadata"] = metadata
        if model is not None:
            body["model"] = model
        if name is not None:
            body["name"] = name
        if pass_threshold is not None:
            body["pass_threshold"] = pass_threshold
        if prompt is not None:
            body["prompt"] = prompt
        if requirements is not None:
            body["requirements"] = requirements
        if source is not None:
            body["source"] = source
        return await self._client.post(
            "/api/v1/evaluators", json=body, headers=extra_headers
        )

    async def retrieve(
        self, evaluator: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> dict[str, Any]:
        """
        Get an evaluator

        Fetch a single evaluator by id or name within the authenticated project.

        Args:
            evaluator: The evaluator.
        """
        return await self._client.get(
            f"/api/v1/evaluators/{evaluator}", headers=extra_headers
        )

    async def update(
        self,
        evaluator: str,
        *,
        api: str | None = None,
        container: str | None = None,
        description: str | None = None,
        inference_parameters: dict[str, Any] | None = None,
        metadata: dict[str, Any] | None = None,
        model: str | None = None,
        name: str | None = None,
        pass_threshold: float | None = None,
        prompt: str | None = None,
        requirements: list[str] | None = None,
        source: str | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> dict[str, Any]:
        """
        Update an evaluator

        Update an existing evaluator by id or name.

        Args:
            evaluator: The evaluator.
            api: API type.
            container: Container label.
            description: Evaluator description.
            inference_parameters: Optional inference parameters for judge evaluators (e.g. ...
            metadata: Optional metadata.
            model: Judge model slug.
            name: Evaluator name.
            pass_threshold: Optional pass threshold.
            prompt: Judge prompt.
            requirements: Optional requirements list.
            source: Code evaluator source.
        """
        body: dict[str, Any] = {}
        if api is not None:
            body["api"] = api
        if container is not None:
            body["container"] = container
        if description is not None:
            body["description"] = description
        if inference_parameters is not None:
            body["inference_parameters"] = inference_parameters
        if metadata is not None:
            body["metadata"] = metadata
        if model is not None:
            body["model"] = model
        if name is not None:
            body["name"] = name
        if pass_threshold is not None:
            body["pass_threshold"] = pass_threshold
        if prompt is not None:
            body["prompt"] = prompt
        if requirements is not None:
            body["requirements"] = requirements
        if source is not None:
            body["source"] = source
        return await self._client.patch(
            f"/api/v1/evaluators/{evaluator}", json=body, headers=extra_headers
        )

    async def delete(
        self, evaluator_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> EvaluatorDeleteResponse:
        """
        Delete an evaluator

        Delete an evaluator by id.

        Args:
            evaluator_id: The evaluator_id.
        """
        return await self._client.delete(
            f"/api/v1/evaluators/{evaluator_id}", headers=extra_headers
        )


class AsyncFilesResource:
    """files resource (async)."""

    def __init__(self, client: AsyncAPIClient) -> None:
        self._client = client

    async def list(
        self,
        purpose: str | None = None,
        limit: int = 100,
        offset: int = 0,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> FileList:
        """
        List files (OpenAI-compatible)

        List files owned by the authenticated project, optionally filtered by purpose.

        Args:
            purpose: Filter by purpose
            limit: Max number of files.
            offset: Number of files to skip.
        """
        params: dict[str, Any] = {}
        if purpose is not None:
            params["purpose"] = purpose
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        return await self._client.get(
            "/api/v1/files", params=params, headers=extra_headers
        )

    async def create(
        self,
        file: BinaryIO | Path | str,
        purpose: str,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> FileObject:
        """
        Upload a file

        Upload a file to the platform. This endpoint accepts a file and a purpose, and uploads the file to the platform, for later use in training or evaluation.
        """
        if isinstance(file, (str, Path)):
            file = open(file, "rb")
            should_close = True
        else:
            should_close = False

        try:
            filename = getattr(file, "name", "file")
            if isinstance(filename, (str, Path)):
                filename = Path(filename).name

            data: dict[str, Any] = {"purpose": purpose}
            files = {"file": (filename, file)}
            return await self._client.post(
                "/api/v1/files", data=data, files=files, headers=extra_headers
            )
        finally:
            if should_close:
                file.close()

    async def retrieve(
        self, file_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> FileObject:
        """
        Retrieve file metadata

        Fetch metadata for a single file by id within the authenticated project.

        Args:
            file_id: File id (UUID)
        """
        return await self._client.get(f"/api/v1/files/{file_id}", headers=extra_headers)

    async def delete(
        self, file_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> FileDeleteResponse:
        """
        Delete a file (OpenAI-compatible)

        Soft-delete a file by id within the authenticated project.

        Args:
            file_id: File id (UUID)
        """
        return await self._client.delete(
            f"/api/v1/files/{file_id}", headers=extra_headers
        )

    async def content(
        self, file_id: str, *, extra_headers: Mapping[str, str] | None = None
    ) -> bytes:
        """
        Retrieve file content (OpenAI-compatible)

        Download the raw contents of a file by id within the authenticated project.

        Args:
            file_id: File id (UUID)
        """
        return await self._client.get_raw(
            f"/api/v1/files/{file_id}/content", headers=extra_headers
        )


class AsyncModelsResource:
    """models resource (async)."""

    def __init__(self, client: AsyncAPIClient) -> None:
        self._client = client

    async def list(
        self,
        limit: int = 100,
        offset: int = 0,
        container: str | None = None,
        *,
        extra_headers: Mapping[str, str] | None = None,
    ) -> ModelList:
        """
        List available models

        List models available to the authenticated project. Optionally filter by container.

        Args:
            limit: Max number of models.
            offset: Number of models to skip.
            container: Container ID or label to filter models by.
        """
        params: dict[str, Any] = {}
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset
        if container is not None:
            params["container"] = container
        return await self._client.get(
            "/api/v1/models", params=params, headers=extra_headers
        )

    async def add(
        self,
        *,
        container: str,
        model: str,
        slug: str,
        default_parameters: dict[str, Any] | None = None,
        default_system_prompt: str | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> ModelAddResponse:
        """
        Add a model to a container

        Attach a model to a container as a submodel with optional defaults.

        Args:
            container: Container id or label.
            model: Model slug to add.
            slug: User specified submodel slug.
            default_parameters: Default inference parameters.
            default_system_prompt: Default system prompt.
        """
        body: dict[str, Any] = {}
        body["container"] = container
        body["model"] = model
        body["slug"] = slug
        if default_parameters is not None:
            body["default_parameters"] = default_parameters
        if default_system_prompt is not None:
            body["default_system_prompt"] = default_system_prompt
        return await self._client.post(
            "/api/v1/models", json=body, headers=extra_headers
        )


class AsyncOptimizationResource:
    """optimization resource (async)."""

    def __init__(self, client: AsyncAPIClient) -> None:
        self._client = client
        self.runs = AsyncOptimizationRunsResource(client)


class AsyncOptimizationRunsResource:
    """optimization.runs resource (async)."""

    def __init__(self, client: AsyncAPIClient) -> None:
        self._client = client

    async def create(
        self,
        *,
        base_models: list[str],
        container: str,
        evals: list[str],
        methods: list[dict[str, Any] | dict[str, Any]],
        data_source: dict[str, Any] | None = None,
        environment: str | None = "main",
        metadata: dict[str, Any] | None = None,
        extra_headers: Mapping[str, str] | None = None,
    ) -> OptimizationRunCreateResponse:
        """
        Create an optimization run

        Create a new optimization run for a container using specified base models
        and evaluation criteria.

        Args:
            base_models: Base model ids or labels.
            container: Container id or label.
            evals: Evaluator ids or labels.
            methods: Optimization methods to run.
            data_source: Optional data source override.
            environment: Execution environment name.
            metadata: Optional metadata.
        """
        body: dict[str, Any] = {}
        body["base_models"] = base_models
        body["container"] = container
        body["evals"] = evals
        body["methods"] = methods
        if data_source is not None:
            body["data_source"] = data_source
        if environment is not None:
            body["environment"] = environment
        if metadata is not None:
            body["metadata"] = metadata
        return await self._client.post(
            "/api/v1/optimization/runs", json=body, headers=extra_headers
        )
