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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//! # Google Gemini Thinking/Reasoning Example
//!
//! Demonstrates the thinking/reasoning capabilities of Gemini 3 and 2.5 models.
//! Gemini's thinking feature lets the model reason through complex problems,
//! with optional thought summaries exposed in the response.
//!
//! ## Requirements
//! - `GOOGLE_GENERATIVE_AI_API_KEY` environment variable
//!
//! ## Run
//! ```bash
//! cargo run --example gemini_thinking --features google
//! ```
use futures::StreamExt;
use qai_sdk::*;
use qai_sdk::LanguageModel;
#[tokio::main]
async fn main() -> Result<()> {
dotenvy::dotenv().ok();
let provider = create_google(ProviderSettings {
api_key: Some(std::env::var("GOOGLE_GENERATIVE_AI_API_KEY").unwrap_or_default()),
..Default::default()
});
// ===================================================================
// 1. Basic Thinking (Gemini 3 with thought summaries)
// ===================================================================
println!("=== Gemini Thinking with Thought Summaries ===\n");
let model = provider.chat("gemini-3-flash-preview");
let prompt = Prompt {
messages: vec![Message {
role: Role::User,
content: vec![Content::Text {
text: "What is the sum of the first 50 prime numbers? Show your reasoning."
.into(),
}],
}],
};
// Enable thought summaries via reasoning_format = "parsed"
// Control thinking level via reasoning_effort
let options = GenerateOptions {
model_id: "gemini-3-flash-preview".to_string(),
max_tokens: Some(4096),
reasoning_format: Some("parsed".to_string()),
reasoning_effort: Some("high".to_string()),
..Default::default()
};
match model.generate(prompt.clone(), options).await {
Ok(result) => {
if let Some(reasoning) = &result.reasoning {
println!("🧠 Thought Summary:\n{}\n", reasoning);
}
println!("📝 Answer:\n{}", result.text);
println!(
"\n📊 Tokens: {} in, {} out",
result.usage.prompt_tokens, result.usage.completion_tokens
);
}
Err(e) => eprintln!("Error: {e}"),
}
// ===================================================================
// 2. Streaming with Thought Deltas
// ===================================================================
println!("\n\n=== Streaming with Thought Deltas ===\n");
let prompt = Prompt {
messages: vec![Message {
role: Role::User,
content: vec![Content::Text {
text: "Alice, Bob, and Carol each live in a different colored house. \
The red house owner has a cat. Bob doesn't live in the green house. \
Carol owns a dog. Who lives where?"
.into(),
}],
}],
};
let options = GenerateOptions {
model_id: "gemini-3-flash-preview".to_string(),
max_tokens: Some(2048),
reasoning_format: Some("parsed".to_string()),
reasoning_effort: Some("medium".to_string()),
..Default::default()
};
match model.generate_stream(prompt, options).await {
Ok(mut stream) => {
let mut in_reasoning = false;
while let Some(part) = stream.next().await {
match part {
StreamPart::ReasoningDelta { delta } => {
if !in_reasoning {
println!("🧠 Thinking:");
in_reasoning = true;
}
print!("{}", delta);
}
StreamPart::TextDelta { delta } => {
if in_reasoning {
println!("\n\n📝 Answer:");
in_reasoning = false;
}
print!("{}", delta);
}
StreamPart::Usage { usage } => {
println!(
"\n\n📊 Tokens: {} in, {} out",
usage.prompt_tokens, usage.completion_tokens
);
}
StreamPart::Finish { finish_reason } => {
println!("✅ Finished: {}", finish_reason);
}
_ => {}
}
}
}
Err(e) => eprintln!("Error: {e}"),
}
// ===================================================================
// 3. Gemini 2.5 with Thinking Budget
// ===================================================================
println!("\n\n=== Gemini 2.5 with Thinking Budget ===\n");
let model_25 = provider.chat("gemini-2.5-flash-preview-05-20");
let prompt = Prompt {
messages: vec![Message {
role: Role::User,
content: vec![Content::Text {
text: "Write a haiku about recursion.".into(),
}],
}],
};
// Use a numeric budget (e.g., "1024") or "dynamic" for Gemini 2.5
let options = GenerateOptions {
model_id: "gemini-2.5-flash-preview-05-20".to_string(),
max_tokens: Some(512),
reasoning_format: Some("parsed".to_string()),
reasoning_effort: Some("1024".to_string()), // thinking_budget = 1024 tokens
..Default::default()
};
match model_25.generate(prompt, options).await {
Ok(result) => {
if let Some(reasoning) = &result.reasoning {
println!("🧠 Thought Summary:\n{}\n", reasoning);
}
println!("📝 Answer:\n{}", result.text);
}
Err(e) => eprintln!("Error: {e}"),
}
Ok(())
}