use crate::models::{ResearchDepth, ResearchProvider};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ThinkingLevel {
Minimal,
Low,
Medium,
High,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResearchConfig {
#[serde(default)]
pub provider: ResearchProvider,
#[serde(default)]
pub depth: ResearchDepth,
#[serde(default = "default_max_sources")]
pub max_sources: u32,
#[serde(default)]
pub include_images: bool,
#[serde(default)]
pub async_mode: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
rename = "thinkingLevel"
)]
pub thinking_level: Option<ThinkingLevel>,
}
fn default_max_sources() -> u32 {
10
}
impl Default for ResearchConfig {
fn default() -> Self {
Self {
provider: ResearchProvider::default(),
depth: ResearchDepth::default(),
max_sources: 10,
include_images: false,
async_mode: false,
model: None,
thinking_level: None,
}
}
}
impl ResearchConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_provider(mut self, provider: ResearchProvider) -> Self {
self.provider = provider;
self
}
pub fn with_depth(mut self, depth: ResearchDepth) -> Self {
self.depth = depth;
self
}
pub fn with_max_sources(mut self, max: u32) -> Self {
self.max_sources = max;
self
}
pub fn with_async(mut self, async_mode: bool) -> Self {
self.async_mode = async_mode;
self
}
pub fn with_model(mut self, model: impl Into<String>) -> Self {
self.model = Some(model.into());
self
}
pub fn with_thinking_level(mut self, level: ThinkingLevel) -> Self {
self.thinking_level = Some(level);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResearchResult {
pub topic: String,
pub content: String,
#[serde(default)]
pub sources: Vec<ResearchSource>,
pub provider: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResearchSource {
pub title: String,
pub url: String,
#[serde(default)]
pub snippet: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SearchResultItem {
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub snippet: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SearchResponse {
#[serde(default)]
pub results: Vec<SearchResultItem>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SearchExtractResponse {
#[serde(default)]
pub results: Vec<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ResearchResponse {
Sync {
success: bool,
mode: String,
result: String,
generated_at: String,
provider: String,
},
Async {
success: bool,
mode: String,
#[serde(rename = "taskId")]
task_id: String,
message: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeepResearchResponse {
pub success: bool,
pub mode: String,
pub result: Option<serde_json::Value>,
#[serde(rename = "taskId")]
pub task_id: Option<String>,
#[serde(rename = "generatedAt")]
pub generated_at: Option<String>,
pub provider: Option<String>,
pub message: Option<String>,
}
pub use crate::search::DeepResearchResponse as ResearchApiResponse;