from __future__ import annotations

"""
Generated API resources for Maniac SDK.

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

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

if TYPE_CHECKING:
    from ._base import SyncAPIClient, AsyncAPIClient


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


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

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

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

        Args:
            messages: List of messages in the conversation.
            model: Model slug (e.g. 'openai/gpt-4o' or 'maniac:my-model').
            stream: Whether to stream the response.
            temperature: Sampling temperature (0-2).
            max_tokens: Maximum tokens to generate.
            max_completion_tokens: Maximum completion tokens.
            top_p: Nucleus sampling parameter.
            frequency_penalty: Frequency penalty (-2 to 2).
            presence_penalty: Presence penalty (-2 to 2).
            stop: Stop sequences.
            tools: List of tool definitions.
            tool_choice: Tool choice configuration.
            response_format: Response format configuration.
            seed: Random seed for reproducibility.
            logprobs: Whether to return log probabilities.
            top_logprobs: Number of top log probabilities to return.
            metadata: Arbitrary metadata to attach.
            container: Container label for routing.
            tags: Tags for tracking.

        Returns:
            Chat completion response or stream generator.
        """
        body: dict[str, Any] = {"messages": messages}

        if model is not None:
            body["model"] = model
        if stream:
            body["stream"] = stream
        if temperature is not None:
            body["temperature"] = temperature
        if max_tokens is not None:
            body["max_tokens"] = max_tokens
        if max_completion_tokens is not None:
            body["max_completion_tokens"] = max_completion_tokens
        if top_p is not None:
            body["top_p"] = top_p
        if frequency_penalty is not None:
            body["frequency_penalty"] = frequency_penalty
        if presence_penalty is not None:
            body["presence_penalty"] = presence_penalty
        if stop is not None:
            body["stop"] = stop
        if tools is not None:
            body["tools"] = tools
        if tool_choice is not None:
            body["tool_choice"] = tool_choice
        if response_format is not None:
            body["response_format"] = response_format
        if seed is not None:
            body["seed"] = seed
        if logprobs is not None:
            body["logprobs"] = logprobs
        if top_logprobs is not None:
            body["top_logprobs"] = top_logprobs
        if metadata is not None:
            body["metadata"] = metadata
        if container is not None:
            body["container"] = container
        if tags is not None:
            body["tags"] = tags

        body.update(kwargs)

        if stream:
            return self._client.post_stream("/api/v1/chat/completions", json=body)
        return self._client.post("/api/v1/chat/completions", json=body)

    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,
    ) -> dict[str, Any]:
        """List chat completions from telemetry.

        Args:
            limit: Maximum number of results (1-100).
            offset: Number of results to skip.
            model: Filter by model.
            container: Filter by container.
            order: Sort order ('asc' or 'desc').
            metadata: Filter by metadata.
        """
        params: dict[str, Any] = {"limit": limit, "offset": offset, "order": order}
        if model is not None:
            params["model"] = model
        if container is not None:
            params["container"] = container

        # Note: metadata is passed in body for GET
        if metadata:
            return self._client._request(
                "GET", "/api/v1/chat/completions", params=params, json=metadata
            ).json()
        return self._client.get("/api/v1/chat/completions", params=params)

    def retrieve(self, completion_id: str) -> dict[str, Any]:
        """Get a single chat completion by ID.

        Args:
            completion_id: The completion ID.
        """
        return self._client.get(f"/api/v1/chat/completions/{completion_id}")

    def register(
        self,
        *,
        items: list[dict[str, Any]],
        container: str,
    ) -> dict[str, Any]:
        """Register chat completion examples for evaluation/analytics.

        Args:
            items: List of input/output example pairs.
            container: Container label to associate examples with.
        """
        return self._client.post(
            "/api/v1/chat/completions/register",
            json={"items": items, "container": container},
        )


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

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


class SyncContainerModelsResource:
    """containers.models resource (sync)."""

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

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

        Args:
            label: Container label.
            model: Model slug to add.
            slug: Submodel slug.
            default_parameters: Default inference parameters.
            default_system_prompt: Default system prompt.
        """
        body: dict[str, Any] = {
            "model": model,
            "container": label,
            "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(f"/api/v1/containers/{label}/models", json=body)


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

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

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

        Args:
            label: Container label.
            initial_model: Initial model slug.
            api: API type (default: 'chat.completions').
            default_parameters: Default inference parameters.
            default_system_prompt: Default system prompt.
        """
        body: dict[str, Any] = {
            "label": label,
            "initial_model": initial_model,
            "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)

    def list(self, *, limit: int = 20, offset: int = 0) -> dict[str, Any]:
        """List containers.

        Args:
            limit: Maximum number of results (1-100).
            offset: Number of results to skip.
        """
        return self._client.get(
            "/api/v1/containers", params={"limit": limit, "offset": offset}
        )

    def retrieve(self, label: str) -> dict[str, Any]:
        """Get a container by label.

        Args:
            label: Container label.
        """
        return self._client.get(f"/api/v1/containers/{label}")

    def delete(self, label: str) -> dict[str, Any]:
        """Delete a container.

        Args:
            label: Container label.
        """
        return self._client.delete(f"/api/v1/containers/{label}")


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

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

    def create(
        self,
        *,
        file: BinaryIO | Path | str,
        purpose: str,
    ) -> dict[str, Any]:
        """Upload a file.

        Args:
            file: File to upload (file object, Path, or path string).
            purpose: Purpose of the file (e.g. 'fine-tune', '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

            return self._client.post(
                "/api/v1/files",
                data={"purpose": purpose},
                files={"file": (filename, file)},
            )
        finally:
            if should_close:
                file.close()

    def list(
        self,
        *,
        purpose: str | None = None,
        limit: int = 100,
        offset: int = 0,
    ) -> dict[str, Any]:
        """List files.

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

    def retrieve(self, file_id: str) -> dict[str, Any]:
        """Get file metadata.

        Args:
            file_id: File ID.
        """
        return self._client.get(f"/api/v1/files/{file_id}")

    def content(self, file_id: str) -> bytes:
        """Download file content.

        Args:
            file_id: File ID.
        """
        return self._client.get_raw(f"/api/v1/files/{file_id}/content")

    def delete(self, file_id: str) -> dict[str, Any]:
        """Delete a file.

        Args:
            file_id: File ID.
        """
        return self._client.delete(f"/api/v1/files/{file_id}")


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 = None
    ) -> dict[str, Any]:
        """
        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)

    def add(
        self,
        *,
        container: str,
        model: str,
        slug: str,
        default_parameters: dict[str, Any] | None | None = None,
        default_system_prompt: str | None | None = None,
    ) -> dict[str, Any]:
        """
        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)


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

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

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

        Args:
            type: Evaluator type ('judge' or 'code').
            name: Evaluator name.
            description: Evaluator description.
            container: Container label.
            model: Judge model slug (for type='judge').
            prompt: Judge prompt (for type='judge').
            source: Source code (for type='code').
            requirements: Package requirements (for type='code').
            pass_threshold: Pass threshold.
            metadata: Optional metadata.
            api: API type.
        """
        body: dict[str, Any] = {"type": type}

        if name is not None:
            body["name"] = name
        if description is not None:
            body["description"] = description
        if container is not None:
            body["container"] = container
        if model is not None:
            body["model"] = model
        if prompt is not None:
            body["prompt"] = prompt
        if source is not None:
            body["source"] = source
        if requirements is not None:
            body["requirements"] = requirements
        if pass_threshold is not None:
            body["pass_threshold"] = pass_threshold
        if metadata is not None:
            body["metadata"] = metadata
        if api is not None:
            body["api"] = api

        return self._client.post("/api/v1/evaluators", json=body)

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

        Args:
            container: Filter by container.
            limit: Maximum number of results (1-100).
            offset: Number of results to skip.
        """
        params: dict[str, Any] = {"limit": limit, "offset": offset}
        if container is not None:
            params["container"] = container
        return self._client.get("/api/v1/evaluators", params=params)

    def retrieve(self, evaluator_id: str) -> dict[str, Any]:
        """Get an evaluator.

        Args:
            evaluator_id: Evaluator ID.
        """
        return self._client.get(f"/api/v1/evaluators/{evaluator_id}")

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

        Args:
            evaluator_id: Evaluator ID.
            name: Evaluator name.
            description: Evaluator description.
            container: Container label.
            model: Judge model slug.
            prompt: Judge prompt.
            source: Source code.
            requirements: Package requirements.
            pass_threshold: Pass threshold.
            metadata: Optional metadata.
            api: API type.
        """
        body: dict[str, Any] = {}

        if name is not None:
            body["name"] = name
        if description is not None:
            body["description"] = description
        if container is not None:
            body["container"] = container
        if model is not None:
            body["model"] = model
        if prompt is not None:
            body["prompt"] = prompt
        if source is not None:
            body["source"] = source
        if requirements is not None:
            body["requirements"] = requirements
        if pass_threshold is not None:
            body["pass_threshold"] = pass_threshold
        if metadata is not None:
            body["metadata"] = metadata
        if api is not None:
            body["api"] = api

        return self._client.patch(f"/api/v1/evaluators/{evaluator_id}", json=body)

    def delete(self, evaluator_id: str) -> dict[str, Any]:
        """Delete an evaluator.

        Args:
            evaluator_id: Evaluator ID.
        """
        return self._client.delete(f"/api/v1/evaluators/{evaluator_id}")


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

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

    def create(
        self,
        *,
        container: str,
        evaluators: list[str],
        environment: str | None = "main",
        ground_truth: (
            dict[str, Any] | dict[str, Any] | dict[str, Any] | None | None
        ) = None,
        metadata: dict[str, Any] | None | None = None,
        sample: dict[str, Any] | dict[str, Any] | dict[str, Any] | None | None = None,
    ) -> dict[str, Any]:
        """
        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)

    def list(
        self,
        container: str | None | None = None,
        status: str | None | None = None,
        limit: int = 20,
        offset: int = 0,
    ) -> dict[str, Any]:
        """
        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)

    def retrieve(self, run_id: str) -> dict[str, Any]:
        """Get an evaluation run.

        Args:
            run_id: Run ID.
        """
        return self._client.get(f"/api/v1/evaluation/runs/{run_id}")

    def cancel(self, run_id: str) -> dict[str, Any]:
        """Cancel an evaluation run.

        Args:
            run_id: Run ID.
        """
        return self._client.post(f"/api/v1/evaluation/runs/{run_id}/cancel")


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

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


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

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

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

        Args:
            name: Dataset name.
            container: Container label for source data.
            size: Requested dataset size.
            description: Dataset description.
            data_source: Optional data source override.
            filters: Filter conditions.
            model_filters: Model filter slugs.
            tags: Optional dataset tags.
            metadata: Arbitrary metadata.
        """
        body: dict[str, Any] = {
            "name": name,
            "container": container,
            "size": size,
        }

        if description is not None:
            body["description"] = description
        if data_source is not None:
            body["data_source"] = data_source
        if filters is not None:
            body["filters"] = filters
        if model_filters is not None:
            body["model_filters"] = model_filters
        if tags is not None:
            body["tags"] = tags
        if metadata is not None:
            body["metadata"] = metadata

        return self._client.post("/api/v1/datasets", json=body)

    def retrieve(self, dataset_id: str) -> dict[str, Any]:
        """Get a dataset.

        Args:
            dataset_id: Dataset ID.
        """
        return self._client.get(f"/api/v1/datasets/{dataset_id}")

    def list(
        self, limit: int = 100, offset: int = 0, container: str | None | None = None
    ) -> dict[str, Any]:
        """
        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)


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


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

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

    async def create(
        self,
        *,
        messages: list[dict[str, Any]],
        model: str | None = None,
        stream: bool = False,
        temperature: float | None = None,
        max_tokens: int | None = None,
        max_completion_tokens: int | None = None,
        top_p: float | None = None,
        frequency_penalty: float | None = None,
        presence_penalty: float | None = None,
        stop: str | list[str] | None = None,
        tools: list[dict[str, Any]] | None = None,
        tool_choice: Any | None = None,
        response_format: dict[str, Any] | None = None,
        seed: int | None = None,
        logprobs: bool | None = None,
        top_logprobs: int | None = None,
        metadata: dict[str, Any] | None = None,
        container: str | None = None,
        tags: list[str] | None = None,
        **kwargs: Any,
    ) -> dict[str, Any] | AsyncGenerator[str, None]:
        """Create a chat completion."""
        body: dict[str, Any] = {"messages": messages}

        if model is not None:
            body["model"] = model
        if stream:
            body["stream"] = stream
        if temperature is not None:
            body["temperature"] = temperature
        if max_tokens is not None:
            body["max_tokens"] = max_tokens
        if max_completion_tokens is not None:
            body["max_completion_tokens"] = max_completion_tokens
        if top_p is not None:
            body["top_p"] = top_p
        if frequency_penalty is not None:
            body["frequency_penalty"] = frequency_penalty
        if presence_penalty is not None:
            body["presence_penalty"] = presence_penalty
        if stop is not None:
            body["stop"] = stop
        if tools is not None:
            body["tools"] = tools
        if tool_choice is not None:
            body["tool_choice"] = tool_choice
        if response_format is not None:
            body["response_format"] = response_format
        if seed is not None:
            body["seed"] = seed
        if logprobs is not None:
            body["logprobs"] = logprobs
        if top_logprobs is not None:
            body["top_logprobs"] = top_logprobs
        if metadata is not None:
            body["metadata"] = metadata
        if container is not None:
            body["container"] = container
        if tags is not None:
            body["tags"] = tags

        body.update(kwargs)

        if stream:
            return self._client.post_stream("/api/v1/chat/completions", json=body)
        return await self._client.post("/api/v1/chat/completions", json=body)

    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,
    ) -> dict[str, Any]:
        """List chat completions from telemetry."""
        params: dict[str, Any] = {"limit": limit, "offset": offset, "order": order}
        if model is not None:
            params["model"] = model
        if container is not None:
            params["container"] = container

        if metadata:
            response = await self._client._request(
                "GET", "/api/v1/chat/completions", params=params, json=metadata
            )
            return response.json()
        return await self._client.get("/api/v1/chat/completions", params=params)

    async def retrieve(self, completion_id: str) -> dict[str, Any]:
        """Get a single chat completion by ID."""
        return await self._client.get(f"/api/v1/chat/completions/{completion_id}")

    async def register(
        self,
        *,
        items: list[dict[str, Any]],
        container: str,
    ) -> dict[str, Any]:
        """Register chat completion examples for evaluation/analytics."""
        return await self._client.post(
            "/api/v1/chat/completions/register",
            json={"items": items, "container": container},
        )


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

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


class AsyncContainerModelsResource:
    """containers.models resource (async)."""

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

    async def add(
        self,
        label: str,
        *,
        model: str,
        slug: str,
        default_parameters: dict[str, Any] | None = None,
        default_system_prompt: str | None = None,
    ) -> dict[str, Any]:
        """Add a model to a container."""
        body: dict[str, Any] = {
            "model": model,
            "container": label,
            "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(f"/api/v1/containers/{label}/models", json=body)


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

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

    async def create(
        self,
        *,
        label: str,
        initial_model: str,
        api: str = "chat.completions",
        default_parameters: dict[str, Any] | None = None,
        default_system_prompt: str | None = None,
    ) -> dict[str, Any]:
        """Create a new container."""
        body: dict[str, Any] = {
            "label": label,
            "initial_model": initial_model,
            "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)

    async def list(self, *, limit: int = 20, offset: int = 0) -> dict[str, Any]:
        """List containers."""
        return await self._client.get(
            "/api/v1/containers", params={"limit": limit, "offset": offset}
        )

    async def retrieve(self, label: str) -> dict[str, Any]:
        """Get a container by label."""
        return await self._client.get(f"/api/v1/containers/{label}")

    async def delete(self, label: str) -> dict[str, Any]:
        """Delete a container."""
        return await self._client.delete(f"/api/v1/containers/{label}")


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

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

    async def create(
        self,
        *,
        file: BinaryIO | Path | str,
        purpose: str,
    ) -> dict[str, Any]:
        """Upload a file."""
        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

            return await self._client.post(
                "/api/v1/files",
                data={"purpose": purpose},
                files={"file": (filename, file)},
            )
        finally:
            if should_close:
                file.close()

    async def list(
        self,
        *,
        purpose: str | None = None,
        limit: int = 100,
        offset: int = 0,
    ) -> dict[str, Any]:
        """List files."""
        params: dict[str, Any] = {"limit": limit, "offset": offset}
        if purpose is not None:
            params["purpose"] = purpose
        return await self._client.get("/api/v1/files", params=params)

    async def retrieve(self, file_id: str) -> dict[str, Any]:
        """Get file metadata."""
        return await self._client.get(f"/api/v1/files/{file_id}")

    async def content(self, file_id: str) -> bytes:
        """Download file content."""
        return await self._client.get_raw(f"/api/v1/files/{file_id}/content")

    async def delete(self, file_id: str) -> dict[str, Any]:
        """Delete a file."""
        return await self._client.delete(f"/api/v1/files/{file_id}")


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 = None
    ) -> dict[str, Any]:
        """
        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)

    async def add(
        self,
        *,
        container: str,
        model: str,
        slug: str,
        default_parameters: dict[str, Any] | None | None = None,
        default_system_prompt: str | None | None = None,
    ) -> dict[str, Any]:
        """
        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)


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

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

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

        if name is not None:
            body["name"] = name
        if description is not None:
            body["description"] = description
        if container is not None:
            body["container"] = container
        if model is not None:
            body["model"] = model
        if prompt is not None:
            body["prompt"] = prompt
        if source is not None:
            body["source"] = source
        if requirements is not None:
            body["requirements"] = requirements
        if pass_threshold is not None:
            body["pass_threshold"] = pass_threshold
        if metadata is not None:
            body["metadata"] = metadata
        if api is not None:
            body["api"] = api

        return await self._client.post("/api/v1/evaluators", json=body)

    async def list(
        self,
        *,
        container: str | None = None,
        limit: int = 20,
        offset: int = 0,
    ) -> dict[str, Any]:
        """List evaluators."""
        params: dict[str, Any] = {"limit": limit, "offset": offset}
        if container is not None:
            params["container"] = container
        return await self._client.get("/api/v1/evaluators", params=params)

    async def retrieve(self, evaluator_id: str) -> dict[str, Any]:
        """Get an evaluator."""
        return await self._client.get(f"/api/v1/evaluators/{evaluator_id}")

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

        if name is not None:
            body["name"] = name
        if description is not None:
            body["description"] = description
        if container is not None:
            body["container"] = container
        if model is not None:
            body["model"] = model
        if prompt is not None:
            body["prompt"] = prompt
        if source is not None:
            body["source"] = source
        if requirements is not None:
            body["requirements"] = requirements
        if pass_threshold is not None:
            body["pass_threshold"] = pass_threshold
        if metadata is not None:
            body["metadata"] = metadata
        if api is not None:
            body["api"] = api

        return await self._client.patch(f"/api/v1/evaluators/{evaluator_id}", json=body)

    async def delete(self, evaluator_id: str) -> dict[str, Any]:
        """Delete an evaluator."""
        return await self._client.delete(f"/api/v1/evaluators/{evaluator_id}")


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

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

    async def create(
        self,
        *,
        container: str,
        evaluators: list[str],
        environment: str | None = "main",
        ground_truth: (
            dict[str, Any] | dict[str, Any] | dict[str, Any] | None | None
        ) = None,
        metadata: dict[str, Any] | None | None = None,
        sample: dict[str, Any] | dict[str, Any] | dict[str, Any] | None | None = None,
    ) -> dict[str, Any]:
        """
        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)

    async def list(
        self,
        container: str | None | None = None,
        status: str | None | None = None,
        limit: int = 20,
        offset: int = 0,
    ) -> dict[str, Any]:
        """
        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)

    async def retrieve(self, run_id: str) -> dict[str, Any]:
        """Get an evaluation run."""
        return await self._client.get(f"/api/v1/evaluation/runs/{run_id}")

    async def cancel(self, run_id: str) -> dict[str, Any]:
        """Cancel an evaluation run."""
        return await self._client.post(f"/api/v1/evaluation/runs/{run_id}/cancel")


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

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


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

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

    async def create(
        self,
        *,
        name: str,
        container: str,
        size: int,
        description: str | None = None,
        data_source: str | None = None,
        filters: list[dict[str, Any]] | None = None,
        model_filters: list[str] | None = None,
        tags: list[str] | None = None,
        metadata: dict[str, Any] | None = None,
    ) -> dict[str, Any]:
        """Create a dataset."""
        body: dict[str, Any] = {
            "name": name,
            "container": container,
            "size": size,
        }

        if description is not None:
            body["description"] = description
        if data_source is not None:
            body["data_source"] = data_source
        if filters is not None:
            body["filters"] = filters
        if model_filters is not None:
            body["model_filters"] = model_filters
        if tags is not None:
            body["tags"] = tags
        if metadata is not None:
            body["metadata"] = metadata

        return await self._client.post("/api/v1/datasets", json=body)

    async def retrieve(self, dataset_id: str) -> dict[str, Any]:
        """Get a dataset."""
        return await self._client.get(f"/api/v1/datasets/{dataset_id}")

    async def list(
        self, limit: int = 100, offset: int = 0, container: str | None | None = None
    ) -> dict[str, Any]:
        """
        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)


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: str | None | None = None,
        environment: str | None = "main",
        metadata: dict[str, Any] | None | None = None,
    ) -> dict[str, Any]:
        """
        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)


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

    def __init__(self, client: SyncAPIClient) -> None:
        self._client = client
        self.runs = SyncOptimizationRunsResource(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: str | None | None = None,
        environment: str | None = "main",
        metadata: dict[str, Any] | None | None = None,
    ) -> dict[str, Any]:
        """
        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)


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

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