///|
/// The error body returned by the OpenAI API.
///
/// ```mbt check
/// test {
/// let error : @openai.ApiErrorBody = {
/// message: "invalid request",
/// type_: Some("invalid_request_error"),
/// param: None,
/// code: None,
/// }
/// assert_eq(error.message, "invalid request")
/// }
/// ```
pub(all) struct ApiErrorBody {
message : String
type_ : String?
param : String?
code : String?
} derive(Eq, Debug)
///|
/// 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}
///|
/// Basic information about an OpenAI model.
pub(all) struct Model {
id : String
created : Int64?
owned_by : String?
} derive(Eq, Debug)
///|
/// Compares model information field by field.
pub extend Model with Eq::{equal, not_equal}
///|
/// Debug representation of model information.
pub extend Model with @debug.Debug::{to_repr}
///|
/// Token usage reported by a response.
pub(all) struct Usage {
input_tokens : Int
output_tokens : Int
total_tokens : Int
} derive(Eq, Debug)
///|
/// Compares response usage field by field.
pub extend Usage with Eq::{equal, not_equal}
///|
/// Debug representation of response usage.
pub extend Usage with @debug.Debug::{to_repr}
///|
/// A function tool definition shared by Chat Completions and Responses.
///
/// ```mbt check
/// test {
/// let tool = @openai.ToolDef::new(name="lookup", parameters={ "type": "object" })
/// assert_eq(tool.name, "lookup")
/// }
/// ```
pub(all) struct ToolDef {
name : String
description : String?
parameters : Json
strict : Bool?
} derive(Eq, Debug)
///|
/// 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 function tool definition with a JSON Schema parameter object.
pub fn ToolDef::new(
name~ : String,
parameters~ : Json,
description? : String,
strict? : Bool,
) -> ToolDef {
{ name, description, parameters, strict, }
}
///|
/// A function call produced by a model. Arguments remain raw text until parsed.
pub(all) struct ToolCall {
id : String
name : String
arguments : String
} derive(Eq, Debug)
///|
/// Compares tool calls field by field.
pub extend ToolCall with Eq::{equal, not_equal}
///|
/// Debug representation of a tool call.
pub extend ToolCall with @debug.Debug::{to_repr}
///|
/// Parses the model-produced argument string as JSON on demand.
///
/// ```mbt check
/// test {
/// let call : @openai.ToolCall = {
/// id: "call_1",
/// name: "lookup",
/// arguments: "{\"id\":1}",
/// }
/// assert_eq(call.arguments_json(), { "id": 1 })
/// }
/// ```
pub fn ToolCall::arguments_json(self : ToolCall) -> Json raise @json.ParseError {
@json.parse(self.arguments)
}
///|
/// One text message sent to the Chat Completions API.
///
/// ```mbt check
/// test {
/// let message = @openai.ChatMessage::user("hello")
/// assert_eq(message.role, "user")
/// assert_eq(message.content, "hello")
/// }
/// ```
pub(all) struct ChatMessage {
role : String
content : String
name : String?
tool_calls : Array[ToolCall]?
tool_call_id : String?
} derive(Eq, Debug)
///|
/// Compares chat messages field by field.
pub extend ChatMessage with Eq::{equal, not_equal}
///|
/// Debug representation of a chat message.
pub extend ChatMessage with @debug.Debug::{to_repr}
///|
/// Creates a system chat message.
///
/// ```mbt check
/// test {
/// assert_eq(@openai.ChatMessage::system("Be concise").role, "system")
/// }
/// ```
pub fn ChatMessage::system(content : String) -> ChatMessage {
{ role: "system", content, name: None, tool_calls: None, tool_call_id: None, }
}
///|
/// Creates a user chat message.
///
/// ```mbt check
/// test {
/// assert_eq(@openai.ChatMessage::user("hello").role, "user")
/// }
/// ```
pub fn ChatMessage::user(content : String) -> ChatMessage {
{ role: "user", content, name: None, tool_calls: None, tool_call_id: None, }
}
///|
/// Creates an assistant chat message.
///
/// ```mbt check
/// test {
/// assert_eq(@openai.ChatMessage::assistant("hello").role, "assistant")
/// }
/// ```
pub fn ChatMessage::assistant(content : String) -> ChatMessage {
{
role: "assistant",
content,
name: None,
tool_calls: None,
tool_call_id: None,
}
}
///|
/// Creates a tool result message associated with one model tool call.
///
/// ```mbt check
/// test {
/// let message = @openai.ChatMessage::tool(tool_call_id="call_1", content="done")
/// assert_eq(message.tool_call_id, Some("call_1"))
/// }
/// ```
pub fn ChatMessage::tool(
tool_call_id~ : String,
content~ : String,
) -> ChatMessage {
{
role: "tool",
content,
name: None,
tool_calls: None,
tool_call_id: Some(tool_call_id),
}
}
///|
/// Creates an assistant message containing function tool calls.
/// When content is absent it is encoded without a content field.
///
/// ```mbt check
/// test {
/// let message = @openai.ChatMessage::assistant_tool_calls([
/// { id: "call_1", name: "lookup", arguments: "{}", },
/// ])
/// assert_eq(message.tool_calls.unwrap().length(), 1)
/// }
/// ```
pub fn ChatMessage::assistant_tool_calls(
tool_calls : Array[ToolCall],
content? : String,
) -> ChatMessage {
{
role: "assistant",
content: content.unwrap_or(""),
name: None,
tool_calls: Some(tool_calls.copy()),
tool_call_id: None,
}
}
///|
/// Input accepted by buffered and streaming Chat Completions operations.
pub(all) struct ChatRequest {
model : String
messages : Array[ChatMessage]
max_tokens : Int?
temperature : Double?
/// Wire value of `reasoning_effort` (`low`, `high`, `xhigh`, ...). Passed
/// through as an open enum, so values newer than the vendored spec work.
reasoning_effort : String?
tools : Array[ToolDef]?
tool_choice : Json?
extra : Map[String, Json]
} derive(Eq, Debug)
///|
/// Compares chat requests field by field.
pub extend ChatRequest with Eq::{equal, not_equal}
///|
/// Debug representation of a chat request.
pub extend ChatRequest with @debug.Debug::{to_repr}
///|
/// Creates a chat request and snapshots mutable inputs.
///
/// ```mbt check
/// test {
/// let request = @openai.ChatRequest::new(model="gpt-4o-mini", messages=[
/// @openai.ChatMessage::user("hello"),
/// ])
/// assert_eq(request.messages.length(), 1)
/// }
/// ```
pub fn ChatRequest::new(
model~ : String,
messages~ : Array[ChatMessage],
max_tokens? : Int,
temperature? : Double,
reasoning_effort? : String,
tools? : Array[ToolDef],
tool_choice? : Json,
extra? : Map[String, Json],
) -> ChatRequest {
{
model,
messages: messages.map(copy_chat_message),
max_tokens,
temperature,
reasoning_effort,
tools: tools.map(Array::copy),
tool_choice,
extra: extra.map(Map::copy).unwrap_or({}),
}
}
///|
fn copy_chat_message(message : ChatMessage) -> ChatMessage {
{ ..message, tool_calls: message.tool_calls.map(Array::copy), }
}
///|
/// Why a chat completion stopped. Unknown values are retained.
pub(all) enum FinishReason {
Stop
Length
ToolCalls
ContentFilter
Unknown(String)
} derive(Eq, Debug)
///|
/// Compares finish reasons, including unknown raw values.
pub extend FinishReason with Eq::{equal, not_equal}
///|
/// Debug representation of a finish reason.
pub extend FinishReason with @debug.Debug::{to_repr}
///|
/// A buffered chat completion together with its original JSON value.
pub(all) struct ChatCompletion {
id : String
model : String
text : String
finish_reason : FinishReason?
usage : Usage?
tool_calls : Array[ToolCall]
raw : Json
} derive(Eq, Debug)
///|
/// Compares chat completions field by field.
pub extend ChatCompletion with Eq::{equal, not_equal}
///|
/// Debug representation of a chat completion.
pub extend ChatCompletion with @debug.Debug::{to_repr}
///|
/// One event from a streaming chat completion. Unknown chunks retain raw JSON.
pub(all) enum ChatEvent {
Delta(String)
ReasoningDelta(String)
ToolCallDelta(
index~ : Int,
id~ : String?,
name~ : String?,
arguments~ : String
)
Finished(FinishReason)
Usage(Usage)
Other(String, Json)
} derive(Eq, Debug)
///|
/// Compares chat events, including retained unknown JSON.
pub extend ChatEvent with Eq::{equal, not_equal}
///|
/// Debug representation of a chat event.
pub extend ChatEvent with @debug.Debug::{to_repr}
///|
/// Incrementally reconstructs tool calls from streamed chat deltas.
///
/// ```mbt check
/// test {
/// let calls = @openai.ToolCallAccumulator::new()
/// calls.feed(index=0, id="call_1", name="lookup", arguments="{}")
/// assert_eq(calls.finish()[0].arguments, "{}")
/// }
/// ```
pub struct ToolCallAccumulator {
priv calls : Array[PendingToolCall]
}
///|
/// Creates an empty streamed tool-call accumulator.
pub fn ToolCallAccumulator::new() -> ToolCallAccumulator {
{ calls: [], }
}
///|
/// Adds one tool-call delta. The first supplied id and name for an index win.
pub fn ToolCallAccumulator::feed(
self : ToolCallAccumulator,
index~ : Int,
id? : String,
name? : String,
arguments~ : String,
) -> Unit {
match self.calls.search_by(call => call.index == index) {
None => {
self.calls.push({ index, id, name, arguments: StringBuilder(), })
self.calls.last().unwrap().arguments.write_string(arguments)
}
Some(call_index) => {
let call = self.calls[call_index]
if call.id is None && id is Some(value) {
call.id = Some(value)
}
if call.name is None && name is Some(value) {
call.name = Some(value)
}
call.arguments.write_string(arguments)
}
}
}
///|
/// Returns reconstructed calls ordered by their stream index.
/// Missing ids or names are returned as empty strings.
pub fn ToolCallAccumulator::finish(
self : ToolCallAccumulator,
) -> Array[ToolCall] {
let pending = self.calls.copy()
pending.sort_by((left, right) => left.index - right.index)
pending.map(call => {
id: call.id.unwrap_or(""),
name: call.name.unwrap_or(""),
arguments: call.arguments.to_string(),
})
}
///|
priv struct PendingToolCall {
index : Int
mut id : String?
mut name : String?
arguments : StringBuilder
}
///|
/// Input accepted by the embeddings operation.
pub(all) struct EmbeddingRequest {
model : String
input : Array[String]
dimensions : Int?
user : String?
} derive(Eq, Debug)
///|
/// Compares embedding requests field by field.
pub extend EmbeddingRequest with Eq::{equal, not_equal}
///|
/// Debug representation of an embedding request.
pub extend EmbeddingRequest with @debug.Debug::{to_repr}
///|
/// Creates an embedding request and snapshots its input array.
///
/// ```mbt check
/// test {
/// let request = @openai.EmbeddingRequest::new(model="text-embedding-3-small", input=[
/// "hello",
/// ])
/// assert_eq(request.input, ["hello"])
/// }
/// ```
pub fn EmbeddingRequest::new(
model~ : String,
input~ : Array[String],
dimensions? : Int,
user? : String,
) -> EmbeddingRequest {
{ model, input: input.copy(), dimensions, user, }
}
///|
/// One embedding vector and its position in the result list.
pub(all) struct Embedding {
index : Int
embedding : Array[Double]
} derive(Eq, Debug)
///|
/// Compares embedding values field by field.
pub extend Embedding with Eq::{equal, not_equal}
///|
/// Debug representation of an embedding value.
pub extend Embedding with @debug.Debug::{to_repr}
///|
/// The flattened result of an embeddings operation.
pub(all) struct EmbeddingResponse {
data : Array[Embedding]
model : String
prompt_tokens : Int
total_tokens : Int
} derive(Eq, Debug)
///|
/// Compares embedding responses field by field.
pub extend EmbeddingResponse with Eq::{equal, not_equal}
///|
/// Debug representation of an embedding response.
pub extend EmbeddingResponse with @debug.Debug::{to_repr}
///|
/// A response lifecycle status. Unknown values are retained for forward compatibility.
pub(all) enum ResponseStatus {
Completed
Failed
InProgress
Incomplete
Cancelled
Queued
Unknown(String)
} derive(Eq, Debug)
///|
/// Compares response statuses, including unknown raw values.
pub extend ResponseStatus with Eq::{equal, not_equal}
///|
/// Debug representation of a response status.
pub extend ResponseStatus with @debug.Debug::{to_repr}
///|
/// Input accepted by buffered and streaming response creation.
pub(all) struct ResponseRequest {
model : String
input : String
instructions : String?
max_output_tokens : Int?
temperature : Double?
previous_response_id : String?
tools : Array[ToolDef]?
tool_choice : Json?
extra : Map[String, Json]
priv tool_outputs : Array[(String, String)]
} derive(Eq, Debug)
///|
/// Compares response requests field by field.
pub extend ResponseRequest with Eq::{equal, not_equal}
///|
/// Debug representation of a response request.
pub extend ResponseRequest with @debug.Debug::{to_repr}
///|
/// Creates a response request and snapshots the extra parameter map.
///
/// ```mbt check
/// test {
/// let request = @openai.ResponseRequest::new(model="gpt-4.1", input="hello")
/// assert_eq(request.extra, {})
/// }
/// ```
pub fn ResponseRequest::new(
model~ : String,
input~ : String,
instructions? : String,
max_output_tokens? : Int,
temperature? : Double,
previous_response_id? : String,
tools? : Array[ToolDef],
tool_choice? : Json,
extra? : Map[String, Json],
) -> ResponseRequest {
{
model,
input,
instructions,
max_output_tokens,
temperature,
previous_response_id,
tools: tools.map(Array::copy),
tool_choice,
extra: extra.map(Map::copy).unwrap_or({}),
tool_outputs: [],
}
}
///|
/// Returns a request with function outputs appended to its input items.
///
/// ```mbt check
/// test {
/// let request = @openai.ResponseRequest::new(model="gpt-4.1", input="continue").with_tool_outputs([
/// ("call_1", "done"),
/// ],
/// )
/// assert_eq(request.input, "continue")
/// }
/// ```
pub fn ResponseRequest::with_tool_outputs(
self : ResponseRequest,
outputs : Array[(String, String)],
) -> ResponseRequest {
{ ..self, tool_outputs: self.tool_outputs + outputs, }
}
///|
/// A decoded response together with its original JSON value.
pub(all) struct Response {
id : String
status : ResponseStatus
model : String
output_text : String
usage : Usage?
tool_calls : Array[ToolCall]
raw : Json
} derive(Eq, Debug)
///|
/// Compares decoded responses field by field.
pub extend Response with Eq::{equal, not_equal}
///|
/// Debug representation of a decoded response.
pub extend Response with @debug.Debug::{to_repr}
///|
/// One event from a streaming response. Unknown event types retain their raw JSON.
pub(all) enum ResponseEvent {
Created(Response)
InProgress(Response)
OutputTextDelta(String)
OutputTextDone(String)
FunctionCallArgumentsDelta(item_id~ : String, delta~ : String)
FunctionCallArgumentsDone(item_id~ : String, arguments~ : String)
Completed(Response)
Failed(Response)
Incomplete(Response)
Error(ApiErrorBody)
Other(String, Json)
} derive(Eq, Debug)
///|
/// Compares response events, including retained unknown JSON.
pub extend ResponseEvent with Eq::{equal, not_equal}
///|
/// Debug representation of a response event.
pub extend ResponseEvent with @debug.Debug::{to_repr}