Thin Anthropic Messages API client for MoonBit built on gaato/http and gaato/mttp.
Status: unofficial and experimental. Minor releases may contain breaking changes; the changelog lists each one with a migration note.
moon add gaato/anthropic
moon add gaato/http
moon add gaato/mttp
moon add gaato/http-async///|
let backend = @codings.Decompress::new(
@backend.AsyncBackend::new(config={
..@h1client.ClientConfig::default(),
connect_timeout_ms: Some(5000),
}),
)
///|
let clock = @runtime.AsyncClock::new()
///|
let timer = @runtime.ClockTimer::new()///|
/// Asks `model` one question and returns its answer.
pub async fn ask(
backend : &@http.Backend,
clock : &@rt.Clock,
timer : &@rt.Timer,
api_key~ : String,
model~ : String,
) -> Result[String, @anthropic.AnthropicFailure] {
let client = @anthropic.Anthropic::new(
api_key~,
backend,
clock,
timer~,
total_timeout_ms=900_000,
)
let reply = client.create_message(
@anthropic.MessageRequest::new(model~, max_tokens=1024, messages=[
@anthropic.Message::user("Hello"),
]),
)
match reply {
Ok(reply) => Ok(reply.text())
Err(error) => Err(error)
}
}| Package | What it is |
|---|---|
| gaato/anthropic | The Anthropic client, MessageRequest, MessageResponse, MessageEvent, and tool helpers |
| gaato/anthropic/gen | Request and response types and operations generated from the official Python SDK's OpenAPI document |
///|
/// Streams a message, passing each piece of text to `on_text` as it arrives.
pub async fn stream_text(
client : @anthropic.Anthropic,
model~ : String,
on_text : (String) -> Unit,
) -> Result[Unit, @anthropic.AnthropicFailure] {
client.stream_message(
@anthropic.MessageRequest::new(model~, max_tokens=1024, messages=[
@anthropic.Message::user("Write a haiku about rivers."),
]),
event => if event is TextDelta(text~, ..) { on_text(text) },
)
}pub struct Anthropic {
// private fields
}async fn Anthropic::count_tokens(self : Anthropic, request : MessageRequest) -> Result[Int, AnthropicFailure]async fn Anthropic::create_message(self : Anthropic, request : MessageRequest) -> Result[MessageResponse, AnthropicFailure]async fn Anthropic::create_message_params(self : Anthropic, params : CreateMessageParams) -> Result[Message, AnthropicFailure]async fn Anthropic::list_models(self : Anthropic, limit? : Int, after_id? : String, before_id? : String, lifecycle? : Array[ModelsListLifecycleItem]) -> Result[ListResponseModelInfo, AnthropicFailure]fn Anthropic::new(api_key~ : String, backend : &Backend, clock : &Clock, base_url? : String, version? : String, auth_header? : AuthHeader, retry? : RetryPolicy, timer? : &Timer, timeout_ms? : Int, max_body_bytes? : Int, total_timeout_ms? : Int) -> Anthropicfn Anthropic::paginate_models(self : Anthropic, limit? : Int, lifecycle? : Array[ModelsListLifecycleItem]) -> Paginator[ModelInfo, AnthropicFailure]async fn Anthropic::retrieve_model(self : Anthropic, model_id : String) -> Result[ModelInfo, AnthropicFailure]async fn Anthropic::stream_message(self : Anthropic, request : MessageRequest, f : async (MessageEvent) -> Unit) -> Result[Unit, AnthropicFailure]async fn Anthropic::stream_message_params(self : Anthropic, params : CreateMessageParams, f : async (MessageStreamEvent) -> Unit) -> Result[Unit, AnthropicFailure]test {
let error : @anthropic.ApiErrorBody = {
type_: "invalid_request_error",
message: "invalid request",
}
assert_eq(error.message, "invalid request")
}test {
assert_eq(@anthropic.Message::assistant("hello"), {
role: @anthropic.Assistant,
content: @anthropic.Text("hello"),
})
}test {
assert_eq(@anthropic.Message::system("answer in French"), {
role: @anthropic.System,
content: @anthropic.Text("answer in French"),
})
}test {
let message = @anthropic.Message::tool_result(
tool_use_id="toolu_1",
content="done",
)
assert_eq(message.role, @anthropic.User)
}test {
assert_eq(@anthropic.Message::user("hello"), {
role: @anthropic.User,
content: @anthropic.Text("hello"),
})
}pub(all) enum MessageEvent {
MessageStart(MessageResponse)
ContentBlockStart(index~ : Int, block~ : ContentBlock)
TextDelta(index~ : Int, text~ : String)
ThinkingDelta(index~ : Int, thinking~ : String)
SignatureDelta(index~ : Int, signature~ : String)
InputJsonDelta(index~ : Int, partial_json~ : String)
ContentBlockStop(index~ : Int)
MessageDelta(delta~ : MessageDelta, usage~ : MessageDeltaUsage)
MessageStop
Ping
Error(ApiErrorBody)
Other(String, Json)
} derive(Eq, Debug)pub(all) struct MessageRequest {
model : String
max_tokens : Int
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]
} derive(Eq, Debug)fn MessageRequest::new(model~ : String, max_tokens~ : Int, 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]) -> MessageRequesttest {
let request = @anthropic.MessageRequest::new(
model="claude-opus-5",
max_tokens=64,
messages=[@anthropic.Message::user("hello")],
)
assert_eq(request.messages.length(), 1)
}pub(all) struct MessageResponse {
id : String
model : String
role : Role
content : Array[ContentBlock]
stop_reason : StopReason?
usage : Usage
message : Message
raw : Json
} derive(Eq, Debug)test {
let tool = @anthropic.ToolDef::new(name="lookup", input_schema={
"type": "object",
})
assert_eq(tool.name, "lookup")
}pub struct ToolUseAccumulator {
// private fields
}test {
let tools = @anthropic.ToolUseAccumulator::new()
tools.feed(
@anthropic.ContentBlockStart(
index=0,
block=@anthropic.ToolUse(id="toolu_1", name="lookup", input={}),
),
)
tools.feed(@anthropic.InputJsonDelta(index=0, partial_json="{}"))
tools.feed(@anthropic.ContentBlockStop(index=0))
assert_eq(tools.finish()[0].2, {})
}fn ToolUseAccumulator::finish(self : ToolUseAccumulator) -> Array[(String, String, Json)] raise ParseErrorInstall
Download zipThin Anthropic Messages API client for MoonBit built on gaato/http and gaato/mttp.