1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4pub const COMPLETE_TARGET: &str = "/llm/complete";
5
6#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7#[serde(rename_all = "camelCase", deny_unknown_fields)]
8pub struct LlmGenerationOptions {
9 #[serde(default)]
10 pub temperature: Option<f32>,
11 #[serde(default)]
12 pub max_tokens: Option<u32>,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize, Default)]
16#[serde(rename_all = "camelCase", deny_unknown_fields)]
17pub struct LlmCompleteRequest {
18 #[serde(default)]
19 pub constraints: crate::ModelConstraints,
20 #[serde(default)]
21 pub use_case: Option<String>,
22 #[serde(default)]
23 pub mode: Option<String>,
24 pub messages: Vec<crate::Message>,
25 #[serde(default)]
26 pub tools: Option<Vec<crate::ToolDefinition>>,
27 #[serde(default)]
28 pub provider: Option<Value>,
29 #[serde(default)]
30 pub response_format: Option<Value>,
31 #[serde(default)]
32 pub options: LlmGenerationOptions,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize, Default)]
36#[serde(rename_all = "camelCase")]
37pub struct LlmRouteInfo {
38 pub provider: String,
39 pub model: String,
40 pub mode: String,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, Default)]
44#[serde(rename_all = "camelCase")]
45pub struct LlmCompleteResponse {
46 pub message: crate::Message,
47 pub finish_reason: crate::FinishReason,
48 #[serde(default, skip_serializing_if = "Option::is_none")]
49 pub usage: Option<crate::TokenUsage>,
50 #[serde(default, skip_serializing_if = "Option::is_none")]
51 pub route: Option<LlmRouteInfo>,
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn request_rejects_removed_top_level_generation_options() {
60 assert!(
61 serde_json::from_value::<LlmCompleteRequest>(serde_json::json!({
62 "messages": [],
63 "options": {},
64 "temperature": 0.2
65 }))
66 .is_err()
67 );
68 }
69
70 #[test]
71 fn response_includes_normalized_usage() {
72 let response = LlmCompleteResponse {
73 usage: Some(crate::TokenUsage {
74 input_tokens: 2,
75 output_tokens: 3,
76 ..crate::TokenUsage::default()
77 }),
78 ..LlmCompleteResponse::default()
79 };
80 assert_eq!(response.usage.unwrap().total_tokens(), 5);
81 }
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
86#[serde(rename_all = "camelCase", deny_unknown_fields)]
87pub struct AsrRequest {
88 pub audio: artifact_api::MediaReference,
89 #[serde(default, skip_serializing_if = "Option::is_none")]
90 pub mode: Option<String>,
91 #[serde(default, skip_serializing_if = "Option::is_none")]
92 pub language: Option<String>,
93}