mod anthropic;
mod openai_chat;
mod openai_responses;
pub use anthropic::{
AnthropicCacheControl, AnthropicCompat, AnthropicParallelToolCalls, AnthropicSamplingParams,
AnthropicStructuredOutput, AnthropicThinkingFormat, AnthropicThinkingReplay,
ResolvedAnthropicCompat, ANTHROPIC_PRESETS, ANTHROPIC_PRESET_BASE_URLS,
};
pub use openai_chat::{
ChatModelOverride, OpenAIChatAssistantAfterToolResult, OpenAIChatAssistantReasoningContent,
OpenAIChatBuiltinTools, OpenAIChatCompat, OpenAIChatForcedToolChoice,
OpenAIChatInstructionRole, OpenAIChatJsonSchema, OpenAIChatMaxTokensField,
OpenAIChatReasoningOff, OpenAIChatStreamUsage, OpenAIChatThinkingFormat,
OpenAIChatThinkingReplay, OpenAIChatTokenScoring, OpenAIChatUserField,
ResolvedOpenAIChatCompat, DEEPINFRA_FORCED_TOOL_CHOICE, OPENAI_CHAT_PRESETS,
OPENAI_CHAT_PRESET_BASE_URLS,
};
pub use openai_responses::{
OpenAIResponsesBuiltinTools, OpenAIResponsesCommentaryPhase, OpenAIResponsesCompat,
OpenAIResponsesDeveloperRole, OpenAIResponsesEditImageField,
OpenAIResponsesMaxOutputTokensField, OpenAIResponsesReasoningFormat,
ResolvedOpenAIResponsesCompat, OPENAI_RESPONSES_PRESETS, OPENAI_RESPONSES_PRESET_BASE_URLS,
};
use crate::types::ReasoningEffort;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Knob<T> {
Auto,
Set(T),
}
impl<T: Copy> Knob<T> {
pub fn resolve(knob: Option<Knob<T>>, default: T) -> T {
match knob {
Some(Knob::Set(value)) => value,
None | Some(Knob::Auto) => default,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ToolResultMedia {
Native,
Images,
Reject,
}
impl ToolResultMedia {
pub fn as_str(self) -> &'static str {
match self {
ToolResultMedia::Native => "native",
ToolResultMedia::Images => "images",
ToolResultMedia::Reject => "reject",
}
}
pub fn parse(value: &str) -> Option<Self> {
match value {
"native" => Some(ToolResultMedia::Native),
"images" => Some(ToolResultMedia::Images),
"reject" => Some(ToolResultMedia::Reject),
_ => None,
}
}
pub fn admits(self, kind: &str) -> bool {
match self {
ToolResultMedia::Native => matches!(kind, "image" | "document"),
ToolResultMedia::Images => kind == "image",
ToolResultMedia::Reject => false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum IncludeOmit {
Include,
Omit,
}
impl IncludeOmit {
pub fn as_str(self) -> &'static str {
match self {
IncludeOmit::Include => "include",
IncludeOmit::Omit => "omit",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SendReject {
Send,
Reject,
}
impl SendReject {
pub fn as_str(self) -> &'static str {
match self {
SendReject::Send => "send",
SendReject::Reject => "reject",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum OpenAICacheControl {
None,
OpenAI,
OpenAIImplicit,
Anthropic,
}
impl OpenAICacheControl {
pub fn as_str(self) -> &'static str {
match self {
OpenAICacheControl::None => "none",
OpenAICacheControl::OpenAI => "openai",
OpenAICacheControl::OpenAIImplicit => "openai_implicit",
OpenAICacheControl::Anthropic => "anthropic",
}
}
}
pub type ReasoningEfforts = &'static [ReasoningEffort];
pub type JsonObject = serde_json::Map<String, serde_json::Value>;
#[derive(Debug, Clone, PartialEq, Default)]
pub enum Compat {
#[default]
None,
Anthropic(AnthropicCompat),
OpenAIResponses(OpenAIResponsesCompat),
OpenAIChat(OpenAIChatCompat),
}
impl Compat {
pub fn anthropic(&self) -> Option<&AnthropicCompat> {
match self {
Compat::Anthropic(c) => Some(c),
_ => None,
}
}
pub fn openai_responses(&self) -> Option<&OpenAIResponsesCompat> {
match self {
Compat::OpenAIResponses(c) => Some(c),
_ => None,
}
}
pub fn openai_chat(&self) -> Option<&OpenAIChatCompat> {
match self {
Compat::OpenAIChat(c) => Some(c),
_ => None,
}
}
}
pub fn preset_key(name: &str) -> String {
let key: String = name
.to_ascii_lowercase()
.chars()
.map(|c| match c {
'-' | ' ' | '.' => '_',
other => other,
})
.collect();
crate::generated::tables::PRESET_ALIASES
.iter()
.find(|(alias, _)| *alias == key)
.map_or(key.clone(), |(_, preset)| (*preset).to_string())
}
fn find<'a, T>(table: &'a [(&'static str, T)], name: &str) -> Option<&'a T> {
let key = preset_key(name);
table
.iter()
.find(|(preset, _)| *preset == key)
.map(|(_, value)| value)
}
pub fn preset_base_url(
table: &'static [(&'static str, &'static str)],
name: &str,
) -> Option<&'static str> {
find(table, name).copied()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn preset_keys_normalize_and_alias() {
assert_eq!(preset_key("LM-Studio"), "lmstudio");
assert_eq!(preset_key("z.ai"), "zai");
assert_eq!(preset_key("openai_chat"), "openai");
assert_eq!(preset_key("bedrock-mantle"), "bedrock_mantle");
assert_eq!(preset_key("groq"), "groq");
}
#[test]
fn knob_resolution() {
assert_eq!(Knob::resolve(None, 1), 1);
assert_eq!(Knob::resolve(Some(Knob::Auto), 1), 1);
assert_eq!(Knob::resolve(Some(Knob::Set(2)), 1), 2);
}
#[test]
fn every_preset_name_resolves_to_a_base_url_when_listed() {
assert_eq!(
preset_base_url(OPENAI_CHAT_PRESET_BASE_URLS, "LM Studio"),
Some("http://localhost:1234/v1")
);
assert_eq!(
preset_base_url(ANTHROPIC_PRESET_BASE_URLS, "anthropic"),
Some("https://api.anthropic.com/v1")
);
assert_eq!(
preset_base_url(OPENAI_RESPONSES_PRESET_BASE_URLS, "bedrock"),
None
);
}
}