///|
/// Why the model stopped generating, as in the `stop_reason` of a
/// `MessageResponse`.
pub using @gen {type StopReason}
///|
/// Token counts billed for a message.
pub using @gen {type Usage}
///|
/// A model as `list_models` and `retrieve_model` return it.
pub using @gen {type ModelInfo}
///|
/// One page of `list_models`.
pub using @gen {type ListResponseModelInfo}
///|
/// A model lifecycle stage that `list_models` can filter by.
pub using @gen {type ModelsListLifecycleItem}
///|
/// A content block of an input message: text, image, document, tool use or
/// result, and others.
pub using @gen {type InputContentBlock}
///|
/// How the model may use the request's tools; the `tool_choice_*` helpers build
/// the common ones.
pub using @gen {type ToolChoice}
///|
/// Whether and how the model thinks before answering.
pub using @gen {type ThinkingConfigParam}
///|
/// Output settings of a request: the effort level and a structured output
/// format.
pub using @gen {type OutputConfig}
///|
/// Request metadata: an opaque id of the end user.
pub using @gen {type Metadata}
///|
/// The top-level changes in a `message_delta` stream event, such as the stop
/// reason.
pub using @gen {type MessageDelta}
///|
/// The cumulative token counts in a `message_delta` stream event.
pub using @gen {type MessageDeltaUsage}
///|
/// The full Messages request, for `create_message_params` and
/// `stream_message_params`.
pub using @gen {type CreateMessageParams}
///|
/// A raw Messages stream event as the server sends it.
pub using @gen {type MessageStreamEvent}
///|
/// Selects the credential header used by the API.
#derive(Eq, Debug)
#non_exhaustive
pub(all) enum AuthHeader {
XApiKey
Bearer
}
///|
/// Compares authentication-header choices.
pub extend AuthHeader with Eq::{equal, not_equal}
///|
/// Debug representation of an authentication-header choice.
pub extend AuthHeader with @debug.Debug::{to_repr}
///|
/// The error body returned by the Anthropic API.
///
/// ```mbt check
/// test {
/// let error : @anthropic.ApiErrorBody = {
/// type_: "invalid_request_error",
/// message: "invalid request",
/// }
/// assert_eq(error.message, "invalid request")
/// }
/// ```
#derive(Eq, Debug)
pub(all) struct ApiErrorBody {
type_ : String
message : String
}
///|
/// Compares API error bodies field by field.
pub extend ApiErrorBody with Eq::{equal, not_equal}
///|
/// Debug representation of an API error body.
pub extend ApiErrorBody with @debug.Debug::{to_repr}
///|
/// A participant in a Messages API conversation. `System` is a
/// mid-conversation system message, which only some models accept and which
/// must directly follow a user turn; a system prompt for the whole
/// conversation goes in `MessageRequest.system`. A response is always
/// `Assistant`.
#derive(Eq, Debug)
#non_exhaustive
pub(all) enum Role {
User
Assistant
System
}
///|
/// Compares message roles.
pub extend Role with Eq::{equal, not_equal}
///|
/// Debug representation of a message role.
pub extend Role with @debug.Debug::{to_repr}
///|
/// Input content as plain text or typed content blocks. A block the generated
/// vocabulary does not know is carried losslessly as
/// `@gen.InputContentBlock::Unknown`.
#derive(Eq, Debug)
#non_exhaustive
pub(all) enum InputContent {
Text(String)
Blocks(Array[InputContentBlock])
}
///|
/// Compares input content, including typed blocks.
pub extend InputContent with Eq::{equal, not_equal}
///|
/// Debug representation of input content.
pub extend InputContent with @debug.Debug::{to_repr}
///|
/// A client tool definition for the Messages API.
///
/// ```mbt check
/// test {
/// let tool = @anthropic.ToolDef::new(name="lookup", input_schema={
/// "type": "object",
/// })
/// assert_eq(tool.name, "lookup")
/// }
/// ```
#derive(Eq, Debug)
pub(all) struct ToolDef {
name : String
description : String?
input_schema : Json
strict : Bool?
}
///|
/// Compares tool definitions field by field.
pub extend ToolDef with Eq::{equal, not_equal}
///|
/// Debug representation of a tool definition.
pub extend ToolDef with @debug.Debug::{to_repr}
///|
/// Creates a client tool definition with a JSON Schema input object.
pub fn ToolDef::new(
name~ : String,
input_schema~ : Json,
description? : String,
strict? : Bool,
) -> ToolDef {
{ name, description, input_schema, strict, }
}
///|
/// One user, assistant or system turn sent to the Messages API.
#derive(Eq, Debug)
pub(all) struct Message {
role : Role
content : InputContent
}
///|
/// Compares messages field by field.
pub extend Message with Eq::{equal, not_equal}
///|
/// Debug representation of a message.
pub extend Message with @debug.Debug::{to_repr}
///|
/// Creates a user message containing plain text.
///
/// ```mbt check
/// test {
/// assert_eq(@anthropic.Message::user("hello"), {
/// role: @anthropic.User,
/// content: @anthropic.Text("hello"),
/// })
/// }
/// ```
pub fn Message::user(text : String) -> Message {
{ role: User, content: Text(text), }
}
///|
/// Creates an assistant message containing plain text.
///
/// ```mbt check
/// test {
/// assert_eq(@anthropic.Message::assistant("hello"), {
/// role: @anthropic.Assistant,
/// content: @anthropic.Text("hello"),
/// })
/// }
/// ```
pub fn Message::assistant(text : String) -> Message {
{ role: Assistant, content: Text(text), }
}
///|
/// Creates a mid-conversation system message containing plain text. Place it
/// right after a user turn; see `Role`.
///
/// ```mbt check
/// test {
/// assert_eq(@anthropic.Message::system("answer in French"), {
/// role: @anthropic.System,
/// content: @anthropic.Text("answer in French"),
/// })
/// }
/// ```
pub fn Message::system(text : String) -> Message {
{ role: System, content: Text(text), }
}
///|
/// Creates a user message from typed content blocks (images, documents, tool
/// results, ...).
pub fn Message::user_blocks(blocks : Array[InputContentBlock]) -> Message {
{ role: User, content: Blocks(blocks.copy()), }
}
///|
/// Creates an assistant message from typed content blocks.
pub fn Message::assistant_blocks(blocks : Array[InputContentBlock]) -> Message {
{ role: Assistant, content: Blocks(blocks.copy()), }
}
///|
/// Creates a user message containing one tool result block.
///
/// ```mbt check
/// test {
/// let message = @anthropic.Message::tool_result(
/// tool_use_id="toolu_1",
/// content="done",
/// )
/// assert_eq(message.role, @anthropic.User)
/// }
/// ```
pub fn Message::tool_result(
tool_use_id~ : String,
content~ : String,
is_error? : Bool,
) -> Message {
{
role: User,
content: Blocks([
@gen.InputContentBlock::ToolResult(
@gen.RequestToolResultBlock::new(
tool_use_id~,
type_="tool_result",
content=@gen.RequestToolResultBlockContent::Text(content),
is_error?,
),
),
]),
}
}
///|
/// The `type` tag of a content block's JSON, or `""` when it has none.
fn block_type(json : Json) -> String {
match json {
Object(fields) =>
match fields.get("type") {
Some(String(kind)) => kind
_ => ""
}
_ => ""
}
}
///|
/// Turns a response into the assistant turn to send back, block for block:
/// text, thinking (with its signature), tool use and every other block the
/// API returned are replayed as input blocks. A block the request vocabulary
/// cannot represent is passed through as raw JSON.
pub fn Message::from_response(response : MessageResponse) -> Message {
let blocks = response.message.content.map(block => {
let json = block.to_json()
let converted : InputContentBlock = @json.from_json(json) catch {
_ => @gen.InputContentBlock::Unknown(block_type(json), json)
}
converted
})
{ role: Assistant, content: Blocks(blocks), }
}
///|
/// Input accepted by buffered and streaming message creation and by token
/// counting.
///
/// The typed fields cover the common surface; `extra` is merged into the JSON
/// body after the typed fields and validated against the generated schema, so
/// any other documented parameter (`service_tier`, `inference_geo`, ...) can be passed
/// without a facade change. For full control build a `@gen.CreateMessageParams`
/// and use `Anthropic::create_message_params`.
#derive(Eq, Debug)
pub(all) struct MessageRequest {
model : String
max_tokens : Int32
messages : Array[Message]
system : String?
stop_sequences : Array[String]?
tools : Array[ToolDef]?
tool_choice : ToolChoice?
thinking : ThinkingConfigParam?
output_config : OutputConfig?
metadata : Metadata?
extra : Map[String, Json]
}
///|
/// Compares message requests field by field.
pub extend MessageRequest with Eq::{equal, not_equal}
///|
/// Debug representation of a message request.
pub extend MessageRequest with @debug.Debug::{to_repr}
///|
/// Creates a message request and snapshots its mutable inputs.
///
/// ```mbt check
/// test {
/// let request = @anthropic.MessageRequest::new(
/// model="claude-opus-5",
/// max_tokens=64,
/// messages=[@anthropic.Message::user("hello")],
/// )
/// assert_eq(request.messages.length(), 1)
/// }
/// ```
pub fn MessageRequest::new(
model~ : String,
max_tokens~ : Int32,
messages~ : Array[Message],
system? : String,
stop_sequences? : Array[String],
tools? : Array[ToolDef],
tool_choice? : ToolChoice,
thinking? : ThinkingConfigParam,
output_config? : OutputConfig,
metadata? : Metadata,
extra? : Map[String, Json],
) -> MessageRequest {
{
model,
max_tokens,
messages: messages.map(copy_message),
system,
stop_sequences: stop_sequences.map(Array::copy),
tools: tools.map(Array::copy),
tool_choice,
thinking,
output_config,
metadata,
extra: extra.map(Map::copy).unwrap_or({}),
}
}
///|
fn copy_message(message : Message) -> Message {
match message.content {
Text(text) => { ..message, content: Text(text), }
Blocks(blocks) => { ..message, content: Blocks(blocks.copy()), }
}
}
///|
/// One output content block. Blocks beyond text, thinking and tool use keep
/// their JSON; the typed form is on `MessageResponse::message`.
#derive(Eq, Debug)
#non_exhaustive
pub(all) enum ContentBlock {
Text(String)
Thinking(thinking~ : String, signature~ : String)
RedactedThinking(String)
ToolUse(id~ : String, name~ : String, input~ : Json)
Other(String, Json)
}
///|
/// Compares output content blocks.
pub extend ContentBlock with Eq::{equal, not_equal}
///|
/// Debug representation of an output content block.
pub extend ContentBlock with @debug.Debug::{to_repr}
///|
/// A decoded message: the facade view (`content`), the generated view
/// (`message`) and the original JSON (`raw`).
#derive(Eq, Debug)
pub(all) struct MessageResponse {
id : String
model : String
role : Role
content : Array[ContentBlock]
stop_reason : StopReason?
usage : Usage
message : @gen.Message
raw : Json
}
///|
/// Compares decoded messages field by field.
pub extend MessageResponse with Eq::{equal, not_equal}
///|
/// Debug representation of a decoded message.
pub extend MessageResponse with @debug.Debug::{to_repr}
///|
/// Concatenates text blocks in response order and ignores other block kinds.
pub fn MessageResponse::text(self : MessageResponse) -> String {
let result = StringBuilder()
for block in self.content {
if block is Text(text) {
result.write_string(text)
}
}
result.to_string()
}
///|
/// The tool uses requested by the response, in content order.
pub fn MessageResponse::tool_uses(
self : MessageResponse,
) -> Array[(String, String, Json)] {
let result = []
for block in self.content {
if block is ToolUse(id~, name~, input~) {
result.push((id, name, input))
}
}
result
}
///|
/// One event from a streaming message. Event and delta kinds outside the
/// generated vocabulary retain their raw JSON.
#derive(Eq, Debug)
#non_exhaustive
pub(all) enum MessageEvent {
MessageStart(MessageResponse)
ContentBlockStart(index~ : Int32, block~ : ContentBlock)
TextDelta(index~ : Int32, text~ : String)
ThinkingDelta(index~ : Int32, thinking~ : String)
SignatureDelta(index~ : Int32, signature~ : String)
InputJsonDelta(index~ : Int32, partial_json~ : String)
ContentBlockStop(index~ : Int32)
MessageDelta(delta~ : MessageDelta, usage~ : MessageDeltaUsage)
MessageStop
Ping
Error(ApiErrorBody)
Other(String, Json)
}
///|
/// Compares message events, including retained unknown JSON.
pub extend MessageEvent with Eq::{equal, not_equal}
///|
/// Debug representation of a message event.
pub extend MessageEvent with @debug.Debug::{to_repr}