use std::collections::HashMap;
use super::{ControlCmd, InputType, LLMRequestType, LLMResponseType, TurnId};
use crate::controller::tools::{AskUserQuestionsRequest, ToolResultStatus};
use crate::permissions::{BatchPermissionRequest, PermissionRequest};
#[derive(Debug, Clone)]
pub struct ToLLMPayload {
pub request_type: LLMRequestType,
pub content: String,
pub tool_results: Vec<ToolResultInfo>,
pub options: Option<LLMRequestOptions>,
pub turn_id: Option<TurnId>,
pub compact_summaries: HashMap<String, String>,
}
#[derive(Debug, Clone, Default)]
pub struct LLMRequestOptions {
pub model: Option<String>,
pub max_tokens: Option<i64>,
pub system_prompt: Option<String>,
}
#[derive(Debug, Clone)]
pub struct FromLLMPayload {
pub session_id: i64,
pub response_type: LLMResponseType,
pub text: String,
pub tool_use: Option<ToolUseInfo>,
pub tool_uses: Vec<ToolUseInfo>,
pub is_complete: bool,
pub error: Option<String>,
pub model: String,
pub message_id: String,
pub content_index: usize,
pub stop_reason: Option<String>,
pub input_tokens: i64,
pub output_tokens: i64,
pub turn_id: Option<TurnId>,
}
impl Default for FromLLMPayload {
fn default() -> Self {
Self {
session_id: 0,
response_type: LLMResponseType::TextChunk,
text: String::new(),
tool_use: None,
tool_uses: Vec::new(),
is_complete: false,
error: None,
model: String::new(),
message_id: String::new(),
content_index: 0,
stop_reason: None,
input_tokens: 0,
output_tokens: 0,
turn_id: None,
}
}
}
#[derive(Debug, Clone)]
pub struct ToolUseInfo {
pub id: String,
pub name: String,
pub input: serde_json::Value,
}
#[derive(Debug, Clone)]
pub struct ToolResultInfo {
pub tool_use_id: String,
pub content: String,
pub is_error: bool,
}
#[derive(Debug, Clone)]
pub struct ControllerInputPayload {
pub input_type: InputType,
pub session_id: i64,
pub content: String,
pub control_cmd: Option<ControlCmd>,
pub turn_id: Option<TurnId>,
}
impl ControllerInputPayload {
pub fn data(session_id: i64, content: impl Into<String>, turn_id: TurnId) -> Self {
Self {
input_type: InputType::Data,
session_id,
content: content.into(),
control_cmd: None,
turn_id: Some(turn_id),
}
}
pub fn control(session_id: i64, cmd: ControlCmd) -> Self {
Self {
input_type: InputType::Control,
session_id,
content: String::new(),
control_cmd: Some(cmd),
turn_id: None,
}
}
}
#[derive(Debug, Clone)]
pub enum ControllerEvent {
StreamStart {
session_id: i64,
message_id: String,
model: String,
turn_id: Option<TurnId>,
},
TextChunk {
session_id: i64,
text: String,
turn_id: Option<TurnId>,
},
ToolUseStart {
session_id: i64,
tool_id: String,
tool_name: String,
turn_id: Option<TurnId>,
},
ToolUse {
session_id: i64,
tool: ToolUseInfo,
display_name: Option<String>,
display_title: Option<String>,
turn_id: Option<TurnId>,
},
Complete {
session_id: i64,
stop_reason: Option<String>,
turn_id: Option<TurnId>,
},
Error {
session_id: i64,
error: String,
turn_id: Option<TurnId>,
},
TokenUpdate {
session_id: i64,
input_tokens: i64,
output_tokens: i64,
context_limit: i32,
},
ToolResult {
session_id: i64,
tool_use_id: String,
tool_name: String,
display_name: Option<String>,
status: ToolResultStatus,
content: String,
error: Option<String>,
turn_id: Option<TurnId>,
},
CommandComplete {
session_id: i64,
command: ControlCmd,
success: bool,
message: Option<String>,
},
UserInteractionRequired {
session_id: i64,
tool_use_id: String,
request: AskUserQuestionsRequest,
turn_id: Option<TurnId>,
},
PermissionRequired {
session_id: i64,
tool_use_id: String,
request: PermissionRequest,
turn_id: Option<TurnId>,
},
BatchPermissionRequired {
session_id: i64,
batch: BatchPermissionRequest,
turn_id: Option<TurnId>,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_controller_input_data() {
let input = ControllerInputPayload::data(1, "Hello", TurnId::new_user_turn(1));
assert_eq!(input.input_type, InputType::Data);
assert_eq!(input.session_id, 1);
assert_eq!(input.content, "Hello");
assert!(input.control_cmd.is_none());
assert!(input.turn_id.is_some());
}
#[test]
fn test_controller_input_control() {
let input = ControllerInputPayload::control(1, ControlCmd::Interrupt);
assert_eq!(input.input_type, InputType::Control);
assert_eq!(input.session_id, 1);
assert_eq!(input.control_cmd, Some(ControlCmd::Interrupt));
assert!(input.turn_id.is_none());
}
#[test]
fn test_from_llm_payload_default() {
let payload = FromLLMPayload::default();
assert_eq!(payload.session_id, 0);
assert_eq!(payload.response_type, LLMResponseType::TextChunk);
assert!(!payload.is_complete);
}
}