use super::json::ValidationError;
macro_rules! vocab {
($(#[$meta:meta])* $name:ident, $label:literal, { $($variant:ident => $s:literal),+ $(,)? }) => {
$(#[$meta])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum $name {
$($variant),+
}
impl $name {
pub const ALL: &'static [$name] = &[$($name::$variant),+];
pub fn as_str(self) -> &'static str {
match self {
$($name::$variant => $s),+
}
}
pub fn parse(value: &str) -> Result<Self, ValidationError> {
match value {
$($s => Ok($name::$variant),)+
_ => Err(ValidationError::value(format!(
"unsupported {}: {}", $label, value
))),
}
}
}
impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl std::str::FromStr for $name {
type Err = ValidationError;
fn from_str(value: &str) -> Result<Self, ValidationError> {
$name::parse(value)
}
}
};
}
vocab!(
Role, "role", {
User => "user",
Assistant => "assistant",
Tool => "tool",
Developer => "developer",
}
);
vocab!(
FinishReason, "finish reason", {
Stop => "stop",
Length => "length",
ToolCall => "tool_call",
ContentFilter => "content_filter",
Error => "error",
}
);
vocab!(
ReasoningEffort, "reasoning effort", {
Off => "off",
Minimal => "minimal",
Low => "low",
Medium => "medium",
High => "high",
Xhigh => "xhigh",
Max => "max",
}
);
vocab!(
ReasoningSummary, "reasoning summary", {
Auto => "auto",
Concise => "concise",
Detailed => "detailed",
}
);
vocab!(
ToolChoiceMode, "tool choice mode", {
Auto => "auto",
Required => "required",
None => "none",
}
);
vocab!(
CacheMode, "cache mode", {
Auto => "auto",
Off => "off",
}
);
vocab!(
CacheRetention, "cache retention", {
Short => "short",
Long => "long",
}
);
vocab!(
CachePrefix, "cache prefix", {
Stable => "stable",
History => "history",
}
);
vocab!(
BatchStatus, "batch status", {
Queued => "queued",
Running => "running",
Cancelling => "cancelling",
Completed => "completed",
Failed => "failed",
Cancelled => "cancelled",
Expired => "expired",
}
);
impl BatchStatus {
pub fn is_terminal(self) -> bool {
matches!(
self,
BatchStatus::Completed
| BatchStatus::Failed
| BatchStatus::Cancelled
| BatchStatus::Expired
)
}
}
vocab!(
BatchOutcome, "batch outcome", {
Succeeded => "succeeded",
Errored => "errored",
Cancelled => "cancelled",
Expired => "expired",
}
);
vocab!(
VideoStatus, "video status", {
Queued => "queued",
Running => "running",
Completed => "completed",
Failed => "failed",
Cancelled => "cancelled",
}
);
impl VideoStatus {
pub fn is_terminal(self) -> bool {
matches!(
self,
VideoStatus::Completed | VideoStatus::Failed | VideoStatus::Cancelled
)
}
}
vocab!(
FileReadiness, "file readiness", {
Pending => "pending",
Ready => "ready",
Failed => "failed",
}
);
vocab!(
AudioEncoding, "audio encoding", {
Pcm16 => "pcm16",
Opus => "opus",
Mp3 => "mp3",
Aac => "aac",
}
);
vocab!(
ImageDetail, "ImagePart.detail", {
Low => "low",
High => "high",
Auto => "auto",
}
);
vocab!(AdaptationAction, "adaptation action", {
Dropped => "dropped", Clamped => "clamped", Substituted => "substituted",
ClientSide => "client_side", Satisfied => "satisfied", Defaulted => "defaulted",
});
vocab!(AdaptationPolicy, "adaptation policy", {
Note => "note", Silent => "silent", Refuse => "refuse",
});
#[allow(clippy::derivable_impls)] impl Default for AdaptationPolicy {
fn default() -> Self {
Self::Note
}
}
vocab!(ProbabilityPolicy, "probability policy", {
Off => "off", IfAvailable => "if_available", Required => "required",
});
vocab!(NamedCredential, "named credential", {
Platform => "platform", Workload => "workload", Environment => "environment", Cli => "cli"
});
impl From<NamedCredential> for String {
fn from(value: NamedCredential) -> Self {
value.as_str().into()
}
}
vocab!(JudgmentMethod, "judgment method", {
ProviderClassification => "provider_classification",
CandidateSequenceLikelihood => "candidate_sequence_likelihood",
});
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn closed_vocabularies_reject_unknown_values() {
assert!(Role::parse("system").is_err());
assert_eq!(Role::parse("developer").unwrap(), Role::Developer);
assert!(FinishReason::parse("done").is_err());
assert!(ReasoningEffort::parse("adaptive").is_err());
assert_eq!(ReasoningEffort::ALL.len(), 7);
assert_eq!(BatchStatus::ALL.len(), 7);
assert!(BatchStatus::Completed.is_terminal());
assert!(!BatchStatus::Cancelling.is_terminal());
}
}