Skip to content

Commit b803884

Browse files
author
Joshua Tracey
committed
feat: add code execution and update grounding to support v2 models
1 parent 01de223 commit b803884

5 files changed

Lines changed: 143 additions & 0 deletions

File tree

examples/code_execution.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use std::collections::HashMap;
2+
3+
use gemini_client_rs::{
4+
types::{GenerateContentRequest, PartResponse},
5+
GeminiClient,
6+
};
7+
8+
use dotenvy::dotenv;
9+
use serde_json::json;
10+
11+
#[tokio::main]
12+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
13+
dotenv().ok();
14+
15+
let api_key = std::env::var("GEMINI_API_KEY").expect("GEMINI_API_KEY must be set");
16+
17+
let client = GeminiClient::new(api_key);
18+
let model_name = "gemini-2.0-flash";
19+
20+
let req_json = json!({
21+
"contents": [
22+
{
23+
"parts": [
24+
{
25+
"text": "Calculate the square root of 16"
26+
}
27+
],
28+
"role": "user"
29+
}
30+
],
31+
"tools": [
32+
{
33+
"code_execution": {}
34+
}
35+
]
36+
});
37+
38+
let request = serde_json::from_value::<GenerateContentRequest>(req_json)?;
39+
let response = client
40+
.generate_content_with_function_calling(model_name, request, &HashMap::new())
41+
.await?;
42+
43+
let candidates = response.candidates.unwrap();
44+
45+
for candidate in &candidates {
46+
for part in &candidate.content.parts {
47+
match part {
48+
PartResponse::Text(text) => println!("{}", text),
49+
_ => { /* Ignore other part types as we are not using tools */ }
50+
}
51+
}
52+
}
53+
54+
Ok(())
55+
}

examples/custom_tool.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
8383
PartResponse::Text(text) => text,
8484
PartResponse::FunctionCall(_) => "Function call found",
8585
PartResponse::FunctionResponse(_) => "Function response found",
86+
PartResponse::ExecutableCode(_) => "Executable code found",
87+
PartResponse::CodeExecutionResult(_) => "Code execution result found",
8688
};
8789

8890
println!("{}", weather);

examples/grounded_2.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use std::collections::HashMap;
2+
3+
use gemini_client_rs::{
4+
types::{GenerateContentRequest, PartResponse},
5+
GeminiClient,
6+
};
7+
8+
use dotenvy::dotenv;
9+
use serde_json::json;
10+
11+
#[tokio::main]
12+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
13+
dotenv().ok();
14+
15+
let api_key = std::env::var("GEMINI_API_KEY").expect("GEMINI_API_KEY must be set");
16+
17+
let client = GeminiClient::new(api_key);
18+
let model_name = "gemini-2.0-flash";
19+
20+
let req_json = json!({
21+
"contents": [
22+
{
23+
"parts": [
24+
{
25+
"text": "What's the weather like in London, UK?"
26+
}
27+
],
28+
"role": "user"
29+
}
30+
],
31+
"tools": [
32+
{
33+
"google_search": {
34+
}
35+
}
36+
]
37+
});
38+
39+
let request = serde_json::from_value::<GenerateContentRequest>(req_json)?;
40+
let response = client
41+
.generate_content_with_function_calling(model_name, request, &HashMap::new())
42+
.await?;
43+
44+
let candidates = response.candidates.unwrap();
45+
46+
for candidate in &candidates {
47+
for part in &candidate.content.parts {
48+
match part {
49+
PartResponse::Text(text) => println!("{}", text),
50+
_ => { /* Ignore other part types as we are not using tools */ }
51+
}
52+
}
53+
}
54+
55+
Ok(())
56+
}

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ impl GeminiClient {
105105
}
106106
}
107107
PartResponse::FunctionResponse(_) => return Ok(response),
108+
PartResponse::ExecutableCode(_) => return Ok(response),
109+
PartResponse::CodeExecutionResult(_) => return Ok(response),
108110
}
109111
} else {
110112
return Ok(response);
@@ -118,3 +120,4 @@ impl GeminiClient {
118120
}
119121
}
120122
}
123+

src/types.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use serde::{Deserialize, Serialize};
2+
use serde_json::Value;
23
use std::collections::HashMap;
34

45
#[derive(Debug, Serialize, Deserialize)]
@@ -23,11 +24,24 @@ pub struct GenerateContentRequest {
2324
#[derive(Debug, Serialize, Deserialize)]
2425
#[serde(untagged)]
2526
pub enum ToolConfig {
27+
// will work for both v1 and v2 models
2628
#[serde(rename = "function_declaration")]
2729
FunctionDeclaration(ToolConfigFunctionDeclaration),
30+
31+
/* NOTE: For v1 models will be depreciated by google in 2025 */
2832
DynamicRetieval {
2933
google_search_retrieval: DynamicRetrieval,
3034
},
35+
36+
/* NOTE: Used by v2 models if they have search built in */
37+
GoogleSearch {
38+
google_search: serde_json::Value,
39+
},
40+
41+
/* NOTE: Used by v2 models if they have the code execution built in */
42+
CodeExecution {
43+
code_execution: serde_json::Value,
44+
},
3145
}
3246

3347
#[derive(Debug, Serialize, Deserialize)]
@@ -44,6 +58,10 @@ pub enum ContentPart {
4458
FunctionCall(FunctionCall),
4559
#[serde(rename = "functionResponse")]
4660
FunctionResponse(FunctionResponse),
61+
#[serde(rename = "executableCode")]
62+
ExecutableCode(ExecutableCode),
63+
#[serde(rename = "codeExecutionResult")]
64+
CodeExecutionResult(Value),
4765
}
4866

4967
#[derive(Debug, Serialize, Deserialize)]
@@ -111,6 +129,10 @@ pub enum PartResponse {
111129
FunctionCall(FunctionCall),
112130
#[serde(rename = "functionResponse")]
113131
FunctionResponse(FunctionResponse),
132+
#[serde(rename = "executableCode")]
133+
ExecutableCode(ExecutableCode),
134+
#[serde(rename = "codeExecutionResult")]
135+
CodeExecutionResult(Value),
114136
}
115137

116138
#[derive(Debug, Serialize, Deserialize, Clone)]
@@ -130,3 +152,8 @@ pub struct FunctionResponse {
130152
pub struct FunctionResponsePayload {
131153
pub content: serde_json::Value,
132154
}
155+
156+
#[derive(Debug, Serialize, Deserialize)]
157+
pub struct ExecutableCode {
158+
pub code: String,
159+
}

0 commit comments

Comments
 (0)