///|
/// A capability a model may declare. The catalogue in `moonmuse/models` uses these
/// to describe what an endpoint can actually do, so a caller can pick a model for a
/// job instead of guessing from its name.
#derive(Eq, Debug)
pub(all) enum Capability {
Chat
Tools
Reasoning
Vision
Audio
Embedding
Json
}
///|
/// What a provider says about one model. Prices are US dollars per million tokens,
/// because that is the unit every vendor publishes and the one a cost estimate wants.
#derive(Eq, Debug)
pub(all) struct ModelInfo {
id : String
context : Int32?
output : Int32?
input_price : Double?
output_price : Double?
capabilities : Array[Capability]
}
///|
/// A model with everything unknown except its id.
pub fn ModelInfo::new(
id : String,
context? : Int32,
output? : Int32,
input_price? : Double,
output_price? : Double,
capabilities~ : Array[Capability] = [],
) -> ModelInfo {
{ id, context, output, input_price, output_price, capabilities, }
}
///|
/// Whether the model declares `capability`.
pub fn ModelInfo::supports(self : ModelInfo, capability : Capability) -> Bool {
for item in self.capabilities {
if item == capability {
return true
}
}
false
}
///|
/// How a request should use tools.
#derive(Eq, Debug)
pub(all) enum ToolChoice {
/// The model decides. The default of every provider here.
Auto
/// The model must answer in text.
NoTools
/// The model must call some tool.
Required
/// The model must call this tool.
Named(String)
}
///|
/// A tool the model may call: a name, a description, and a JSON Schema object for
/// the arguments.
#derive(Eq, Debug)
pub(all) struct Tool {
name : String
description : String
schema : Json
}
///|
/// A tool with an empty object schema, for a tool that takes no arguments.
pub fn Tool::new(
name : String,
description : String,
schema~ : Json = { "type": "object", "properties": {} },
) -> Tool {
{ name, description, schema, }
}
///|
/// One request, in the vocabulary every provider shares. `extra` is merged into the
/// request body last of all, so a field this library does not model — a vendor's
/// beta switch, a reasoning budget — still reaches the wire.
#derive(Eq, Debug)
pub(all) struct Request {
model : String
messages : Array[Message]
tools : Array[Tool]
choice : ToolChoice
temperature : Double?
max_tokens : Int32?
stop : Array[String]
extra : Map[String, Json]
}
///|
/// A request with the provider's defaults.
pub fn Request::new(
model : String,
messages : Array[Message],
tools~ : Array[Tool] = [],
choice~ : ToolChoice = Auto,
temperature? : Double,
max_tokens? : Int32,
stop~ : Array[String] = [],
extra~ : Map[String, Json] = Map([]),
) -> Request {
{ model, messages, tools, choice, temperature, max_tokens, stop, extra, }
}
///|
/// A copy with one more message — the tool loop appends the assistant's call and the
/// tool's result this way.
pub fn Request::push(self : Request, message : Message) -> Request {
{ ..self, messages: [..self.messages, message], }
}
///|
/// A copy with the messages replaced.
pub fn Request::with_messages(
self : Request,
messages : Array[Message],
) -> Request {
{ ..self, messages, }
}
///|
pub extend Capability with Eq::{not_equal, equal}
///|
pub extend Capability with Debug::{to_repr}
///|
pub extend ModelInfo with Eq::{not_equal, equal}
///|
pub extend ModelInfo with Debug::{to_repr}
///|
pub extend ToolChoice with Eq::{not_equal, equal}
///|
pub extend ToolChoice with Debug::{to_repr}
///|
pub extend Tool with Eq::{not_equal, equal}
///|
pub extend Tool with Debug::{to_repr}
///|
pub extend Request with Eq::{not_equal, equal}
///|
pub extend Request with Debug::{to_repr}