rust_genai/
deep_research.rs1use std::pin::Pin;
4use std::sync::Arc;
5
6use futures_util::Stream;
7use rust_genai_types::interactions::{
8 AgentConfig, CreateInteractionConfig, DeepResearchAgentConfig, Interaction, InteractionInput,
9 InteractionSseEvent, InteractionThinkingSummaries, Tool,
10};
11
12use crate::client::ClientInner;
13use crate::error::Result;
14use crate::interactions::Interactions;
15
16const DEEP_RESEARCH_AGENT: &str = "deep-research-pro-preview-12-2025";
17
18#[derive(Clone)]
19pub struct DeepResearch {
20 inner: Arc<ClientInner>,
21}
22
23impl DeepResearch {
24 pub(crate) const fn new(inner: Arc<ClientInner>) -> Self {
25 Self { inner }
26 }
27
28 pub async fn start(&self, input: impl Into<InteractionInput>) -> Result<Interaction> {
34 let mut config = CreateInteractionConfig::new_agent(DEEP_RESEARCH_AGENT, input);
35 apply_deep_research_defaults(&mut config);
36 Interactions::new(self.inner.clone()).create(config).await
37 }
38
39 pub async fn start_with_config(
45 &self,
46 mut config: CreateInteractionConfig,
47 ) -> Result<Interaction> {
48 apply_deep_research_defaults(&mut config);
49 Interactions::new(self.inner.clone()).create(config).await
50 }
51
52 pub async fn stream_with_config(
58 &self,
59 mut config: CreateInteractionConfig,
60 ) -> Result<Pin<Box<dyn Stream<Item = Result<InteractionSseEvent>> + Send>>> {
61 apply_deep_research_defaults(&mut config);
62 Interactions::new(self.inner.clone())
63 .create_stream(config)
64 .await
65 }
66}
67
68fn apply_deep_research_defaults(config: &mut CreateInteractionConfig) {
69 if config.agent.is_none() {
71 config.agent = Some(DEEP_RESEARCH_AGENT.to_string());
72 }
73 config.model = None;
74 config.generation_config = None;
75
76 if config.background.is_none() {
77 config.background = Some(true);
78 }
79 if config.store.is_none() {
80 config.store = Some(true);
81 }
82
83 match &mut config.agent_config {
85 None => {
86 config.agent_config = Some(AgentConfig::DeepResearch(DeepResearchAgentConfig {
87 thinking_summaries: Some(InteractionThinkingSummaries::Auto),
88 ..Default::default()
89 }));
90 }
91 Some(AgentConfig::DeepResearch(cfg)) => {
92 if cfg.thinking_summaries.is_none() {
93 cfg.thinking_summaries = Some(InteractionThinkingSummaries::Auto);
94 }
95 }
96 Some(AgentConfig::Dynamic(_)) => {}
97 }
98
99 if config.tools.is_none() {
100 config.tools = Some(vec![Tool::GoogleSearch]);
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn apply_defaults_sets_missing_fields() {
110 let mut config = CreateInteractionConfig::new_agent(
111 DEEP_RESEARCH_AGENT,
112 InteractionInput::Text("hi".into()),
113 );
114 apply_deep_research_defaults(&mut config);
115 assert_eq!(config.agent.as_deref(), Some(DEEP_RESEARCH_AGENT));
116 assert!(config.model.is_none());
117 assert_eq!(config.background, Some(true));
118 assert_eq!(config.store, Some(true));
119 assert!(config.tools.is_some());
120
121 match config.agent_config {
122 Some(AgentConfig::DeepResearch(cfg)) => {
123 assert_eq!(
124 cfg.thinking_summaries,
125 Some(InteractionThinkingSummaries::Auto)
126 );
127 }
128 _ => panic!("expected deep research agent config"),
129 }
130 }
131
132 #[test]
133 fn apply_defaults_respects_existing_fields() {
134 let mut config = CreateInteractionConfig::new_agent(
135 DEEP_RESEARCH_AGENT,
136 InteractionInput::Text("hi".into()),
137 );
138 config.background = Some(false);
139 config.store = Some(false);
140 config.agent_config = Some(AgentConfig::DeepResearch(DeepResearchAgentConfig {
141 thinking_summaries: Some(InteractionThinkingSummaries::NoneValue),
142 ..Default::default()
143 }));
144 config.tools = Some(Vec::new());
145 apply_deep_research_defaults(&mut config);
146 assert_eq!(config.agent.as_deref(), Some(DEEP_RESEARCH_AGENT));
147 assert!(config.model.is_none());
148 assert_eq!(config.background, Some(false));
149 assert_eq!(config.store, Some(false));
150 match config.agent_config {
151 Some(AgentConfig::DeepResearch(cfg)) => {
152 assert_eq!(
153 cfg.thinking_summaries,
154 Some(InteractionThinkingSummaries::NoneValue)
155 );
156 }
157 _ => panic!("expected deep research agent config"),
158 }
159 assert!(config.tools.as_ref().unwrap().is_empty());
160 }
161}