"""Arcade Starter Tools for Exa

DO NOT EDIT THIS MODULE DIRECTLY.

THIS MODULE WAS AUTO-GENERATED BY TRANSPILING THE API STARTER TOOL JSON DEFINITIONS
IN THE ../wrapper_tools DIRECTORY INTO PYTHON CODE. ANY CHANGES TO THIS MODULE WILL
BE OVERWRITTEN BY THE TRANSPILER.
"""

import asyncio
import json
from enum import Enum
from typing import Annotated, Any

import httpx
import jsonschema
from arcade_tdk import ToolContext, tool
from arcade_tdk.errors import RetryableToolError

from .request_body_schemas import REQUEST_BODY_SCHEMAS

# Retry configuration
INITIAL_RETRY_DELAY = 0.5  # seconds

HTTP_CLIENT = httpx.AsyncClient(
    timeout=httpx.Timeout(60.0, connect=10.0),
    limits=httpx.Limits(max_keepalive_connections=20, max_connections=100),
    transport=httpx.AsyncHTTPTransport(retries=3),
    http2=True,
    follow_redirects=True,
)


class ToolMode(str, Enum):
    """Mode for tools with complex request bodies."""

    GET_REQUEST_SCHEMA = "get_request_schema"
    EXECUTE = "execute"


def remove_none_values(data: dict[str, Any]) -> dict[str, Any]:
    return {k: v for k, v in data.items() if v is not None}


async def make_request(
    url: str,
    method: str,
    params: dict[str, Any] | None = None,
    headers: dict[str, Any] | None = None,
    content: str | None = None,
    data: dict[str, Any] | None = None,
    auth: tuple[str, str] | None = None,
    max_retries: int = 3,
) -> httpx.Response:
    """Make an HTTP request with retry logic for 5xx server errors."""
    for attempt in range(max_retries):
        try:
            response = await HTTP_CLIENT.request(
                url=url,
                auth=auth,
                method=method,
                params=params,
                headers=headers,
                content=content,
            )
            response.raise_for_status()
        except httpx.HTTPStatusError as e:
            # Only retry on 5xx server errors
            if e.response.status_code >= 500 and attempt < max_retries - 1:
                # Exponential backoff: 0.5s, 1s, 2s
                await asyncio.sleep(INITIAL_RETRY_DELAY * (2**attempt))
                continue
            # Re-raise for 4xx errors or if max retries reached
            raise
        except httpx.RequestError:
            # Don't retry request errors (network issues are handled by transport)
            raise
        else:
            return response

    # This should never be reached, but satisfies type checker
    raise httpx.RequestError("Max retries exceeded")  # noqa: TRY003


async def make_request_with_schema_validation(
    url: str,
    method: str,
    request_data: dict[str, Any],
    schema: dict[str, Any] | str,
    auth: tuple[str, str] | None = None,
    params: dict[str, Any] | None = None,
    headers: dict[str, Any] | None = None,
    max_retries: int = 3,
) -> httpx.Response:
    """Make an HTTP request with schema validation on format errors."""
    # Parse schema if it's a string, skip validation if parsing fails
    parsed_schema = None
    if isinstance(schema, str):
        try:
            parsed_schema = json.loads(schema)
        except Exception:
            # If schema parsing fails, just skip validation
            parsed_schema = None
    else:
        parsed_schema = schema

    try:
        response = await make_request(
            url=url,
            auth=auth,
            method=method,
            params=params,
            headers=headers,
            content=json.dumps(request_data),
            max_retries=max_retries,
        )
    except httpx.HTTPStatusError as e:
        # Only provide schema validation for format-related errors
        if e.response.status_code in (400, 422):
            api_error_details = f"API returned {e.response.status_code}: {e.response.text}"

            # Only run validation if we have a valid parsed schema
            if parsed_schema is not None:
                # Run validation to provide additional context
                is_valid, validation_error = validate_json_against_schema(
                    request_data, parsed_schema
                )

                if not is_valid:
                    # Schema validation found issues - additional context
                    additional_context = (
                        f"{api_error_details}\n\n"
                        f"Schema validation found the following issues:\n"
                        f"{validation_error}"
                    )
                else:
                    # Schema validation passed - just show API error
                    additional_context = api_error_details
            else:
                # No valid schema - just show API error
                additional_context = api_error_details

            raise RetryableToolError(
                message=(f"API request failed with validation error: {e.response.status_code}"),
                developer_message=api_error_details,
                additional_prompt_content=additional_context,
            ) from e
        else:
            # For non-validation errors, re-raise as-is
            raise
    else:
        return response


def validate_json_against_schema(
    json_data: dict[str, Any], schema: dict[str, Any]
) -> tuple[bool, str | None]:
    """Validate JSON data against an OpenAPI/JSON Schema.

    This provides full JSON Schema Draft 7 validation including:
    - Required fields, types, enums
    - Pattern validation (regex)
    - Format validation (email, uuid, date-time, etc.)
    - Min/max length and values
    - oneOf, anyOf, allOf
    - And all other JSON Schema features

    Args:
        json_data: The JSON data to validate
        schema: The JSON Schema to validate against

    Returns:
        Tuple of (is_valid, error_messages). If valid, error_messages is None.
        If invalid, error_messages contains all validation errors.
    """
    try:
        validator = jsonschema.Draft7Validator(
            schema, format_checker=jsonschema.Draft7Validator.FORMAT_CHECKER
        )
        # Collect ALL validation errors
        errors = list(validator.iter_errors(json_data))
        if errors:
            # Format all errors with their paths
            error_messages = []
            for error in errors:
                error_path = ".".join(str(p) for p in error.path) if error.path else "root"
                error_messages.append(f"{error.message} at {error_path}")
            # Join all errors with newlines
            return False, "\n".join(error_messages)
        else:
            return True, None
    except jsonschema.SchemaError as e:
        return False, f"Invalid schema: {e.message}"
    except Exception as e:
        return False, f"Validation error: {e!s}"


@tool(requires_secrets=["EXA_API_KEY"])
async def perform_exa_search(
    context: ToolContext,
    mode: Annotated[
        ToolMode,
        "Operation mode: 'get_request_schema' returns the OpenAPI spec "
        "for the request body, 'execute' performs the actual operation",
    ],
    request_body: Annotated[
        str | None,
        "Stringified JSON representing the request body. Required when "
        "mode is 'execute', ignored when mode is 'get_request_schema'",
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'search'."]:
    """Conduct a search using Exa and retrieve relevant results.

    This tool performs a search using the Exa prompt-engineered query system. It retrieves a list of relevant search results based on the query, with an optional feature to include content details.

    Note: Understanding the request schema is necessary to properly create
    the stringified JSON input object for execution.

    Modes:
    - GET_REQUEST_SCHEMA: Returns the schema. Only call if you don't
      already have it. Do NOT call repeatedly if you already received
      the schema.
    - EXECUTE: Performs the operation with the provided request body
      JSON.

    If you need the schema, call with mode='get_request_schema' ONCE, then execute.
    """  # noqa: E501
    if mode == ToolMode.GET_REQUEST_SCHEMA:
        return {
            "request_body_schema": REQUEST_BODY_SCHEMAS["PERFORMEXASEARCH"],
            "instructions": (
                "Use the request_body_schema to construct a valid JSON object. "
                "Once you have populated the object following the schema "
                "structure and requirements, call this tool again with "
                "mode='execute' and the stringified JSON as the "
                "request_body parameter. "
                "Do NOT call the schema mode again - you already have "
                "the schema now."
            ),
        }

    # Mode is EXECUTE - validate parameters

    # Validate request body is provided (not None or empty string)
    # Note: Empty objects like {} are allowed - schema validation will check if valid
    if request_body is None or request_body.strip() == "":
        raise RetryableToolError(
            message="Request body is required when mode is 'execute'",
            developer_message="The request_body parameter was null or empty string",
            additional_prompt_content=(
                "The request body is required to perform this operation. "
                "Use the schema below to construct a valid JSON object, "
                "then call this tool again in execute mode with the "
                "stringified JSON as the request_body parameter.\n\n"
                "Schema:\n\n```json\n" + REQUEST_BODY_SCHEMAS["PERFORMEXASEARCH"] + "\n```"
            ),
        )

    # Parse JSON
    try:
        request_data = json.loads(request_body)
    except json.JSONDecodeError as e:
        raise RetryableToolError(
            message=f"Invalid JSON in request body: {e!s}",
            developer_message=f"JSON parsing failed: {e!s}",
            additional_prompt_content=(
                f"The request body contains invalid JSON. Error: {e!s}\n\n"
                "Please provide a valid JSON string that matches the schema "
                "below, then call this tool again in execute mode.\n\n"
                "Schema:\n\n```json\n" + REQUEST_BODY_SCHEMAS["PERFORMEXASEARCH"] + "\n```"
            ),
        ) from e

    response = await make_request_with_schema_validation(
        url="https://api.exa.ai/search",
        method="POST",
        request_data=request_data,
        schema=REQUEST_BODY_SCHEMAS["PERFORMEXASEARCH"],
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def find_similar_links(
    context: ToolContext,
    mode: Annotated[
        ToolMode,
        "Operation mode: 'get_request_schema' returns the OpenAPI spec "
        "for the request body, 'execute' performs the actual operation",
    ],
    request_body: Annotated[
        str | None,
        "Stringified JSON representing the request body. Required when "
        "mode is 'execute', ignored when mode is 'get_request_schema'",
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'findSimilar'."]:
    """Find similar links to a given link.

    This tool finds links similar to the provided link and can optionally retrieve their contents. It should be called when a user needs to discover related web pages or resources.

    Note: Understanding the request schema is necessary to properly create
    the stringified JSON input object for execution.

    Modes:
    - GET_REQUEST_SCHEMA: Returns the schema. Only call if you don't
      already have it. Do NOT call repeatedly if you already received
      the schema.
    - EXECUTE: Performs the operation with the provided request body
      JSON.

    If you need the schema, call with mode='get_request_schema' ONCE, then execute.
    """  # noqa: E501
    if mode == ToolMode.GET_REQUEST_SCHEMA:
        return {
            "request_body_schema": REQUEST_BODY_SCHEMAS["FINDSIMILARLINKS"],
            "instructions": (
                "Use the request_body_schema to construct a valid JSON object. "
                "Once you have populated the object following the schema "
                "structure and requirements, call this tool again with "
                "mode='execute' and the stringified JSON as the "
                "request_body parameter. "
                "Do NOT call the schema mode again - you already have "
                "the schema now."
            ),
        }

    # Mode is EXECUTE - validate parameters

    # Validate request body is provided (not None or empty string)
    # Note: Empty objects like {} are allowed - schema validation will check if valid
    if request_body is None or request_body.strip() == "":
        raise RetryableToolError(
            message="Request body is required when mode is 'execute'",
            developer_message="The request_body parameter was null or empty string",
            additional_prompt_content=(
                "The request body is required to perform this operation. "
                "Use the schema below to construct a valid JSON object, "
                "then call this tool again in execute mode with the "
                "stringified JSON as the request_body parameter.\n\n"
                "Schema:\n\n```json\n" + REQUEST_BODY_SCHEMAS["FINDSIMILARLINKS"] + "\n```"
            ),
        )

    # Parse JSON
    try:
        request_data = json.loads(request_body)
    except json.JSONDecodeError as e:
        raise RetryableToolError(
            message=f"Invalid JSON in request body: {e!s}",
            developer_message=f"JSON parsing failed: {e!s}",
            additional_prompt_content=(
                f"The request body contains invalid JSON. Error: {e!s}\n\n"
                "Please provide a valid JSON string that matches the schema "
                "below, then call this tool again in execute mode.\n\n"
                "Schema:\n\n```json\n" + REQUEST_BODY_SCHEMAS["FINDSIMILARLINKS"] + "\n```"
            ),
        ) from e

    response = await make_request_with_schema_validation(
        url="https://api.exa.ai/findSimilar",
        method="POST",
        request_data=request_data,
        schema=REQUEST_BODY_SCHEMAS["FINDSIMILARLINKS"],
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def get_content_details(
    context: ToolContext,
    mode: Annotated[
        ToolMode,
        "Operation mode: 'get_request_schema' returns the OpenAPI spec "
        "for the request body, 'execute' performs the actual operation",
    ],
    request_body: Annotated[
        str | None,
        "Stringified JSON representing the request body. Required when "
        "mode is 'execute', ignored when mode is 'get_request_schema'",
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'getContents'."]:
    """Retrieve details about specific content.

    Use this tool to retrieve detailed information about specific content from the EXA service. It should be called when content details are needed for further processing or display.

    Note: Understanding the request schema is necessary to properly create
    the stringified JSON input object for execution.

    Modes:
    - GET_REQUEST_SCHEMA: Returns the schema. Only call if you don't
      already have it. Do NOT call repeatedly if you already received
      the schema.
    - EXECUTE: Performs the operation with the provided request body
      JSON.

    If you need the schema, call with mode='get_request_schema' ONCE, then execute.
    """  # noqa: E501
    if mode == ToolMode.GET_REQUEST_SCHEMA:
        return {
            "request_body_schema": REQUEST_BODY_SCHEMAS["GETCONTENTDETAILS"],
            "instructions": (
                "Use the request_body_schema to construct a valid JSON object. "
                "Once you have populated the object following the schema "
                "structure and requirements, call this tool again with "
                "mode='execute' and the stringified JSON as the "
                "request_body parameter. "
                "Do NOT call the schema mode again - you already have "
                "the schema now."
            ),
        }

    # Mode is EXECUTE - validate parameters

    # Validate request body is provided (not None or empty string)
    # Note: Empty objects like {} are allowed - schema validation will check if valid
    if request_body is None or request_body.strip() == "":
        raise RetryableToolError(
            message="Request body is required when mode is 'execute'",
            developer_message="The request_body parameter was null or empty string",
            additional_prompt_content=(
                "The request body is required to perform this operation. "
                "Use the schema below to construct a valid JSON object, "
                "then call this tool again in execute mode with the "
                "stringified JSON as the request_body parameter.\n\n"
                "Schema:\n\n```json\n" + REQUEST_BODY_SCHEMAS["GETCONTENTDETAILS"] + "\n```"
            ),
        )

    # Parse JSON
    try:
        request_data = json.loads(request_body)
    except json.JSONDecodeError as e:
        raise RetryableToolError(
            message=f"Invalid JSON in request body: {e!s}",
            developer_message=f"JSON parsing failed: {e!s}",
            additional_prompt_content=(
                f"The request body contains invalid JSON. Error: {e!s}\n\n"
                "Please provide a valid JSON string that matches the schema "
                "below, then call this tool again in execute mode.\n\n"
                "Schema:\n\n```json\n" + REQUEST_BODY_SCHEMAS["GETCONTENTDETAILS"] + "\n```"
            ),
        ) from e

    response = await make_request_with_schema_validation(
        url="https://api.exa.ai/contents",
        method="POST",
        request_data=request_data,
        schema=REQUEST_BODY_SCHEMAS["GETCONTENTDETAILS"],
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def generate_answer_summary(
    context: ToolContext,
    search_query: Annotated[str, "The question or query to be answered or summarized."],
    enable_streaming_response: Annotated[
        bool | None, "Return the response as a server-sent events (SSE) stream if set to true."
    ] = False,
    include_full_text: Annotated[
        bool | None, "If true, the response includes full text content in the search results."
    ] = False,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'answer'."]:
    """Retrieve direct answers or detailed summaries with citations.

    Use this tool to perform a search based on a query. It generates either a direct answer or a detailed summary with citations, depending on the nature of the query."""  # noqa: E501
    request_data: Any = {
        "query": search_query,
        "stream": enable_streaming_response,
        "text": include_full_text,
    }
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/answer",
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def list_research_requests(
    context: ToolContext,
    pagination_cursor: Annotated[
        str | None,
        "A string representing the position in the paginated results to continue retrieving data from.",  # noqa: E501
    ] = None,
    results_limit: Annotated[
        float | None,
        "Specifies the number of research requests to return in the response. Helps manage pagination effectively.",  # noqa: E501
    ] = 10,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'ResearchController_listResearch'."]:
    """Retrieve a paginated list of research requests.

    Use this tool to obtain a paginated list of all research requests. Ideal for reviewing or analyzing current research queries."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/research/v1",
        method="GET",
        params=remove_none_values({"cursor": pagination_cursor, "limit": results_limit}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def create_research_request(
    context: ToolContext,
    research_request_details: Annotated[
        dict[str, str],
        "JSON object containing details of the research request including parameters and criteria.",
    ],
) -> Annotated[
    dict[str, Any], "Response from the API endpoint 'ResearchController_createResearch'."
]:
    """Create a new research request.

    Use this tool to initiate a new research request when you need to gather specific information or data."""  # noqa: E501
    request_data: Any = research_request_details
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/research/v1",
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def get_research_by_id(
    context: ToolContext,
    enable_streaming: Annotated[
        str, "Set to 'true' to receive real-time streaming updates of the research information."
    ],
    event_filter: Annotated[
        str,
        "Specify the events to filter for in the research retrieval. Accepts a comma-separated list of event types.",  # noqa: E501
    ],
    research_id: Annotated[
        str, "A string representing the unique identifier of the research to be retrieved."
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'ResearchController_getResearch'."]:
    """Retrieve research information using a specific ID.

    Use this tool to obtain detailed research information by providing a specific research ID. Supports real-time updates with streaming."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/research/v1/{researchId}".format(researchId=research_id),  # noqa: UP032
        method="GET",
        params=remove_none_values({"stream": enable_streaming, "events": event_filter}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def create_webset(
    context: ToolContext,
    webset_configuration: Annotated[
        dict[str, str],
        "A JSON object detailing optional search, import, and enrichment configurations for the Webset. Include any necessary identifiers like `externalId`.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-create'."]:
    """Create a new Webset with optional configurations.

    This tool creates a new Webset with optional search, import, and enrichment configurations. The Webset processing starts automatically once it's created. You can specify an `externalId` for easier integration with your own identifiers."""  # noqa: E501
    request_data: Any = webset_configuration
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets",
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def list_websets(
    context: ToolContext,
    pagination_cursor: Annotated[
        str | None, "A string used to paginate through the list of Websets."
    ] = None,
    websets_return_limit: Annotated[
        float | None, "Specify the maximum number of Websets to return in the response."
    ] = 25,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-list'."]:
    """Retrieve a list of available websets.

    Use this tool to obtain a list of websets. You can paginate through results using a cursor."""
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets",
        method="GET",
        params=remove_none_values({"cursor": pagination_cursor, "limit": websets_return_limit}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def get_webset_details(
    context: ToolContext,
    webset_identifier: Annotated[
        str, "The unique identifier or external ID for the Webset to retrieve."
    ],
    resources_to_expand: Annotated[
        list[str] | None, "A list of resources to include in the response for additional details."
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-get'."]:
    """Retrieve detailed information about a specific webset.

    This tool is used to obtain the details of a specific webset using its unique identifier. Call this when you need information related to a particular webset."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{id}".format(id=webset_identifier),  # noqa: UP032
        method="GET",
        params=remove_none_values({"expand": resources_to_expand}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def update_webset(
    context: ToolContext,
    webset_details: Annotated[
        dict[str, str],
        "A JSON object containing the details to update for the webset. This includes any attributes that need to be changed.",  # noqa: E501
    ],
    webset_id: Annotated[
        str,
        "The unique id or externalId of the Webset to be updated. Ensure it matches a valid Webset.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-update'."]:
    """Update details of an existing webset.

    Use this tool to update the information of a specific webset identified by its ID. Ideal for modifying webset attributes when changes are needed."""  # noqa: E501
    request_data: Any = webset_details
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{id}".format(id=webset_id),  # noqa: UP032
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def delete_webset(
    context: ToolContext,
    webset_identifier: Annotated[
        str, "The unique identifier or external ID of the Webset to delete."
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-delete'."]:
    """Deletes a Webset and its associated items.

    Use this tool to permanently delete a Webset and all its associated items. Once deleted, it cannot be recovered."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{id}".format(id=webset_identifier),  # noqa: UP032
        method="DELETE",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def cancel_webset_operations(
    context: ToolContext,
    webset_identifier: Annotated[
        str, "The ID or external ID of the Webset to cancel operations on."
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-cancel'."]:
    """Cancel all operations on a specified Webset.

    Use this tool to stop any ongoing enrichment or search processes on a Webset, marking it as 'idle'."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{id}/cancel".format(id=webset_identifier),  # noqa: UP032
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def preview_search_decomposition(
    context: ToolContext,
    search_query_details: Annotated[
        dict[str, str],
        "A JSON object detailing the search query to preview. It includes elements like the search string and any additional parameters for analysis.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-preview'."]:
    """Preview and analyze search query decomposition.

    This tool previews how a search query will be decomposed before creating a webset, showing the detected entity type, generated search criteria, and available enrichment columns. Use it to understand the search interpretation before full webset creation."""  # noqa: E501
    request_data: Any = search_query_details
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/preview",
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def get_webset_item(
    context: ToolContext,
    webset_identifier: Annotated[
        str,
        "The ID or external ID of the Webset to identify the desired Webset from which the item is to be retrieved.",  # noqa: E501
    ],
    webset_item_id: Annotated[str, "The unique identifier of the Webset item to retrieve."],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-items-get'."]:
    """Retrieve a specific Webset Item by ID.

    This tool is used to retrieve information about a specific Webset Item using its ID. It should be called when you need detailed information about a particular item associated with a Webset."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{webset}/items/{id}".format(  # noqa: UP032
            webset=webset_identifier, id=webset_item_id
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def delete_webset_item(
    context: ToolContext,
    webset_identifier: Annotated[
        str, "The ID or external ID of the Webset from which the item will be deleted."
    ],
    webset_item_id: Annotated[
        str, "The unique identifier of the item to be deleted from the webset."
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-items-delete'."]:
    """Delete an item from a webset and cancel its enrichment process.

    Use this tool to remove an item from the specified webset. This will also cancel any ongoing enrichment process associated with the item."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{webset}/items/{id}".format(  # noqa: UP032
            webset=webset_identifier, id=webset_item_id
        ),
        method="DELETE",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def list_webset_items(
    context: ToolContext,
    webset_identifier: Annotated[
        str, "The ID or external ID of the Webset to retrieve items from."
    ],
    pagination_cursor: Annotated[
        str | None,
        "A string used to paginate through the results. Pass this to retrieve the next set of items in the webset.",  # noqa: E501
    ] = None,
    result_limit: Annotated[
        float | None,
        "Specify the number of results to return. This controls the size of the page in a paginated response.",  # noqa: E501
    ] = 20,
    source_id: Annotated[
        str | None, "The unique identifier for the source from which to retrieve items."
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-items-list'."]:
    """Retrieve a list of items from a specific webset.

    This tool fetches items from a designated webset, allowing pagination with the 'cursor' parameter if needed."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{webset}/items".format(webset=webset_identifier),  # noqa: UP032
        method="GET",
        params=remove_none_values({
            "cursor": pagination_cursor,
            "limit": result_limit,
            "sourceId": source_id,
        }),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def create_webset_enrichment(
    context: ToolContext,
    enrichment_details: Annotated[
        dict[str, str],
        "A JSON object containing the details required to create the enrichment for the webset.",
    ],
    webset_identifier: Annotated[str, "The ID or external ID of the webset to enrich."],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-enrichments-create'."]:
    """Create an enrichment for a specified webset.

    This tool is used to create an enrichment for a given webset. It should be called when there is a need to enhance a webset with additional data or features."""  # noqa: E501
    request_data: Any = enrichment_details
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{webset}/enrichments".format(  # noqa: UP032
            webset=webset_identifier
        ),
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def update_webset_enrichment(
    context: ToolContext,
    enrichment_configuration_details: Annotated[
        dict[str, str],
        "A JSON object containing the details of the enrichment configuration to update.",
    ],
    enrichment_configuration_id: Annotated[
        str, "The unique identifier of the enrichment configuration to be updated."
    ],
    webset_identifier: Annotated[
        str,
        "The identifier of the webset to be updated. Provide the specific name or ID of the webset.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-enrichments-update'."]:
    """Update an enrichment configuration for a webset.

    This tool updates the enrichment configuration for a specified webset. It should be called when an existing enrichment configuration needs modification."""  # noqa: E501
    request_data: Any = enrichment_configuration_details
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{webset}/enrichments/{id}".format(  # noqa: UP032
            webset=webset_identifier, id=enrichment_configuration_id
        ),
        method="PATCH",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def get_enrichment_details(
    context: ToolContext,
    enrichment_id: Annotated[
        str,
        "The unique identifier for the specific enrichment you want to retrieve within the webset.",
    ],
    webset_identifier: Annotated[
        str, "The ID or external ID of the webset to retrieve enrichment details for."
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-enrichments-get'."]:
    """Retrieve detailed information about a specific enrichment.

    Use this tool to get detailed information about a specific enrichment in a webset by providing the webset and enrichment IDs."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{webset}/enrichments/{id}".format(  # noqa: UP032
            webset=webset_identifier, id=enrichment_id
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def delete_enrichment(
    context: ToolContext,
    enrichment_id: Annotated[str, "The unique identifier of the enrichment to be deleted."],
    webset_id: Annotated[
        str, "The ID or external ID of the Webset to identify which enrichment to delete."
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-enrichments-delete'."]:
    """Delete an enrichment and cancel running processes.

    Use this tool to delete an enrichment, cancel any running processes, and remove all generated enrichment results."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{webset}/enrichments/{id}".format(  # noqa: UP032
            webset=webset_id, id=enrichment_id
        ),
        method="DELETE",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def cancel_enrichment_process(
    context: ToolContext,
    enrichment_id: Annotated[
        str, "The unique identifier of the enrichment process to be canceled."
    ],
    webset_id: Annotated[
        str, "The ID or external ID of the Webset to identify which enrichment process to cancel."
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-enrichments-cancel'."]:
    """Cancel a running enrichment process.

    Use this tool to cancel any currently running enrichment process. Once canceled, the process cannot be resumed."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{webset}/enrichments/{id}/cancel".format(  # noqa: UP032
            webset=webset_id, id=enrichment_id
        ),
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def create_webhook_for_notifications(
    context: ToolContext,
    webhook_configuration: Annotated[
        dict[str, str],
        "A JSON object detailing the events to monitor and the destination URL for notifications.",
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'webhooks-create'."]:
    """Create webhooks to receive event notifications.

    This tool allows you to set up webhooks for receiving notifications about specific events in your Websets. Upon creation, you'll specify the events to monitor and the destination URL for the notifications. The webhook activates immediately, and you'll receive a secret key for signature verification, visible only once at this point."""  # noqa: E501
    request_data: Any = webhook_configuration
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/webhooks",
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def get_webhooks_list(
    context: ToolContext,
    pagination_cursor: Annotated[
        str | None, "The cursor used to navigate through pages of results for webhooks."
    ] = None,
    results_per_page: Annotated[
        float | None, "The number of webhooks to return per page, up to a maximum of 200."
    ] = 25,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'webhooks-list'."]:
    """Retrieve a paginated list of all webhooks in your account.

    Use this tool to get all the webhooks associated with your account, with options to paginate through results using limit and cursor parameters."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/webhooks",
        method="GET",
        params=remove_none_values({"cursor": pagination_cursor, "limit": results_per_page}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def get_webhook_info(
    context: ToolContext,
    webhook_id: Annotated[str, "The unique identifier for the webhook you want details about."],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'webhooks-get'."]:
    """Retrieve details of a webhook using its ID.

    This tool is used to get details about a specific webhook by providing its ID. It should be called when you need to access information about a particular webhook. The secret associated with the webhook is not included for security reasons."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/webhooks/{id}".format(id=webhook_id),  # noqa: UP032
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def update_webhook_settings(
    context: ToolContext,
    webhook_id: Annotated[str, "The unique identifier of the webhook to be updated."],
    webhook_update_request_body: Annotated[
        dict[str, str],
        "JSON object containing webhook updates, such as events list, new URL, and metadata.",
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'webhooks-update'."]:
    """Update a webhook's settings for events, URL, and metadata.

    Use this tool to modify a webhook's configuration, including the events it tracks, the URL for notifications, and any custom metadata. Changes are applied immediately, and the webhook's status remains the same."""  # noqa: E501
    request_data: Any = webhook_update_request_body
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/webhooks/{id}".format(id=webhook_id),  # noqa: UP032
        method="PATCH",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def remove_webhook(
    context: ToolContext,
    webhook_id: Annotated[
        str,
        "The unique identifier of the webhook to remove. This is necessary for specifying which webhook to delete.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'webhooks-delete'."]:
    """Remove a webhook from your account.

    Use this tool to delete a webhook. Once deleted, it stops receiving notifications immediately and cannot be restored. You'll need to create a new webhook if you wish to reinstate it. Use when you need to stop a webhook permanently."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/webhooks/{id}".format(id=webhook_id),  # noqa: UP032
        method="DELETE",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def list_webhook_attempts(
    context: ToolContext,
    webhook_id: Annotated[
        str, "The unique identifier for the webhook to retrieve attempt records for."
    ],
    event_type_filter: Annotated[
        str | None,
        "Filter webhook attempts by specifying the type of event, such as 'webset.created' or 'monitor.run.completed'.",  # noqa: E501
    ] = None,
    filter_by_successful_attempts: Annotated[
        bool | None,
        "Use 'true' to filter for successful webhook attempts and 'false' for unsuccessful ones.",
    ] = None,
    pagination_cursor: Annotated[
        str | None, "A string used to paginate through the webhook attempt results."
    ] = None,
    results_limit: Annotated[
        float | None, "Specify the maximum number of webhook attempt records to return."
    ] = 25,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'webhooks-attempts-list'."]:
    """Retrieve and list all webhook attempt records.

    This tool retrieves all attempts made by a specific webhook, ordered in descending order. It is useful for monitoring webhook activity and diagnosing issues."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/webhooks/{id}/attempts".format(id=webhook_id),  # noqa: UP032
        method="GET",
        params=remove_none_values({
            "cursor": pagination_cursor,
            "limit": results_limit,
            "eventType": event_type_filter,
            "successful": filter_by_successful_attempts,
        }),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def list_system_events(
    context: ToolContext,
    created_after: Annotated[
        str | None,
        "Filter events created after or at this timestamp. Use a valid ISO 8601 datetime string in UTC.",  # noqa: E501
    ] = None,
    event_types_filter: Annotated[
        list[str] | None, "Filter events by specifying an array of event type names."
    ] = None,
    filter_created_before: Annotated[
        str | None,
        "Filter events created before or at this timestamp (inclusive). Provide a valid ISO 8601 datetime string in UTC.",  # noqa: E501
    ] = None,
    pagination_cursor: Annotated[
        str | None,
        "Cursor for paginating through event results. Use it to navigate through pages of events.",
    ] = None,
    results_limit: Annotated[
        float | None,
        "Specify the number of event results to return. This controls the size of the result set for a single request.",  # noqa: E501
    ] = 25,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'events-list'."]:
    """Retrieve a list of all system events.

    Call this tool to get a detailed list of events that have occurred within the system. Useful for auditing, monitoring, or reviewing activities. Supports pagination through a cursor parameter."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/events",
        method="GET",
        params=remove_none_values({
            "cursor": pagination_cursor,
            "limit": results_limit,
            "types": event_types_filter,
            "createdBefore": filter_created_before,
            "createdAfter": created_after,
        }),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def get_event_by_id(
    context: ToolContext,
    event_id: Annotated[str, "The unique identifier of the event to retrieve details for."],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'events-get'."]:
    """Retrieve details of an event using its ID.

    Use this tool to obtain information about a specific event by providing its unique identifier."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/events/{id}".format(id=event_id),  # noqa: UP032
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def create_webset_search(
    context: ToolContext,
    search_criteria: Annotated[
        dict[str, str],
        "JSON object representing new search criteria for the webset. This specifies the parameters or conditions for the new search.",  # noqa: E501
    ],
    webset_id: Annotated[
        str, "The unique identifier for the Webset you want to create a search in."
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-searches-create'."]:
    """Create a new search for a specified webset.

    Use this tool to create a new search within a webset, reusing previous search results and applying new criteria."""  # noqa: E501
    request_data: Any = search_criteria
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{webset}/searches".format(webset=webset_id),  # noqa: UP032
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def get_search_by_id(
    context: ToolContext,
    search_id: Annotated[str, "The ID of the search to retrieve details for."],
    webset_id: Annotated[str, "The ID of the Webset to retrieve the specific search."],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-searches-get'."]:
    """Retrieve a search by its ID.

    Use this tool to get detailed information about a specific search by providing its ID."""
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{webset}/searches/{id}".format(  # noqa: UP032
            webset=webset_id, id=search_id
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def cancel_running_search(
    context: ToolContext,
    search_id: Annotated[
        str,
        "The ID of the search to cancel. Provide the unique string identifier for the targeted search operation.",  # noqa: E501
    ],
    webset_id: Annotated[
        str,
        "The ID of the Webset where the search is executing. Use this to specify the Webset to be canceled.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'websets-searches-cancel'."]:
    """Cancels a currently running search operation.

    This tool cancels an ongoing search by using the specified webset and search ID. Useful when you need to stop a search that is still in progress."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/websets/{webset}/searches/{id}/cancel".format(  # noqa: UP032
            webset=webset_id, id=search_id
        ),
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def create_monitor_for_websets(
    context: ToolContext,
    monitor_configuration: Annotated[
        dict[str, str],
        "JSON object describing the configuration for the new monitor, including schedule, search and refresh operations.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'monitors-create'."]:
    """Create a scheduled monitor to update Websets with fresh data.

    Use this tool to set up a new monitor that automatically updates Websets. It enables execution of 'search' and 'refresh' operations based on your defined schedule, using cron expressions and timezone settings, to keep your Websets current without manual intervention."""  # noqa: E501
    request_data: Any = monitor_configuration
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/monitors",
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def list_website_monitors(
    context: ToolContext,
    pagination_cursor: Annotated[
        str | None, "The cursor for paginating through the monitor results."
    ] = None,
    results_limit: Annotated[
        float | None,
        "Specifies the maximum number of monitor results to return. Use for pagination.",
    ] = 25,
    webset_id: Annotated[
        str | None,
        "The unique identifier for the Webset to retrieve monitors for. This is required to specify which website's monitors you want to list.",  # noqa: E501
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'monitors-list'."]:
    """Fetch all monitors associated with a website.

    Use this tool to retrieve a comprehensive list of all monitoring services set up for a specific website. This is helpful for maintenance, auditing, or upgrading processes."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/monitors",
        method="GET",
        params=remove_none_values({
            "cursor": pagination_cursor,
            "limit": results_limit,
            "websetId": webset_id,
        }),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def get_specific_monitor(
    context: ToolContext,
    monitor_id: Annotated[str, "The unique identifier of the monitor to retrieve details for."],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'monitors-get'."]:
    """Retrieve details of a specific monitor using its ID.

    This tool is used to obtain information about a particular monitor by providing its unique ID. Call this tool when you need to get specific details about a monitor."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/monitors/{id}".format(id=monitor_id),  # noqa: UP032
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def update_monitor_configuration(
    context: ToolContext,
    monitor_configuration_details: Annotated[
        dict[str, str], "A JSON object containing the new configuration settings for the monitor."
    ],
    monitor_id: Annotated[str, "The unique identifier for the monitor to update."],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'monitors-update'."]:
    """Update the configuration of a monitor.

    Use this tool to update the settings of an existing monitor. Provide the monitor ID and new configuration details to modify its setup."""  # noqa: E501
    request_data: Any = monitor_configuration_details
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/monitors/{id}".format(id=monitor_id),  # noqa: UP032
        method="PATCH",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def delete_monitor(
    context: ToolContext,
    monitor_id: Annotated[str, "The unique identifier for the monitor to be deleted."],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'monitors-delete'."]:
    """Deletes a specified monitor using its ID.

    Use this tool to delete a monitor by providing its ID. It should be called when you need to remove a monitor from the system."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/monitors/{id}".format(id=monitor_id),  # noqa: UP032
        method="DELETE",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def list_monitor_runs(
    context: ToolContext,
    monitor_id: Annotated[str, "The ID of the monitor to list all associated runs."],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'monitors-runs-list'."]:
    """Lists all runs for a given monitor.

    Use this tool to retrieve a list of all runs associated with a specific monitor. It's helpful for tracking and analyzing past monitor activities."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/monitors/{monitor}/runs".format(monitor=monitor_id),  # noqa: UP032
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def get_specific_monitor_run(
    context: ToolContext,
    monitor_id: Annotated[str, "The unique identifier of the monitor to retrieve the run for."],
    run_id: Annotated[str, "The unique identifier of the specific run to retrieve details for."],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'monitors-runs-get'."]:
    """Retrieve details of a specific monitor run.

    This tool retrieves details of a specific monitor run by using the monitor ID and run ID. It should be called when you need to access information about a particular monitor run."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/monitors/{monitor}/runs/{id}".format(  # noqa: UP032
            monitor=monitor_id, id=run_id
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def create_data_import(
    context: ToolContext,
    data_import_details: Annotated[
        dict[str, str],
        "The JSON object containing data to import for Websets. This includes details for enrichment, search, or exclusion processes.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'imports-create'."]:
    """Initiates a new data import for uploading data into Websets.

    Use this tool to create a new import allowing you to upload and manage your data within Websets. The import facilitates data enrichment, searching with natural language filters, and exclusion of duplicates. Upon creation, you'll receive an upload URL valid for a set duration to complete the data upload."""  # noqa: E501
    request_data: Any = data_import_details
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/imports",
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def list_imports(
    context: ToolContext,
    pagination_cursor: Annotated[
        str | None,
        "String used for paginating through results. Pass it to retrieve the next set of results.",
    ] = None,
    results_limit: Annotated[
        float | None, "Specify the maximum number of import results to return."
    ] = 25,
) -> Annotated[dict[str, Any], "Response from the API endpoint 'imports-list'."]:
    """Retrieve all import entries for the Webset.

    Use this tool to get a comprehensive list of all imports associated with the Webset, useful for tracking or auditing purposes."""  # noqa: E501
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/imports",
        method="GET",
        params=remove_none_values({"cursor": pagination_cursor, "limit": results_limit}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def get_specific_import(
    context: ToolContext,
    import_id: Annotated[
        str, "The unique identifier for the specific import to retrieve details about."
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'imports-get'."]:
    """Retrieve details of a specific import.

    Use this tool to get detailed information about a particular import by providing its ID."""
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/imports/{id}".format(id=import_id),  # noqa: UP032
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def update_imports_configuration(
    context: ToolContext,
    import_configuration_details: Annotated[
        dict[str, str],
        "JSON object containing the new settings for the import configuration. Include all necessary fields that need to be updated.",  # noqa: E501
    ],
    import_id: Annotated[str, "The identifier for the import configuration to be updated."],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'imports-update'."]:
    """Update an import configuration with new settings.

    Use this tool to update an existing import configuration by providing the necessary changes to its settings."""  # noqa: E501
    request_data: Any = import_configuration_details
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/imports/{id}".format(id=import_id),  # noqa: UP032
        method="PATCH",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Content-Type": "application/json",
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            ),
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_secrets=["EXA_API_KEY"])
async def delete_import(
    context: ToolContext,
    import_id: Annotated[str, "The unique identifier of the import to be deleted."],
) -> Annotated[dict[str, Any], "Response from the API endpoint 'imports-delete'."]:
    """Delete an import by its ID.

    Use this tool to delete an import record when you have the import ID."""
    request_data: Any = {}
    if isinstance(request_data, dict):
        request_data = remove_none_values(request_data)
    content = json.dumps(request_data) if request_data else None
    response = await make_request(
        url="https://api.exa.ai/websets/v0/imports/{id}".format(id=import_id),  # noqa: UP032
        method="DELETE",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(
                authorization=context.get_secret("EXA_API_KEY")
            )
        }),
        content=content,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}
