94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
519 lines
15 KiB
Python
519 lines
15 KiB
Python
"""Pydantic models for Anthropic Messages API protocol.
|
|
|
|
Mirrors the shape of the official Anthropic Python SDK
|
|
(``anthropic-sdk-python``): ``ContentBlock``, ``Tool``, ``MessageStreamEvent``
|
|
and ``ContentBlockDelta`` are discriminated unions over the ``type`` field,
|
|
so each variant carries only the fields it actually uses.
|
|
"""
|
|
|
|
import uuid
|
|
from typing import Annotated, Any, Literal, Optional, Union
|
|
|
|
from pydantic import (
|
|
BaseModel,
|
|
Discriminator,
|
|
Field,
|
|
NonNegativeInt,
|
|
Tag,
|
|
field_validator,
|
|
model_validator,
|
|
)
|
|
|
|
|
|
class AnthropicError(BaseModel):
|
|
"""Error structure for Anthropic API."""
|
|
|
|
type: str
|
|
message: str
|
|
|
|
|
|
class AnthropicErrorResponse(BaseModel):
|
|
"""Error response structure for Anthropic API."""
|
|
|
|
type: Literal["error"] = "error"
|
|
error: AnthropicError
|
|
|
|
|
|
class AnthropicUsage(BaseModel):
|
|
"""Token usage information.
|
|
|
|
``input_tokens``/``output_tokens`` are ``Optional`` because Anthropic's
|
|
streaming ``message_delta`` event omits ``input_tokens`` (the spec
|
|
requires it only on ``message_start``). Non-streaming responses set both.
|
|
"""
|
|
|
|
input_tokens: Optional[NonNegativeInt] = None
|
|
output_tokens: Optional[NonNegativeInt] = None
|
|
cache_creation_input_tokens: Optional[NonNegativeInt] = None
|
|
cache_read_input_tokens: Optional[NonNegativeInt] = None
|
|
|
|
|
|
# ---------- Content blocks (discriminated by ``type``) ----------
|
|
|
|
|
|
class TextBlock(BaseModel):
|
|
type: Literal["text"] = "text"
|
|
text: str
|
|
|
|
|
|
class ImageBlock(BaseModel):
|
|
type: Literal["image"] = "image"
|
|
# Kept loosely typed for compat with both base64 and URL sources; the
|
|
# serving layer normalises to OpenAI ``image_url`` parts.
|
|
source: Optional[Union[dict[str, Any], str]] = None
|
|
|
|
|
|
class ToolUseBlock(BaseModel):
|
|
type: Literal["tool_use"] = "tool_use"
|
|
id: str
|
|
name: str
|
|
input: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ToolResultBlock(BaseModel):
|
|
type: Literal["tool_result"] = "tool_result"
|
|
tool_use_id: Optional[str] = None
|
|
# Some legacy payloads use ``id`` instead of ``tool_use_id``.
|
|
id: Optional[str] = None
|
|
content: Optional[Union[str, list["AnthropicContentBlock"]]] = None
|
|
is_error: Optional[bool] = None
|
|
|
|
|
|
class ToolReferenceBlock(BaseModel):
|
|
"""sglang extension: references a deferred-loaded tool by name."""
|
|
|
|
type: Literal["tool_reference"] = "tool_reference"
|
|
name: Optional[str] = None
|
|
# Anthropic-style payloads sometimes use ``tool_name``; accept both.
|
|
tool_name: Optional[str] = None
|
|
id: Optional[str] = None
|
|
|
|
|
|
class SearchResultBlock(BaseModel):
|
|
type: Literal["search_result"] = "search_result"
|
|
# ``source`` here is a URL/identifier string (unlike ImageBlock.source).
|
|
source: Optional[Union[str, dict[str, Any]]] = None
|
|
title: Optional[str] = None
|
|
content: Optional[list[dict[str, Any]]] = None
|
|
|
|
|
|
class ThinkingBlock(BaseModel):
|
|
type: Literal["thinking"] = "thinking"
|
|
thinking: str
|
|
signature: Optional[str] = None
|
|
|
|
|
|
class RedactedThinkingBlock(BaseModel):
|
|
type: Literal["redacted_thinking"] = "redacted_thinking"
|
|
data: Optional[str] = None
|
|
|
|
|
|
AnthropicContentBlock = Annotated[
|
|
Union[
|
|
TextBlock,
|
|
ImageBlock,
|
|
ToolUseBlock,
|
|
ToolResultBlock,
|
|
ToolReferenceBlock,
|
|
SearchResultBlock,
|
|
ThinkingBlock,
|
|
RedactedThinkingBlock,
|
|
],
|
|
Field(discriminator="type"),
|
|
]
|
|
|
|
|
|
class AnthropicMessage(BaseModel):
|
|
role: Literal["user", "assistant", "system"]
|
|
content: Union[str, list[AnthropicContentBlock]]
|
|
|
|
|
|
# ---------- Tools (discriminated by ``type`` family) ----------
|
|
|
|
|
|
class AnthropicCustomTool(BaseModel):
|
|
"""Custom tool defined by the API user — requires ``input_schema``."""
|
|
|
|
type: Optional[Literal["custom"]] = None # absent or explicit "custom"
|
|
name: str
|
|
description: Optional[str] = None
|
|
input_schema: dict[str, Any]
|
|
defer_loading: Optional[bool] = None
|
|
|
|
@field_validator("input_schema")
|
|
@classmethod
|
|
def _ensure_object_schema(cls, v):
|
|
if not isinstance(v, dict):
|
|
raise ValueError("input_schema must be a dictionary")
|
|
if "type" not in v:
|
|
v["type"] = "object"
|
|
return v
|
|
|
|
|
|
class AnthropicWebSearchTool(BaseModel):
|
|
"""Anthropic ``web_search_*`` server tool family.
|
|
|
|
No client-side ``input_schema`` — Anthropic provides the backing
|
|
search implementation. Tag format is ``web_search_YYYYMMDD``.
|
|
"""
|
|
|
|
type: str = Field(pattern=r"^web_search_\d{8}$")
|
|
name: Literal["web_search"] = "web_search"
|
|
description: Optional[str] = None
|
|
defer_loading: Optional[bool] = None
|
|
max_uses: Optional[int] = None
|
|
allowed_domains: Optional[list[str]] = None
|
|
blocked_domains: Optional[list[str]] = None
|
|
|
|
|
|
class AnthropicComputerTool(BaseModel):
|
|
"""Anthropic ``computer_*`` server tool family."""
|
|
|
|
type: str = Field(pattern=r"^computer_\d{8}$")
|
|
name: Literal["computer"] = "computer"
|
|
description: Optional[str] = None
|
|
defer_loading: Optional[bool] = None
|
|
display_width_px: Optional[int] = None
|
|
display_height_px: Optional[int] = None
|
|
display_number: Optional[int] = None
|
|
|
|
|
|
class AnthropicBashTool(BaseModel):
|
|
"""Anthropic ``bash_*`` server tool family."""
|
|
|
|
type: str = Field(pattern=r"^bash_\d{8}$")
|
|
name: Literal["bash"] = "bash"
|
|
description: Optional[str] = None
|
|
defer_loading: Optional[bool] = None
|
|
|
|
|
|
class AnthropicTextEditorTool(BaseModel):
|
|
"""Anthropic ``text_editor_*`` server tool family."""
|
|
|
|
type: str = Field(pattern=r"^text_editor_\d{8}$")
|
|
name: Literal["str_replace_editor", "str_replace_based_edit_tool"]
|
|
description: Optional[str] = None
|
|
defer_loading: Optional[bool] = None
|
|
|
|
|
|
def _tool_discriminator(v) -> str:
|
|
"""Pick the right tool variant from a dict or model instance.
|
|
|
|
Pydantic discriminators don't accept ``None`` as a tag, and custom
|
|
tools allow ``type`` to be absent. Map missing/``custom`` to
|
|
``"custom"`` and prefix-match server-tool families.
|
|
"""
|
|
if isinstance(v, dict):
|
|
t = v.get("type")
|
|
else:
|
|
t = getattr(v, "type", None)
|
|
if not t or t == "custom":
|
|
return "custom"
|
|
if t.startswith("web_search_"):
|
|
return "web_search"
|
|
if t.startswith("computer_"):
|
|
return "computer"
|
|
if t.startswith("bash_"):
|
|
return "bash"
|
|
if t.startswith("text_editor_"):
|
|
return "text_editor"
|
|
return "custom"
|
|
|
|
|
|
AnthropicTool = Annotated[
|
|
Union[
|
|
Annotated[AnthropicCustomTool, Tag("custom")],
|
|
Annotated[AnthropicWebSearchTool, Tag("web_search")],
|
|
Annotated[AnthropicComputerTool, Tag("computer")],
|
|
Annotated[AnthropicBashTool, Tag("bash")],
|
|
Annotated[AnthropicTextEditorTool, Tag("text_editor")],
|
|
],
|
|
Discriminator(_tool_discriminator),
|
|
]
|
|
|
|
|
|
def is_server_tool(tool) -> bool:
|
|
"""Return True for Anthropic built-in server-side tools."""
|
|
return isinstance(
|
|
tool,
|
|
(
|
|
AnthropicWebSearchTool,
|
|
AnthropicComputerTool,
|
|
AnthropicBashTool,
|
|
AnthropicTextEditorTool,
|
|
),
|
|
)
|
|
|
|
|
|
class AnthropicToolChoice(BaseModel):
|
|
"""Tool choice strategy."""
|
|
|
|
type: Literal["auto", "any", "tool", "none"]
|
|
name: Optional[str] = None
|
|
|
|
|
|
class AnthropicThinkingParam(BaseModel):
|
|
"""Anthropic extended-thinking control on the request.
|
|
|
|
Mirrors the Anthropic SDK's ``ThinkingConfigParam`` discriminated
|
|
union of three variants — see ``anthropic-sdk-python``'s
|
|
``thinking_config_{enabled,disabled,adaptive}_param.py``:
|
|
|
|
* ``enabled`` requires ``budget_tokens`` (≥1024) and accepts
|
|
``display``.
|
|
* ``disabled`` accepts no other fields.
|
|
* ``adaptive`` (Claude 4.7) accepts ``display`` but not
|
|
``budget_tokens``.
|
|
|
|
The serving layer treats ``adaptive`` identically to ``enabled``
|
|
because the local OpenAI-compatible backend has no auto-throttle
|
|
equivalent. ``budget_tokens`` is accepted on ``enabled`` for SDK
|
|
compatibility but the backend has no hard-cap knob to honor it; the
|
|
serving layer logs a WARNING so operators see that the requested
|
|
budget is not enforced. ``display="omitted"`` is accepted but
|
|
similarly cannot suppress reasoning mid-stream and is logged.
|
|
"""
|
|
|
|
type: Literal["enabled", "disabled", "adaptive"]
|
|
budget_tokens: Optional[int] = None
|
|
display: Optional[Literal["summarized", "omitted"]] = None
|
|
|
|
@model_validator(mode="after")
|
|
def _validate_thinking_shape(self):
|
|
# Cross-field rules mirror the SDK's three discriminated variants.
|
|
if self.type == "enabled":
|
|
if self.budget_tokens is None:
|
|
raise ValueError(
|
|
"thinking.budget_tokens is required when "
|
|
"thinking.type is 'enabled'"
|
|
)
|
|
if self.budget_tokens < 1024:
|
|
raise ValueError(
|
|
"thinking.budget_tokens must be >= 1024 "
|
|
"(got {})".format(self.budget_tokens)
|
|
)
|
|
elif self.type == "disabled":
|
|
if self.budget_tokens is not None:
|
|
raise ValueError(
|
|
"thinking.budget_tokens is not allowed when "
|
|
"thinking.type is 'disabled'"
|
|
)
|
|
if self.display is not None:
|
|
raise ValueError(
|
|
"thinking.display is not allowed when "
|
|
"thinking.type is 'disabled'"
|
|
)
|
|
elif self.type == "adaptive":
|
|
if self.budget_tokens is not None:
|
|
raise ValueError(
|
|
"thinking.budget_tokens is not allowed when "
|
|
"thinking.type is 'adaptive'"
|
|
)
|
|
return self
|
|
|
|
|
|
class AnthropicTaskBudget(BaseModel):
|
|
"""Claude 4.7 ``output_config.task_budget`` — soft hint, not a hard cap.
|
|
|
|
Mirrors ``BetaTokenTaskBudgetParam`` in the Anthropic SDK: ``total``
|
|
and ``type`` are required; ``remaining`` is the client-tracked
|
|
countdown used for compaction. The hard cap on generation is still
|
|
``max_tokens``; we never enforce ``task_budget`` ourselves.
|
|
"""
|
|
|
|
type: Literal["tokens"]
|
|
total: int = Field(gt=0)
|
|
remaining: Optional[int] = Field(default=None, ge=0)
|
|
|
|
|
|
class AnthropicOutputConfig(BaseModel):
|
|
"""Claude 4.7 ``output_config`` block.
|
|
|
|
``effort`` maps to the OpenAI ``reasoning_effort`` knob (``xhigh`` →
|
|
``max`` because the OpenAI Literal does not include ``xhigh``).
|
|
``task_budget`` is propagated as a custom-param hint.
|
|
"""
|
|
|
|
effort: Optional[Literal["low", "medium", "high", "xhigh", "max"]] = None
|
|
task_budget: Optional[AnthropicTaskBudget] = None
|
|
|
|
|
|
class AnthropicCountTokensRequest(BaseModel):
|
|
"""Anthropic count_tokens API request."""
|
|
|
|
model: str
|
|
messages: list[AnthropicMessage]
|
|
system: Optional[Union[str, list[AnthropicContentBlock]]] = None
|
|
thinking: Optional[AnthropicThinkingParam] = None
|
|
tool_choice: Optional[AnthropicToolChoice] = None
|
|
tools: Optional[list[AnthropicTool]] = None
|
|
# Claude 4.7 / SDK-compatibility fields. Accepted but no-op on count.
|
|
output_config: Optional[AnthropicOutputConfig] = None
|
|
betas: Optional[list[str]] = None
|
|
|
|
|
|
class AnthropicCountTokensResponse(BaseModel):
|
|
"""Anthropic count_tokens API response."""
|
|
|
|
input_tokens: int
|
|
|
|
|
|
class AnthropicMessagesRequest(BaseModel):
|
|
"""Anthropic Messages API request."""
|
|
|
|
model: str
|
|
messages: list[AnthropicMessage]
|
|
max_tokens: int
|
|
metadata: Optional[dict[str, Any]] = None
|
|
stop_sequences: Optional[list[str]] = None
|
|
stream: Optional[bool] = False
|
|
system: Optional[Union[str, list[AnthropicContentBlock]]] = None
|
|
temperature: Optional[float] = None
|
|
thinking: Optional[AnthropicThinkingParam] = None
|
|
tool_choice: Optional[AnthropicToolChoice] = None
|
|
tools: Optional[list[AnthropicTool]] = None
|
|
top_k: Optional[int] = None
|
|
top_p: Optional[float] = None
|
|
# Claude 4.7 fields. The Anthropic SDK / Claude Code attach these even
|
|
# when targeting non-Anthropic backends, so the schema must accept them.
|
|
output_config: Optional[AnthropicOutputConfig] = None
|
|
betas: Optional[list[str]] = None
|
|
|
|
@field_validator("model")
|
|
@classmethod
|
|
def _validate_model(cls, v):
|
|
if not v:
|
|
raise ValueError("Model is required")
|
|
return v
|
|
|
|
@field_validator("max_tokens")
|
|
@classmethod
|
|
def _validate_max_tokens(cls, v):
|
|
if v <= 0:
|
|
raise ValueError("max_tokens must be positive")
|
|
return v
|
|
|
|
|
|
# ---------- Stream deltas ----------
|
|
# Content-block deltas (discriminated by ``type``) vs message-end delta
|
|
# (separate model; the wire format does not put ``type`` inside its payload).
|
|
|
|
|
|
class TextDelta(BaseModel):
|
|
type: Literal["text_delta"] = "text_delta"
|
|
text: str
|
|
|
|
|
|
class InputJsonDelta(BaseModel):
|
|
type: Literal["input_json_delta"] = "input_json_delta"
|
|
partial_json: str
|
|
|
|
|
|
class ThinkingDelta(BaseModel):
|
|
type: Literal["thinking_delta"] = "thinking_delta"
|
|
thinking: str
|
|
|
|
|
|
class SignatureDelta(BaseModel):
|
|
type: Literal["signature_delta"] = "signature_delta"
|
|
signature: str
|
|
|
|
|
|
AnthropicContentDelta = Annotated[
|
|
Union[TextDelta, InputJsonDelta, ThinkingDelta, SignatureDelta],
|
|
Field(discriminator="type"),
|
|
]
|
|
|
|
|
|
class AnthropicMessageEndDelta(BaseModel):
|
|
"""Delta carried on ``message_delta`` events.
|
|
|
|
Anthropic's protocol does NOT put a ``type`` field inside this delta
|
|
payload — the SSE ``event:`` header already says ``message_delta``.
|
|
Stop reason and stop sequence are the only fields.
|
|
"""
|
|
|
|
stop_reason: Optional[
|
|
Literal["end_turn", "max_tokens", "stop_sequence", "tool_use"]
|
|
] = None
|
|
stop_sequence: Optional[str] = None
|
|
|
|
|
|
# ---------- Stream events (discriminated by ``type``) ----------
|
|
|
|
|
|
class MessageStartEvent(BaseModel):
|
|
type: Literal["message_start"] = "message_start"
|
|
message: "AnthropicMessagesResponse"
|
|
|
|
|
|
class MessageDeltaEvent(BaseModel):
|
|
type: Literal["message_delta"] = "message_delta"
|
|
delta: AnthropicMessageEndDelta
|
|
usage: AnthropicUsage
|
|
|
|
|
|
class MessageStopEvent(BaseModel):
|
|
type: Literal["message_stop"] = "message_stop"
|
|
|
|
|
|
class ContentBlockStartEvent(BaseModel):
|
|
type: Literal["content_block_start"] = "content_block_start"
|
|
index: int
|
|
content_block: AnthropicContentBlock
|
|
|
|
|
|
class ContentBlockDeltaEvent(BaseModel):
|
|
type: Literal["content_block_delta"] = "content_block_delta"
|
|
index: int
|
|
delta: AnthropicContentDelta
|
|
|
|
|
|
class ContentBlockStopEvent(BaseModel):
|
|
type: Literal["content_block_stop"] = "content_block_stop"
|
|
index: int
|
|
|
|
|
|
class PingEvent(BaseModel):
|
|
type: Literal["ping"] = "ping"
|
|
|
|
|
|
class ErrorEvent(BaseModel):
|
|
type: Literal["error"] = "error"
|
|
error: AnthropicError
|
|
|
|
|
|
AnthropicStreamEvent = Annotated[
|
|
Union[
|
|
MessageStartEvent,
|
|
MessageDeltaEvent,
|
|
MessageStopEvent,
|
|
ContentBlockStartEvent,
|
|
ContentBlockDeltaEvent,
|
|
ContentBlockStopEvent,
|
|
PingEvent,
|
|
ErrorEvent,
|
|
],
|
|
Field(discriminator="type"),
|
|
]
|
|
|
|
|
|
class AnthropicMessagesResponse(BaseModel):
|
|
"""Anthropic Messages API response."""
|
|
|
|
id: str = Field(default_factory=lambda: f"msg_{uuid.uuid4().hex}")
|
|
type: Literal["message"] = "message"
|
|
role: Literal["assistant"] = "assistant"
|
|
content: list[AnthropicContentBlock]
|
|
model: str
|
|
stop_reason: Optional[
|
|
Literal["end_turn", "max_tokens", "stop_sequence", "tool_use"]
|
|
] = None
|
|
stop_sequence: Optional[str] = None
|
|
usage: Optional[AnthropicUsage] = None
|
|
|
|
|
|
# Resolve forward references for nested types.
|
|
ToolResultBlock.model_rebuild()
|
|
MessageStartEvent.model_rebuild()
|