-
Notifications
You must be signed in to change notification settings - Fork 438
Expand file tree
/
Copy pathrequest.rs
More file actions
131 lines (114 loc) · 3.82 KB
/
request.rs
File metadata and controls
131 lines (114 loc) · 3.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! Request models for the API endpoints.
//!
//! This module defines the structures used to represent incoming API requests,
//! including chat messages, configuration options, and request parameters.
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// Primary request structure for chat API endpoints.
///
/// This structure represents a complete chat request, including messages,
/// system prompts, and configuration options for both DeepSeek and Anthropic APIs.
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ApiRequest {
#[serde(default)]
pub stream: bool,
#[serde(default)]
pub verbose: bool,
pub system: Option<String>,
pub messages: Vec<Message>,
#[serde(default)]
pub deepseek_config: ApiConfig,
#[serde(default)]
pub anthropic_config: ApiConfig,
}
/// A single message in a chat conversation.
///
/// Represents one message in the conversation history, including
/// its role (system, user, or assistant) and content.
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Message {
pub role: Role,
pub content: String,
}
/// Possible roles for a message in a chat conversation.
///
/// Each message must be associated with one of these roles to
/// properly structure the conversation flow.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum Role {
System,
User,
Assistant,
}
/// Configuration options for external API requests.
///
/// Contains headers and body parameters that will be passed
/// to the external AI model APIs.
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct ApiConfig {
#[serde(default)]
pub headers: HashMap<String, String>,
#[serde(default)]
pub body: serde_json::Value,
}
impl ApiRequest {
/// Validates that system prompts are not duplicated.
///
/// Checks that a system prompt is not provided in both the root level
/// and messages array. The system prompt itself is optional.
///
/// # Returns
///
/// * `bool` - True if system prompt validation passes (no duplicates), false otherwise
pub fn validate_system_prompt(&self) -> bool {
let system_in_messages = self
.messages
.iter()
.any(|msg| matches!(msg.role, Role::System));
// Only invalid if system prompt is provided in both places
!(self.system.is_some() && system_in_messages)
}
/// Returns messages with the system prompt in the correct position.
///
/// Ensures the system prompt (if present) is the first message,
/// followed by the conversation messages in order.
///
/// # Returns
///
/// * `Vec<Message>` - Messages with system prompt correctly positioned
pub fn get_messages_with_system(&self) -> Vec<Message> {
let mut messages = Vec::new();
// Add system message first
if let Some(system) = &self.get_system_prompt() {
messages.push(Message {
role: Role::System,
content: system.to_string(),
});
}
// Add remaining messages
messages.extend(
self.messages
.iter()
.filter(|msg| !matches!(msg.role, Role::System))
.cloned(),
);
messages
}
/// Retrieves the system prompt if one is present.
///
/// Checks both the root level system field and the messages array
/// for a system prompt.
///
/// # Returns
///
/// * `Option<&str>` - The system prompt if found, None otherwise
pub fn get_system_prompt(&self) -> Option<&str> {
self.system.as_deref().or_else(|| {
self.messages
.iter()
.find(|msg| matches!(msg.role, Role::System))
.map(|msg| msg.content.as_str())
})
}
}