Skip to main content

Agent

Struct Agent 

Source
pub struct Agent<S: AgentLifecycle = Unstarted> { /* private fields */ }

Implementations§

Source§

impl Agent<Unstarted>

Source

pub fn new(config: AgentConfig) -> Self

Creates a new Agent with the given configuration.

Source

pub fn builder() -> AgentBuilder<NoPolicies>

Returns an AgentBuilder to configure and construct an Agent.

Examples found in repository?
examples/hello_world.rs (line 18)
5async fn main() -> Result<(), anyhow::Error> {
6    // Initialize tracing subscriber to print info/debug logs by default
7    tracing_subscriber::fmt()
8        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
9        .init();
10
11    // Load environment variables from .env file if present
12    dotenvy::dotenv().ok();
13
14    // Check if the user specified a binary path or check the environment variable
15    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
16    let api_key = std::env::var("GEMINI_API_KEY").ok();
17
18    let mut builder = Agent::builder();
19    if let Some(path) = harness_path {
20        builder = builder.binary_path(path);
21    }
22    if let Some(key) = api_key {
23        builder = builder.api_key(key);
24    }
25
26    let agent = builder
27        .default_model("gemini-3.5-flash")
28        .allow_all()
29        .build();
30
31    println!("Starting agent...");
32    let agent = agent.start().await?;
33
34    let prompt = "Say 'Hello World!'";
35    println!("  User: {}", prompt);
36
37    let response = agent.chat(prompt).await?;
38    println!("  Agent: {}", response.text);
39
40    agent.stop().await?;
41    Ok(())
42}
More examples
Hide additional examples
examples/subagents.rs (line 72)
60async fn main() -> Result<(), anyhow::Error> {
61    // Initialize tracing subscriber
62    tracing_subscriber::fmt()
63        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
64        .init();
65
66    // Load environment variables from .env file if present
67    dotenvy::dotenv().ok();
68
69    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
70    let api_key = std::env::var("GEMINI_API_KEY").ok();
71
72    let mut builder = Agent::builder();
73    if let Some(path) = harness_path {
74        builder = builder.binary_path(path);
75    }
76    if let Some(key) = api_key {
77        builder = builder.api_key(key);
78    }
79
80    // Enable subagents capability and file viewing
81    let capabilities = CapabilitiesConfig {
82        enabled_tools: Some(vec![
83            BuiltinTools::StartSubagent,
84            BuiltinTools::ListDir,
85            BuiltinTools::ViewFile,
86            BuiltinTools::Finish,
87        ]),
88        ..Default::default()
89    };
90
91    let subagent_active = Arc::new(AtomicBool::new(false));
92
93    let agent = builder
94        .default_model("gemini-3.5-flash")
95        .capabilities(capabilities)
96        .hook(Arc::new(SubagentHook { subagent_active }))
97        .allow_all()
98        .build();
99
100    println!("Starting agent...");
101    let agent = agent.start().await?;
102
103    let prompt = "Use a subagent to research the files in the current directory. \
104                  Delegate the task of listing the directory to the subagent, and then \
105                  tell me what files you found.";
106
107    println!("  User: {}", prompt);
108    let response = agent.chat(prompt).await?;
109    println!("\n  Agent:\n{}", response.text);
110
111    agent.stop().await?;
112    Ok(())
113}
examples/streaming.rs (line 19)
7async fn main() -> Result<(), anyhow::Error> {
8    // Initialize tracing subscriber
9    tracing_subscriber::fmt()
10        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
11        .init();
12
13    // Load environment variables from .env file if present
14    dotenvy::dotenv().ok();
15
16    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
17    let api_key = std::env::var("GEMINI_API_KEY").ok();
18
19    let mut builder = Agent::builder();
20    if let Some(path) = harness_path {
21        builder = builder.binary_path(path);
22    }
23    if let Some(key) = api_key {
24        builder = builder.api_key(key);
25    }
26
27    let agent = builder
28        .default_model("gemini-3.5-flash")
29        .allow_all()
30        .build();
31
32    println!("Starting agent...");
33    let agent = agent.start().await?;
34
35    let prompt = "Solve this riddle: I speak without a mouth and hear without ears. I have no body, but I come alive with wind. What am I? Explain your reasoning.";
36    println!("\n  User: {}\n", prompt);
37
38    let conversation = agent.conversation();
39    let mut stream = conversation.chat(prompt).await?;
40
41    println!("  Agent (Streaming response):");
42    println!("  -------------------------------------------------------");
43
44    while let Some(chunk_res) = stream.next().await {
45        match chunk_res? {
46            StreamChunk::Thought { text, .. } => {
47                // Print thought chunks (e.g. in grey or wrapped in brackets if desired, or directly)
48                print!("{}", text);
49                std::io::Write::flush(&mut std::io::stdout())?;
50            }
51            StreamChunk::Text { text, .. } => {
52                // Print response text chunks
53                print!("{}", text);
54                std::io::Write::flush(&mut std::io::stdout())?;
55            }
56            StreamChunk::ToolCall(call) => {
57                println!(
58                    "\n[Tool Call Requested: {} with args: {}]",
59                    call.name, call.args
60                );
61            }
62        }
63    }
64    println!("\n  -------------------------------------------------------\n");
65
66    agent.stop().await?;
67    Ok(())
68}
examples/custom_tools.rs (line 123)
110async fn main() -> Result<(), anyhow::Error> {
111    // Initialize tracing subscriber
112    tracing_subscriber::fmt()
113        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
114        .init();
115
116    // Load environment variables from .env file if present
117    dotenvy::dotenv().ok();
118
119    // Check if the user specified a binary path or check the environment variable
120    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
121    let api_key = std::env::var("GEMINI_API_KEY").ok();
122
123    let mut builder = Agent::builder();
124    if let Some(path) = harness_path {
125        builder = builder.binary_path(path);
126    }
127    if let Some(key) = api_key {
128        builder = builder.api_key(key);
129    }
130
131    // Initialize shared mutable state for stateful tool
132    let inventory = Arc::new(Mutex::new(HashMap::new()));
133
134    let agent = builder
135        .default_model("gemini-3.5-flash")
136        .system_instructions(antigravity_sdk_rust::types::SystemInstructions::Custom(
137            antigravity_sdk_rust::types::CustomSystemInstructions {
138                text: "You keep track of fruit inventory. To record fruits, you MUST first look up the \
139                       fruit's SKU using lookup_fruit_sku, and then use that SKU with record_fruit."
140                        .to_string(),
141            },
142        ))
143        .tools(vec![
144            Arc::new(LookupSkuTool),
145            Arc::new(RecordFruitTool {
146                inventory: inventory.clone(),
147            }),
148        ])
149        .policies(vec![
150            policy::deny_all(),
151            policy::allow("lookup_fruit_sku"),
152            policy::allow("record_fruit"),
153        ])
154        .build();
155
156    println!("Starting agent...");
157    let agent = agent.start().await?;
158
159    println!("  === Custom Tools Demo ===");
160
161    // Turn 1: Lookup fruit SKU
162    let prompt1 = "What is the SKU for apples? We need to order more.";
163    println!("\n  User: {}", prompt1);
164    let response1 = agent.chat(prompt1).await?;
165    println!("  Agent: {}", response1.text);
166
167    // Stateful interaction: record fruits across multiple turns
168    println!("\n  === Stateful Tool (Fruit Counter) Demo ===");
169
170    let turns = vec![
171        "I have 5 apples.",
172        "And I just got 3 bananas.",
173        "Oh, and another 2 apples.",
174    ];
175
176    for user_input in turns {
177        println!("\n  User: {}", user_input);
178        let response = agent.chat(user_input).await?;
179        println!("  Agent: {}", response.text);
180    }
181
182    agent.stop().await?;
183    Ok(())
184}
examples/policies.rs (line 54)
42async fn main() -> Result<(), anyhow::Error> {
43    // Initialize tracing subscriber
44    tracing_subscriber::fmt()
45        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
46        .init();
47
48    // Load environment variables from .env file if present
49    dotenvy::dotenv().ok();
50
51    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
52    let api_key = std::env::var("GEMINI_API_KEY").ok();
53
54    let mut builder = Agent::builder();
55    if let Some(path) = harness_path {
56        builder = builder.binary_path(path);
57    }
58    if let Some(key) = api_key {
59        builder = builder.api_key(key);
60    }
61
62    let agent = builder
63        .default_model("gemini-3.5-flash")
64        // 1. Deny everything by default
65        .policy(policy::deny_all())
66        // 2. Allow listing directories
67        .policy(policy::allow("LIST_DIR"))
68        // 3. Allow running commands, but block dangerous 'rm' commands
69        .policy(Policy::new(
70            "RUN_COMMAND".to_string(),
71            Decision::Deny,
72            Some(Arc::new(block_rm_predicate)),
73            None,
74            "block-rm".to_string(),
75        ))
76        // Fallback: Allow general RUN_COMMAND calls if they don't match the rm block predicate
77        .policy(policy::allow("RUN_COMMAND"))
78        // 4. Allow editing/creating files, but ask the user first if it's a critical file
79        .policy(Policy::new(
80            "WRITE_TO_FILE".to_string(),
81            Decision::AskUser,
82            Some(Arc::new(critical_file_predicate)),
83            Some(Arc::new(programmatic_approval_handler)),
84            "ask-for-critical-writes".to_string(),
85        ))
86        .policy(policy::allow("WRITE_TO_FILE"))
87        .build();
88
89    println!("Starting agent...");
90    let agent = agent.start().await?;
91
92    println!("\n  Chatting with agent...");
93
94    // 1. Try a safe command (should be allowed)
95    let prompt1 = "List the files in the current directory.";
96    println!("\n  User: {}", prompt1);
97    let response1 = agent.chat(prompt1).await?;
98    println!("  Agent: {}", response1.text);
99
100    // 2. Try a dangerous command (should be denied by policy)
101    let prompt2 = "Delete all files using rm -rf.";
102    println!("\n  User: {}", prompt2);
103    let response2 = agent.chat(prompt2).await?;
104    println!("  Agent: {}", response2.text);
105
106    // 3. Try creating a critical file (triggers programmatic ask_user handler)
107    let prompt3 = "Create a new configuration file named production.key with content 'debug=true'.";
108    println!("\n  User: {}", prompt3);
109    let response3 = agent.chat(prompt3).await?;
110    println!("  Agent: {}", response3.text);
111
112    agent.stop().await?;
113    Ok(())
114}
examples/persistence.rs (line 33)
6async fn main() -> Result<(), anyhow::Error> {
7    // Initialize tracing subscriber
8    tracing_subscriber::fmt()
9        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
10        .init();
11
12    // Load environment variables from .env file if present
13    dotenvy::dotenv().ok();
14
15    // Create a temporary path for save_dir
16    let mut save_dir = std::env::temp_dir();
17    let epoch = SystemTime::now()
18        .duration_since(SystemTime::UNIX_EPOCH)
19        .unwrap_or_default()
20        .as_secs();
21    save_dir.push(format!("agent_session_{}", epoch));
22    let save_dir_str = save_dir.to_string_lossy().to_string();
23    println!("  Save directory: {}", save_dir_str);
24
25    // Ensure the save_dir exists
26    std::fs::create_dir_all(&save_dir)?;
27
28    println!("\n  === Session 1: establishing context ===");
29
30    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
31    let api_key = std::env::var("GEMINI_API_KEY").ok();
32
33    let mut builder1 = Agent::builder();
34    if let Some(path) = harness_path.clone() {
35        builder1 = builder1.binary_path(path);
36    }
37    if let Some(key) = api_key.clone() {
38        builder1 = builder1.api_key(key);
39    }
40
41    let agent1 = builder1
42        .default_model("gemini-3.5-flash")
43        .allow_all()
44        .save_dir(save_dir_str.clone())
45        .build();
46
47    let conversation_id = {
48        let agent1 = agent1.start().await?;
49
50        let prompt1 = "Remember this: my favorite color is blue.";
51        println!("  User: {}", prompt1);
52        let response1 = agent1.chat(prompt1).await?;
53        println!("  Agent: {}", response1.text);
54
55        let conv_id = agent1.conversation_id();
56        println!("  Assigned conversation ID: {}", conv_id);
57
58        agent1.stop().await?;
59        println!("  Session 1 ended.\n");
60        conv_id
61    };
62
63    println!("  === Session 2: resuming and verifying recall ===");
64
65    let mut builder2 = Agent::builder();
66    if let Some(path) = harness_path {
67        builder2 = builder2.binary_path(path);
68    }
69    if let Some(key) = api_key {
70        builder2 = builder2.api_key(key);
71    }
72
73    let agent2 = builder2
74        .default_model("gemini-3.5-flash")
75        .allow_all()
76        .save_dir(save_dir_str.clone())
77        .conversation_id(conversation_id)
78        .build();
79
80    let agent2 = agent2.start().await?;
81
82    let prompt2 = "What is my favorite color?";
83    println!("  User: {}", prompt2);
84    let response2 = agent2.chat(prompt2).await?;
85    println!("  Agent: {}", response2.text);
86
87    agent2.stop().await?;
88    println!("  Session 2 ended.");
89
90    // Clean up temporary session directory
91    let _ = std::fs::remove_dir_all(&save_dir);
92
93    Ok(())
94}
Source

pub fn register_hook(&mut self, hook: Arc<dyn DynHook>)

Registers a custom lifecycle hook during configuration.

Source

pub fn register_trigger( &mut self, trigger: Arc<dyn DynTrigger>, ) -> Result<(), Error>

Registers a custom background trigger.

Source

pub fn register_tool(&mut self, tool: Arc<dyn DynTool>)

Registers a custom tool during configuration.

Source

pub fn start(self) -> BoxFuture<'static, Result<Agent<Started>, Error>>

Spawns the subprocess communication harness, initializes safety policies, registers tools/hooks, establishes the WebSocket session, and starts any configured triggers.

§Errors

Returns an error if:

  • The localharness binary cannot be resolved.
  • Write tools are enabled but no safety policies are configured.
  • The WebSocket upgrade or subprocess connection fails.
Examples found in repository?
examples/hello_world.rs (line 32)
5async fn main() -> Result<(), anyhow::Error> {
6    // Initialize tracing subscriber to print info/debug logs by default
7    tracing_subscriber::fmt()
8        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
9        .init();
10
11    // Load environment variables from .env file if present
12    dotenvy::dotenv().ok();
13
14    // Check if the user specified a binary path or check the environment variable
15    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
16    let api_key = std::env::var("GEMINI_API_KEY").ok();
17
18    let mut builder = Agent::builder();
19    if let Some(path) = harness_path {
20        builder = builder.binary_path(path);
21    }
22    if let Some(key) = api_key {
23        builder = builder.api_key(key);
24    }
25
26    let agent = builder
27        .default_model("gemini-3.5-flash")
28        .allow_all()
29        .build();
30
31    println!("Starting agent...");
32    let agent = agent.start().await?;
33
34    let prompt = "Say 'Hello World!'";
35    println!("  User: {}", prompt);
36
37    let response = agent.chat(prompt).await?;
38    println!("  Agent: {}", response.text);
39
40    agent.stop().await?;
41    Ok(())
42}
More examples
Hide additional examples
examples/subagents.rs (line 101)
60async fn main() -> Result<(), anyhow::Error> {
61    // Initialize tracing subscriber
62    tracing_subscriber::fmt()
63        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
64        .init();
65
66    // Load environment variables from .env file if present
67    dotenvy::dotenv().ok();
68
69    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
70    let api_key = std::env::var("GEMINI_API_KEY").ok();
71
72    let mut builder = Agent::builder();
73    if let Some(path) = harness_path {
74        builder = builder.binary_path(path);
75    }
76    if let Some(key) = api_key {
77        builder = builder.api_key(key);
78    }
79
80    // Enable subagents capability and file viewing
81    let capabilities = CapabilitiesConfig {
82        enabled_tools: Some(vec![
83            BuiltinTools::StartSubagent,
84            BuiltinTools::ListDir,
85            BuiltinTools::ViewFile,
86            BuiltinTools::Finish,
87        ]),
88        ..Default::default()
89    };
90
91    let subagent_active = Arc::new(AtomicBool::new(false));
92
93    let agent = builder
94        .default_model("gemini-3.5-flash")
95        .capabilities(capabilities)
96        .hook(Arc::new(SubagentHook { subagent_active }))
97        .allow_all()
98        .build();
99
100    println!("Starting agent...");
101    let agent = agent.start().await?;
102
103    let prompt = "Use a subagent to research the files in the current directory. \
104                  Delegate the task of listing the directory to the subagent, and then \
105                  tell me what files you found.";
106
107    println!("  User: {}", prompt);
108    let response = agent.chat(prompt).await?;
109    println!("\n  Agent:\n{}", response.text);
110
111    agent.stop().await?;
112    Ok(())
113}
examples/streaming.rs (line 33)
7async fn main() -> Result<(), anyhow::Error> {
8    // Initialize tracing subscriber
9    tracing_subscriber::fmt()
10        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
11        .init();
12
13    // Load environment variables from .env file if present
14    dotenvy::dotenv().ok();
15
16    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
17    let api_key = std::env::var("GEMINI_API_KEY").ok();
18
19    let mut builder = Agent::builder();
20    if let Some(path) = harness_path {
21        builder = builder.binary_path(path);
22    }
23    if let Some(key) = api_key {
24        builder = builder.api_key(key);
25    }
26
27    let agent = builder
28        .default_model("gemini-3.5-flash")
29        .allow_all()
30        .build();
31
32    println!("Starting agent...");
33    let agent = agent.start().await?;
34
35    let prompt = "Solve this riddle: I speak without a mouth and hear without ears. I have no body, but I come alive with wind. What am I? Explain your reasoning.";
36    println!("\n  User: {}\n", prompt);
37
38    let conversation = agent.conversation();
39    let mut stream = conversation.chat(prompt).await?;
40
41    println!("  Agent (Streaming response):");
42    println!("  -------------------------------------------------------");
43
44    while let Some(chunk_res) = stream.next().await {
45        match chunk_res? {
46            StreamChunk::Thought { text, .. } => {
47                // Print thought chunks (e.g. in grey or wrapped in brackets if desired, or directly)
48                print!("{}", text);
49                std::io::Write::flush(&mut std::io::stdout())?;
50            }
51            StreamChunk::Text { text, .. } => {
52                // Print response text chunks
53                print!("{}", text);
54                std::io::Write::flush(&mut std::io::stdout())?;
55            }
56            StreamChunk::ToolCall(call) => {
57                println!(
58                    "\n[Tool Call Requested: {} with args: {}]",
59                    call.name, call.args
60                );
61            }
62        }
63    }
64    println!("\n  -------------------------------------------------------\n");
65
66    agent.stop().await?;
67    Ok(())
68}
examples/custom_tools.rs (line 157)
110async fn main() -> Result<(), anyhow::Error> {
111    // Initialize tracing subscriber
112    tracing_subscriber::fmt()
113        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
114        .init();
115
116    // Load environment variables from .env file if present
117    dotenvy::dotenv().ok();
118
119    // Check if the user specified a binary path or check the environment variable
120    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
121    let api_key = std::env::var("GEMINI_API_KEY").ok();
122
123    let mut builder = Agent::builder();
124    if let Some(path) = harness_path {
125        builder = builder.binary_path(path);
126    }
127    if let Some(key) = api_key {
128        builder = builder.api_key(key);
129    }
130
131    // Initialize shared mutable state for stateful tool
132    let inventory = Arc::new(Mutex::new(HashMap::new()));
133
134    let agent = builder
135        .default_model("gemini-3.5-flash")
136        .system_instructions(antigravity_sdk_rust::types::SystemInstructions::Custom(
137            antigravity_sdk_rust::types::CustomSystemInstructions {
138                text: "You keep track of fruit inventory. To record fruits, you MUST first look up the \
139                       fruit's SKU using lookup_fruit_sku, and then use that SKU with record_fruit."
140                        .to_string(),
141            },
142        ))
143        .tools(vec![
144            Arc::new(LookupSkuTool),
145            Arc::new(RecordFruitTool {
146                inventory: inventory.clone(),
147            }),
148        ])
149        .policies(vec![
150            policy::deny_all(),
151            policy::allow("lookup_fruit_sku"),
152            policy::allow("record_fruit"),
153        ])
154        .build();
155
156    println!("Starting agent...");
157    let agent = agent.start().await?;
158
159    println!("  === Custom Tools Demo ===");
160
161    // Turn 1: Lookup fruit SKU
162    let prompt1 = "What is the SKU for apples? We need to order more.";
163    println!("\n  User: {}", prompt1);
164    let response1 = agent.chat(prompt1).await?;
165    println!("  Agent: {}", response1.text);
166
167    // Stateful interaction: record fruits across multiple turns
168    println!("\n  === Stateful Tool (Fruit Counter) Demo ===");
169
170    let turns = vec![
171        "I have 5 apples.",
172        "And I just got 3 bananas.",
173        "Oh, and another 2 apples.",
174    ];
175
176    for user_input in turns {
177        println!("\n  User: {}", user_input);
178        let response = agent.chat(user_input).await?;
179        println!("  Agent: {}", response.text);
180    }
181
182    agent.stop().await?;
183    Ok(())
184}
examples/policies.rs (line 90)
42async fn main() -> Result<(), anyhow::Error> {
43    // Initialize tracing subscriber
44    tracing_subscriber::fmt()
45        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
46        .init();
47
48    // Load environment variables from .env file if present
49    dotenvy::dotenv().ok();
50
51    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
52    let api_key = std::env::var("GEMINI_API_KEY").ok();
53
54    let mut builder = Agent::builder();
55    if let Some(path) = harness_path {
56        builder = builder.binary_path(path);
57    }
58    if let Some(key) = api_key {
59        builder = builder.api_key(key);
60    }
61
62    let agent = builder
63        .default_model("gemini-3.5-flash")
64        // 1. Deny everything by default
65        .policy(policy::deny_all())
66        // 2. Allow listing directories
67        .policy(policy::allow("LIST_DIR"))
68        // 3. Allow running commands, but block dangerous 'rm' commands
69        .policy(Policy::new(
70            "RUN_COMMAND".to_string(),
71            Decision::Deny,
72            Some(Arc::new(block_rm_predicate)),
73            None,
74            "block-rm".to_string(),
75        ))
76        // Fallback: Allow general RUN_COMMAND calls if they don't match the rm block predicate
77        .policy(policy::allow("RUN_COMMAND"))
78        // 4. Allow editing/creating files, but ask the user first if it's a critical file
79        .policy(Policy::new(
80            "WRITE_TO_FILE".to_string(),
81            Decision::AskUser,
82            Some(Arc::new(critical_file_predicate)),
83            Some(Arc::new(programmatic_approval_handler)),
84            "ask-for-critical-writes".to_string(),
85        ))
86        .policy(policy::allow("WRITE_TO_FILE"))
87        .build();
88
89    println!("Starting agent...");
90    let agent = agent.start().await?;
91
92    println!("\n  Chatting with agent...");
93
94    // 1. Try a safe command (should be allowed)
95    let prompt1 = "List the files in the current directory.";
96    println!("\n  User: {}", prompt1);
97    let response1 = agent.chat(prompt1).await?;
98    println!("  Agent: {}", response1.text);
99
100    // 2. Try a dangerous command (should be denied by policy)
101    let prompt2 = "Delete all files using rm -rf.";
102    println!("\n  User: {}", prompt2);
103    let response2 = agent.chat(prompt2).await?;
104    println!("  Agent: {}", response2.text);
105
106    // 3. Try creating a critical file (triggers programmatic ask_user handler)
107    let prompt3 = "Create a new configuration file named production.key with content 'debug=true'.";
108    println!("\n  User: {}", prompt3);
109    let response3 = agent.chat(prompt3).await?;
110    println!("  Agent: {}", response3.text);
111
112    agent.stop().await?;
113    Ok(())
114}
examples/persistence.rs (line 48)
6async fn main() -> Result<(), anyhow::Error> {
7    // Initialize tracing subscriber
8    tracing_subscriber::fmt()
9        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
10        .init();
11
12    // Load environment variables from .env file if present
13    dotenvy::dotenv().ok();
14
15    // Create a temporary path for save_dir
16    let mut save_dir = std::env::temp_dir();
17    let epoch = SystemTime::now()
18        .duration_since(SystemTime::UNIX_EPOCH)
19        .unwrap_or_default()
20        .as_secs();
21    save_dir.push(format!("agent_session_{}", epoch));
22    let save_dir_str = save_dir.to_string_lossy().to_string();
23    println!("  Save directory: {}", save_dir_str);
24
25    // Ensure the save_dir exists
26    std::fs::create_dir_all(&save_dir)?;
27
28    println!("\n  === Session 1: establishing context ===");
29
30    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
31    let api_key = std::env::var("GEMINI_API_KEY").ok();
32
33    let mut builder1 = Agent::builder();
34    if let Some(path) = harness_path.clone() {
35        builder1 = builder1.binary_path(path);
36    }
37    if let Some(key) = api_key.clone() {
38        builder1 = builder1.api_key(key);
39    }
40
41    let agent1 = builder1
42        .default_model("gemini-3.5-flash")
43        .allow_all()
44        .save_dir(save_dir_str.clone())
45        .build();
46
47    let conversation_id = {
48        let agent1 = agent1.start().await?;
49
50        let prompt1 = "Remember this: my favorite color is blue.";
51        println!("  User: {}", prompt1);
52        let response1 = agent1.chat(prompt1).await?;
53        println!("  Agent: {}", response1.text);
54
55        let conv_id = agent1.conversation_id();
56        println!("  Assigned conversation ID: {}", conv_id);
57
58        agent1.stop().await?;
59        println!("  Session 1 ended.\n");
60        conv_id
61    };
62
63    println!("  === Session 2: resuming and verifying recall ===");
64
65    let mut builder2 = Agent::builder();
66    if let Some(path) = harness_path {
67        builder2 = builder2.binary_path(path);
68    }
69    if let Some(key) = api_key {
70        builder2 = builder2.api_key(key);
71    }
72
73    let agent2 = builder2
74        .default_model("gemini-3.5-flash")
75        .allow_all()
76        .save_dir(save_dir_str.clone())
77        .conversation_id(conversation_id)
78        .build();
79
80    let agent2 = agent2.start().await?;
81
82    let prompt2 = "What is my favorite color?";
83    println!("  User: {}", prompt2);
84    let response2 = agent2.chat(prompt2).await?;
85    println!("  Agent: {}", response2.text);
86
87    agent2.stop().await?;
88    println!("  Session 2 ended.");
89
90    // Clean up temporary session directory
91    let _ = std::fs::remove_dir_all(&save_dir);
92
93    Ok(())
94}
Source§

impl Agent<Started>

Source

pub async fn chat(&self, prompt: &str) -> Result<ChatResponse, Error>

Sends a prompt message to the active agent session and awaits the final completed response.

§Errors

Returns an error if the execution stream encounters a failure.

Examples found in repository?
examples/hello_world.rs (line 37)
5async fn main() -> Result<(), anyhow::Error> {
6    // Initialize tracing subscriber to print info/debug logs by default
7    tracing_subscriber::fmt()
8        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
9        .init();
10
11    // Load environment variables from .env file if present
12    dotenvy::dotenv().ok();
13
14    // Check if the user specified a binary path or check the environment variable
15    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
16    let api_key = std::env::var("GEMINI_API_KEY").ok();
17
18    let mut builder = Agent::builder();
19    if let Some(path) = harness_path {
20        builder = builder.binary_path(path);
21    }
22    if let Some(key) = api_key {
23        builder = builder.api_key(key);
24    }
25
26    let agent = builder
27        .default_model("gemini-3.5-flash")
28        .allow_all()
29        .build();
30
31    println!("Starting agent...");
32    let agent = agent.start().await?;
33
34    let prompt = "Say 'Hello World!'";
35    println!("  User: {}", prompt);
36
37    let response = agent.chat(prompt).await?;
38    println!("  Agent: {}", response.text);
39
40    agent.stop().await?;
41    Ok(())
42}
More examples
Hide additional examples
examples/subagents.rs (line 108)
60async fn main() -> Result<(), anyhow::Error> {
61    // Initialize tracing subscriber
62    tracing_subscriber::fmt()
63        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
64        .init();
65
66    // Load environment variables from .env file if present
67    dotenvy::dotenv().ok();
68
69    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
70    let api_key = std::env::var("GEMINI_API_KEY").ok();
71
72    let mut builder = Agent::builder();
73    if let Some(path) = harness_path {
74        builder = builder.binary_path(path);
75    }
76    if let Some(key) = api_key {
77        builder = builder.api_key(key);
78    }
79
80    // Enable subagents capability and file viewing
81    let capabilities = CapabilitiesConfig {
82        enabled_tools: Some(vec![
83            BuiltinTools::StartSubagent,
84            BuiltinTools::ListDir,
85            BuiltinTools::ViewFile,
86            BuiltinTools::Finish,
87        ]),
88        ..Default::default()
89    };
90
91    let subagent_active = Arc::new(AtomicBool::new(false));
92
93    let agent = builder
94        .default_model("gemini-3.5-flash")
95        .capabilities(capabilities)
96        .hook(Arc::new(SubagentHook { subagent_active }))
97        .allow_all()
98        .build();
99
100    println!("Starting agent...");
101    let agent = agent.start().await?;
102
103    let prompt = "Use a subagent to research the files in the current directory. \
104                  Delegate the task of listing the directory to the subagent, and then \
105                  tell me what files you found.";
106
107    println!("  User: {}", prompt);
108    let response = agent.chat(prompt).await?;
109    println!("\n  Agent:\n{}", response.text);
110
111    agent.stop().await?;
112    Ok(())
113}
examples/custom_tools.rs (line 164)
110async fn main() -> Result<(), anyhow::Error> {
111    // Initialize tracing subscriber
112    tracing_subscriber::fmt()
113        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
114        .init();
115
116    // Load environment variables from .env file if present
117    dotenvy::dotenv().ok();
118
119    // Check if the user specified a binary path or check the environment variable
120    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
121    let api_key = std::env::var("GEMINI_API_KEY").ok();
122
123    let mut builder = Agent::builder();
124    if let Some(path) = harness_path {
125        builder = builder.binary_path(path);
126    }
127    if let Some(key) = api_key {
128        builder = builder.api_key(key);
129    }
130
131    // Initialize shared mutable state for stateful tool
132    let inventory = Arc::new(Mutex::new(HashMap::new()));
133
134    let agent = builder
135        .default_model("gemini-3.5-flash")
136        .system_instructions(antigravity_sdk_rust::types::SystemInstructions::Custom(
137            antigravity_sdk_rust::types::CustomSystemInstructions {
138                text: "You keep track of fruit inventory. To record fruits, you MUST first look up the \
139                       fruit's SKU using lookup_fruit_sku, and then use that SKU with record_fruit."
140                        .to_string(),
141            },
142        ))
143        .tools(vec![
144            Arc::new(LookupSkuTool),
145            Arc::new(RecordFruitTool {
146                inventory: inventory.clone(),
147            }),
148        ])
149        .policies(vec![
150            policy::deny_all(),
151            policy::allow("lookup_fruit_sku"),
152            policy::allow("record_fruit"),
153        ])
154        .build();
155
156    println!("Starting agent...");
157    let agent = agent.start().await?;
158
159    println!("  === Custom Tools Demo ===");
160
161    // Turn 1: Lookup fruit SKU
162    let prompt1 = "What is the SKU for apples? We need to order more.";
163    println!("\n  User: {}", prompt1);
164    let response1 = agent.chat(prompt1).await?;
165    println!("  Agent: {}", response1.text);
166
167    // Stateful interaction: record fruits across multiple turns
168    println!("\n  === Stateful Tool (Fruit Counter) Demo ===");
169
170    let turns = vec![
171        "I have 5 apples.",
172        "And I just got 3 bananas.",
173        "Oh, and another 2 apples.",
174    ];
175
176    for user_input in turns {
177        println!("\n  User: {}", user_input);
178        let response = agent.chat(user_input).await?;
179        println!("  Agent: {}", response.text);
180    }
181
182    agent.stop().await?;
183    Ok(())
184}
examples/policies.rs (line 97)
42async fn main() -> Result<(), anyhow::Error> {
43    // Initialize tracing subscriber
44    tracing_subscriber::fmt()
45        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
46        .init();
47
48    // Load environment variables from .env file if present
49    dotenvy::dotenv().ok();
50
51    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
52    let api_key = std::env::var("GEMINI_API_KEY").ok();
53
54    let mut builder = Agent::builder();
55    if let Some(path) = harness_path {
56        builder = builder.binary_path(path);
57    }
58    if let Some(key) = api_key {
59        builder = builder.api_key(key);
60    }
61
62    let agent = builder
63        .default_model("gemini-3.5-flash")
64        // 1. Deny everything by default
65        .policy(policy::deny_all())
66        // 2. Allow listing directories
67        .policy(policy::allow("LIST_DIR"))
68        // 3. Allow running commands, but block dangerous 'rm' commands
69        .policy(Policy::new(
70            "RUN_COMMAND".to_string(),
71            Decision::Deny,
72            Some(Arc::new(block_rm_predicate)),
73            None,
74            "block-rm".to_string(),
75        ))
76        // Fallback: Allow general RUN_COMMAND calls if they don't match the rm block predicate
77        .policy(policy::allow("RUN_COMMAND"))
78        // 4. Allow editing/creating files, but ask the user first if it's a critical file
79        .policy(Policy::new(
80            "WRITE_TO_FILE".to_string(),
81            Decision::AskUser,
82            Some(Arc::new(critical_file_predicate)),
83            Some(Arc::new(programmatic_approval_handler)),
84            "ask-for-critical-writes".to_string(),
85        ))
86        .policy(policy::allow("WRITE_TO_FILE"))
87        .build();
88
89    println!("Starting agent...");
90    let agent = agent.start().await?;
91
92    println!("\n  Chatting with agent...");
93
94    // 1. Try a safe command (should be allowed)
95    let prompt1 = "List the files in the current directory.";
96    println!("\n  User: {}", prompt1);
97    let response1 = agent.chat(prompt1).await?;
98    println!("  Agent: {}", response1.text);
99
100    // 2. Try a dangerous command (should be denied by policy)
101    let prompt2 = "Delete all files using rm -rf.";
102    println!("\n  User: {}", prompt2);
103    let response2 = agent.chat(prompt2).await?;
104    println!("  Agent: {}", response2.text);
105
106    // 3. Try creating a critical file (triggers programmatic ask_user handler)
107    let prompt3 = "Create a new configuration file named production.key with content 'debug=true'.";
108    println!("\n  User: {}", prompt3);
109    let response3 = agent.chat(prompt3).await?;
110    println!("  Agent: {}", response3.text);
111
112    agent.stop().await?;
113    Ok(())
114}
examples/persistence.rs (line 52)
6async fn main() -> Result<(), anyhow::Error> {
7    // Initialize tracing subscriber
8    tracing_subscriber::fmt()
9        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
10        .init();
11
12    // Load environment variables from .env file if present
13    dotenvy::dotenv().ok();
14
15    // Create a temporary path for save_dir
16    let mut save_dir = std::env::temp_dir();
17    let epoch = SystemTime::now()
18        .duration_since(SystemTime::UNIX_EPOCH)
19        .unwrap_or_default()
20        .as_secs();
21    save_dir.push(format!("agent_session_{}", epoch));
22    let save_dir_str = save_dir.to_string_lossy().to_string();
23    println!("  Save directory: {}", save_dir_str);
24
25    // Ensure the save_dir exists
26    std::fs::create_dir_all(&save_dir)?;
27
28    println!("\n  === Session 1: establishing context ===");
29
30    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
31    let api_key = std::env::var("GEMINI_API_KEY").ok();
32
33    let mut builder1 = Agent::builder();
34    if let Some(path) = harness_path.clone() {
35        builder1 = builder1.binary_path(path);
36    }
37    if let Some(key) = api_key.clone() {
38        builder1 = builder1.api_key(key);
39    }
40
41    let agent1 = builder1
42        .default_model("gemini-3.5-flash")
43        .allow_all()
44        .save_dir(save_dir_str.clone())
45        .build();
46
47    let conversation_id = {
48        let agent1 = agent1.start().await?;
49
50        let prompt1 = "Remember this: my favorite color is blue.";
51        println!("  User: {}", prompt1);
52        let response1 = agent1.chat(prompt1).await?;
53        println!("  Agent: {}", response1.text);
54
55        let conv_id = agent1.conversation_id();
56        println!("  Assigned conversation ID: {}", conv_id);
57
58        agent1.stop().await?;
59        println!("  Session 1 ended.\n");
60        conv_id
61    };
62
63    println!("  === Session 2: resuming and verifying recall ===");
64
65    let mut builder2 = Agent::builder();
66    if let Some(path) = harness_path {
67        builder2 = builder2.binary_path(path);
68    }
69    if let Some(key) = api_key {
70        builder2 = builder2.api_key(key);
71    }
72
73    let agent2 = builder2
74        .default_model("gemini-3.5-flash")
75        .allow_all()
76        .save_dir(save_dir_str.clone())
77        .conversation_id(conversation_id)
78        .build();
79
80    let agent2 = agent2.start().await?;
81
82    let prompt2 = "What is my favorite color?";
83    println!("  User: {}", prompt2);
84    let response2 = agent2.chat(prompt2).await?;
85    println!("  Agent: {}", response2.text);
86
87    agent2.stop().await?;
88    println!("  Session 2 ended.");
89
90    // Clean up temporary session directory
91    let _ = std::fs::remove_dir_all(&save_dir);
92
93    Ok(())
94}
examples/structured_output.rs (line 108)
51async fn main() -> Result<(), anyhow::Error> {
52    // Initialize tracing subscriber
53    tracing_subscriber::fmt()
54        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
55        .init();
56
57    // Load environment variables from .env file if present
58    dotenvy::dotenv().ok();
59
60    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
61    let api_key = std::env::var("GEMINI_API_KEY").ok();
62
63    let mut builder = Agent::builder();
64    if let Some(path) = harness_path {
65        builder = builder.binary_path(path);
66    }
67    if let Some(key) = api_key {
68        builder = builder.api_key(key);
69    }
70
71    // Define response schema for meeting summaries and action items
72    let response_schema = r#"{
73        "type": "object",
74        "properties": {
75            "action_items": {
76                "type": "array",
77                "items": {
78                    "type": "object",
79                    "properties": {
80                        "assignee": { "type": "string" },
81                        "task": { "type": "string" },
82                        "deadline": { "type": "string" }
83                    },
84                    "required": ["assignee", "task", "deadline"]
85                }
86            }
87        },
88        "required": ["action_items"]
89    }"#;
90
91    let agent = builder
92        .default_model("gemini-3.5-flash")
93        .response_schema(response_schema.to_string())
94        .tool(Arc::new(FetchNotesTool))
95        .policy(policy::deny_all())
96        .policy(policy::allow("fetch_unstructured_meeting_notes"))
97        .build();
98
99    println!("Starting agent...");
100    let agent = agent.start().await?;
101
102    let prompt = "Use the fetch_unstructured_meeting_notes tool to retrieve notes for \
103                  'meeting-2026-05' and return the meeting summary with the appropriate \
104                  action item list. Ensure each action item includes 'assignee', \
105                  'task', and 'deadline'.";
106
107    println!("\n  Sending prompt to agent...\n  {}", prompt);
108    let response = agent.chat(prompt).await?;
109
110    println!("\n  Extracting structured meeting action items...");
111
112    // Find the step that contains structured_output
113    let mut found = false;
114    for step in &response.steps {
115        if let Some(ref structured) = step.structured_output {
116            println!("\n  === Structured Meeting Action Items ===");
117            if let Some(items) = structured.get("action_items").and_then(Value::as_array) {
118                for item in items {
119                    println!(
120                        "  - Assignee: {:?}",
121                        item.get("assignee").and_then(Value::as_str).unwrap_or("")
122                    );
123                    println!(
124                        "    Task:     {:?}",
125                        item.get("task").and_then(Value::as_str).unwrap_or("")
126                    );
127                    println!(
128                        "    Deadline: {:?}",
129                        item.get("deadline").and_then(Value::as_str).unwrap_or("")
130                    );
131                    println!();
132                }
133            } else {
134                println!("No action_items field or not an array: {:?}", structured);
135            }
136            found = true;
137            break;
138        }
139    }
140
141    if !found {
142        println!("\n  Failed to extract structured summary natively.");
143        println!("  Final Text Response: {}", response.text);
144    }
145
146    agent.stop().await?;
147    Ok(())
148}
Source

pub fn conversation(&self) -> Arc<Conversation>

Returns the active Conversation session.

Examples found in repository?
examples/streaming.rs (line 38)
7async fn main() -> Result<(), anyhow::Error> {
8    // Initialize tracing subscriber
9    tracing_subscriber::fmt()
10        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
11        .init();
12
13    // Load environment variables from .env file if present
14    dotenvy::dotenv().ok();
15
16    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
17    let api_key = std::env::var("GEMINI_API_KEY").ok();
18
19    let mut builder = Agent::builder();
20    if let Some(path) = harness_path {
21        builder = builder.binary_path(path);
22    }
23    if let Some(key) = api_key {
24        builder = builder.api_key(key);
25    }
26
27    let agent = builder
28        .default_model("gemini-3.5-flash")
29        .allow_all()
30        .build();
31
32    println!("Starting agent...");
33    let agent = agent.start().await?;
34
35    let prompt = "Solve this riddle: I speak without a mouth and hear without ears. I have no body, but I come alive with wind. What am I? Explain your reasoning.";
36    println!("\n  User: {}\n", prompt);
37
38    let conversation = agent.conversation();
39    let mut stream = conversation.chat(prompt).await?;
40
41    println!("  Agent (Streaming response):");
42    println!("  -------------------------------------------------------");
43
44    while let Some(chunk_res) = stream.next().await {
45        match chunk_res? {
46            StreamChunk::Thought { text, .. } => {
47                // Print thought chunks (e.g. in grey or wrapped in brackets if desired, or directly)
48                print!("{}", text);
49                std::io::Write::flush(&mut std::io::stdout())?;
50            }
51            StreamChunk::Text { text, .. } => {
52                // Print response text chunks
53                print!("{}", text);
54                std::io::Write::flush(&mut std::io::stdout())?;
55            }
56            StreamChunk::ToolCall(call) => {
57                println!(
58                    "\n[Tool Call Requested: {} with args: {}]",
59                    call.name, call.args
60                );
61            }
62        }
63    }
64    println!("\n  -------------------------------------------------------\n");
65
66    agent.stop().await?;
67    Ok(())
68}
Source

pub fn conversation_id(&self) -> String

Returns the active conversation ID.

Examples found in repository?
examples/persistence.rs (line 55)
6async fn main() -> Result<(), anyhow::Error> {
7    // Initialize tracing subscriber
8    tracing_subscriber::fmt()
9        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
10        .init();
11
12    // Load environment variables from .env file if present
13    dotenvy::dotenv().ok();
14
15    // Create a temporary path for save_dir
16    let mut save_dir = std::env::temp_dir();
17    let epoch = SystemTime::now()
18        .duration_since(SystemTime::UNIX_EPOCH)
19        .unwrap_or_default()
20        .as_secs();
21    save_dir.push(format!("agent_session_{}", epoch));
22    let save_dir_str = save_dir.to_string_lossy().to_string();
23    println!("  Save directory: {}", save_dir_str);
24
25    // Ensure the save_dir exists
26    std::fs::create_dir_all(&save_dir)?;
27
28    println!("\n  === Session 1: establishing context ===");
29
30    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
31    let api_key = std::env::var("GEMINI_API_KEY").ok();
32
33    let mut builder1 = Agent::builder();
34    if let Some(path) = harness_path.clone() {
35        builder1 = builder1.binary_path(path);
36    }
37    if let Some(key) = api_key.clone() {
38        builder1 = builder1.api_key(key);
39    }
40
41    let agent1 = builder1
42        .default_model("gemini-3.5-flash")
43        .allow_all()
44        .save_dir(save_dir_str.clone())
45        .build();
46
47    let conversation_id = {
48        let agent1 = agent1.start().await?;
49
50        let prompt1 = "Remember this: my favorite color is blue.";
51        println!("  User: {}", prompt1);
52        let response1 = agent1.chat(prompt1).await?;
53        println!("  Agent: {}", response1.text);
54
55        let conv_id = agent1.conversation_id();
56        println!("  Assigned conversation ID: {}", conv_id);
57
58        agent1.stop().await?;
59        println!("  Session 1 ended.\n");
60        conv_id
61    };
62
63    println!("  === Session 2: resuming and verifying recall ===");
64
65    let mut builder2 = Agent::builder();
66    if let Some(path) = harness_path {
67        builder2 = builder2.binary_path(path);
68    }
69    if let Some(key) = api_key {
70        builder2 = builder2.api_key(key);
71    }
72
73    let agent2 = builder2
74        .default_model("gemini-3.5-flash")
75        .allow_all()
76        .save_dir(save_dir_str.clone())
77        .conversation_id(conversation_id)
78        .build();
79
80    let agent2 = agent2.start().await?;
81
82    let prompt2 = "What is my favorite color?";
83    println!("  User: {}", prompt2);
84    let response2 = agent2.chat(prompt2).await?;
85    println!("  Agent: {}", response2.text);
86
87    agent2.stop().await?;
88    println!("  Session 2 ended.");
89
90    // Clean up temporary session directory
91    let _ = std::fs::remove_dir_all(&save_dir);
92
93    Ok(())
94}
Source

pub async fn stop(&self) -> Result<(), Error>

Gracefully stops the agent connection and disconnects the underlying harness.

§Errors

Returns an error if closing the connection fails.

Examples found in repository?
examples/hello_world.rs (line 40)
5async fn main() -> Result<(), anyhow::Error> {
6    // Initialize tracing subscriber to print info/debug logs by default
7    tracing_subscriber::fmt()
8        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
9        .init();
10
11    // Load environment variables from .env file if present
12    dotenvy::dotenv().ok();
13
14    // Check if the user specified a binary path or check the environment variable
15    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
16    let api_key = std::env::var("GEMINI_API_KEY").ok();
17
18    let mut builder = Agent::builder();
19    if let Some(path) = harness_path {
20        builder = builder.binary_path(path);
21    }
22    if let Some(key) = api_key {
23        builder = builder.api_key(key);
24    }
25
26    let agent = builder
27        .default_model("gemini-3.5-flash")
28        .allow_all()
29        .build();
30
31    println!("Starting agent...");
32    let agent = agent.start().await?;
33
34    let prompt = "Say 'Hello World!'";
35    println!("  User: {}", prompt);
36
37    let response = agent.chat(prompt).await?;
38    println!("  Agent: {}", response.text);
39
40    agent.stop().await?;
41    Ok(())
42}
More examples
Hide additional examples
examples/subagents.rs (line 111)
60async fn main() -> Result<(), anyhow::Error> {
61    // Initialize tracing subscriber
62    tracing_subscriber::fmt()
63        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
64        .init();
65
66    // Load environment variables from .env file if present
67    dotenvy::dotenv().ok();
68
69    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
70    let api_key = std::env::var("GEMINI_API_KEY").ok();
71
72    let mut builder = Agent::builder();
73    if let Some(path) = harness_path {
74        builder = builder.binary_path(path);
75    }
76    if let Some(key) = api_key {
77        builder = builder.api_key(key);
78    }
79
80    // Enable subagents capability and file viewing
81    let capabilities = CapabilitiesConfig {
82        enabled_tools: Some(vec![
83            BuiltinTools::StartSubagent,
84            BuiltinTools::ListDir,
85            BuiltinTools::ViewFile,
86            BuiltinTools::Finish,
87        ]),
88        ..Default::default()
89    };
90
91    let subagent_active = Arc::new(AtomicBool::new(false));
92
93    let agent = builder
94        .default_model("gemini-3.5-flash")
95        .capabilities(capabilities)
96        .hook(Arc::new(SubagentHook { subagent_active }))
97        .allow_all()
98        .build();
99
100    println!("Starting agent...");
101    let agent = agent.start().await?;
102
103    let prompt = "Use a subagent to research the files in the current directory. \
104                  Delegate the task of listing the directory to the subagent, and then \
105                  tell me what files you found.";
106
107    println!("  User: {}", prompt);
108    let response = agent.chat(prompt).await?;
109    println!("\n  Agent:\n{}", response.text);
110
111    agent.stop().await?;
112    Ok(())
113}
examples/streaming.rs (line 66)
7async fn main() -> Result<(), anyhow::Error> {
8    // Initialize tracing subscriber
9    tracing_subscriber::fmt()
10        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
11        .init();
12
13    // Load environment variables from .env file if present
14    dotenvy::dotenv().ok();
15
16    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
17    let api_key = std::env::var("GEMINI_API_KEY").ok();
18
19    let mut builder = Agent::builder();
20    if let Some(path) = harness_path {
21        builder = builder.binary_path(path);
22    }
23    if let Some(key) = api_key {
24        builder = builder.api_key(key);
25    }
26
27    let agent = builder
28        .default_model("gemini-3.5-flash")
29        .allow_all()
30        .build();
31
32    println!("Starting agent...");
33    let agent = agent.start().await?;
34
35    let prompt = "Solve this riddle: I speak without a mouth and hear without ears. I have no body, but I come alive with wind. What am I? Explain your reasoning.";
36    println!("\n  User: {}\n", prompt);
37
38    let conversation = agent.conversation();
39    let mut stream = conversation.chat(prompt).await?;
40
41    println!("  Agent (Streaming response):");
42    println!("  -------------------------------------------------------");
43
44    while let Some(chunk_res) = stream.next().await {
45        match chunk_res? {
46            StreamChunk::Thought { text, .. } => {
47                // Print thought chunks (e.g. in grey or wrapped in brackets if desired, or directly)
48                print!("{}", text);
49                std::io::Write::flush(&mut std::io::stdout())?;
50            }
51            StreamChunk::Text { text, .. } => {
52                // Print response text chunks
53                print!("{}", text);
54                std::io::Write::flush(&mut std::io::stdout())?;
55            }
56            StreamChunk::ToolCall(call) => {
57                println!(
58                    "\n[Tool Call Requested: {} with args: {}]",
59                    call.name, call.args
60                );
61            }
62        }
63    }
64    println!("\n  -------------------------------------------------------\n");
65
66    agent.stop().await?;
67    Ok(())
68}
examples/custom_tools.rs (line 182)
110async fn main() -> Result<(), anyhow::Error> {
111    // Initialize tracing subscriber
112    tracing_subscriber::fmt()
113        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
114        .init();
115
116    // Load environment variables from .env file if present
117    dotenvy::dotenv().ok();
118
119    // Check if the user specified a binary path or check the environment variable
120    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
121    let api_key = std::env::var("GEMINI_API_KEY").ok();
122
123    let mut builder = Agent::builder();
124    if let Some(path) = harness_path {
125        builder = builder.binary_path(path);
126    }
127    if let Some(key) = api_key {
128        builder = builder.api_key(key);
129    }
130
131    // Initialize shared mutable state for stateful tool
132    let inventory = Arc::new(Mutex::new(HashMap::new()));
133
134    let agent = builder
135        .default_model("gemini-3.5-flash")
136        .system_instructions(antigravity_sdk_rust::types::SystemInstructions::Custom(
137            antigravity_sdk_rust::types::CustomSystemInstructions {
138                text: "You keep track of fruit inventory. To record fruits, you MUST first look up the \
139                       fruit's SKU using lookup_fruit_sku, and then use that SKU with record_fruit."
140                        .to_string(),
141            },
142        ))
143        .tools(vec![
144            Arc::new(LookupSkuTool),
145            Arc::new(RecordFruitTool {
146                inventory: inventory.clone(),
147            }),
148        ])
149        .policies(vec![
150            policy::deny_all(),
151            policy::allow("lookup_fruit_sku"),
152            policy::allow("record_fruit"),
153        ])
154        .build();
155
156    println!("Starting agent...");
157    let agent = agent.start().await?;
158
159    println!("  === Custom Tools Demo ===");
160
161    // Turn 1: Lookup fruit SKU
162    let prompt1 = "What is the SKU for apples? We need to order more.";
163    println!("\n  User: {}", prompt1);
164    let response1 = agent.chat(prompt1).await?;
165    println!("  Agent: {}", response1.text);
166
167    // Stateful interaction: record fruits across multiple turns
168    println!("\n  === Stateful Tool (Fruit Counter) Demo ===");
169
170    let turns = vec![
171        "I have 5 apples.",
172        "And I just got 3 bananas.",
173        "Oh, and another 2 apples.",
174    ];
175
176    for user_input in turns {
177        println!("\n  User: {}", user_input);
178        let response = agent.chat(user_input).await?;
179        println!("  Agent: {}", response.text);
180    }
181
182    agent.stop().await?;
183    Ok(())
184}
examples/policies.rs (line 112)
42async fn main() -> Result<(), anyhow::Error> {
43    // Initialize tracing subscriber
44    tracing_subscriber::fmt()
45        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
46        .init();
47
48    // Load environment variables from .env file if present
49    dotenvy::dotenv().ok();
50
51    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
52    let api_key = std::env::var("GEMINI_API_KEY").ok();
53
54    let mut builder = Agent::builder();
55    if let Some(path) = harness_path {
56        builder = builder.binary_path(path);
57    }
58    if let Some(key) = api_key {
59        builder = builder.api_key(key);
60    }
61
62    let agent = builder
63        .default_model("gemini-3.5-flash")
64        // 1. Deny everything by default
65        .policy(policy::deny_all())
66        // 2. Allow listing directories
67        .policy(policy::allow("LIST_DIR"))
68        // 3. Allow running commands, but block dangerous 'rm' commands
69        .policy(Policy::new(
70            "RUN_COMMAND".to_string(),
71            Decision::Deny,
72            Some(Arc::new(block_rm_predicate)),
73            None,
74            "block-rm".to_string(),
75        ))
76        // Fallback: Allow general RUN_COMMAND calls if they don't match the rm block predicate
77        .policy(policy::allow("RUN_COMMAND"))
78        // 4. Allow editing/creating files, but ask the user first if it's a critical file
79        .policy(Policy::new(
80            "WRITE_TO_FILE".to_string(),
81            Decision::AskUser,
82            Some(Arc::new(critical_file_predicate)),
83            Some(Arc::new(programmatic_approval_handler)),
84            "ask-for-critical-writes".to_string(),
85        ))
86        .policy(policy::allow("WRITE_TO_FILE"))
87        .build();
88
89    println!("Starting agent...");
90    let agent = agent.start().await?;
91
92    println!("\n  Chatting with agent...");
93
94    // 1. Try a safe command (should be allowed)
95    let prompt1 = "List the files in the current directory.";
96    println!("\n  User: {}", prompt1);
97    let response1 = agent.chat(prompt1).await?;
98    println!("  Agent: {}", response1.text);
99
100    // 2. Try a dangerous command (should be denied by policy)
101    let prompt2 = "Delete all files using rm -rf.";
102    println!("\n  User: {}", prompt2);
103    let response2 = agent.chat(prompt2).await?;
104    println!("  Agent: {}", response2.text);
105
106    // 3. Try creating a critical file (triggers programmatic ask_user handler)
107    let prompt3 = "Create a new configuration file named production.key with content 'debug=true'.";
108    println!("\n  User: {}", prompt3);
109    let response3 = agent.chat(prompt3).await?;
110    println!("  Agent: {}", response3.text);
111
112    agent.stop().await?;
113    Ok(())
114}
examples/persistence.rs (line 58)
6async fn main() -> Result<(), anyhow::Error> {
7    // Initialize tracing subscriber
8    tracing_subscriber::fmt()
9        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
10        .init();
11
12    // Load environment variables from .env file if present
13    dotenvy::dotenv().ok();
14
15    // Create a temporary path for save_dir
16    let mut save_dir = std::env::temp_dir();
17    let epoch = SystemTime::now()
18        .duration_since(SystemTime::UNIX_EPOCH)
19        .unwrap_or_default()
20        .as_secs();
21    save_dir.push(format!("agent_session_{}", epoch));
22    let save_dir_str = save_dir.to_string_lossy().to_string();
23    println!("  Save directory: {}", save_dir_str);
24
25    // Ensure the save_dir exists
26    std::fs::create_dir_all(&save_dir)?;
27
28    println!("\n  === Session 1: establishing context ===");
29
30    let harness_path = std::env::var("ANTIGRAVITY_HARNESS_PATH").ok();
31    let api_key = std::env::var("GEMINI_API_KEY").ok();
32
33    let mut builder1 = Agent::builder();
34    if let Some(path) = harness_path.clone() {
35        builder1 = builder1.binary_path(path);
36    }
37    if let Some(key) = api_key.clone() {
38        builder1 = builder1.api_key(key);
39    }
40
41    let agent1 = builder1
42        .default_model("gemini-3.5-flash")
43        .allow_all()
44        .save_dir(save_dir_str.clone())
45        .build();
46
47    let conversation_id = {
48        let agent1 = agent1.start().await?;
49
50        let prompt1 = "Remember this: my favorite color is blue.";
51        println!("  User: {}", prompt1);
52        let response1 = agent1.chat(prompt1).await?;
53        println!("  Agent: {}", response1.text);
54
55        let conv_id = agent1.conversation_id();
56        println!("  Assigned conversation ID: {}", conv_id);
57
58        agent1.stop().await?;
59        println!("  Session 1 ended.\n");
60        conv_id
61    };
62
63    println!("  === Session 2: resuming and verifying recall ===");
64
65    let mut builder2 = Agent::builder();
66    if let Some(path) = harness_path {
67        builder2 = builder2.binary_path(path);
68    }
69    if let Some(key) = api_key {
70        builder2 = builder2.api_key(key);
71    }
72
73    let agent2 = builder2
74        .default_model("gemini-3.5-flash")
75        .allow_all()
76        .save_dir(save_dir_str.clone())
77        .conversation_id(conversation_id)
78        .build();
79
80    let agent2 = agent2.start().await?;
81
82    let prompt2 = "What is my favorite color?";
83    println!("  User: {}", prompt2);
84    let response2 = agent2.chat(prompt2).await?;
85    println!("  Agent: {}", response2.text);
86
87    agent2.stop().await?;
88    println!("  Session 2 ended.");
89
90    // Clean up temporary session directory
91    let _ = std::fs::remove_dir_all(&save_dir);
92
93    Ok(())
94}

Trait Implementations§

Source§

impl<S: AgentLifecycle> Debug for Agent<S>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<S> Freeze for Agent<S>
where S: Freeze,

§

impl<S = Unstarted> !RefUnwindSafe for Agent<S>

§

impl<S> Send for Agent<S>

§

impl<S> Sync for Agent<S>

§

impl<S> Unpin for Agent<S>
where S: Unpin,

§

impl<S> UnsafeUnpin for Agent<S>
where S: UnsafeUnpin,

§

impl<S = Unstarted> !UnwindSafe for Agent<S>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more