1use serde::{Deserialize, Serialize};
3use serde_json::Value;
4mod continuation;
5mod policy;
6pub use artifact_api::ArtifactUri;
7pub use continuation::Continuation;
8pub use policy::{
9 controls, input_modality_for_kind, input_modality_for_mime, normalize_capability_input,
10 normalize_constraint_input, normalize_input_token, payload_input_modalities, resolve,
11 BackendCapability, EffectiveGeneration, GenerationControls, GenerationParameters,
12 GenerationSupport, ModelCapabilities, DEFAULT_MAX_OUTPUT_TOKENS, INPUT_AUDIO, INPUT_FILE,
13 INPUT_IMAGE, INPUT_VIDEO, REASONING_EFFORT_LADDER,
14};
15
16#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
18#[serde(transparent)]
19pub struct UseCase(pub String);
20
21#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
23#[serde(transparent)]
24pub struct ModelMode(pub String);
25
26#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
30#[serde(deny_unknown_fields)]
31pub struct ModelConstraints {
32 #[serde(default)]
34 pub input: Vec<String>,
35 pub tool_calling: bool,
37 pub structured_output: bool,
39}
40
41#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
43#[serde(rename_all = "snake_case")]
44#[derive(Default)]
45pub enum MessageRole {
46 System,
48 #[default]
50 User,
51 Assistant,
53 Tool,
55}
56
57#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
59#[serde(tag = "type", rename_all = "snake_case")]
60#[serde(deny_unknown_fields)]
61pub enum ContentPart {
62 Text {
64 text: String,
66 },
67 Artifact {
69 uri: ArtifactUri,
71 },
72 ToolCall(ToolCall),
74 ToolResult {
76 call_id: String,
78 result: Value,
80 is_error: bool,
82 },
83}
84
85#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
87#[serde(deny_unknown_fields)]
88pub struct Message {
89 pub role: MessageRole,
91 pub content: Vec<ContentPart>,
93 #[serde(default, skip_serializing_if = "Option::is_none")]
95 pub continuation: Option<Continuation>,
96}
97
98#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
100pub struct ToolDefinition {
101 pub name: String,
102 pub description: String,
103 pub input_schema: Value,
104}
105#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
107#[serde(deny_unknown_fields)]
108pub struct ToolCall {
109 pub id: String,
111 pub name: String,
113 pub arguments: Value,
115}
116
117#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
119pub struct CompletionRequest {
120 pub use_case: UseCase,
122 pub model_mode: ModelMode,
124 pub messages: Vec<Message>,
126 pub tools: Vec<ToolDefinition>,
128 pub constraints: ModelConstraints,
130 pub max_output_tokens: Option<u32>,
132 pub diagnostics: bool,
134}
135
136#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
141pub struct ModelProfile {
142 pub profile_key: String,
144 pub context_window_tokens: u32,
146}
147
148#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
150#[serde(rename_all = "snake_case")]
151#[derive(Default)]
152pub enum FinishReason {
153 #[default]
155 Stop,
156 ToolCalls,
158 Length,
160 Other,
162}
163
164#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
166pub struct TokenUsage {
167 pub input_tokens: u64,
169 pub output_tokens: u64,
171 pub cached_input_tokens: Option<u64>,
173 pub reasoning_output_tokens: Option<u64>,
175 pub credits: Option<u64>,
177}
178
179#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
181pub struct Completion {
182 pub message: Message,
184 pub finish_reason: FinishReason,
186 pub usage: Option<TokenUsage>,
188 pub diagnostics: Option<Value>,
190}
191
192pub mod service;
193
194impl MessageRole {
195 pub const fn as_str(self) -> &'static str {
196 match self {
197 Self::System => "system",
198 Self::User => "user",
199 Self::Assistant => "assistant",
200 Self::Tool => "tool",
201 }
202 }
203}
204
205impl Default for Message {
206 fn default() -> Self {
207 Self::text(MessageRole::User, "")
208 }
209}
210impl Message {
211 pub fn text(role: MessageRole, text: impl Into<String>) -> Self {
212 Self {
213 role,
214 content: vec![ContentPart::Text { text: text.into() }],
215 continuation: None,
216 }
217 }
218 pub fn text_content(&self) -> String {
219 self.content
220 .iter()
221 .filter_map(|part| match part {
222 ContentPart::Text { text } => Some(text.as_str()),
223 _ => None,
224 })
225 .collect::<Vec<_>>()
226 .join("\n")
227 }
228}
229
230impl TokenUsage {
231 pub fn total_tokens(self) -> u64 {
232 self.input_tokens.saturating_add(self.output_tokens)
233 }
234}
235impl Message {
236 pub fn with_artifacts(mut self, artifacts: impl IntoIterator<Item = ArtifactUri>) -> Self {
237 self.content.extend(
238 artifacts
239 .into_iter()
240 .map(|uri| ContentPart::Artifact { uri }),
241 );
242 self
243 }
244}
245
246pub const MESSAGE_SCHEMA: &str = include_str!("../schema/message.v1.schema.json");