```python:inference/core/workflows/core_steps/models/foundation/anthropic_claude/v3.py
from typing import Literal

from inference.core.workflows.core_steps.common.vlms import VLM_TASKS_METADATA
from inference.core.workflows.prototypes.block import WorkflowBlockManifest

CLAUDE_MODELS = [
    {
        "id": "claude-opus-4-6",
        "name": "Claude Opus 4.6",
        "exact_version": "claude-opus-4-6",
        "max_output_tokens": 128000,
    },
    {
        "id": "claude-sonnet-4-6",
        "name": "Claude Sonnet 4.6",
        "exact_version": "claude-sonnet-4-6",
        "max_output_tokens": 64000,
    },
    {
        "id": "claude-sonnet-4-5",
        "name": "Claude Sonnet 4.5",
        "exact_version": "claude-sonnet-4-5-20250929",
        "max_output_tokens": 64000,
    },
    {
        "id": "claude-haiku-4-5",
        "name": "Claude Haiku 4.5",
        "exact_version": "claude-haiku-4-5-20251001",
        "max_output_tokens": 64000,
    },
    {
        "id": "claude-opus-4-5",
        "name": "Claude Opus 4.5",
        "exact_version": "claude-opus-4-5-20251101",
        "max_output_tokens": 64000,
    },
    {
        "id": "claude-sonnet-4",
        "name": "Claude Sonnet 4",
        "exact_version": "claude-sonnet-4-20250514",
        "max_output_tokens": 64000,
    },
    {
        "id": "claude-opus-4-1",
        "name": "Claude Opus 4.1",
        "exact_version": "claude-opus-4-1-20250805",
        "max_output_tokens": 32000,
    },
    {
        "id": "claude-opus-4",
        "name": "Claude Opus 4",
        "exact_version": "claude-opus-4-20250514",
        "max_output_tokens": 32000,
    },
]

MODEL_VERSION_IDS = tuple(model["id"] for model in CLAUDE_MODELS)


MODEL_VERSION_METADATA = {
    model["id"]: {"name": model["name"]} for model in CLAUDE_MODELS
}

SUPPORTED_TASK_TYPES_LIST = (
    "unconstrained",
    "ocr",
    "structured-answering",
    "classification",
    "multi-label-classification",
    "visual-question-answering",
    "caption",
    "detailed-caption",
    "object-detection",
)
SUPPORTED_TASK_TYPES = set(SUPPORTED_TASK_TYPES_LIST)
RELEVANT_TASKS_METADATA = {
    k: v for k, v in VLM_TASKS_METADATA.items() if k in SUPPORTED_TASK_TYPES
}
RELEVANT_TASKS_DOCS_DESCRIPTION = "\n\n".join(
    f"* **{v['name']}** (`{k}`) - {v['description']}"
    for k, v in RELEVANT_TASKS_METADATA.items()
)
LONG_DESCRIPTION = f"""
Ask a question to Anthropic Claude model with vision capabilities.

You can specify arbitrary text prompts or predefined ones, the block supports the following types of prompt:

{RELEVANT_TASKS_DOCS_DESCRIPTION}

### API Key Options

This block supports two API key modes:

1. **Roboflow Managed API Key (Default)** - Use `rf_key:account` to proxy requests through Roboflow's API:
   * **Simplified setup** - no Anthropic API key required
   * **Secure** - your workflow API key is used for authentication
   * **Usage-based billing** - charged per token based on the model used

2. **Custom Anthropic API Key** - Provide your own Anthropic API key:
   * Full control over API usage
   * You pay Anthropic directly
"""

TaskType = Literal[tuple(SUPPORTED_TASK_TYPES_LIST)]

TASKS_REQUIRING_PROMPT = {
    "unconstrained",
    "visual-question-answering",
}

TASKS_REQUIRING_CLASSES = {
    "classification",
    "multi-label-classification",
    "object-detection",
}

TASKS_REQUIRING_OUTPUT_STRUCTURE = {
    "structured-answering",
}



# Module-level constant to avoid allocating a new dict on every call.
_AIR_GAPPED_AVAILABILITY = {"available": False, "reason": "requires_internet"}


class BlockManifest(WorkflowBlockManifest):

    @classmethod
    def get_air_gapped_availability(cls) -> dict:
        return _AIR_GAPPED_AVAILABILITY
```