pub struct Agent<S: AgentLifecycle = Unstarted> { /* private fields */ }Implementations§
Source§impl Agent<Unstarted>
impl Agent<Unstarted>
Sourcepub fn new(config: AgentConfig) -> Self
pub fn new(config: AgentConfig) -> Self
Creates a new Agent with the given configuration.
Sourcepub fn builder() -> AgentBuilder<NoPolicies>
pub fn builder() -> AgentBuilder<NoPolicies>
Returns an AgentBuilder to configure and construct an Agent.
Examples found in repository?
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
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}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}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}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}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}Sourcepub fn register_hook(&mut self, hook: Arc<dyn DynHook>)
pub fn register_hook(&mut self, hook: Arc<dyn DynHook>)
Registers a custom lifecycle hook during configuration.
Sourcepub fn register_trigger(
&mut self,
trigger: Arc<dyn DynTrigger>,
) -> Result<(), Error>
pub fn register_trigger( &mut self, trigger: Arc<dyn DynTrigger>, ) -> Result<(), Error>
Registers a custom background trigger.
Sourcepub fn register_tool(&mut self, tool: Arc<dyn DynTool>)
pub fn register_tool(&mut self, tool: Arc<dyn DynTool>)
Registers a custom tool during configuration.
Sourcepub fn start(self) -> BoxFuture<'static, Result<Agent<Started>, Error>>
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
localharnessbinary cannot be resolved. - Write tools are enabled but no safety policies are configured.
- The WebSocket upgrade or subprocess connection fails.
Examples found in repository?
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
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}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}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}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}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>
impl Agent<Started>
Sourcepub async fn chat(&self, prompt: &str) -> Result<ChatResponse, Error>
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?
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
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}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}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}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}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}Sourcepub fn conversation(&self) -> Arc<Conversation>
pub fn conversation(&self) -> Arc<Conversation>
Returns the active Conversation session.
Examples found in repository?
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}Sourcepub fn conversation_id(&self) -> String
pub fn conversation_id(&self) -> String
Returns the active conversation ID.
Examples found in repository?
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}Sourcepub async fn stop(&self) -> Result<(), Error>
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?
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
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}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}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}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}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}