Skip to main content

j_agent/llm/
types.rs

1use serde::{Deserialize, Serialize};
2
3// ── Request types ──
4
5/// The role of a message author in a conversation.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "lowercase")]
8pub enum Role {
9    System,
10    User,
11    Assistant,
12    Tool,
13}
14
15/// Message content: simple text or multimodal parts.
16#[derive(Debug, Clone, Serialize, Deserialize)]
17#[serde(untagged)]
18pub enum Content {
19    Text(String),
20    Parts(Vec<ContentPart>),
21}
22
23/// A single part of multimodal content — text or image URL.
24#[derive(Debug, Clone, Serialize, Deserialize)]
25#[serde(tag = "type", rename_all = "snake_case")]
26pub enum ContentPart {
27    Text { text: String },
28    ImageUrl { image_url: ImageUrl },
29}
30
31/// Image URL payload for multimodal content parts.
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct ImageUrl {
34    pub url: String,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub detail: Option<String>,
37}
38
39/// Flat message — single struct, no per-role variants.
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct Message {
42    pub role: Role,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub content: Option<Content>,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub name: Option<String>,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub tool_calls: Option<Vec<ToolCall>>,
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub tool_call_id: Option<String>,
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub reasoning_content: Option<String>,
53}
54
55/// A tool call issued by the assistant in a response.
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct ToolCall {
58    pub id: String,
59    #[serde(rename = "type")]
60    pub call_type: String,
61    pub function: FunctionCall,
62}
63
64/// The function call details inside a tool call.
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct FunctionCall {
67    pub name: String,
68    pub arguments: String,
69}
70
71/// Tool definition for request.
72#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct ToolDefinition {
74    #[serde(rename = "type")]
75    pub tool_type: String,
76    pub function: FunctionObject,
77}
78
79/// Function specification within a tool definition.
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct FunctionObject {
82    pub name: String,
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub description: Option<String>,
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub parameters: Option<serde_json::Value>,
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub strict: Option<bool>,
89}
90
91/// Chat completion request.
92#[derive(Debug, Clone, Serialize)]
93pub struct ChatRequest {
94    pub model: String,
95    pub messages: Vec<Message>,
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub tools: Option<Vec<ToolDefinition>>,
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub stream: Option<bool>,
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub max_tokens: Option<u32>,
102    #[serde(flatten)]
103    pub extra: serde_json::Map<String, serde_json::Value>,
104}
105
106// ── Response types (non-streaming) ──
107
108/// Token usage reported by the API.
109#[derive(Debug, Clone, Deserialize, Default)]
110pub struct TokenUsage {
111    #[serde(default)]
112    pub prompt_tokens: u64,
113    #[serde(default)]
114    pub completion_tokens: u64,
115    #[serde(default)]
116    #[allow(dead_code)]
117    pub total_tokens: u64,
118}
119
120/// Non-streaming chat completion response.
121#[derive(Debug, Clone, Deserialize)]
122pub struct ChatResponse {
123    pub choices: Vec<Choice>,
124    #[serde(default)]
125    pub usage: Option<TokenUsage>,
126}
127
128/// A single choice in a completion response.
129#[derive(Debug, Clone, Deserialize)]
130pub struct Choice {
131    pub message: ResponseMessage,
132    pub finish_reason: Option<String>,
133}
134
135#[allow(dead_code)]
136impl Choice {
137    /// Returns true if the finish reason indicates a tool call.
138    pub fn is_tool_calls(&self) -> bool {
139        self.finish_reason.as_deref() == Some("tool_calls")
140    }
141}
142
143/// The message payload inside a non-streaming response choice.
144#[derive(Debug, Clone, Deserialize)]
145#[allow(dead_code)]
146pub struct ResponseMessage {
147    pub content: Option<String>,
148    pub reasoning_content: Option<String>,
149    pub tool_calls: Option<Vec<ToolCall>>,
150}
151
152// ── Streaming response types ──
153
154/// A single chunk from a streaming chat completion.
155#[derive(Debug, Clone, Deserialize)]
156pub struct ChatStreamChunk {
157    pub choices: Vec<StreamChoice>,
158    #[serde(default)]
159    pub usage: Option<TokenUsage>,
160}
161
162/// A single choice within a streaming chunk.
163#[derive(Debug, Clone, Deserialize)]
164pub struct StreamChoice {
165    #[serde(default)]
166    pub index: u32,
167    pub delta: Delta,
168    pub finish_reason: Option<String>,
169}
170
171impl StreamChoice {
172    /// Returns true if the finish reason indicates a tool call.
173    #[allow(dead_code)]
174    pub fn is_tool_calls(&self) -> bool {
175        self.finish_reason.as_deref() == Some("tool_calls")
176    }
177}
178
179/// The incremental delta in a streaming response.
180#[derive(Debug, Clone, Deserialize)]
181pub struct Delta {
182    #[allow(dead_code)]
183    pub role: Option<Role>,
184    pub content: Option<String>,
185    pub reasoning_content: Option<String>,
186    pub tool_calls: Option<Vec<DeltaToolCall>>,
187}
188
189/// A tool call delta carried by a streaming chunk.
190#[derive(Debug, Clone, Deserialize)]
191pub struct DeltaToolCall {
192    #[serde(default)]
193    pub index: u32,
194    #[serde(default)]
195    pub id: Option<String>,
196    pub function: Option<DeltaFunction>,
197}
198
199/// Function call delta within a streaming tool call.
200#[derive(Debug, Clone, Deserialize)]
201pub struct DeltaFunction {
202    pub name: Option<String>,
203    pub arguments: Option<String>,
204}