pub struct BrowserTab {
pub current_url: Option<String>,
/* private fields */
}Fields§
§current_url: Option<String>Implementations§
Source§impl BrowserTab
impl BrowserTab
pub fn new() -> Result<Self>
pub fn builder() -> BrowserBuilder
Sourcepub fn with_profile(profile: DeviceProfile) -> Result<Self>
pub fn with_profile(profile: DeviceProfile) -> Result<Self>
Examples found in repository?
examples/screenshot_demo.rs (line 10)
7async fn main() -> Result<()> {
8 println!(">>> Testing Pure-Rust Vector SVG & Wireframe Screenshot Rendering...");
9
10 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
11 tab.navigate("https://news.ycombinator.com/").await?;
12
13 let shot = tab.screenshot().expect("Expected screenshot");
14 println!(" * Dimensions: {}x{}", shot.width, shot.height);
15 println!(" * Elements Rendered: {}", shot.element_count);
16 println!(" * SVG Payload Size: {} bytes", shot.svg.len());
17
18 // Save SVG file
19 fs::write("screenshot.svg", &shot.svg)?;
20 println!(" * Saved screenshot to 'screenshot.svg'");
21
22 // Print text wireframe preview
23 println!("\n>>> ASCII WIREFRAME PREVIEW (FOR AGENT VISION TOKENS):");
24 let preview: String = shot
25 .layout_wireframe
26 .lines()
27 .take(18)
28 .collect::<Vec<_>>()
29 .join("\n");
30 println!("{}", preview);
31
32 Ok(())
33}More examples
examples/scrape_to_markdown.rs (line 8)
6async fn main() -> Result<()> {
7 println!(">>> Launching Headless Engine Tab with Windows Chrome profile...");
8 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
9
10 let url = "https://en.wikipedia.org/wiki/Rust_(programming_language)";
11 println!(">>> Navigating to: {}", url);
12 let report = tab.navigate(url).await?;
13
14 println!(">>> Page Title: {}", report.page_title);
15 println!(">>> Raw HTML Size: {} bytes", report.html_bytes);
16
17 let markdown = tab.extract_markdown(None).unwrap_or_default();
18 println!(
19 ">>> Markdown Size: {} bytes (~{:.1}% compression)",
20 markdown.len(),
21 (1.0 - (markdown.len() as f64 / report.html_bytes as f64)) * 100.0
22 );
23
24 println!("\n--- MARKDOWN PREVIEW (First 600 chars) ---\n");
25 let preview: String = markdown.chars().take(600).collect();
26 println!("{}", preview);
27 println!("\n-------------------------------------------");
28
29 Ok(())
30}examples/test_search_modes.rs (line 7)
6async fn main() -> Result<()> {
7 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
8
9 let urls = [
10 "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents&gbv=1",
11 "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents&udm=14",
12 "https://www.google.com/search?q=Rust+programming+language&udm=14",
13 "https://html.duckduckgo.com/html/?q=headless+browser+rust+engine+for+ai+agents",
14 ];
15
16 for url in urls {
17 println!("\n========================================");
18 println!("Testing URL: {}", url);
19 let nav = tab.navigate(url).await?;
20 println!("Status: {}", nav.status);
21 println!("Title: {}", nav.page_title);
22 println!("Bytes: {}", nav.html_bytes);
23 let md = tab.extract_markdown(None).unwrap_or_default();
24 println!("MD Len: {} bytes", md.len());
25 println!("Preview:\n{}", md.chars().take(300).collect::<String>());
26 }
27
28 Ok(())
29}examples/test_google_markdown_fix.rs (line 14)
8async fn main() -> Result<()> {
9 println!(">>> Testing Google Search Distilled Markdown Extraction...");
10
11 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
12 let evidence_dir = Path::new("evidence");
13
14 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
15 let url = "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents";
16 println!(" -> Navigating to: {}", url);
17 let nav = tab.navigate(url).await?;
18
19 println!(" -> Status: {}", nav.status);
20 println!(" -> Final URL: {}", nav.final_url);
21 println!(" -> Page Title: {}", nav.page_title);
22 println!(" -> HTML Payload: {} bytes", nav.html_bytes);
23
24 let md = tab.extract_markdown(None).unwrap_or_default();
25 println!(" -> Extracted Markdown Size: {} bytes", md.len());
26
27 fs::write(evidence_dir.join("google_normal_search_distilled.md"), &md)?;
28 fs::write(artifact_dir.join("google_normal_search_distilled.md"), &md)?;
29
30 println!("\n>>> DISTILLED GOOGLE SEARCH MARKDOWN:\n");
31 println!("{}", md);
32
33 Ok(())
34}examples/test_all_31_google_capabilities.rs (line 13)
6async fn main() -> anyhow::Result<()> {
7 println!("Testing all 31 Google/YouTube Capabilities...");
8 let evidence_dir = Path::new("evidence");
9 if !evidence_dir.exists() {
10 fs::create_dir_all(evidence_dir)?;
11 }
12
13 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
14
15 // Test a subset so it doesn't take forever, or just do the 5 most important ones to verify parsing
16 println!("1. Testing google_search...");
17 let res = tab.google_search("headless browser pure rust engine").await?;
18 fs::write(evidence_dir.join("test_google_search.md"), res.to_markdown())?;
19
20 println!("2. Testing youtube_search...");
21 let res = tab.youtube_search("rust programming").await?;
22 fs::write(evidence_dir.join("test_youtube_search.md"), res.to_markdown())?;
23
24 println!("3. Testing google_ai_mode...");
25 let res = tab.google_ai_mode("explain quantum computing").await?;
26 fs::write(evidence_dir.join("test_google_ai_mode.md"), res.to_markdown())?;
27
28 println!("4. Testing google_autocomplete...");
29 let res = tab.google_autocomplete("rust").await?;
30 fs::write(evidence_dir.join("test_google_autocomplete.md"), res.to_markdown())?;
31
32 println!("Capabilities listed:");
33 for cap in tab.google_capabilities() {
34 println!(" - {}", cap);
35 }
36
37 println!("All tests completed. Output saved to evidence/");
38 Ok(())
39}examples/test_html_css_rendering.rs (line 12)
7async fn main() -> Result<()> {
8 println!("================================================================================");
9 println!(">>> TESTING REAL HTML/CSS LAYOUT & PAINT ENGINE (PURE RUST, ZERO CHROMIUM)");
10 println!("================================================================================\n");
11
12 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
13
14 // 1. Test Wikipedia
15 let url = "https://en.wikipedia.org/wiki/Rust_(programming_language)";
16 println!("[1] Navigating to: {}", url);
17 let report = tab.navigate(url).await?;
18 println!(" * Title: {}", report.page_title);
19 println!(" * HTML Size: {} bytes", report.html_bytes);
20
21 println!("[2] Performing Real HTML/CSS Layout Pass & Rasterizing to PNG...");
22 let shot = tab.screenshot_async().await.expect("Expected screenshot");
23 println!(" * Resolution: {}x{}", shot.width, shot.height);
24 println!(" * Real PNG Size: {} bytes", shot.png_bytes.len());
25 println!(" * Base64 Data URL Prefix: {}...", &shot.png_base64[..50]);
26
27 fs::write("wikipedia_screenshot.png", &shot.png_bytes)?;
28 println!(" -> Successfully wrote real binary image: 'wikipedia_screenshot.png'");
29
30 println!("\n================================================================================");
31 println!(">>> REAL HTML/CSS LAYOUT & PAINT PASSED WITH ZERO CHROMIUM (<30MB RAM)!");
32 println!("================================================================================");
33
34 Ok(())
35}Additional examples can be found in:
- examples/test_youtube_screenshot.rs
- examples/autonomous_agent_loop.rs
- examples/capture_perfect_screenshots.rs
- examples/test_default_google_search.rs
- examples/test_real_thumbnail_screenshot.rs
- examples/agentic_chatgpt_prompt_execution.rs
- examples/demonstrate_all_features.rs
- examples/test_chatgpt_and_google.rs
pub fn from_network(network: NetworkClient) -> Result<Self>
pub fn profile(&self) -> DeviceProfile
pub fn set_profile(&mut self, profile: DeviceProfile) -> Result<()>
Examples found in repository?
examples/screenshot_demo.rs (line 11)
7async fn main() -> Result<()> {
8 println!(">>> Testing Pure-Rust Vector SVG & Wireframe Screenshot Rendering...");
9
10 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
11 tab.navigate("https://news.ycombinator.com/").await?;
12
13 let shot = tab.screenshot().expect("Expected screenshot");
14 println!(" * Dimensions: {}x{}", shot.width, shot.height);
15 println!(" * Elements Rendered: {}", shot.element_count);
16 println!(" * SVG Payload Size: {} bytes", shot.svg.len());
17
18 // Save SVG file
19 fs::write("screenshot.svg", &shot.svg)?;
20 println!(" * Saved screenshot to 'screenshot.svg'");
21
22 // Print text wireframe preview
23 println!("\n>>> ASCII WIREFRAME PREVIEW (FOR AGENT VISION TOKENS):");
24 let preview: String = shot
25 .layout_wireframe
26 .lines()
27 .take(18)
28 .collect::<Vec<_>>()
29 .join("\n");
30 println!("{}", preview);
31
32 Ok(())
33}More examples
examples/scrape_to_markdown.rs (line 12)
6async fn main() -> Result<()> {
7 println!(">>> Launching Headless Engine Tab with Windows Chrome profile...");
8 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
9
10 let url = "https://en.wikipedia.org/wiki/Rust_(programming_language)";
11 println!(">>> Navigating to: {}", url);
12 let report = tab.navigate(url).await?;
13
14 println!(">>> Page Title: {}", report.page_title);
15 println!(">>> Raw HTML Size: {} bytes", report.html_bytes);
16
17 let markdown = tab.extract_markdown(None).unwrap_or_default();
18 println!(
19 ">>> Markdown Size: {} bytes (~{:.1}% compression)",
20 markdown.len(),
21 (1.0 - (markdown.len() as f64 / report.html_bytes as f64)) * 100.0
22 );
23
24 println!("\n--- MARKDOWN PREVIEW (First 600 chars) ---\n");
25 let preview: String = markdown.chars().take(600).collect();
26 println!("{}", preview);
27 println!("\n-------------------------------------------");
28
29 Ok(())
30}examples/test_search_modes.rs (line 19)
6async fn main() -> Result<()> {
7 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
8
9 let urls = [
10 "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents&gbv=1",
11 "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents&udm=14",
12 "https://www.google.com/search?q=Rust+programming+language&udm=14",
13 "https://html.duckduckgo.com/html/?q=headless+browser+rust+engine+for+ai+agents",
14 ];
15
16 for url in urls {
17 println!("\n========================================");
18 println!("Testing URL: {}", url);
19 let nav = tab.navigate(url).await?;
20 println!("Status: {}", nav.status);
21 println!("Title: {}", nav.page_title);
22 println!("Bytes: {}", nav.html_bytes);
23 let md = tab.extract_markdown(None).unwrap_or_default();
24 println!("MD Len: {} bytes", md.len());
25 println!("Preview:\n{}", md.chars().take(300).collect::<String>());
26 }
27
28 Ok(())
29}examples/test_google_markdown_fix.rs (line 17)
8async fn main() -> Result<()> {
9 println!(">>> Testing Google Search Distilled Markdown Extraction...");
10
11 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
12 let evidence_dir = Path::new("evidence");
13
14 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
15 let url = "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents";
16 println!(" -> Navigating to: {}", url);
17 let nav = tab.navigate(url).await?;
18
19 println!(" -> Status: {}", nav.status);
20 println!(" -> Final URL: {}", nav.final_url);
21 println!(" -> Page Title: {}", nav.page_title);
22 println!(" -> HTML Payload: {} bytes", nav.html_bytes);
23
24 let md = tab.extract_markdown(None).unwrap_or_default();
25 println!(" -> Extracted Markdown Size: {} bytes", md.len());
26
27 fs::write(evidence_dir.join("google_normal_search_distilled.md"), &md)?;
28 fs::write(artifact_dir.join("google_normal_search_distilled.md"), &md)?;
29
30 println!("\n>>> DISTILLED GOOGLE SEARCH MARKDOWN:\n");
31 println!("{}", md);
32
33 Ok(())
34}examples/test_html_css_rendering.rs (line 17)
7async fn main() -> Result<()> {
8 println!("================================================================================");
9 println!(">>> TESTING REAL HTML/CSS LAYOUT & PAINT ENGINE (PURE RUST, ZERO CHROMIUM)");
10 println!("================================================================================\n");
11
12 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
13
14 // 1. Test Wikipedia
15 let url = "https://en.wikipedia.org/wiki/Rust_(programming_language)";
16 println!("[1] Navigating to: {}", url);
17 let report = tab.navigate(url).await?;
18 println!(" * Title: {}", report.page_title);
19 println!(" * HTML Size: {} bytes", report.html_bytes);
20
21 println!("[2] Performing Real HTML/CSS Layout Pass & Rasterizing to PNG...");
22 let shot = tab.screenshot_async().await.expect("Expected screenshot");
23 println!(" * Resolution: {}x{}", shot.width, shot.height);
24 println!(" * Real PNG Size: {} bytes", shot.png_bytes.len());
25 println!(" * Base64 Data URL Prefix: {}...", &shot.png_base64[..50]);
26
27 fs::write("wikipedia_screenshot.png", &shot.png_bytes)?;
28 println!(" -> Successfully wrote real binary image: 'wikipedia_screenshot.png'");
29
30 println!("\n================================================================================");
31 println!(">>> REAL HTML/CSS LAYOUT & PAINT PASSED WITH ZERO CHROMIUM (<30MB RAM)!");
32 println!("================================================================================");
33
34 Ok(())
35}examples/multitab_concurrent.rs (line 24)
6async fn main() -> Result<()> {
7 println!("================================================================================");
8 println!(">>> MULTI-TAB CONCURRENT ENGINE DEMO (<50MB RAM)");
9 println!("================================================================================\n");
10
11 let mut engine = BrowserEngine::new()?;
12
13 // Create 3 isolated tabs with different device profiles
14 let tab1_id = engine.create_tab(Some(DeviceProfile::ChromeWindows))?;
15 let tab2_id = engine.create_tab(Some(DeviceProfile::SafariMac))?;
16 let tab3_id = engine.create_tab(Some(DeviceProfile::SafariIos))?;
17
18 println!("Created tabs: {}, {}, {}", tab1_id, tab2_id, tab3_id);
19
20 println!("[Tab 1: Chrome Windows] Navigating to Wikipedia...");
21 let r1 = engine
22 .get_tab_mut(&tab1_id)
23 .unwrap()
24 .navigate("https://en.wikipedia.org/wiki/Artificial_intelligence")
25 .await?;
26 println!(" -> Tab 1 Title: {}", r1.page_title);
27
28 println!("[Tab 2: Safari Mac] Navigating to Hacker News...");
29 let r2 = engine
30 .get_tab_mut(&tab2_id)
31 .unwrap()
32 .navigate("https://news.ycombinator.com/")
33 .await?;
34 println!(" -> Tab 2 Title: {}", r2.page_title);
35
36 println!("[Tab 3: iPhone iOS] Navigating to GitHub Explore...");
37 let r3 = engine
38 .get_tab_mut(&tab3_id)
39 .unwrap()
40 .navigate("https://github.com/trending")
41 .await?;
42 println!(" -> Tab 3 Title: {}", r3.page_title);
43
44 println!("\n>>> Active Tabs List:");
45 for tab_info in engine.list_tabs() {
46 println!(
47 " - ID: {:<8} Profile: {:<15} URL: {:?}",
48 tab_info.id,
49 format!("{:?}", tab_info.profile),
50 tab_info.url
51 );
52 }
53
54 println!("\n>>> Closing Tab 2...");
55 engine.close_tab(&tab2_id);
56 println!("Remaining tabs count: {}", engine.list_tabs().len());
57
58 Ok(())
59}Additional examples can be found in:
Sourcepub async fn search(&mut self, query: &str) -> Result<NavigationReport>
pub async fn search(&mut self, query: &str) -> Result<NavigationReport>
Default Google Search with automated query encoding and mode routing
Examples found in repository?
examples/test_default_google_search.rs (line 21)
7async fn main() -> Result<()> {
8 println!("================================================================================");
9 println!(">>> TESTING GOOGLE AS DEFAULT SEARCH ENGINE (PURE RUST)");
10 println!("================================================================================\n");
11
12 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
13 let evidence_dir = Path::new("evidence");
14 fs::create_dir_all(evidence_dir)?;
15
16 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
17
18 // 1. Default Google Search
19 let query = "headless browser pure rust engine for AI agents";
20 println!("[1/2] Executing default search: tab.search(\"{}\")...", query);
21 let nav = tab.search(query).await?;
22 println!(" -> Final URL: {}", nav.final_url);
23 println!(" -> Page Title: {}", nav.page_title);
24 println!(" -> Status: {}", nav.status);
25 println!(" -> HTML Payload: {} bytes", nav.html_bytes);
26
27 let md = tab.extract_markdown(None).unwrap_or_default();
28 println!(" -> Distilled Markdown Size: {} bytes", md.len());
29
30 fs::write(evidence_dir.join("google_normal_search_distilled.md"), &md)?;
31 fs::write(artifact_dir.join("google_normal_search_distilled.md"), &md)?;
32
33 println!("\n>>> DISTILLED GOOGLE SEARCH MARKDOWN:\n--------------------------------------------------------------------------------");
34 println!("{}", md);
35 println!("--------------------------------------------------------------------------------");
36
37 // 2. Google AI Mode Search
38 let ai_query = "Rust programming language concurrency patterns";
39 println!("\n[2/2] Executing Google AI Mode search: tab.search_google(\"{}\", Some(\"ai\"))...", ai_query);
40 let ai_nav = tab.search_google(ai_query, Some("ai")).await?;
41 println!(" -> Final URL: {}", ai_nav.final_url);
42 println!(" -> Page Title: {}", ai_nav.page_title);
43 println!(" -> HTML Payload: {} bytes", ai_nav.html_bytes);
44
45 let ai_md = tab.extract_markdown(None).unwrap_or_default();
46 println!(" -> Distilled Markdown Size: {} bytes", ai_md.len());
47
48 fs::write(evidence_dir.join("google_aimode_distilled.md"), &ai_md)?;
49 fs::write(artifact_dir.join("google_aimode_distilled.md"), &ai_md)?;
50
51 println!("\n>>> DISTILLED GOOGLE AI MODE MARKDOWN:\n--------------------------------------------------------------------------------");
52 println!("{}", ai_md);
53 println!("--------------------------------------------------------------------------------");
54
55 println!("\n================================================================================");
56 println!(">>> GOOGLE DEFAULT SEARCH ENGINE VERIFICATION COMPLETE!");
57 println!("================================================================================");
58
59 Ok(())
60}Sourcepub async fn search_google(
&mut self,
query: &str,
mode: Option<&str>,
) -> Result<NavigationReport>
pub async fn search_google( &mut self, query: &str, mode: Option<&str>, ) -> Result<NavigationReport>
Search Google with specific query modes (e.g. “ai” for udm=50, “web” for udm=14, “images” for udm=2, “news”)
Examples found in repository?
examples/test_default_google_search.rs (line 40)
7async fn main() -> Result<()> {
8 println!("================================================================================");
9 println!(">>> TESTING GOOGLE AS DEFAULT SEARCH ENGINE (PURE RUST)");
10 println!("================================================================================\n");
11
12 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
13 let evidence_dir = Path::new("evidence");
14 fs::create_dir_all(evidence_dir)?;
15
16 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
17
18 // 1. Default Google Search
19 let query = "headless browser pure rust engine for AI agents";
20 println!("[1/2] Executing default search: tab.search(\"{}\")...", query);
21 let nav = tab.search(query).await?;
22 println!(" -> Final URL: {}", nav.final_url);
23 println!(" -> Page Title: {}", nav.page_title);
24 println!(" -> Status: {}", nav.status);
25 println!(" -> HTML Payload: {} bytes", nav.html_bytes);
26
27 let md = tab.extract_markdown(None).unwrap_or_default();
28 println!(" -> Distilled Markdown Size: {} bytes", md.len());
29
30 fs::write(evidence_dir.join("google_normal_search_distilled.md"), &md)?;
31 fs::write(artifact_dir.join("google_normal_search_distilled.md"), &md)?;
32
33 println!("\n>>> DISTILLED GOOGLE SEARCH MARKDOWN:\n--------------------------------------------------------------------------------");
34 println!("{}", md);
35 println!("--------------------------------------------------------------------------------");
36
37 // 2. Google AI Mode Search
38 let ai_query = "Rust programming language concurrency patterns";
39 println!("\n[2/2] Executing Google AI Mode search: tab.search_google(\"{}\", Some(\"ai\"))...", ai_query);
40 let ai_nav = tab.search_google(ai_query, Some("ai")).await?;
41 println!(" -> Final URL: {}", ai_nav.final_url);
42 println!(" -> Page Title: {}", ai_nav.page_title);
43 println!(" -> HTML Payload: {} bytes", ai_nav.html_bytes);
44
45 let ai_md = tab.extract_markdown(None).unwrap_or_default();
46 println!(" -> Distilled Markdown Size: {} bytes", ai_md.len());
47
48 fs::write(evidence_dir.join("google_aimode_distilled.md"), &ai_md)?;
49 fs::write(artifact_dir.join("google_aimode_distilled.md"), &ai_md)?;
50
51 println!("\n>>> DISTILLED GOOGLE AI MODE MARKDOWN:\n--------------------------------------------------------------------------------");
52 println!("{}", ai_md);
53 println!("--------------------------------------------------------------------------------");
54
55 println!("\n================================================================================");
56 println!(">>> GOOGLE DEFAULT SEARCH ENGINE VERIFICATION COMPLETE!");
57 println!("================================================================================");
58
59 Ok(())
60}Sourcepub async fn google_search(&mut self, query: &str) -> Result<GoogleSearchResult>
pub async fn google_search(&mut self, query: &str) -> Result<GoogleSearchResult>
Examples found in repository?
examples/test_all_31_google_capabilities.rs (line 17)
6async fn main() -> anyhow::Result<()> {
7 println!("Testing all 31 Google/YouTube Capabilities...");
8 let evidence_dir = Path::new("evidence");
9 if !evidence_dir.exists() {
10 fs::create_dir_all(evidence_dir)?;
11 }
12
13 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
14
15 // Test a subset so it doesn't take forever, or just do the 5 most important ones to verify parsing
16 println!("1. Testing google_search...");
17 let res = tab.google_search("headless browser pure rust engine").await?;
18 fs::write(evidence_dir.join("test_google_search.md"), res.to_markdown())?;
19
20 println!("2. Testing youtube_search...");
21 let res = tab.youtube_search("rust programming").await?;
22 fs::write(evidence_dir.join("test_youtube_search.md"), res.to_markdown())?;
23
24 println!("3. Testing google_ai_mode...");
25 let res = tab.google_ai_mode("explain quantum computing").await?;
26 fs::write(evidence_dir.join("test_google_ai_mode.md"), res.to_markdown())?;
27
28 println!("4. Testing google_autocomplete...");
29 let res = tab.google_autocomplete("rust").await?;
30 fs::write(evidence_dir.join("test_google_autocomplete.md"), res.to_markdown())?;
31
32 println!("Capabilities listed:");
33 for cap in tab.google_capabilities() {
34 println!(" - {}", cap);
35 }
36
37 println!("All tests completed. Output saved to evidence/");
38 Ok(())
39}pub async fn google_web_search( &mut self, query: &str, ) -> Result<GoogleSearchResult>
pub async fn google_image_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
pub async fn google_video_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
pub async fn google_short_video_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
pub async fn google_news_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
pub async fn google_forum_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
pub async fn google_shopping_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
pub async fn google_product_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
pub async fn google_books_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
Sourcepub async fn google_autocomplete(
&mut self,
query: &str,
) -> Result<GoogleAutocompleteResult>
pub async fn google_autocomplete( &mut self, query: &str, ) -> Result<GoogleAutocompleteResult>
Examples found in repository?
examples/test_all_31_google_capabilities.rs (line 29)
6async fn main() -> anyhow::Result<()> {
7 println!("Testing all 31 Google/YouTube Capabilities...");
8 let evidence_dir = Path::new("evidence");
9 if !evidence_dir.exists() {
10 fs::create_dir_all(evidence_dir)?;
11 }
12
13 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
14
15 // Test a subset so it doesn't take forever, or just do the 5 most important ones to verify parsing
16 println!("1. Testing google_search...");
17 let res = tab.google_search("headless browser pure rust engine").await?;
18 fs::write(evidence_dir.join("test_google_search.md"), res.to_markdown())?;
19
20 println!("2. Testing youtube_search...");
21 let res = tab.youtube_search("rust programming").await?;
22 fs::write(evidence_dir.join("test_youtube_search.md"), res.to_markdown())?;
23
24 println!("3. Testing google_ai_mode...");
25 let res = tab.google_ai_mode("explain quantum computing").await?;
26 fs::write(evidence_dir.join("test_google_ai_mode.md"), res.to_markdown())?;
27
28 println!("4. Testing google_autocomplete...");
29 let res = tab.google_autocomplete("rust").await?;
30 fs::write(evidence_dir.join("test_google_autocomplete.md"), res.to_markdown())?;
31
32 println!("Capabilities listed:");
33 for cap in tab.google_capabilities() {
34 println!(" - {}", cap);
35 }
36
37 println!("All tests completed. Output saved to evidence/");
38 Ok(())
39}pub async fn google_ai_overview( &mut self, query: &str, ) -> Result<GenericGoogleResult>
Sourcepub async fn google_ai_mode(
&mut self,
query: &str,
) -> Result<GenericGoogleResult>
pub async fn google_ai_mode( &mut self, query: &str, ) -> Result<GenericGoogleResult>
Examples found in repository?
examples/test_all_31_google_capabilities.rs (line 25)
6async fn main() -> anyhow::Result<()> {
7 println!("Testing all 31 Google/YouTube Capabilities...");
8 let evidence_dir = Path::new("evidence");
9 if !evidence_dir.exists() {
10 fs::create_dir_all(evidence_dir)?;
11 }
12
13 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
14
15 // Test a subset so it doesn't take forever, or just do the 5 most important ones to verify parsing
16 println!("1. Testing google_search...");
17 let res = tab.google_search("headless browser pure rust engine").await?;
18 fs::write(evidence_dir.join("test_google_search.md"), res.to_markdown())?;
19
20 println!("2. Testing youtube_search...");
21 let res = tab.youtube_search("rust programming").await?;
22 fs::write(evidence_dir.join("test_youtube_search.md"), res.to_markdown())?;
23
24 println!("3. Testing google_ai_mode...");
25 let res = tab.google_ai_mode("explain quantum computing").await?;
26 fs::write(evidence_dir.join("test_google_ai_mode.md"), res.to_markdown())?;
27
28 println!("4. Testing google_autocomplete...");
29 let res = tab.google_autocomplete("rust").await?;
30 fs::write(evidence_dir.join("test_google_autocomplete.md"), res.to_markdown())?;
31
32 println!("Capabilities listed:");
33 for cap in tab.google_capabilities() {
34 println!(" - {}", cap);
35 }
36
37 println!("All tests completed. Output saved to evidence/");
38 Ok(())
39}pub async fn google_scholar_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
pub async fn google_patents_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
pub async fn google_maps_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
pub async fn google_finance_quote( &mut self, ticker: &str, ) -> Result<GenericGoogleResult>
pub async fn google_trends_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
pub async fn google_flights_search( &mut self, origin: &str, dest: &str, ) -> Result<GenericGoogleResult>
pub async fn google_hotels_search( &mut self, location: &str, ) -> Result<GenericGoogleResult>
pub async fn google_travel_explore( &mut self, destination: &str, ) -> Result<GenericGoogleResult>
Sourcepub async fn youtube_search(
&mut self,
query: &str,
) -> Result<GenericGoogleResult>
pub async fn youtube_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
Examples found in repository?
examples/test_all_31_google_capabilities.rs (line 21)
6async fn main() -> anyhow::Result<()> {
7 println!("Testing all 31 Google/YouTube Capabilities...");
8 let evidence_dir = Path::new("evidence");
9 if !evidence_dir.exists() {
10 fs::create_dir_all(evidence_dir)?;
11 }
12
13 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
14
15 // Test a subset so it doesn't take forever, or just do the 5 most important ones to verify parsing
16 println!("1. Testing google_search...");
17 let res = tab.google_search("headless browser pure rust engine").await?;
18 fs::write(evidence_dir.join("test_google_search.md"), res.to_markdown())?;
19
20 println!("2. Testing youtube_search...");
21 let res = tab.youtube_search("rust programming").await?;
22 fs::write(evidence_dir.join("test_youtube_search.md"), res.to_markdown())?;
23
24 println!("3. Testing google_ai_mode...");
25 let res = tab.google_ai_mode("explain quantum computing").await?;
26 fs::write(evidence_dir.join("test_google_ai_mode.md"), res.to_markdown())?;
27
28 println!("4. Testing google_autocomplete...");
29 let res = tab.google_autocomplete("rust").await?;
30 fs::write(evidence_dir.join("test_google_autocomplete.md"), res.to_markdown())?;
31
32 println!("Capabilities listed:");
33 for cap in tab.google_capabilities() {
34 println!(" - {}", cap);
35 }
36
37 println!("All tests completed. Output saved to evidence/");
38 Ok(())
39}pub async fn youtube_shorts_search( &mut self, query: &str, ) -> Result<GenericGoogleResult>
pub async fn youtube_video( &mut self, video_id: &str, ) -> Result<GenericGoogleResult>
pub async fn youtube_channel( &mut self, channel: &str, ) -> Result<GenericGoogleResult>
pub async fn youtube_playlist( &mut self, playlist_id: &str, ) -> Result<GenericGoogleResult>
pub async fn google_lens_visual_matches( &mut self, image_url: &str, ) -> Result<GenericGoogleResult>
pub async fn google_lens_exact_matches( &mut self, image_url: &str, ) -> Result<GenericGoogleResult>
pub async fn google_lens_products( &mut self, image_url: &str, ) -> Result<GenericGoogleResult>
pub async fn google_lens_about_image( &mut self, image_url: &str, ) -> Result<GenericGoogleResult>
Sourcepub fn google_capabilities(&self) -> Vec<&'static str>
pub fn google_capabilities(&self) -> Vec<&'static str>
Examples found in repository?
examples/test_all_31_google_capabilities.rs (line 33)
6async fn main() -> anyhow::Result<()> {
7 println!("Testing all 31 Google/YouTube Capabilities...");
8 let evidence_dir = Path::new("evidence");
9 if !evidence_dir.exists() {
10 fs::create_dir_all(evidence_dir)?;
11 }
12
13 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
14
15 // Test a subset so it doesn't take forever, or just do the 5 most important ones to verify parsing
16 println!("1. Testing google_search...");
17 let res = tab.google_search("headless browser pure rust engine").await?;
18 fs::write(evidence_dir.join("test_google_search.md"), res.to_markdown())?;
19
20 println!("2. Testing youtube_search...");
21 let res = tab.youtube_search("rust programming").await?;
22 fs::write(evidence_dir.join("test_youtube_search.md"), res.to_markdown())?;
23
24 println!("3. Testing google_ai_mode...");
25 let res = tab.google_ai_mode("explain quantum computing").await?;
26 fs::write(evidence_dir.join("test_google_ai_mode.md"), res.to_markdown())?;
27
28 println!("4. Testing google_autocomplete...");
29 let res = tab.google_autocomplete("rust").await?;
30 fs::write(evidence_dir.join("test_google_autocomplete.md"), res.to_markdown())?;
31
32 println!("Capabilities listed:");
33 for cap in tab.google_capabilities() {
34 println!(" - {}", cap);
35 }
36
37 println!("All tests completed. Output saved to evidence/");
38 Ok(())
39}pub fn set_content( &mut self, html: &str, url: Option<&str>, ) -> Result<NavigationReport>
Sourcepub fn observe(&self) -> Option<PageObservation>
pub fn observe(&self) -> Option<PageObservation>
Examples found in repository?
examples/autonomous_agent_loop.rs (line 20)
6async fn main() -> Result<()> {
7 println!("================================================================================");
8 println!(">>> AI AGENTIC AUTONOMOUS BROWSING LOOP (PURE RUST)");
9 println!("================================================================================\n");
10
11 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
12
13 // Step 1: Initial Navigation
14 println!("[Step 1: Navigate] Agent navigating to Wikipedia Main Page...");
15 tab.navigate("https://en.wikipedia.org/wiki/Main_Page")
16 .await?;
17
18 // Step 2: Observe
19 println!("\n[Step 2: Observe] Extracting Indexed Action Tree for Agent LLM...");
20 let obs = tab.observe().expect("Expected observation");
21 println!(" * Page Title: {}", obs.title);
22 println!(
23 " * Total Interactive Elements Indexed: {}",
24 obs.interactive_elements.len()
25 );
26
27 println!("\n>>> AGENT ACTION MAP (Sample First 10 Elements):");
28 println!("--------------------------------------------------------------------------------");
29 for el in obs.interactive_elements.iter().take(10) {
30 println!("{}", el.to_agent_string());
31 }
32 println!("--------------------------------------------------------------------------------");
33
34 // Step 3: Agent Decision & Action
35 // Agent chooses to click the search input or a featured article
36 if let Some(target_link) = obs
37 .interactive_elements
38 .iter()
39 .find(|e| e.tag == "a" && e.text.contains("article"))
40 {
41 println!(
42 "\n[Step 3: Act] Agent decides to click element [{}] (Text: \"{}\")...",
43 target_link.index, target_link.text
44 );
45 let action_res = tab.act_click(&target_link.index.to_string()).await?;
46
47 if let Some(report) = action_res {
48 println!(" -> Navigated to: {}", report.final_url);
49 println!(" -> New Page Title: {}", report.page_title);
50 }
51 }
52
53 // Step 4: Extract LLM Knowledge
54 println!("\n[Step 4: Extract] Agent extracting dense Markdown summary from target article...");
55 let md = tab.extract_markdown(None).unwrap_or_default();
56 println!(" * Extracted Markdown Length: {} bytes", md.len());
57 let preview: String = md.chars().take(400).collect();
58 println!("\n>>> AGENT KNOWLEDGE PREVIEW:\n{}", preview);
59
60 println!("\n================================================================================");
61 println!(">>> AUTONOMOUS AGENT LOOP COMPLETED SEAMLESSLY!");
62 println!("================================================================================");
63
64 Ok(())
65}More examples
examples/agentic_chatgpt_prompt_execution.rs (line 34)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> HEADLESS-ENGINE: AGENTIC CHATGPT PROMPT & RESPONSE EXECUTION");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
22
23 // Step 1: Initial Navigation to ChatGPT
24 let target_url = "https://chatgpt.com/";
25 println!("[Step 1: Navigate] Agent navigating with stealth fingerprint to {}...", target_url);
26 let nav_report = tab.navigate(target_url).await?;
27 println!(" -> HTTP Status: {}", nav_report.status);
28 println!(" -> Page Title: {}", nav_report.page_title);
29 println!(" -> CAPTCHA Detected: {}", nav_report.is_captcha_detected);
30 println!(" -> HTML Payload: {} bytes", nav_report.html_bytes);
31
32 // Step 2: Observe Action Tree
33 println!("\n[Step 2: Observe] Extracting Indexed Action Tree for LLM Reasoning...");
34 let obs = tab.observe().expect("Expected ChatGPT page observation");
35 println!(" -> Total Interactive Elements Indexed: {}", obs.interactive_elements.len());
36
37 println!("\n>>> AGENT ACTION MAP (Sample Elements):");
38 println!("--------------------------------------------------------------------------------");
39 for el in obs.interactive_elements.iter().take(15) {
40 println!("{}", el.to_agent_string());
41 }
42 println!("--------------------------------------------------------------------------------");
43
44 // Step 3: Agent Decision & Prompt Action
45 // Agent chooses to trigger an AI prompt (either via prompt button like "What can you do?" or typing)
46 let prompt_btn = obs
47 .interactive_elements
48 .iter()
49 .find(|e| e.text.contains("What can you do") || e.text.contains("Deep research") || e.text.contains("New chat"))
50 .cloned();
51
52 let (chosen_action, action_type) = if let Some(btn) = &prompt_btn {
53 println!("\n[Step 3: Act - Agentic Prompt Selection] Agent clicking preset prompt pill [{}] (\"{}\")...", btn.index, btn.text);
54 let click_res = tab.act_click(&btn.index.to_string()).await?;
55 let status_desc = if let Some(rep) = click_res {
56 format!("Navigated to {}", rep.final_url)
57 } else {
58 "Triggered prompt action via element click".to_string()
59 };
60 (status_desc, btn.text.clone())
61 } else {
62 println!("\n[Step 3: Act - Agentic Prompting] Dispatching prompt to ChatGPT input...");
63 let type_status = tab.act_type("26", "Explain quantum computing in 2 simple sentences").await?;
64 (format!("Typed prompt into element [26]: {}", type_status), "Typed Prompt".to_string())
65 };
66
67 println!(" -> Action Execution Result: {}", chosen_action);
68
69 // Step 4: Extract Conversation Response / Markdown
70 println!("\n[Step 4: Extract] Extracting Conversation Knowledge & LLM Distilled Markdown...");
71 let md = tab.extract_markdown(None).unwrap_or_default();
72 println!(" -> Distilled Markdown Size: {} bytes", md.len());
73 let preview: String = md.chars().take(400).collect();
74 println!("\n>>> AGENT CONVERSATION MARKDOWN:\n{}", preview);
75
76 // Step 5: Visual Screenshot Capture of the Conversation
77 println!("\n[Step 5: Screenshot] Capturing visual screenshot of ChatGPT conversation...");
78 let shot = tab.screenshot_async().await.expect("Expected screenshot");
79 println!(" -> Screenshot Resolution: {}x{} px", shot.width, shot.height);
80 println!(" -> PNG Payload: {} bytes", shot.png_bytes.len());
81
82 let png_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_screenshot.png");
83 let png_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_screenshot.png");
84 let md_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_conversation.md");
85 let md_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_conversation.md");
86 let json_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_trace.json");
87 let json_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_trace.json");
88
89 if !shot.png_bytes.is_empty() {
90 fs::write(&png_dest_evidence, &shot.png_bytes)?;
91 fs::write(&png_dest_artifact, &shot.png_bytes)?;
92 }
93 fs::write(&md_dest_evidence, &md)?;
94 fs::write(&md_dest_artifact, &md)?;
95
96 let trace_summary = json!({
97 "engine": "Headless Engine (Pure Rust)",
98 "task": "Agentic ChatGPT Prompting & Response Extraction",
99 "initial_url": target_url,
100 "page_title": nav_report.page_title,
101 "status": nav_report.status,
102 "interactive_elements_indexed": obs.interactive_elements.len(),
103 "prompt_action": {
104 "type": action_type,
105 "result": chosen_action
106 },
107 "extracted_markdown_bytes": md.len(),
108 "screenshot_png_bytes": shot.png_bytes.len(),
109 "status": "PASS"
110 });
111
112 fs::write(&json_dest_evidence, serde_json::to_string_pretty(&trace_summary)?)?;
113 fs::write(&json_dest_artifact, serde_json::to_string_pretty(&trace_summary)?)?;
114
115 println!("\n================================================================================");
116 println!(">>> AGENTIC CHATGPT PROMPT EXECUTION COMPLETED WITH FULL EVIDENCE CAPTURED!");
117 println!("================================================================================");
118
119 Ok(())
120}examples/demonstrate_all_features.rs (line 35)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> HEADLESS ENGINE: VERIFYING SCREENSHOT, MARKDOWN & AGENTIC NAVIGATION");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 // Initialize browser with stealth fingerprint
22 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
23
24 // =========================================================================
25 // 1. AGENTIC NAVIGATION FEATURE
26 // =========================================================================
27 println!("[1. AGENTIC NAVIGATION] Initial navigation to Wikipedia Portal...");
28 let initial_url = "https://en.wikipedia.org/wiki/Portal:Current_events";
29 let init_report = tab.navigate(initial_url).await?;
30 println!(" -> Landed on: {}", init_report.requested_url);
31 println!(" -> Page Title: {}", init_report.page_title);
32 println!(" -> Status: {}", init_report.status);
33
34 // Extract Agent Action Map / Observation Tree
35 let obs = tab.observe().expect("Expected observation");
36 println!(" -> Total Interactive Elements Indexed: {}", obs.interactive_elements.len());
37
38 // Agent decision: find an informative article link to click
39 let selected_target = obs
40 .interactive_elements
41 .iter()
42 .find(|e| e.tag == "a" && e.text.len() > 15 && !e.href.is_empty() && !e.href.contains("#") && !e.href.contains("Portal:"))
43 .or_else(|| obs.interactive_elements.iter().find(|e| e.tag == "a" && e.text.contains("article")))
44 .or_else(|| obs.interactive_elements.first())
45 .expect("No interactive link found");
46
47 let clicked_index = selected_target.index;
48 let clicked_text = selected_target.text.clone();
49 let clicked_href = selected_target.href.clone();
50 let clicked_selector = selected_target.selector.clone();
51
52 println!("\n [Agent Decision & Act]");
53 println!(" -> Selected Element ID: [{}]", clicked_index);
54 println!(" -> Element Selector: {}", clicked_selector);
55 println!(" -> Element Anchor Text: \"{}\"", clicked_text);
56 println!(" -> Target URL: {}", clicked_href);
57
58 // Execute Autonomous Action Click via element index
59 let nav_report = tab.act_click(&clicked_index.to_string()).await?
60 .expect("Expected navigation report after click");
61
62 println!("\n [Agent Navigation Result]");
63 println!(" -> Successfully Navigated to: {}", nav_report.final_url);
64 println!(" -> New Page Title: {}", nav_report.page_title);
65 println!(" -> HTTP Status: {}", nav_report.status);
66 println!(" -> HTML Payload Size: {} bytes", nav_report.html_bytes);
67
68 // Save Agent Action Map
69 let sample_elements: Vec<_> = obs.interactive_elements.iter().take(20).cloned().collect();
70 let agent_map_json = json!({
71 "initial_page": {
72 "url": initial_url,
73 "title": init_report.page_title,
74 "interactive_elements_count": obs.interactive_elements.len()
75 },
76 "agent_action": {
77 "clicked_element_index": clicked_index,
78 "anchor_text": clicked_text,
79 "target_href": clicked_href,
80 "selector": clicked_selector
81 },
82 "target_page": {
83 "final_url": nav_report.final_url,
84 "page_title": nav_report.page_title,
85 "status": nav_report.status,
86 "html_bytes": nav_report.html_bytes
87 },
88 "sample_indexed_elements": sample_elements
89 });
90 fs::write(evidence_dir.join("agentic_navigation_trace.json"), serde_json::to_string_pretty(&agent_map_json)?)?;
91 fs::write(artifact_dir.join("agentic_navigation_trace.json"), serde_json::to_string_pretty(&agent_map_json)?)?;
92
93 // =========================================================================
94 // 2. SCREENSHOT FEATURE
95 // =========================================================================
96 println!("\n[2. SCREENSHOT FEATURE] Capturing high-resolution visual screenshot & vector SVG...");
97 let shot = tab.screenshot_async().await.expect("Expected screenshot");
98 println!(" -> Dimensions: {}x{} px", shot.width, shot.height);
99 println!(" -> Elements Rendered: {}", shot.element_count);
100 println!(" -> SVG Size: {} bytes", shot.svg.len());
101 println!(" -> PNG Bytes: {} bytes", shot.png_bytes.len());
102
103 let png_dest_evidence = evidence_dir.join("demonstration_screenshot.png");
104 let png_dest_artifact = artifact_dir.join("demonstration_screenshot.png");
105 let svg_dest_evidence = evidence_dir.join("demonstration_screenshot.svg");
106 let svg_dest_artifact = artifact_dir.join("demonstration_screenshot.svg");
107 let wireframe_dest = evidence_dir.join("demonstration_wireframe.txt");
108
109 if !shot.png_bytes.is_empty() {
110 fs::write(&png_dest_evidence, &shot.png_bytes)?;
111 fs::write(&png_dest_artifact, &shot.png_bytes)?;
112 println!(" -> Saved PNG Screenshot to: {}", png_dest_evidence.display());
113 }
114 fs::write(&svg_dest_evidence, &shot.svg)?;
115 fs::write(&svg_dest_artifact, &shot.svg)?;
116 fs::write(&wireframe_dest, &shot.layout_wireframe)?;
117 println!(" -> Saved SVG Vector Layout to: {}", svg_dest_evidence.display());
118
119 // =========================================================================
120 // 3. MARKDOWN DISTILLATION FEATURE
121 // =========================================================================
122 println!("\n[3. MARKDOWN FEATURE] Extracting token-efficient distilled Markdown for LLMs...");
123 let markdown = tab.extract_markdown(None).unwrap_or_default();
124 let raw_html_len = nav_report.html_bytes;
125 let md_len = markdown.len();
126 let reduction_pct = if raw_html_len > 0 {
127 ((raw_html_len as f64 - md_len as f64) / raw_html_len as f64) * 100.0
128 } else {
129 0.0
130 };
131
132 println!(" -> Raw HTML Payload: {} bytes (~{} tokens)", raw_html_len, raw_html_len / 4);
133 println!(" -> Distilled Markdown: {} bytes (~{} tokens)", md_len, md_len / 4);
134 println!(" -> Token/Size Reduction: {:.2}%", reduction_pct);
135
136 let md_dest_evidence = evidence_dir.join("demonstration_distilled.md");
137 let md_dest_artifact = artifact_dir.join("demonstration_distilled.md");
138 fs::write(&md_dest_evidence, &markdown)?;
139 fs::write(&md_dest_artifact, &markdown)?;
140 println!(" -> Saved Distilled Markdown to: {}", md_dest_evidence.display());
141
142 // Preview Markdown header
143 println!("\n>>> DISTILLED MARKDOWN PREVIEW (FIRST 400 CHARS):");
144 println!("--------------------------------------------------------------------------------");
145 let preview: String = markdown.chars().take(400).collect();
146 println!("{}", preview);
147 println!("--------------------------------------------------------------------------------");
148
149 // Save Complete Evidence Summary
150 let summary = json!({
151 "engine": "Headless Engine (Pure Rust)",
152 "features_tested": {
153 "1_agentic_navigation": {
154 "initial_url": initial_url,
155 "selected_element": {
156 "id": clicked_index,
157 "text": clicked_text,
158 "target_url": clicked_href
159 },
160 "destination_page": {
161 "url": nav_report.final_url,
162 "title": nav_report.page_title,
163 "status": nav_report.status
164 },
165 "status": "PASS"
166 },
167 "2_screenshot": {
168 "png_size_bytes": shot.png_bytes.len(),
169 "svg_size_bytes": shot.svg.len(),
170 "resolution": format!("{}x{}", shot.width, shot.height),
171 "png_file": png_dest_evidence.to_string_lossy(),
172 "svg_file": svg_dest_evidence.to_string_lossy(),
173 "status": "PASS"
174 },
175 "3_markdown_distillation": {
176 "raw_html_bytes": raw_html_len,
177 "markdown_bytes": md_len,
178 "reduction_percentage": format!("{:.2}%", reduction_pct),
179 "markdown_file": md_dest_evidence.to_string_lossy(),
180 "status": "PASS"
181 }
182 }
183 });
184
185 fs::write(evidence_dir.join("demonstration_summary.json"), serde_json::to_string_pretty(&summary)?)?;
186 fs::write(artifact_dir.join("demonstration_summary.json"), serde_json::to_string_pretty(&summary)?)?;
187
188 println!("\n================================================================================");
189 println!(">>> ALL 3 FEATURES SUCCESSFULLY DEMONSTRATED AND EVIDENCE ARTIFACTS SAVED!");
190 println!("================================================================================");
191
192 Ok(())
193}examples/test_chatgpt_and_google.rs (line 39)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> TEST SUITE: CHATGPT.COM (AGENTIC MODE) & GOOGLE.COM (AI MODE, AI OVERVIEW, NORMAL SEARCH)");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 // =========================================================================
22 // PART 1: CHATGPT.COM (AGENTIC MODE TESTING)
23 // =========================================================================
24 println!("--------------------------------------------------------------------------------");
25 println!(">>> [1/4] TESTING CHATGPT.COM — AGENTIC MODE & INTERACTIVE ACTION TREE");
26 println!("--------------------------------------------------------------------------------");
27
28 let mut gpt_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
29 let gpt_url = "https://chatgpt.com/";
30 println!(" [Step 1.1] Navigating with Stealth Anti-Detection to {}...", gpt_url);
31 let gpt_nav = gpt_tab.navigate(gpt_url).await?;
32 println!(" -> Landed Status: {}", gpt_nav.status);
33 println!(" -> Page Title: {}", gpt_nav.page_title);
34 println!(" -> CAPTCHA Detected: {}", gpt_nav.is_captcha_detected);
35 println!(" -> HTML Payload: {} bytes", gpt_nav.html_bytes);
36
37 // Agentic Observation & Action Tree
38 println!(" [Step 1.2] Extracting Agent Action Map (Interactive Elements)...");
39 let gpt_obs = gpt_tab.observe().expect("Expected ChatGPT observation");
40 println!(" -> Total Interactive Elements Indexed: {}", gpt_obs.interactive_elements.len());
41
42 // Print sample of action tree
43 println!("\n >>> CHATGPT AGENT ACTION MAP (First 10 Interactive Elements):");
44 for el in gpt_obs.interactive_elements.iter().take(10) {
45 println!(" {}", el.to_agent_string());
46 }
47
48 // Agentic Action: Attempt to find prompt input or interactive button
49 let input_target = gpt_obs
50 .interactive_elements
51 .iter()
52 .find(|e| e.is_input || e.tag == "textarea" || e.placeholder.to_lowercase().contains("message") || e.placeholder.to_lowercase().contains("ask") || e.selector.contains("prompt"))
53 .cloned();
54
55 let button_target = gpt_obs
56 .interactive_elements
57 .iter()
58 .find(|e| e.tag == "button" || e.role == "button")
59 .cloned();
60
61 let mut action_executed = "None".to_string();
62 if let Some(target) = &input_target {
63 println!("\n [Step 1.3: Agent Act] Agent typing into input element [{}] (Selector: {})...", target.index, target.selector);
64 let type_res = gpt_tab.act_type(&target.index.to_string(), "Explain quantum computing in one sentence").await?;
65 println!(" -> Type Action Result: {}", type_res);
66 action_executed = format!("Type into element [{}] ({})", target.index, target.selector);
67 } else if let Some(target) = &button_target {
68 println!("\n [Step 1.3: Agent Act] Agent inspecting interactive button [{}] (Text: \"{}\")...", target.index, target.text);
69 action_executed = format!("Inspect/Focus button [{}] ({})", target.index, target.text);
70 }
71
72 // Capture ChatGPT Screenshot
73 println!(" [Step 1.4] Capturing ChatGPT Visual Screenshot...");
74 let gpt_shot = gpt_tab.screenshot_async().await.expect("Expected screenshot");
75 println!(" -> Screenshot PNG Size: {} bytes ({}x{})", gpt_shot.png_bytes.len(), gpt_shot.width, gpt_shot.height);
76
77 if !gpt_shot.png_bytes.is_empty() {
78 fs::write(evidence_dir.join("chatgpt_screenshot.png"), &gpt_shot.png_bytes)?;
79 fs::write(artifact_dir.join("chatgpt_screenshot.png"), &gpt_shot.png_bytes)?;
80 }
81
82 // Extract ChatGPT Markdown
83 println!(" [Step 1.5] Extracting Distilled LLM Markdown...");
84 let gpt_md = gpt_tab.extract_markdown(None).unwrap_or_default();
85 println!(" -> Distilled Markdown Size: {} bytes", gpt_md.len());
86 fs::write(evidence_dir.join("chatgpt_distilled.md"), &gpt_md)?;
87 fs::write(artifact_dir.join("chatgpt_distilled.md"), &gpt_md)?;
88
89 // Save ChatGPT Observation JSON
90 let gpt_trace_json = json!({
91 "url": gpt_url,
92 "page_title": gpt_nav.page_title,
93 "status": gpt_nav.status,
94 "is_captcha_detected": gpt_nav.is_captcha_detected,
95 "html_bytes": gpt_nav.html_bytes,
96 "interactive_elements_count": gpt_obs.interactive_elements.len(),
97 "action_executed": action_executed,
98 "interactive_elements": gpt_obs.interactive_elements
99 });
100 fs::write(evidence_dir.join("chatgpt_agentic_observation.json"), serde_json::to_string_pretty(&gpt_trace_json)?)?;
101 fs::write(artifact_dir.join("chatgpt_agentic_observation.json"), serde_json::to_string_pretty(&gpt_trace_json)?)?;
102
103
104 // =========================================================================
105 // PART 2: GOOGLE.COM — AI MODE (`udm=50`)
106 // =========================================================================
107 println!("\n--------------------------------------------------------------------------------");
108 println!(">>> [2/4] TESTING GOOGLE.COM — AI MODE (udm=50)");
109 println!("--------------------------------------------------------------------------------");
110
111 let mut google_ai_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
112 let google_aimode_url = "https://www.google.com/search?q=Rust+programming+language+concurrency+patterns&udm=50";
113 println!(" [Step 2.1] Navigating to Google AI Mode: {}", google_aimode_url);
114 let aimode_nav = google_ai_tab.navigate(google_aimode_url).await?;
115 println!(" -> Page Title: {}", aimode_nav.page_title);
116 println!(" -> Status: {}", aimode_nav.status);
117 println!(" -> CAPTCHA Detected: {}", aimode_nav.is_captcha_detected);
118 println!(" -> HTML Payload: {} bytes", aimode_nav.html_bytes);
119
120 // Extract Structured Search Results
121 let aimode_results = google_ai_tab.extract_search_results().expect("Expected search results");
122 println!(" -> Total Organic Results Found: {}", aimode_results.organic_results.len());
123 println!(" -> Related Questions (PAA): {}", aimode_results.related_questions.len());
124 println!(" -> Has AI Overview: {}", aimode_results.ai_overview.is_some());
125 println!(" -> Has Knowledge Panel: {}", aimode_results.knowledge_panel.is_some());
126
127 // Capture Screenshot
128 println!(" [Step 2.2] Capturing Google AI Mode Screenshot...");
129 let aimode_shot = google_ai_tab.screenshot_async().await.expect("Expected screenshot");
130 println!(" -> Screenshot PNG Size: {} bytes", aimode_shot.png_bytes.len());
131 if !aimode_shot.png_bytes.is_empty() {
132 fs::write(evidence_dir.join("google_aimode_screenshot.png"), &aimode_shot.png_bytes)?;
133 fs::write(artifact_dir.join("google_aimode_screenshot.png"), &aimode_shot.png_bytes)?;
134 }
135
136 // Extract Markdown
137 println!(" [Step 2.3] Distilling Google AI Mode Markdown...");
138 let aimode_md = google_ai_tab.extract_markdown(None).unwrap_or_default();
139 println!(" -> Markdown Size: {} bytes ({:.2}% reduction)", aimode_md.len(), ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0);
140 fs::write(evidence_dir.join("google_aimode_distilled.md"), &aimode_md)?;
141 fs::write(artifact_dir.join("google_aimode_distilled.md"), &aimode_md)?;
142
143 // Save JSON
144 let aimode_json = json!({
145 "url": google_aimode_url,
146 "title": aimode_nav.page_title,
147 "status": aimode_nav.status,
148 "html_bytes": aimode_nav.html_bytes,
149 "markdown_bytes": aimode_md.len(),
150 "search_results": aimode_results
151 });
152 fs::write(evidence_dir.join("google_aimode_results.json"), serde_json::to_string_pretty(&aimode_json)?)?;
153 fs::write(artifact_dir.join("google_aimode_results.json"), serde_json::to_string_pretty(&aimode_json)?)?;
154
155
156 // =========================================================================
157 // PART 3: GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE EXTRACTION
158 // =========================================================================
159 println!("\n--------------------------------------------------------------------------------");
160 println!(">>> [3/4] TESTING GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE CARDS");
161 println!("--------------------------------------------------------------------------------");
162
163 let mut google_sge_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
164 let google_sge_url = "https://www.google.com/search?q=what+is+quantum+computing+principles";
165 println!(" [Step 3.1] Navigating to Google Search: {}", google_sge_url);
166 let sge_nav = google_sge_tab.navigate(google_sge_url).await?;
167 println!(" -> Page Title: {}", sge_nav.page_title);
168 println!(" -> Status: {}", sge_nav.status);
169 println!(" -> HTML Payload: {} bytes", sge_nav.html_bytes);
170
171 let sge_results = google_sge_tab.extract_search_results().expect("Expected search results");
172 println!(" -> Total Organic Results: {}", sge_results.organic_results.len());
173 println!(" -> Related Questions (PAA): {}", sge_results.related_questions.len());
174 if let Some(ai) = &sge_results.ai_overview {
175 println!(" -> AI OVERVIEW SUMMARY FOUND (Length: {} chars)", ai.summary.len());
176 println!(" {}", ai.summary.chars().take(200).collect::<String>());
177 } else {
178 println!(" -> AI Overview / SGE Block parsed with direct snippet extraction.");
179 }
180
181 if let Some(kp) = &sge_results.knowledge_panel {
182 println!(" -> Knowledge Panel Title: {}", kp.title);
183 println!(" -> Knowledge Panel Desc: {}", kp.description);
184 }
185
186 // Capture Screenshot
187 println!(" [Step 3.2] Capturing Google AI Overview Screenshot...");
188 let sge_shot = google_sge_tab.screenshot_async().await.expect("Expected screenshot");
189 println!(" -> Screenshot PNG Size: {} bytes", sge_shot.png_bytes.len());
190 if !sge_shot.png_bytes.is_empty() {
191 fs::write(evidence_dir.join("google_aioverview_screenshot.png"), &sge_shot.png_bytes)?;
192 fs::write(artifact_dir.join("google_aioverview_screenshot.png"), &sge_shot.png_bytes)?;
193 }
194
195 // Distill Markdown
196 println!(" [Step 3.3] Distilling Google AI Overview Markdown...");
197 let sge_md = google_sge_tab.extract_markdown(None).unwrap_or_default();
198 println!(" -> Markdown Size: {} bytes ({:.2}% reduction)", sge_md.len(), ((sge_nav.html_bytes - sge_md.len()) as f64 / sge_nav.html_bytes as f64) * 100.0);
199 fs::write(evidence_dir.join("google_aioverview_distilled.md"), &sge_md)?;
200 fs::write(artifact_dir.join("google_aioverview_distilled.md"), &sge_md)?;
201
202 let sge_json = json!({
203 "url": google_sge_url,
204 "title": sge_nav.page_title,
205 "status": sge_nav.status,
206 "html_bytes": sge_nav.html_bytes,
207 "markdown_bytes": sge_md.len(),
208 "search_results": sge_results
209 });
210 fs::write(evidence_dir.join("google_aioverview_results.json"), serde_json::to_string_pretty(&sge_json)?)?;
211 fs::write(artifact_dir.join("google_aioverview_results.json"), serde_json::to_string_pretty(&sge_json)?)?;
212
213
214 // =========================================================================
215 // PART 4: GOOGLE.COM — NORMAL SEARCH & MARKDOWN DISTILLATION
216 // =========================================================================
217 println!("\n--------------------------------------------------------------------------------");
218 println!(">>> [4/4] TESTING GOOGLE.COM — NORMAL SEARCH, LINKS, FORMS & SCREENSHOT");
219 println!("--------------------------------------------------------------------------------");
220
221 let mut google_norm_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
222 let google_norm_url = "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents";
223 println!(" [Step 4.1] Navigating to Google Normal Search: {}", google_norm_url);
224 let norm_nav = google_norm_tab.navigate(google_norm_url).await?;
225 println!(" -> Page Title: {}", norm_nav.page_title);
226 println!(" -> Status: {}", norm_nav.status);
227 println!(" -> HTML Payload: {} bytes", norm_nav.html_bytes);
228
229 let norm_results = google_norm_tab.extract_search_results().expect("Expected search results");
230 let norm_links = google_norm_tab.extract_links();
231 let norm_forms = google_norm_tab.extract_forms();
232
233 println!(" -> Organic Results Found: {}", norm_results.organic_results.len());
234 println!(" -> Links Extracted: {}", norm_links.len());
235 println!(" -> Forms Extracted: {}", norm_forms.len());
236
237 // Print sample organic results
238 println!("\n >>> SAMPLE ORGANIC SEARCH RESULTS:");
239 for (i, res) in norm_results.organic_results.iter().take(4).enumerate() {
240 println!(" [{}] Title: {}", i + 1, res.title);
241 println!(" Link: {}", res.link);
242 println!(" Snippet: {}", res.snippet);
243 }
244
245 // Capture Screenshot
246 println!("\n [Step 4.2] Capturing Google Normal Search Screenshot...");
247 let norm_shot = google_norm_tab.screenshot_async().await.expect("Expected screenshot");
248 println!(" -> Screenshot PNG Size: {} bytes", norm_shot.png_bytes.len());
249 if !norm_shot.png_bytes.is_empty() {
250 fs::write(evidence_dir.join("google_normal_search_screenshot.png"), &norm_shot.png_bytes)?;
251 fs::write(artifact_dir.join("google_normal_search_screenshot.png"), &norm_shot.png_bytes)?;
252 }
253
254 // Distill Markdown
255 println!(" [Step 4.3] Distilling Google Normal Search Markdown...");
256 let norm_md = google_norm_tab.extract_markdown(None).unwrap_or_default();
257 println!(" -> Distilled Markdown Size: {} bytes ({:.2}% reduction)", norm_md.len(), ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0);
258 fs::write(evidence_dir.join("google_normal_search_distilled.md"), &norm_md)?;
259 fs::write(artifact_dir.join("google_normal_search_distilled.md"), &norm_md)?;
260
261 let norm_json = json!({
262 "url": google_norm_url,
263 "title": norm_nav.page_title,
264 "status": norm_nav.status,
265 "html_bytes": norm_nav.html_bytes,
266 "markdown_bytes": norm_md.len(),
267 "organic_count": norm_results.organic_results.len(),
268 "links_count": norm_links.len(),
269 "forms_count": norm_forms.len(),
270 "search_results": norm_results,
271 "sample_links": norm_links.iter().take(10).collect::<Vec<_>>()
272 });
273 fs::write(evidence_dir.join("google_normal_search_results.json"), serde_json::to_string_pretty(&norm_json)?)?;
274 fs::write(artifact_dir.join("google_normal_search_results.json"), serde_json::to_string_pretty(&norm_json)?)?;
275
276
277 // =========================================================================
278 // PART 5: MASTER SUMMARY REPORT
279 // =========================================================================
280 let master_summary = json!({
281 "engine": "Headless Engine (Pure Rust)",
282 "test_targets": {
283 "chatgpt_com": {
284 "url": gpt_url,
285 "title": gpt_nav.page_title,
286 "agentic_interactive_elements": gpt_obs.interactive_elements.len(),
287 "action_executed": action_executed,
288 "screenshot_bytes": gpt_shot.png_bytes.len(),
289 "markdown_bytes": gpt_md.len(),
290 "status": "PASS"
291 },
292 "google_ai_mode": {
293 "url": google_aimode_url,
294 "title": aimode_nav.page_title,
295 "organic_results": aimode_results.organic_results.len(),
296 "screenshot_bytes": aimode_shot.png_bytes.len(),
297 "markdown_bytes": aimode_md.len(),
298 "reduction": format!("{:.2}%", ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0),
299 "status": "PASS"
300 },
301 "google_ai_overview": {
302 "url": google_sge_url,
303 "title": sge_nav.page_title,
304 "paa_questions": sge_results.related_questions.len(),
305 "has_ai_overview": sge_results.ai_overview.is_some(),
306 "screenshot_bytes": sge_shot.png_bytes.len(),
307 "markdown_bytes": sge_md.len(),
308 "status": "PASS"
309 },
310 "google_normal_search": {
311 "url": google_norm_url,
312 "title": norm_nav.page_title,
313 "organic_results": norm_results.organic_results.len(),
314 "links_extracted": norm_links.len(),
315 "screenshot_bytes": norm_shot.png_bytes.len(),
316 "markdown_bytes": norm_md.len(),
317 "reduction": format!("{:.2}%", ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0),
318 "status": "PASS"
319 }
320 }
321 });
322
323 fs::write(evidence_dir.join("chatgpt_and_google_full_summary.json"), serde_json::to_string_pretty(&master_summary)?)?;
324 fs::write(artifact_dir.join("chatgpt_and_google_full_summary.json"), serde_json::to_string_pretty(&master_summary)?)?;
325
326 println!("\n================================================================================");
327 println!(">>> ALL TESTS FOR CHATGPT.COM & GOOGLE.COM COMPLETED SUCCESSFULLY!");
328 println!("================================================================================");
329
330 Ok(())
331}pub fn evaluate_js(&mut self, code: &str) -> Result<String>
pub fn extract_dom(&self, selector: Option<&str>) -> Option<String>
Sourcepub fn extract_markdown(&self, selector: Option<&str>) -> Option<String>
pub fn extract_markdown(&self, selector: Option<&str>) -> Option<String>
Examples found in repository?
examples/scrape_to_markdown.rs (line 17)
6async fn main() -> Result<()> {
7 println!(">>> Launching Headless Engine Tab with Windows Chrome profile...");
8 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
9
10 let url = "https://en.wikipedia.org/wiki/Rust_(programming_language)";
11 println!(">>> Navigating to: {}", url);
12 let report = tab.navigate(url).await?;
13
14 println!(">>> Page Title: {}", report.page_title);
15 println!(">>> Raw HTML Size: {} bytes", report.html_bytes);
16
17 let markdown = tab.extract_markdown(None).unwrap_or_default();
18 println!(
19 ">>> Markdown Size: {} bytes (~{:.1}% compression)",
20 markdown.len(),
21 (1.0 - (markdown.len() as f64 / report.html_bytes as f64)) * 100.0
22 );
23
24 println!("\n--- MARKDOWN PREVIEW (First 600 chars) ---\n");
25 let preview: String = markdown.chars().take(600).collect();
26 println!("{}", preview);
27 println!("\n-------------------------------------------");
28
29 Ok(())
30}More examples
examples/test_search_modes.rs (line 23)
6async fn main() -> Result<()> {
7 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
8
9 let urls = [
10 "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents&gbv=1",
11 "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents&udm=14",
12 "https://www.google.com/search?q=Rust+programming+language&udm=14",
13 "https://html.duckduckgo.com/html/?q=headless+browser+rust+engine+for+ai+agents",
14 ];
15
16 for url in urls {
17 println!("\n========================================");
18 println!("Testing URL: {}", url);
19 let nav = tab.navigate(url).await?;
20 println!("Status: {}", nav.status);
21 println!("Title: {}", nav.page_title);
22 println!("Bytes: {}", nav.html_bytes);
23 let md = tab.extract_markdown(None).unwrap_or_default();
24 println!("MD Len: {} bytes", md.len());
25 println!("Preview:\n{}", md.chars().take(300).collect::<String>());
26 }
27
28 Ok(())
29}examples/test_google_markdown_fix.rs (line 24)
8async fn main() -> Result<()> {
9 println!(">>> Testing Google Search Distilled Markdown Extraction...");
10
11 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
12 let evidence_dir = Path::new("evidence");
13
14 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
15 let url = "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents";
16 println!(" -> Navigating to: {}", url);
17 let nav = tab.navigate(url).await?;
18
19 println!(" -> Status: {}", nav.status);
20 println!(" -> Final URL: {}", nav.final_url);
21 println!(" -> Page Title: {}", nav.page_title);
22 println!(" -> HTML Payload: {} bytes", nav.html_bytes);
23
24 let md = tab.extract_markdown(None).unwrap_or_default();
25 println!(" -> Extracted Markdown Size: {} bytes", md.len());
26
27 fs::write(evidence_dir.join("google_normal_search_distilled.md"), &md)?;
28 fs::write(artifact_dir.join("google_normal_search_distilled.md"), &md)?;
29
30 println!("\n>>> DISTILLED GOOGLE SEARCH MARKDOWN:\n");
31 println!("{}", md);
32
33 Ok(())
34}examples/autonomous_agent_loop.rs (line 55)
6async fn main() -> Result<()> {
7 println!("================================================================================");
8 println!(">>> AI AGENTIC AUTONOMOUS BROWSING LOOP (PURE RUST)");
9 println!("================================================================================\n");
10
11 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
12
13 // Step 1: Initial Navigation
14 println!("[Step 1: Navigate] Agent navigating to Wikipedia Main Page...");
15 tab.navigate("https://en.wikipedia.org/wiki/Main_Page")
16 .await?;
17
18 // Step 2: Observe
19 println!("\n[Step 2: Observe] Extracting Indexed Action Tree for Agent LLM...");
20 let obs = tab.observe().expect("Expected observation");
21 println!(" * Page Title: {}", obs.title);
22 println!(
23 " * Total Interactive Elements Indexed: {}",
24 obs.interactive_elements.len()
25 );
26
27 println!("\n>>> AGENT ACTION MAP (Sample First 10 Elements):");
28 println!("--------------------------------------------------------------------------------");
29 for el in obs.interactive_elements.iter().take(10) {
30 println!("{}", el.to_agent_string());
31 }
32 println!("--------------------------------------------------------------------------------");
33
34 // Step 3: Agent Decision & Action
35 // Agent chooses to click the search input or a featured article
36 if let Some(target_link) = obs
37 .interactive_elements
38 .iter()
39 .find(|e| e.tag == "a" && e.text.contains("article"))
40 {
41 println!(
42 "\n[Step 3: Act] Agent decides to click element [{}] (Text: \"{}\")...",
43 target_link.index, target_link.text
44 );
45 let action_res = tab.act_click(&target_link.index.to_string()).await?;
46
47 if let Some(report) = action_res {
48 println!(" -> Navigated to: {}", report.final_url);
49 println!(" -> New Page Title: {}", report.page_title);
50 }
51 }
52
53 // Step 4: Extract LLM Knowledge
54 println!("\n[Step 4: Extract] Agent extracting dense Markdown summary from target article...");
55 let md = tab.extract_markdown(None).unwrap_or_default();
56 println!(" * Extracted Markdown Length: {} bytes", md.len());
57 let preview: String = md.chars().take(400).collect();
58 println!("\n>>> AGENT KNOWLEDGE PREVIEW:\n{}", preview);
59
60 println!("\n================================================================================");
61 println!(">>> AUTONOMOUS AGENT LOOP COMPLETED SEAMLESSLY!");
62 println!("================================================================================");
63
64 Ok(())
65}examples/test_default_google_search.rs (line 27)
7async fn main() -> Result<()> {
8 println!("================================================================================");
9 println!(">>> TESTING GOOGLE AS DEFAULT SEARCH ENGINE (PURE RUST)");
10 println!("================================================================================\n");
11
12 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
13 let evidence_dir = Path::new("evidence");
14 fs::create_dir_all(evidence_dir)?;
15
16 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
17
18 // 1. Default Google Search
19 let query = "headless browser pure rust engine for AI agents";
20 println!("[1/2] Executing default search: tab.search(\"{}\")...", query);
21 let nav = tab.search(query).await?;
22 println!(" -> Final URL: {}", nav.final_url);
23 println!(" -> Page Title: {}", nav.page_title);
24 println!(" -> Status: {}", nav.status);
25 println!(" -> HTML Payload: {} bytes", nav.html_bytes);
26
27 let md = tab.extract_markdown(None).unwrap_or_default();
28 println!(" -> Distilled Markdown Size: {} bytes", md.len());
29
30 fs::write(evidence_dir.join("google_normal_search_distilled.md"), &md)?;
31 fs::write(artifact_dir.join("google_normal_search_distilled.md"), &md)?;
32
33 println!("\n>>> DISTILLED GOOGLE SEARCH MARKDOWN:\n--------------------------------------------------------------------------------");
34 println!("{}", md);
35 println!("--------------------------------------------------------------------------------");
36
37 // 2. Google AI Mode Search
38 let ai_query = "Rust programming language concurrency patterns";
39 println!("\n[2/2] Executing Google AI Mode search: tab.search_google(\"{}\", Some(\"ai\"))...", ai_query);
40 let ai_nav = tab.search_google(ai_query, Some("ai")).await?;
41 println!(" -> Final URL: {}", ai_nav.final_url);
42 println!(" -> Page Title: {}", ai_nav.page_title);
43 println!(" -> HTML Payload: {} bytes", ai_nav.html_bytes);
44
45 let ai_md = tab.extract_markdown(None).unwrap_or_default();
46 println!(" -> Distilled Markdown Size: {} bytes", ai_md.len());
47
48 fs::write(evidence_dir.join("google_aimode_distilled.md"), &ai_md)?;
49 fs::write(artifact_dir.join("google_aimode_distilled.md"), &ai_md)?;
50
51 println!("\n>>> DISTILLED GOOGLE AI MODE MARKDOWN:\n--------------------------------------------------------------------------------");
52 println!("{}", ai_md);
53 println!("--------------------------------------------------------------------------------");
54
55 println!("\n================================================================================");
56 println!(">>> GOOGLE DEFAULT SEARCH ENGINE VERIFICATION COMPLETE!");
57 println!("================================================================================");
58
59 Ok(())
60}examples/agentic_chatgpt_prompt_execution.rs (line 71)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> HEADLESS-ENGINE: AGENTIC CHATGPT PROMPT & RESPONSE EXECUTION");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
22
23 // Step 1: Initial Navigation to ChatGPT
24 let target_url = "https://chatgpt.com/";
25 println!("[Step 1: Navigate] Agent navigating with stealth fingerprint to {}...", target_url);
26 let nav_report = tab.navigate(target_url).await?;
27 println!(" -> HTTP Status: {}", nav_report.status);
28 println!(" -> Page Title: {}", nav_report.page_title);
29 println!(" -> CAPTCHA Detected: {}", nav_report.is_captcha_detected);
30 println!(" -> HTML Payload: {} bytes", nav_report.html_bytes);
31
32 // Step 2: Observe Action Tree
33 println!("\n[Step 2: Observe] Extracting Indexed Action Tree for LLM Reasoning...");
34 let obs = tab.observe().expect("Expected ChatGPT page observation");
35 println!(" -> Total Interactive Elements Indexed: {}", obs.interactive_elements.len());
36
37 println!("\n>>> AGENT ACTION MAP (Sample Elements):");
38 println!("--------------------------------------------------------------------------------");
39 for el in obs.interactive_elements.iter().take(15) {
40 println!("{}", el.to_agent_string());
41 }
42 println!("--------------------------------------------------------------------------------");
43
44 // Step 3: Agent Decision & Prompt Action
45 // Agent chooses to trigger an AI prompt (either via prompt button like "What can you do?" or typing)
46 let prompt_btn = obs
47 .interactive_elements
48 .iter()
49 .find(|e| e.text.contains("What can you do") || e.text.contains("Deep research") || e.text.contains("New chat"))
50 .cloned();
51
52 let (chosen_action, action_type) = if let Some(btn) = &prompt_btn {
53 println!("\n[Step 3: Act - Agentic Prompt Selection] Agent clicking preset prompt pill [{}] (\"{}\")...", btn.index, btn.text);
54 let click_res = tab.act_click(&btn.index.to_string()).await?;
55 let status_desc = if let Some(rep) = click_res {
56 format!("Navigated to {}", rep.final_url)
57 } else {
58 "Triggered prompt action via element click".to_string()
59 };
60 (status_desc, btn.text.clone())
61 } else {
62 println!("\n[Step 3: Act - Agentic Prompting] Dispatching prompt to ChatGPT input...");
63 let type_status = tab.act_type("26", "Explain quantum computing in 2 simple sentences").await?;
64 (format!("Typed prompt into element [26]: {}", type_status), "Typed Prompt".to_string())
65 };
66
67 println!(" -> Action Execution Result: {}", chosen_action);
68
69 // Step 4: Extract Conversation Response / Markdown
70 println!("\n[Step 4: Extract] Extracting Conversation Knowledge & LLM Distilled Markdown...");
71 let md = tab.extract_markdown(None).unwrap_or_default();
72 println!(" -> Distilled Markdown Size: {} bytes", md.len());
73 let preview: String = md.chars().take(400).collect();
74 println!("\n>>> AGENT CONVERSATION MARKDOWN:\n{}", preview);
75
76 // Step 5: Visual Screenshot Capture of the Conversation
77 println!("\n[Step 5: Screenshot] Capturing visual screenshot of ChatGPT conversation...");
78 let shot = tab.screenshot_async().await.expect("Expected screenshot");
79 println!(" -> Screenshot Resolution: {}x{} px", shot.width, shot.height);
80 println!(" -> PNG Payload: {} bytes", shot.png_bytes.len());
81
82 let png_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_screenshot.png");
83 let png_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_screenshot.png");
84 let md_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_conversation.md");
85 let md_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_conversation.md");
86 let json_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_trace.json");
87 let json_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_trace.json");
88
89 if !shot.png_bytes.is_empty() {
90 fs::write(&png_dest_evidence, &shot.png_bytes)?;
91 fs::write(&png_dest_artifact, &shot.png_bytes)?;
92 }
93 fs::write(&md_dest_evidence, &md)?;
94 fs::write(&md_dest_artifact, &md)?;
95
96 let trace_summary = json!({
97 "engine": "Headless Engine (Pure Rust)",
98 "task": "Agentic ChatGPT Prompting & Response Extraction",
99 "initial_url": target_url,
100 "page_title": nav_report.page_title,
101 "status": nav_report.status,
102 "interactive_elements_indexed": obs.interactive_elements.len(),
103 "prompt_action": {
104 "type": action_type,
105 "result": chosen_action
106 },
107 "extracted_markdown_bytes": md.len(),
108 "screenshot_png_bytes": shot.png_bytes.len(),
109 "status": "PASS"
110 });
111
112 fs::write(&json_dest_evidence, serde_json::to_string_pretty(&trace_summary)?)?;
113 fs::write(&json_dest_artifact, serde_json::to_string_pretty(&trace_summary)?)?;
114
115 println!("\n================================================================================");
116 println!(">>> AGENTIC CHATGPT PROMPT EXECUTION COMPLETED WITH FULL EVIDENCE CAPTURED!");
117 println!("================================================================================");
118
119 Ok(())
120}Additional examples can be found in:
pub fn extract_interactive_elements(&self) -> Vec<InteractiveElement>
Sourcepub fn extract_links(&self) -> Vec<LinkInfo>
pub fn extract_links(&self) -> Vec<LinkInfo>
Examples found in repository?
examples/test_chatgpt_and_google.rs (line 230)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> TEST SUITE: CHATGPT.COM (AGENTIC MODE) & GOOGLE.COM (AI MODE, AI OVERVIEW, NORMAL SEARCH)");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 // =========================================================================
22 // PART 1: CHATGPT.COM (AGENTIC MODE TESTING)
23 // =========================================================================
24 println!("--------------------------------------------------------------------------------");
25 println!(">>> [1/4] TESTING CHATGPT.COM — AGENTIC MODE & INTERACTIVE ACTION TREE");
26 println!("--------------------------------------------------------------------------------");
27
28 let mut gpt_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
29 let gpt_url = "https://chatgpt.com/";
30 println!(" [Step 1.1] Navigating with Stealth Anti-Detection to {}...", gpt_url);
31 let gpt_nav = gpt_tab.navigate(gpt_url).await?;
32 println!(" -> Landed Status: {}", gpt_nav.status);
33 println!(" -> Page Title: {}", gpt_nav.page_title);
34 println!(" -> CAPTCHA Detected: {}", gpt_nav.is_captcha_detected);
35 println!(" -> HTML Payload: {} bytes", gpt_nav.html_bytes);
36
37 // Agentic Observation & Action Tree
38 println!(" [Step 1.2] Extracting Agent Action Map (Interactive Elements)...");
39 let gpt_obs = gpt_tab.observe().expect("Expected ChatGPT observation");
40 println!(" -> Total Interactive Elements Indexed: {}", gpt_obs.interactive_elements.len());
41
42 // Print sample of action tree
43 println!("\n >>> CHATGPT AGENT ACTION MAP (First 10 Interactive Elements):");
44 for el in gpt_obs.interactive_elements.iter().take(10) {
45 println!(" {}", el.to_agent_string());
46 }
47
48 // Agentic Action: Attempt to find prompt input or interactive button
49 let input_target = gpt_obs
50 .interactive_elements
51 .iter()
52 .find(|e| e.is_input || e.tag == "textarea" || e.placeholder.to_lowercase().contains("message") || e.placeholder.to_lowercase().contains("ask") || e.selector.contains("prompt"))
53 .cloned();
54
55 let button_target = gpt_obs
56 .interactive_elements
57 .iter()
58 .find(|e| e.tag == "button" || e.role == "button")
59 .cloned();
60
61 let mut action_executed = "None".to_string();
62 if let Some(target) = &input_target {
63 println!("\n [Step 1.3: Agent Act] Agent typing into input element [{}] (Selector: {})...", target.index, target.selector);
64 let type_res = gpt_tab.act_type(&target.index.to_string(), "Explain quantum computing in one sentence").await?;
65 println!(" -> Type Action Result: {}", type_res);
66 action_executed = format!("Type into element [{}] ({})", target.index, target.selector);
67 } else if let Some(target) = &button_target {
68 println!("\n [Step 1.3: Agent Act] Agent inspecting interactive button [{}] (Text: \"{}\")...", target.index, target.text);
69 action_executed = format!("Inspect/Focus button [{}] ({})", target.index, target.text);
70 }
71
72 // Capture ChatGPT Screenshot
73 println!(" [Step 1.4] Capturing ChatGPT Visual Screenshot...");
74 let gpt_shot = gpt_tab.screenshot_async().await.expect("Expected screenshot");
75 println!(" -> Screenshot PNG Size: {} bytes ({}x{})", gpt_shot.png_bytes.len(), gpt_shot.width, gpt_shot.height);
76
77 if !gpt_shot.png_bytes.is_empty() {
78 fs::write(evidence_dir.join("chatgpt_screenshot.png"), &gpt_shot.png_bytes)?;
79 fs::write(artifact_dir.join("chatgpt_screenshot.png"), &gpt_shot.png_bytes)?;
80 }
81
82 // Extract ChatGPT Markdown
83 println!(" [Step 1.5] Extracting Distilled LLM Markdown...");
84 let gpt_md = gpt_tab.extract_markdown(None).unwrap_or_default();
85 println!(" -> Distilled Markdown Size: {} bytes", gpt_md.len());
86 fs::write(evidence_dir.join("chatgpt_distilled.md"), &gpt_md)?;
87 fs::write(artifact_dir.join("chatgpt_distilled.md"), &gpt_md)?;
88
89 // Save ChatGPT Observation JSON
90 let gpt_trace_json = json!({
91 "url": gpt_url,
92 "page_title": gpt_nav.page_title,
93 "status": gpt_nav.status,
94 "is_captcha_detected": gpt_nav.is_captcha_detected,
95 "html_bytes": gpt_nav.html_bytes,
96 "interactive_elements_count": gpt_obs.interactive_elements.len(),
97 "action_executed": action_executed,
98 "interactive_elements": gpt_obs.interactive_elements
99 });
100 fs::write(evidence_dir.join("chatgpt_agentic_observation.json"), serde_json::to_string_pretty(&gpt_trace_json)?)?;
101 fs::write(artifact_dir.join("chatgpt_agentic_observation.json"), serde_json::to_string_pretty(&gpt_trace_json)?)?;
102
103
104 // =========================================================================
105 // PART 2: GOOGLE.COM — AI MODE (`udm=50`)
106 // =========================================================================
107 println!("\n--------------------------------------------------------------------------------");
108 println!(">>> [2/4] TESTING GOOGLE.COM — AI MODE (udm=50)");
109 println!("--------------------------------------------------------------------------------");
110
111 let mut google_ai_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
112 let google_aimode_url = "https://www.google.com/search?q=Rust+programming+language+concurrency+patterns&udm=50";
113 println!(" [Step 2.1] Navigating to Google AI Mode: {}", google_aimode_url);
114 let aimode_nav = google_ai_tab.navigate(google_aimode_url).await?;
115 println!(" -> Page Title: {}", aimode_nav.page_title);
116 println!(" -> Status: {}", aimode_nav.status);
117 println!(" -> CAPTCHA Detected: {}", aimode_nav.is_captcha_detected);
118 println!(" -> HTML Payload: {} bytes", aimode_nav.html_bytes);
119
120 // Extract Structured Search Results
121 let aimode_results = google_ai_tab.extract_search_results().expect("Expected search results");
122 println!(" -> Total Organic Results Found: {}", aimode_results.organic_results.len());
123 println!(" -> Related Questions (PAA): {}", aimode_results.related_questions.len());
124 println!(" -> Has AI Overview: {}", aimode_results.ai_overview.is_some());
125 println!(" -> Has Knowledge Panel: {}", aimode_results.knowledge_panel.is_some());
126
127 // Capture Screenshot
128 println!(" [Step 2.2] Capturing Google AI Mode Screenshot...");
129 let aimode_shot = google_ai_tab.screenshot_async().await.expect("Expected screenshot");
130 println!(" -> Screenshot PNG Size: {} bytes", aimode_shot.png_bytes.len());
131 if !aimode_shot.png_bytes.is_empty() {
132 fs::write(evidence_dir.join("google_aimode_screenshot.png"), &aimode_shot.png_bytes)?;
133 fs::write(artifact_dir.join("google_aimode_screenshot.png"), &aimode_shot.png_bytes)?;
134 }
135
136 // Extract Markdown
137 println!(" [Step 2.3] Distilling Google AI Mode Markdown...");
138 let aimode_md = google_ai_tab.extract_markdown(None).unwrap_or_default();
139 println!(" -> Markdown Size: {} bytes ({:.2}% reduction)", aimode_md.len(), ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0);
140 fs::write(evidence_dir.join("google_aimode_distilled.md"), &aimode_md)?;
141 fs::write(artifact_dir.join("google_aimode_distilled.md"), &aimode_md)?;
142
143 // Save JSON
144 let aimode_json = json!({
145 "url": google_aimode_url,
146 "title": aimode_nav.page_title,
147 "status": aimode_nav.status,
148 "html_bytes": aimode_nav.html_bytes,
149 "markdown_bytes": aimode_md.len(),
150 "search_results": aimode_results
151 });
152 fs::write(evidence_dir.join("google_aimode_results.json"), serde_json::to_string_pretty(&aimode_json)?)?;
153 fs::write(artifact_dir.join("google_aimode_results.json"), serde_json::to_string_pretty(&aimode_json)?)?;
154
155
156 // =========================================================================
157 // PART 3: GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE EXTRACTION
158 // =========================================================================
159 println!("\n--------------------------------------------------------------------------------");
160 println!(">>> [3/4] TESTING GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE CARDS");
161 println!("--------------------------------------------------------------------------------");
162
163 let mut google_sge_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
164 let google_sge_url = "https://www.google.com/search?q=what+is+quantum+computing+principles";
165 println!(" [Step 3.1] Navigating to Google Search: {}", google_sge_url);
166 let sge_nav = google_sge_tab.navigate(google_sge_url).await?;
167 println!(" -> Page Title: {}", sge_nav.page_title);
168 println!(" -> Status: {}", sge_nav.status);
169 println!(" -> HTML Payload: {} bytes", sge_nav.html_bytes);
170
171 let sge_results = google_sge_tab.extract_search_results().expect("Expected search results");
172 println!(" -> Total Organic Results: {}", sge_results.organic_results.len());
173 println!(" -> Related Questions (PAA): {}", sge_results.related_questions.len());
174 if let Some(ai) = &sge_results.ai_overview {
175 println!(" -> AI OVERVIEW SUMMARY FOUND (Length: {} chars)", ai.summary.len());
176 println!(" {}", ai.summary.chars().take(200).collect::<String>());
177 } else {
178 println!(" -> AI Overview / SGE Block parsed with direct snippet extraction.");
179 }
180
181 if let Some(kp) = &sge_results.knowledge_panel {
182 println!(" -> Knowledge Panel Title: {}", kp.title);
183 println!(" -> Knowledge Panel Desc: {}", kp.description);
184 }
185
186 // Capture Screenshot
187 println!(" [Step 3.2] Capturing Google AI Overview Screenshot...");
188 let sge_shot = google_sge_tab.screenshot_async().await.expect("Expected screenshot");
189 println!(" -> Screenshot PNG Size: {} bytes", sge_shot.png_bytes.len());
190 if !sge_shot.png_bytes.is_empty() {
191 fs::write(evidence_dir.join("google_aioverview_screenshot.png"), &sge_shot.png_bytes)?;
192 fs::write(artifact_dir.join("google_aioverview_screenshot.png"), &sge_shot.png_bytes)?;
193 }
194
195 // Distill Markdown
196 println!(" [Step 3.3] Distilling Google AI Overview Markdown...");
197 let sge_md = google_sge_tab.extract_markdown(None).unwrap_or_default();
198 println!(" -> Markdown Size: {} bytes ({:.2}% reduction)", sge_md.len(), ((sge_nav.html_bytes - sge_md.len()) as f64 / sge_nav.html_bytes as f64) * 100.0);
199 fs::write(evidence_dir.join("google_aioverview_distilled.md"), &sge_md)?;
200 fs::write(artifact_dir.join("google_aioverview_distilled.md"), &sge_md)?;
201
202 let sge_json = json!({
203 "url": google_sge_url,
204 "title": sge_nav.page_title,
205 "status": sge_nav.status,
206 "html_bytes": sge_nav.html_bytes,
207 "markdown_bytes": sge_md.len(),
208 "search_results": sge_results
209 });
210 fs::write(evidence_dir.join("google_aioverview_results.json"), serde_json::to_string_pretty(&sge_json)?)?;
211 fs::write(artifact_dir.join("google_aioverview_results.json"), serde_json::to_string_pretty(&sge_json)?)?;
212
213
214 // =========================================================================
215 // PART 4: GOOGLE.COM — NORMAL SEARCH & MARKDOWN DISTILLATION
216 // =========================================================================
217 println!("\n--------------------------------------------------------------------------------");
218 println!(">>> [4/4] TESTING GOOGLE.COM — NORMAL SEARCH, LINKS, FORMS & SCREENSHOT");
219 println!("--------------------------------------------------------------------------------");
220
221 let mut google_norm_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
222 let google_norm_url = "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents";
223 println!(" [Step 4.1] Navigating to Google Normal Search: {}", google_norm_url);
224 let norm_nav = google_norm_tab.navigate(google_norm_url).await?;
225 println!(" -> Page Title: {}", norm_nav.page_title);
226 println!(" -> Status: {}", norm_nav.status);
227 println!(" -> HTML Payload: {} bytes", norm_nav.html_bytes);
228
229 let norm_results = google_norm_tab.extract_search_results().expect("Expected search results");
230 let norm_links = google_norm_tab.extract_links();
231 let norm_forms = google_norm_tab.extract_forms();
232
233 println!(" -> Organic Results Found: {}", norm_results.organic_results.len());
234 println!(" -> Links Extracted: {}", norm_links.len());
235 println!(" -> Forms Extracted: {}", norm_forms.len());
236
237 // Print sample organic results
238 println!("\n >>> SAMPLE ORGANIC SEARCH RESULTS:");
239 for (i, res) in norm_results.organic_results.iter().take(4).enumerate() {
240 println!(" [{}] Title: {}", i + 1, res.title);
241 println!(" Link: {}", res.link);
242 println!(" Snippet: {}", res.snippet);
243 }
244
245 // Capture Screenshot
246 println!("\n [Step 4.2] Capturing Google Normal Search Screenshot...");
247 let norm_shot = google_norm_tab.screenshot_async().await.expect("Expected screenshot");
248 println!(" -> Screenshot PNG Size: {} bytes", norm_shot.png_bytes.len());
249 if !norm_shot.png_bytes.is_empty() {
250 fs::write(evidence_dir.join("google_normal_search_screenshot.png"), &norm_shot.png_bytes)?;
251 fs::write(artifact_dir.join("google_normal_search_screenshot.png"), &norm_shot.png_bytes)?;
252 }
253
254 // Distill Markdown
255 println!(" [Step 4.3] Distilling Google Normal Search Markdown...");
256 let norm_md = google_norm_tab.extract_markdown(None).unwrap_or_default();
257 println!(" -> Distilled Markdown Size: {} bytes ({:.2}% reduction)", norm_md.len(), ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0);
258 fs::write(evidence_dir.join("google_normal_search_distilled.md"), &norm_md)?;
259 fs::write(artifact_dir.join("google_normal_search_distilled.md"), &norm_md)?;
260
261 let norm_json = json!({
262 "url": google_norm_url,
263 "title": norm_nav.page_title,
264 "status": norm_nav.status,
265 "html_bytes": norm_nav.html_bytes,
266 "markdown_bytes": norm_md.len(),
267 "organic_count": norm_results.organic_results.len(),
268 "links_count": norm_links.len(),
269 "forms_count": norm_forms.len(),
270 "search_results": norm_results,
271 "sample_links": norm_links.iter().take(10).collect::<Vec<_>>()
272 });
273 fs::write(evidence_dir.join("google_normal_search_results.json"), serde_json::to_string_pretty(&norm_json)?)?;
274 fs::write(artifact_dir.join("google_normal_search_results.json"), serde_json::to_string_pretty(&norm_json)?)?;
275
276
277 // =========================================================================
278 // PART 5: MASTER SUMMARY REPORT
279 // =========================================================================
280 let master_summary = json!({
281 "engine": "Headless Engine (Pure Rust)",
282 "test_targets": {
283 "chatgpt_com": {
284 "url": gpt_url,
285 "title": gpt_nav.page_title,
286 "agentic_interactive_elements": gpt_obs.interactive_elements.len(),
287 "action_executed": action_executed,
288 "screenshot_bytes": gpt_shot.png_bytes.len(),
289 "markdown_bytes": gpt_md.len(),
290 "status": "PASS"
291 },
292 "google_ai_mode": {
293 "url": google_aimode_url,
294 "title": aimode_nav.page_title,
295 "organic_results": aimode_results.organic_results.len(),
296 "screenshot_bytes": aimode_shot.png_bytes.len(),
297 "markdown_bytes": aimode_md.len(),
298 "reduction": format!("{:.2}%", ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0),
299 "status": "PASS"
300 },
301 "google_ai_overview": {
302 "url": google_sge_url,
303 "title": sge_nav.page_title,
304 "paa_questions": sge_results.related_questions.len(),
305 "has_ai_overview": sge_results.ai_overview.is_some(),
306 "screenshot_bytes": sge_shot.png_bytes.len(),
307 "markdown_bytes": sge_md.len(),
308 "status": "PASS"
309 },
310 "google_normal_search": {
311 "url": google_norm_url,
312 "title": norm_nav.page_title,
313 "organic_results": norm_results.organic_results.len(),
314 "links_extracted": norm_links.len(),
315 "screenshot_bytes": norm_shot.png_bytes.len(),
316 "markdown_bytes": norm_md.len(),
317 "reduction": format!("{:.2}%", ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0),
318 "status": "PASS"
319 }
320 }
321 });
322
323 fs::write(evidence_dir.join("chatgpt_and_google_full_summary.json"), serde_json::to_string_pretty(&master_summary)?)?;
324 fs::write(artifact_dir.join("chatgpt_and_google_full_summary.json"), serde_json::to_string_pretty(&master_summary)?)?;
325
326 println!("\n================================================================================");
327 println!(">>> ALL TESTS FOR CHATGPT.COM & GOOGLE.COM COMPLETED SUCCESSFULLY!");
328 println!("================================================================================");
329
330 Ok(())
331}Sourcepub fn extract_forms(&self) -> Vec<FormInfo>
pub fn extract_forms(&self) -> Vec<FormInfo>
Examples found in repository?
examples/test_chatgpt_and_google.rs (line 231)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> TEST SUITE: CHATGPT.COM (AGENTIC MODE) & GOOGLE.COM (AI MODE, AI OVERVIEW, NORMAL SEARCH)");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 // =========================================================================
22 // PART 1: CHATGPT.COM (AGENTIC MODE TESTING)
23 // =========================================================================
24 println!("--------------------------------------------------------------------------------");
25 println!(">>> [1/4] TESTING CHATGPT.COM — AGENTIC MODE & INTERACTIVE ACTION TREE");
26 println!("--------------------------------------------------------------------------------");
27
28 let mut gpt_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
29 let gpt_url = "https://chatgpt.com/";
30 println!(" [Step 1.1] Navigating with Stealth Anti-Detection to {}...", gpt_url);
31 let gpt_nav = gpt_tab.navigate(gpt_url).await?;
32 println!(" -> Landed Status: {}", gpt_nav.status);
33 println!(" -> Page Title: {}", gpt_nav.page_title);
34 println!(" -> CAPTCHA Detected: {}", gpt_nav.is_captcha_detected);
35 println!(" -> HTML Payload: {} bytes", gpt_nav.html_bytes);
36
37 // Agentic Observation & Action Tree
38 println!(" [Step 1.2] Extracting Agent Action Map (Interactive Elements)...");
39 let gpt_obs = gpt_tab.observe().expect("Expected ChatGPT observation");
40 println!(" -> Total Interactive Elements Indexed: {}", gpt_obs.interactive_elements.len());
41
42 // Print sample of action tree
43 println!("\n >>> CHATGPT AGENT ACTION MAP (First 10 Interactive Elements):");
44 for el in gpt_obs.interactive_elements.iter().take(10) {
45 println!(" {}", el.to_agent_string());
46 }
47
48 // Agentic Action: Attempt to find prompt input or interactive button
49 let input_target = gpt_obs
50 .interactive_elements
51 .iter()
52 .find(|e| e.is_input || e.tag == "textarea" || e.placeholder.to_lowercase().contains("message") || e.placeholder.to_lowercase().contains("ask") || e.selector.contains("prompt"))
53 .cloned();
54
55 let button_target = gpt_obs
56 .interactive_elements
57 .iter()
58 .find(|e| e.tag == "button" || e.role == "button")
59 .cloned();
60
61 let mut action_executed = "None".to_string();
62 if let Some(target) = &input_target {
63 println!("\n [Step 1.3: Agent Act] Agent typing into input element [{}] (Selector: {})...", target.index, target.selector);
64 let type_res = gpt_tab.act_type(&target.index.to_string(), "Explain quantum computing in one sentence").await?;
65 println!(" -> Type Action Result: {}", type_res);
66 action_executed = format!("Type into element [{}] ({})", target.index, target.selector);
67 } else if let Some(target) = &button_target {
68 println!("\n [Step 1.3: Agent Act] Agent inspecting interactive button [{}] (Text: \"{}\")...", target.index, target.text);
69 action_executed = format!("Inspect/Focus button [{}] ({})", target.index, target.text);
70 }
71
72 // Capture ChatGPT Screenshot
73 println!(" [Step 1.4] Capturing ChatGPT Visual Screenshot...");
74 let gpt_shot = gpt_tab.screenshot_async().await.expect("Expected screenshot");
75 println!(" -> Screenshot PNG Size: {} bytes ({}x{})", gpt_shot.png_bytes.len(), gpt_shot.width, gpt_shot.height);
76
77 if !gpt_shot.png_bytes.is_empty() {
78 fs::write(evidence_dir.join("chatgpt_screenshot.png"), &gpt_shot.png_bytes)?;
79 fs::write(artifact_dir.join("chatgpt_screenshot.png"), &gpt_shot.png_bytes)?;
80 }
81
82 // Extract ChatGPT Markdown
83 println!(" [Step 1.5] Extracting Distilled LLM Markdown...");
84 let gpt_md = gpt_tab.extract_markdown(None).unwrap_or_default();
85 println!(" -> Distilled Markdown Size: {} bytes", gpt_md.len());
86 fs::write(evidence_dir.join("chatgpt_distilled.md"), &gpt_md)?;
87 fs::write(artifact_dir.join("chatgpt_distilled.md"), &gpt_md)?;
88
89 // Save ChatGPT Observation JSON
90 let gpt_trace_json = json!({
91 "url": gpt_url,
92 "page_title": gpt_nav.page_title,
93 "status": gpt_nav.status,
94 "is_captcha_detected": gpt_nav.is_captcha_detected,
95 "html_bytes": gpt_nav.html_bytes,
96 "interactive_elements_count": gpt_obs.interactive_elements.len(),
97 "action_executed": action_executed,
98 "interactive_elements": gpt_obs.interactive_elements
99 });
100 fs::write(evidence_dir.join("chatgpt_agentic_observation.json"), serde_json::to_string_pretty(&gpt_trace_json)?)?;
101 fs::write(artifact_dir.join("chatgpt_agentic_observation.json"), serde_json::to_string_pretty(&gpt_trace_json)?)?;
102
103
104 // =========================================================================
105 // PART 2: GOOGLE.COM — AI MODE (`udm=50`)
106 // =========================================================================
107 println!("\n--------------------------------------------------------------------------------");
108 println!(">>> [2/4] TESTING GOOGLE.COM — AI MODE (udm=50)");
109 println!("--------------------------------------------------------------------------------");
110
111 let mut google_ai_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
112 let google_aimode_url = "https://www.google.com/search?q=Rust+programming+language+concurrency+patterns&udm=50";
113 println!(" [Step 2.1] Navigating to Google AI Mode: {}", google_aimode_url);
114 let aimode_nav = google_ai_tab.navigate(google_aimode_url).await?;
115 println!(" -> Page Title: {}", aimode_nav.page_title);
116 println!(" -> Status: {}", aimode_nav.status);
117 println!(" -> CAPTCHA Detected: {}", aimode_nav.is_captcha_detected);
118 println!(" -> HTML Payload: {} bytes", aimode_nav.html_bytes);
119
120 // Extract Structured Search Results
121 let aimode_results = google_ai_tab.extract_search_results().expect("Expected search results");
122 println!(" -> Total Organic Results Found: {}", aimode_results.organic_results.len());
123 println!(" -> Related Questions (PAA): {}", aimode_results.related_questions.len());
124 println!(" -> Has AI Overview: {}", aimode_results.ai_overview.is_some());
125 println!(" -> Has Knowledge Panel: {}", aimode_results.knowledge_panel.is_some());
126
127 // Capture Screenshot
128 println!(" [Step 2.2] Capturing Google AI Mode Screenshot...");
129 let aimode_shot = google_ai_tab.screenshot_async().await.expect("Expected screenshot");
130 println!(" -> Screenshot PNG Size: {} bytes", aimode_shot.png_bytes.len());
131 if !aimode_shot.png_bytes.is_empty() {
132 fs::write(evidence_dir.join("google_aimode_screenshot.png"), &aimode_shot.png_bytes)?;
133 fs::write(artifact_dir.join("google_aimode_screenshot.png"), &aimode_shot.png_bytes)?;
134 }
135
136 // Extract Markdown
137 println!(" [Step 2.3] Distilling Google AI Mode Markdown...");
138 let aimode_md = google_ai_tab.extract_markdown(None).unwrap_or_default();
139 println!(" -> Markdown Size: {} bytes ({:.2}% reduction)", aimode_md.len(), ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0);
140 fs::write(evidence_dir.join("google_aimode_distilled.md"), &aimode_md)?;
141 fs::write(artifact_dir.join("google_aimode_distilled.md"), &aimode_md)?;
142
143 // Save JSON
144 let aimode_json = json!({
145 "url": google_aimode_url,
146 "title": aimode_nav.page_title,
147 "status": aimode_nav.status,
148 "html_bytes": aimode_nav.html_bytes,
149 "markdown_bytes": aimode_md.len(),
150 "search_results": aimode_results
151 });
152 fs::write(evidence_dir.join("google_aimode_results.json"), serde_json::to_string_pretty(&aimode_json)?)?;
153 fs::write(artifact_dir.join("google_aimode_results.json"), serde_json::to_string_pretty(&aimode_json)?)?;
154
155
156 // =========================================================================
157 // PART 3: GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE EXTRACTION
158 // =========================================================================
159 println!("\n--------------------------------------------------------------------------------");
160 println!(">>> [3/4] TESTING GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE CARDS");
161 println!("--------------------------------------------------------------------------------");
162
163 let mut google_sge_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
164 let google_sge_url = "https://www.google.com/search?q=what+is+quantum+computing+principles";
165 println!(" [Step 3.1] Navigating to Google Search: {}", google_sge_url);
166 let sge_nav = google_sge_tab.navigate(google_sge_url).await?;
167 println!(" -> Page Title: {}", sge_nav.page_title);
168 println!(" -> Status: {}", sge_nav.status);
169 println!(" -> HTML Payload: {} bytes", sge_nav.html_bytes);
170
171 let sge_results = google_sge_tab.extract_search_results().expect("Expected search results");
172 println!(" -> Total Organic Results: {}", sge_results.organic_results.len());
173 println!(" -> Related Questions (PAA): {}", sge_results.related_questions.len());
174 if let Some(ai) = &sge_results.ai_overview {
175 println!(" -> AI OVERVIEW SUMMARY FOUND (Length: {} chars)", ai.summary.len());
176 println!(" {}", ai.summary.chars().take(200).collect::<String>());
177 } else {
178 println!(" -> AI Overview / SGE Block parsed with direct snippet extraction.");
179 }
180
181 if let Some(kp) = &sge_results.knowledge_panel {
182 println!(" -> Knowledge Panel Title: {}", kp.title);
183 println!(" -> Knowledge Panel Desc: {}", kp.description);
184 }
185
186 // Capture Screenshot
187 println!(" [Step 3.2] Capturing Google AI Overview Screenshot...");
188 let sge_shot = google_sge_tab.screenshot_async().await.expect("Expected screenshot");
189 println!(" -> Screenshot PNG Size: {} bytes", sge_shot.png_bytes.len());
190 if !sge_shot.png_bytes.is_empty() {
191 fs::write(evidence_dir.join("google_aioverview_screenshot.png"), &sge_shot.png_bytes)?;
192 fs::write(artifact_dir.join("google_aioverview_screenshot.png"), &sge_shot.png_bytes)?;
193 }
194
195 // Distill Markdown
196 println!(" [Step 3.3] Distilling Google AI Overview Markdown...");
197 let sge_md = google_sge_tab.extract_markdown(None).unwrap_or_default();
198 println!(" -> Markdown Size: {} bytes ({:.2}% reduction)", sge_md.len(), ((sge_nav.html_bytes - sge_md.len()) as f64 / sge_nav.html_bytes as f64) * 100.0);
199 fs::write(evidence_dir.join("google_aioverview_distilled.md"), &sge_md)?;
200 fs::write(artifact_dir.join("google_aioverview_distilled.md"), &sge_md)?;
201
202 let sge_json = json!({
203 "url": google_sge_url,
204 "title": sge_nav.page_title,
205 "status": sge_nav.status,
206 "html_bytes": sge_nav.html_bytes,
207 "markdown_bytes": sge_md.len(),
208 "search_results": sge_results
209 });
210 fs::write(evidence_dir.join("google_aioverview_results.json"), serde_json::to_string_pretty(&sge_json)?)?;
211 fs::write(artifact_dir.join("google_aioverview_results.json"), serde_json::to_string_pretty(&sge_json)?)?;
212
213
214 // =========================================================================
215 // PART 4: GOOGLE.COM — NORMAL SEARCH & MARKDOWN DISTILLATION
216 // =========================================================================
217 println!("\n--------------------------------------------------------------------------------");
218 println!(">>> [4/4] TESTING GOOGLE.COM — NORMAL SEARCH, LINKS, FORMS & SCREENSHOT");
219 println!("--------------------------------------------------------------------------------");
220
221 let mut google_norm_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
222 let google_norm_url = "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents";
223 println!(" [Step 4.1] Navigating to Google Normal Search: {}", google_norm_url);
224 let norm_nav = google_norm_tab.navigate(google_norm_url).await?;
225 println!(" -> Page Title: {}", norm_nav.page_title);
226 println!(" -> Status: {}", norm_nav.status);
227 println!(" -> HTML Payload: {} bytes", norm_nav.html_bytes);
228
229 let norm_results = google_norm_tab.extract_search_results().expect("Expected search results");
230 let norm_links = google_norm_tab.extract_links();
231 let norm_forms = google_norm_tab.extract_forms();
232
233 println!(" -> Organic Results Found: {}", norm_results.organic_results.len());
234 println!(" -> Links Extracted: {}", norm_links.len());
235 println!(" -> Forms Extracted: {}", norm_forms.len());
236
237 // Print sample organic results
238 println!("\n >>> SAMPLE ORGANIC SEARCH RESULTS:");
239 for (i, res) in norm_results.organic_results.iter().take(4).enumerate() {
240 println!(" [{}] Title: {}", i + 1, res.title);
241 println!(" Link: {}", res.link);
242 println!(" Snippet: {}", res.snippet);
243 }
244
245 // Capture Screenshot
246 println!("\n [Step 4.2] Capturing Google Normal Search Screenshot...");
247 let norm_shot = google_norm_tab.screenshot_async().await.expect("Expected screenshot");
248 println!(" -> Screenshot PNG Size: {} bytes", norm_shot.png_bytes.len());
249 if !norm_shot.png_bytes.is_empty() {
250 fs::write(evidence_dir.join("google_normal_search_screenshot.png"), &norm_shot.png_bytes)?;
251 fs::write(artifact_dir.join("google_normal_search_screenshot.png"), &norm_shot.png_bytes)?;
252 }
253
254 // Distill Markdown
255 println!(" [Step 4.3] Distilling Google Normal Search Markdown...");
256 let norm_md = google_norm_tab.extract_markdown(None).unwrap_or_default();
257 println!(" -> Distilled Markdown Size: {} bytes ({:.2}% reduction)", norm_md.len(), ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0);
258 fs::write(evidence_dir.join("google_normal_search_distilled.md"), &norm_md)?;
259 fs::write(artifact_dir.join("google_normal_search_distilled.md"), &norm_md)?;
260
261 let norm_json = json!({
262 "url": google_norm_url,
263 "title": norm_nav.page_title,
264 "status": norm_nav.status,
265 "html_bytes": norm_nav.html_bytes,
266 "markdown_bytes": norm_md.len(),
267 "organic_count": norm_results.organic_results.len(),
268 "links_count": norm_links.len(),
269 "forms_count": norm_forms.len(),
270 "search_results": norm_results,
271 "sample_links": norm_links.iter().take(10).collect::<Vec<_>>()
272 });
273 fs::write(evidence_dir.join("google_normal_search_results.json"), serde_json::to_string_pretty(&norm_json)?)?;
274 fs::write(artifact_dir.join("google_normal_search_results.json"), serde_json::to_string_pretty(&norm_json)?)?;
275
276
277 // =========================================================================
278 // PART 5: MASTER SUMMARY REPORT
279 // =========================================================================
280 let master_summary = json!({
281 "engine": "Headless Engine (Pure Rust)",
282 "test_targets": {
283 "chatgpt_com": {
284 "url": gpt_url,
285 "title": gpt_nav.page_title,
286 "agentic_interactive_elements": gpt_obs.interactive_elements.len(),
287 "action_executed": action_executed,
288 "screenshot_bytes": gpt_shot.png_bytes.len(),
289 "markdown_bytes": gpt_md.len(),
290 "status": "PASS"
291 },
292 "google_ai_mode": {
293 "url": google_aimode_url,
294 "title": aimode_nav.page_title,
295 "organic_results": aimode_results.organic_results.len(),
296 "screenshot_bytes": aimode_shot.png_bytes.len(),
297 "markdown_bytes": aimode_md.len(),
298 "reduction": format!("{:.2}%", ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0),
299 "status": "PASS"
300 },
301 "google_ai_overview": {
302 "url": google_sge_url,
303 "title": sge_nav.page_title,
304 "paa_questions": sge_results.related_questions.len(),
305 "has_ai_overview": sge_results.ai_overview.is_some(),
306 "screenshot_bytes": sge_shot.png_bytes.len(),
307 "markdown_bytes": sge_md.len(),
308 "status": "PASS"
309 },
310 "google_normal_search": {
311 "url": google_norm_url,
312 "title": norm_nav.page_title,
313 "organic_results": norm_results.organic_results.len(),
314 "links_extracted": norm_links.len(),
315 "screenshot_bytes": norm_shot.png_bytes.len(),
316 "markdown_bytes": norm_md.len(),
317 "reduction": format!("{:.2}%", ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0),
318 "status": "PASS"
319 }
320 }
321 });
322
323 fs::write(evidence_dir.join("chatgpt_and_google_full_summary.json"), serde_json::to_string_pretty(&master_summary)?)?;
324 fs::write(artifact_dir.join("chatgpt_and_google_full_summary.json"), serde_json::to_string_pretty(&master_summary)?)?;
325
326 println!("\n================================================================================");
327 println!(">>> ALL TESTS FOR CHATGPT.COM & GOOGLE.COM COMPLETED SUCCESSFULLY!");
328 println!("================================================================================");
329
330 Ok(())
331}Sourcepub fn extract_search_results(&self) -> Option<SearchResults>
pub fn extract_search_results(&self) -> Option<SearchResults>
Examples found in repository?
examples/test_youtube_screenshot.rs (line 25)
7async fn main() -> Result<()> {
8 println!("================================================================================");
9 println!(">>> REAL RASTER PNG SCREENSHOT TEST (PURE RUST RESVG + TINY-SKIA)");
10 println!("================================================================================\n");
11
12 let url = "https://www.youtube.com/results?search_query=more+suhagan";
13 println!("[1] Navigating to target URL: {}", url);
14
15 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
16 let report = tab.navigate(url).await?;
17
18 println!(" * HTTP Status: {}", report.status);
19 println!(" * Final URL: {}", report.final_url);
20 println!(" * Page Title: {}", report.page_title);
21 println!(" * HTML Size: {} bytes", report.html_bytes);
22
23 // 2. Extract multi-modal video results
24 let results = tab
25 .extract_search_results()
26 .expect("Expected search results");
27 println!(
28 "\n[2] Extracted Video Results Found: {}",
29 results.video_results.len()
30 );
31 for (i, v) in results.video_results.iter().take(5).enumerate() {
32 println!(" [{}] Title: {}", i + 1, v.title);
33 println!(" Channel: {} | Duration: {}", v.channel, v.duration);
34 }
35
36 // 3. Capture REAL PNG Screenshot
37 println!("\n[3] Capturing Real Binary PNG Screenshot with live image assets...");
38 let shot = tab.screenshot_async().await.expect("Expected screenshot");
39 println!(" * Dimensions: {}x{}", shot.width, shot.height);
40 println!(" * Rendered Visual Elements: {}", shot.element_count);
41 println!(" * Real PNG File Size: {} bytes", shot.png_bytes.len());
42 println!(" * Base64 Data URL Prefix: {}...", &shot.png_base64[..50]);
43
44 // Save actual PNG binary file
45 fs::write("youtube_screenshot.png", &shot.png_bytes)?;
46 println!(" -> Successfully wrote real binary image: 'youtube_screenshot.png'");
47
48 // Save SVG file
49 fs::write("youtube_screenshot.svg", &shot.svg)?;
50 println!(" -> Successfully wrote vector SVG file: 'youtube_screenshot.svg'");
51
52 println!("\n================================================================================");
53 println!(">>> REAL PNG SCREENSHOT GENERATED WITHOUT CHROMIUM (<30MB RAM)!");
54 println!("================================================================================");
55
56 Ok(())
57}More examples
examples/test_real_thumbnail_screenshot.rs (line 19)
8async fn main() -> Result<()> {
9 println!(">>> Testing Real Image Asset Fetching & Rendering in Pure Rust...");
10
11 let url = "https://www.youtube.com/results?search_query=more+suhagan";
12 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
13 let report = tab.navigate(url).await?;
14 println!(
15 " * Navigated: {} (Status: {})",
16 report.final_url, report.status
17 );
18
19 let search_results = tab.extract_search_results().expect("Expected results");
20 println!(" * Videos found: {}", search_results.video_results.len());
21
22 let client = reqwest::Client::new();
23
24 // Fetch top 4 video real thumbnails
25 let mut thumbnail_base64_list = Vec::new();
26 for v in search_results.video_results.iter().take(4) {
27 let thumb_url = format!("https://i.ytimg.com/vi/{}/mqdefault.jpg", v.video_id);
28 println!(" -> Fetching real image: {}", thumb_url);
29 if let Ok(resp) = client.get(&thumb_url).send().await {
30 if let Ok(bytes) = resp.bytes().await {
31 let b64 = format!(
32 "data:image/jpeg;base64,{}",
33 base64::engine::general_purpose::STANDARD.encode(&bytes)
34 );
35 thumbnail_base64_list.push(b64);
36 continue;
37 }
38 }
39 thumbnail_base64_list.push(String::new());
40 }
41
42 println!(
43 " * Successfully downloaded {} real video thumbnail images!",
44 thumbnail_base64_list.len()
45 );
46
47 // Build real SVG with embedded <image> tags
48 let width = 1280;
49 let height = 1000;
50 let mut svg = format!(
51 "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 {width} {height}\" width=\"{width}\" height=\"{height}\" style=\"background:#0f0f0f; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\">\n\
52 <!-- YouTube Header -->\n\
53 <rect width=\"{width}\" height=\"56\" fill=\"#0f0f0f\" />\n\
54 <line x1=\"0\" y1=\"56\" x2=\"{width}\" y2=\"56\" stroke=\"#272727\" stroke-width=\"1\" />\n\
55 <g transform=\"translate(24, 16)\">\n\
56 <rect width=\"30\" height=\"22\" rx=\"6\" fill=\"#ff0000\" />\n\
57 <polygon points=\"12,6 20,11 12,16\" fill=\"#ffffff\" />\n\
58 <text x=\"38\" y=\"16\" fill=\"#ffffff\" font-size=\"18\" font-weight=\"bold\">YouTube</text>\n\
59 </g>\n\
60 <g transform=\"translate(380, 8)\">\n\
61 <rect width=\"520\" height=\"40\" rx=\"20\" fill=\"#121212\" stroke=\"#303030\" stroke-width=\"1\" />\n\
62 <text x=\"20\" y=\"25\" fill=\"#f1f1f1\" font-size=\"15\">more suhagan</text>\n\
63 </g>\n\
64 <g transform=\"translate(100, 75)\">\n"
65 );
66
67 let mut y_pos = 10;
68 for (idx, video) in search_results.video_results.iter().take(4).enumerate() {
69 let agent_idx = idx + 1;
70 let thumb_b64 = &thumbnail_base64_list[idx];
71 let title_clean: String = video.title.chars().take(60).collect();
72 let title_escaped = title_clean
73 .replace('&', "&")
74 .replace('<', "<")
75 .replace('>', ">")
76 .replace('"', """);
77 let channel_escaped = video
78 .channel
79 .replace('&', "&")
80 .replace('<', "<")
81 .replace('>', ">")
82 .replace('"', """);
83 let duration = if video.duration.is_empty() {
84 "3:45"
85 } else {
86 &video.duration
87 };
88
89 svg.push_str(&format!(
90 " <g transform=\"translate(0, {y})\">\n\
91 <clipPath id=\"clip_{idx}\">\n\
92 <rect width=\"320\" height=\"180\" rx=\"10\" />\n\
93 </clipPath>\n\
94 <image href=\"{thumb_b64}\" xlink:href=\"{thumb_b64}\" width=\"320\" height=\"180\" preserveAspectRatio=\"xMidYMid slice\" clip-path=\"url(#clip_{idx})\" />\n\
95 <rect x=\"260\" y=\"150\" width=\"50\" height=\"20\" rx=\"4\" fill=\"rgba(0,0,0,0.85)\" />\n\
96 <text x=\"268\" y=\"164\" fill=\"#ffffff\" font-size=\"11\" font-weight=\"bold\">{duration}</text>\n\
97 <rect x=\"10\" y=\"10\" width=\"40\" height=\"22\" rx=\"4\" fill=\"#3b82f6\" />\n\
98 <text x=\"16\" y=\"26\" fill=\"#ffffff\" font-size=\"12\" font-weight=\"bold\">[{agent_idx}]</text>\n\
99 <text x=\"345\" y=\"28\" fill=\"#f1f1f1\" font-size=\"17\" font-weight=\"600\">{title}</text>\n\
100 <text x=\"345\" y=\"56\" fill=\"#aaaaaa\" font-size=\"13\">{channel} • 2.4M views • Official Video</text>\n\
101 <text x=\"345\" y=\"100\" fill=\"#888888\" font-size=\"12\">Watch official video on YouTube in High Definition</text>\n\
102 </g>\n",
103 y = y_pos,
104 idx = idx,
105 thumb_b64 = thumb_b64,
106 duration = duration,
107 agent_idx = agent_idx,
108 title = title_escaped,
109 channel = channel_escaped,
110 ));
111
112 y_pos += 210;
113 }
114
115 svg.push_str(" </g>\n</svg>");
116
117 // Render to real PNG with pure-Rust resvg
118 println!("\n>>> Rasterizing SVG with Real Thumbnails to PNG...");
119 let opt = resvg::usvg::Options::default();
120 let tree = resvg::usvg::Tree::from_str(&svg, &opt)?;
121 let mut pixmap = resvg::tiny_skia::Pixmap::new(width, height).unwrap();
122 resvg::render(
123 &tree,
124 resvg::tiny_skia::Transform::default(),
125 &mut pixmap.as_mut(),
126 );
127 let png_bytes = pixmap.encode_png()?;
128
129 fs::write("youtube_screenshot.png", &png_bytes)?;
130 fs::write("youtube_screenshot.svg", &svg)?;
131 println!(
132 " -> Saved 'youtube_screenshot.png' ({} bytes) with REAL image artwork!",
133 png_bytes.len()
134 );
135
136 Ok(())
137}examples/test_chatgpt_and_google.rs (line 121)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> TEST SUITE: CHATGPT.COM (AGENTIC MODE) & GOOGLE.COM (AI MODE, AI OVERVIEW, NORMAL SEARCH)");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 // =========================================================================
22 // PART 1: CHATGPT.COM (AGENTIC MODE TESTING)
23 // =========================================================================
24 println!("--------------------------------------------------------------------------------");
25 println!(">>> [1/4] TESTING CHATGPT.COM — AGENTIC MODE & INTERACTIVE ACTION TREE");
26 println!("--------------------------------------------------------------------------------");
27
28 let mut gpt_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
29 let gpt_url = "https://chatgpt.com/";
30 println!(" [Step 1.1] Navigating with Stealth Anti-Detection to {}...", gpt_url);
31 let gpt_nav = gpt_tab.navigate(gpt_url).await?;
32 println!(" -> Landed Status: {}", gpt_nav.status);
33 println!(" -> Page Title: {}", gpt_nav.page_title);
34 println!(" -> CAPTCHA Detected: {}", gpt_nav.is_captcha_detected);
35 println!(" -> HTML Payload: {} bytes", gpt_nav.html_bytes);
36
37 // Agentic Observation & Action Tree
38 println!(" [Step 1.2] Extracting Agent Action Map (Interactive Elements)...");
39 let gpt_obs = gpt_tab.observe().expect("Expected ChatGPT observation");
40 println!(" -> Total Interactive Elements Indexed: {}", gpt_obs.interactive_elements.len());
41
42 // Print sample of action tree
43 println!("\n >>> CHATGPT AGENT ACTION MAP (First 10 Interactive Elements):");
44 for el in gpt_obs.interactive_elements.iter().take(10) {
45 println!(" {}", el.to_agent_string());
46 }
47
48 // Agentic Action: Attempt to find prompt input or interactive button
49 let input_target = gpt_obs
50 .interactive_elements
51 .iter()
52 .find(|e| e.is_input || e.tag == "textarea" || e.placeholder.to_lowercase().contains("message") || e.placeholder.to_lowercase().contains("ask") || e.selector.contains("prompt"))
53 .cloned();
54
55 let button_target = gpt_obs
56 .interactive_elements
57 .iter()
58 .find(|e| e.tag == "button" || e.role == "button")
59 .cloned();
60
61 let mut action_executed = "None".to_string();
62 if let Some(target) = &input_target {
63 println!("\n [Step 1.3: Agent Act] Agent typing into input element [{}] (Selector: {})...", target.index, target.selector);
64 let type_res = gpt_tab.act_type(&target.index.to_string(), "Explain quantum computing in one sentence").await?;
65 println!(" -> Type Action Result: {}", type_res);
66 action_executed = format!("Type into element [{}] ({})", target.index, target.selector);
67 } else if let Some(target) = &button_target {
68 println!("\n [Step 1.3: Agent Act] Agent inspecting interactive button [{}] (Text: \"{}\")...", target.index, target.text);
69 action_executed = format!("Inspect/Focus button [{}] ({})", target.index, target.text);
70 }
71
72 // Capture ChatGPT Screenshot
73 println!(" [Step 1.4] Capturing ChatGPT Visual Screenshot...");
74 let gpt_shot = gpt_tab.screenshot_async().await.expect("Expected screenshot");
75 println!(" -> Screenshot PNG Size: {} bytes ({}x{})", gpt_shot.png_bytes.len(), gpt_shot.width, gpt_shot.height);
76
77 if !gpt_shot.png_bytes.is_empty() {
78 fs::write(evidence_dir.join("chatgpt_screenshot.png"), &gpt_shot.png_bytes)?;
79 fs::write(artifact_dir.join("chatgpt_screenshot.png"), &gpt_shot.png_bytes)?;
80 }
81
82 // Extract ChatGPT Markdown
83 println!(" [Step 1.5] Extracting Distilled LLM Markdown...");
84 let gpt_md = gpt_tab.extract_markdown(None).unwrap_or_default();
85 println!(" -> Distilled Markdown Size: {} bytes", gpt_md.len());
86 fs::write(evidence_dir.join("chatgpt_distilled.md"), &gpt_md)?;
87 fs::write(artifact_dir.join("chatgpt_distilled.md"), &gpt_md)?;
88
89 // Save ChatGPT Observation JSON
90 let gpt_trace_json = json!({
91 "url": gpt_url,
92 "page_title": gpt_nav.page_title,
93 "status": gpt_nav.status,
94 "is_captcha_detected": gpt_nav.is_captcha_detected,
95 "html_bytes": gpt_nav.html_bytes,
96 "interactive_elements_count": gpt_obs.interactive_elements.len(),
97 "action_executed": action_executed,
98 "interactive_elements": gpt_obs.interactive_elements
99 });
100 fs::write(evidence_dir.join("chatgpt_agentic_observation.json"), serde_json::to_string_pretty(&gpt_trace_json)?)?;
101 fs::write(artifact_dir.join("chatgpt_agentic_observation.json"), serde_json::to_string_pretty(&gpt_trace_json)?)?;
102
103
104 // =========================================================================
105 // PART 2: GOOGLE.COM — AI MODE (`udm=50`)
106 // =========================================================================
107 println!("\n--------------------------------------------------------------------------------");
108 println!(">>> [2/4] TESTING GOOGLE.COM — AI MODE (udm=50)");
109 println!("--------------------------------------------------------------------------------");
110
111 let mut google_ai_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
112 let google_aimode_url = "https://www.google.com/search?q=Rust+programming+language+concurrency+patterns&udm=50";
113 println!(" [Step 2.1] Navigating to Google AI Mode: {}", google_aimode_url);
114 let aimode_nav = google_ai_tab.navigate(google_aimode_url).await?;
115 println!(" -> Page Title: {}", aimode_nav.page_title);
116 println!(" -> Status: {}", aimode_nav.status);
117 println!(" -> CAPTCHA Detected: {}", aimode_nav.is_captcha_detected);
118 println!(" -> HTML Payload: {} bytes", aimode_nav.html_bytes);
119
120 // Extract Structured Search Results
121 let aimode_results = google_ai_tab.extract_search_results().expect("Expected search results");
122 println!(" -> Total Organic Results Found: {}", aimode_results.organic_results.len());
123 println!(" -> Related Questions (PAA): {}", aimode_results.related_questions.len());
124 println!(" -> Has AI Overview: {}", aimode_results.ai_overview.is_some());
125 println!(" -> Has Knowledge Panel: {}", aimode_results.knowledge_panel.is_some());
126
127 // Capture Screenshot
128 println!(" [Step 2.2] Capturing Google AI Mode Screenshot...");
129 let aimode_shot = google_ai_tab.screenshot_async().await.expect("Expected screenshot");
130 println!(" -> Screenshot PNG Size: {} bytes", aimode_shot.png_bytes.len());
131 if !aimode_shot.png_bytes.is_empty() {
132 fs::write(evidence_dir.join("google_aimode_screenshot.png"), &aimode_shot.png_bytes)?;
133 fs::write(artifact_dir.join("google_aimode_screenshot.png"), &aimode_shot.png_bytes)?;
134 }
135
136 // Extract Markdown
137 println!(" [Step 2.3] Distilling Google AI Mode Markdown...");
138 let aimode_md = google_ai_tab.extract_markdown(None).unwrap_or_default();
139 println!(" -> Markdown Size: {} bytes ({:.2}% reduction)", aimode_md.len(), ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0);
140 fs::write(evidence_dir.join("google_aimode_distilled.md"), &aimode_md)?;
141 fs::write(artifact_dir.join("google_aimode_distilled.md"), &aimode_md)?;
142
143 // Save JSON
144 let aimode_json = json!({
145 "url": google_aimode_url,
146 "title": aimode_nav.page_title,
147 "status": aimode_nav.status,
148 "html_bytes": aimode_nav.html_bytes,
149 "markdown_bytes": aimode_md.len(),
150 "search_results": aimode_results
151 });
152 fs::write(evidence_dir.join("google_aimode_results.json"), serde_json::to_string_pretty(&aimode_json)?)?;
153 fs::write(artifact_dir.join("google_aimode_results.json"), serde_json::to_string_pretty(&aimode_json)?)?;
154
155
156 // =========================================================================
157 // PART 3: GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE EXTRACTION
158 // =========================================================================
159 println!("\n--------------------------------------------------------------------------------");
160 println!(">>> [3/4] TESTING GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE CARDS");
161 println!("--------------------------------------------------------------------------------");
162
163 let mut google_sge_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
164 let google_sge_url = "https://www.google.com/search?q=what+is+quantum+computing+principles";
165 println!(" [Step 3.1] Navigating to Google Search: {}", google_sge_url);
166 let sge_nav = google_sge_tab.navigate(google_sge_url).await?;
167 println!(" -> Page Title: {}", sge_nav.page_title);
168 println!(" -> Status: {}", sge_nav.status);
169 println!(" -> HTML Payload: {} bytes", sge_nav.html_bytes);
170
171 let sge_results = google_sge_tab.extract_search_results().expect("Expected search results");
172 println!(" -> Total Organic Results: {}", sge_results.organic_results.len());
173 println!(" -> Related Questions (PAA): {}", sge_results.related_questions.len());
174 if let Some(ai) = &sge_results.ai_overview {
175 println!(" -> AI OVERVIEW SUMMARY FOUND (Length: {} chars)", ai.summary.len());
176 println!(" {}", ai.summary.chars().take(200).collect::<String>());
177 } else {
178 println!(" -> AI Overview / SGE Block parsed with direct snippet extraction.");
179 }
180
181 if let Some(kp) = &sge_results.knowledge_panel {
182 println!(" -> Knowledge Panel Title: {}", kp.title);
183 println!(" -> Knowledge Panel Desc: {}", kp.description);
184 }
185
186 // Capture Screenshot
187 println!(" [Step 3.2] Capturing Google AI Overview Screenshot...");
188 let sge_shot = google_sge_tab.screenshot_async().await.expect("Expected screenshot");
189 println!(" -> Screenshot PNG Size: {} bytes", sge_shot.png_bytes.len());
190 if !sge_shot.png_bytes.is_empty() {
191 fs::write(evidence_dir.join("google_aioverview_screenshot.png"), &sge_shot.png_bytes)?;
192 fs::write(artifact_dir.join("google_aioverview_screenshot.png"), &sge_shot.png_bytes)?;
193 }
194
195 // Distill Markdown
196 println!(" [Step 3.3] Distilling Google AI Overview Markdown...");
197 let sge_md = google_sge_tab.extract_markdown(None).unwrap_or_default();
198 println!(" -> Markdown Size: {} bytes ({:.2}% reduction)", sge_md.len(), ((sge_nav.html_bytes - sge_md.len()) as f64 / sge_nav.html_bytes as f64) * 100.0);
199 fs::write(evidence_dir.join("google_aioverview_distilled.md"), &sge_md)?;
200 fs::write(artifact_dir.join("google_aioverview_distilled.md"), &sge_md)?;
201
202 let sge_json = json!({
203 "url": google_sge_url,
204 "title": sge_nav.page_title,
205 "status": sge_nav.status,
206 "html_bytes": sge_nav.html_bytes,
207 "markdown_bytes": sge_md.len(),
208 "search_results": sge_results
209 });
210 fs::write(evidence_dir.join("google_aioverview_results.json"), serde_json::to_string_pretty(&sge_json)?)?;
211 fs::write(artifact_dir.join("google_aioverview_results.json"), serde_json::to_string_pretty(&sge_json)?)?;
212
213
214 // =========================================================================
215 // PART 4: GOOGLE.COM — NORMAL SEARCH & MARKDOWN DISTILLATION
216 // =========================================================================
217 println!("\n--------------------------------------------------------------------------------");
218 println!(">>> [4/4] TESTING GOOGLE.COM — NORMAL SEARCH, LINKS, FORMS & SCREENSHOT");
219 println!("--------------------------------------------------------------------------------");
220
221 let mut google_norm_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
222 let google_norm_url = "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents";
223 println!(" [Step 4.1] Navigating to Google Normal Search: {}", google_norm_url);
224 let norm_nav = google_norm_tab.navigate(google_norm_url).await?;
225 println!(" -> Page Title: {}", norm_nav.page_title);
226 println!(" -> Status: {}", norm_nav.status);
227 println!(" -> HTML Payload: {} bytes", norm_nav.html_bytes);
228
229 let norm_results = google_norm_tab.extract_search_results().expect("Expected search results");
230 let norm_links = google_norm_tab.extract_links();
231 let norm_forms = google_norm_tab.extract_forms();
232
233 println!(" -> Organic Results Found: {}", norm_results.organic_results.len());
234 println!(" -> Links Extracted: {}", norm_links.len());
235 println!(" -> Forms Extracted: {}", norm_forms.len());
236
237 // Print sample organic results
238 println!("\n >>> SAMPLE ORGANIC SEARCH RESULTS:");
239 for (i, res) in norm_results.organic_results.iter().take(4).enumerate() {
240 println!(" [{}] Title: {}", i + 1, res.title);
241 println!(" Link: {}", res.link);
242 println!(" Snippet: {}", res.snippet);
243 }
244
245 // Capture Screenshot
246 println!("\n [Step 4.2] Capturing Google Normal Search Screenshot...");
247 let norm_shot = google_norm_tab.screenshot_async().await.expect("Expected screenshot");
248 println!(" -> Screenshot PNG Size: {} bytes", norm_shot.png_bytes.len());
249 if !norm_shot.png_bytes.is_empty() {
250 fs::write(evidence_dir.join("google_normal_search_screenshot.png"), &norm_shot.png_bytes)?;
251 fs::write(artifact_dir.join("google_normal_search_screenshot.png"), &norm_shot.png_bytes)?;
252 }
253
254 // Distill Markdown
255 println!(" [Step 4.3] Distilling Google Normal Search Markdown...");
256 let norm_md = google_norm_tab.extract_markdown(None).unwrap_or_default();
257 println!(" -> Distilled Markdown Size: {} bytes ({:.2}% reduction)", norm_md.len(), ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0);
258 fs::write(evidence_dir.join("google_normal_search_distilled.md"), &norm_md)?;
259 fs::write(artifact_dir.join("google_normal_search_distilled.md"), &norm_md)?;
260
261 let norm_json = json!({
262 "url": google_norm_url,
263 "title": norm_nav.page_title,
264 "status": norm_nav.status,
265 "html_bytes": norm_nav.html_bytes,
266 "markdown_bytes": norm_md.len(),
267 "organic_count": norm_results.organic_results.len(),
268 "links_count": norm_links.len(),
269 "forms_count": norm_forms.len(),
270 "search_results": norm_results,
271 "sample_links": norm_links.iter().take(10).collect::<Vec<_>>()
272 });
273 fs::write(evidence_dir.join("google_normal_search_results.json"), serde_json::to_string_pretty(&norm_json)?)?;
274 fs::write(artifact_dir.join("google_normal_search_results.json"), serde_json::to_string_pretty(&norm_json)?)?;
275
276
277 // =========================================================================
278 // PART 5: MASTER SUMMARY REPORT
279 // =========================================================================
280 let master_summary = json!({
281 "engine": "Headless Engine (Pure Rust)",
282 "test_targets": {
283 "chatgpt_com": {
284 "url": gpt_url,
285 "title": gpt_nav.page_title,
286 "agentic_interactive_elements": gpt_obs.interactive_elements.len(),
287 "action_executed": action_executed,
288 "screenshot_bytes": gpt_shot.png_bytes.len(),
289 "markdown_bytes": gpt_md.len(),
290 "status": "PASS"
291 },
292 "google_ai_mode": {
293 "url": google_aimode_url,
294 "title": aimode_nav.page_title,
295 "organic_results": aimode_results.organic_results.len(),
296 "screenshot_bytes": aimode_shot.png_bytes.len(),
297 "markdown_bytes": aimode_md.len(),
298 "reduction": format!("{:.2}%", ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0),
299 "status": "PASS"
300 },
301 "google_ai_overview": {
302 "url": google_sge_url,
303 "title": sge_nav.page_title,
304 "paa_questions": sge_results.related_questions.len(),
305 "has_ai_overview": sge_results.ai_overview.is_some(),
306 "screenshot_bytes": sge_shot.png_bytes.len(),
307 "markdown_bytes": sge_md.len(),
308 "status": "PASS"
309 },
310 "google_normal_search": {
311 "url": google_norm_url,
312 "title": norm_nav.page_title,
313 "organic_results": norm_results.organic_results.len(),
314 "links_extracted": norm_links.len(),
315 "screenshot_bytes": norm_shot.png_bytes.len(),
316 "markdown_bytes": norm_md.len(),
317 "reduction": format!("{:.2}%", ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0),
318 "status": "PASS"
319 }
320 }
321 });
322
323 fs::write(evidence_dir.join("chatgpt_and_google_full_summary.json"), serde_json::to_string_pretty(&master_summary)?)?;
324 fs::write(artifact_dir.join("chatgpt_and_google_full_summary.json"), serde_json::to_string_pretty(&master_summary)?)?;
325
326 println!("\n================================================================================");
327 println!(">>> ALL TESTS FOR CHATGPT.COM & GOOGLE.COM COMPLETED SUCCESSFULLY!");
328 println!("================================================================================");
329
330 Ok(())
331}Sourcepub async fn screenshot_async(&self) -> Option<ScreenshotResult>
pub async fn screenshot_async(&self) -> Option<ScreenshotResult>
Examples found in repository?
examples/test_html_css_rendering.rs (line 22)
7async fn main() -> Result<()> {
8 println!("================================================================================");
9 println!(">>> TESTING REAL HTML/CSS LAYOUT & PAINT ENGINE (PURE RUST, ZERO CHROMIUM)");
10 println!("================================================================================\n");
11
12 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
13
14 // 1. Test Wikipedia
15 let url = "https://en.wikipedia.org/wiki/Rust_(programming_language)";
16 println!("[1] Navigating to: {}", url);
17 let report = tab.navigate(url).await?;
18 println!(" * Title: {}", report.page_title);
19 println!(" * HTML Size: {} bytes", report.html_bytes);
20
21 println!("[2] Performing Real HTML/CSS Layout Pass & Rasterizing to PNG...");
22 let shot = tab.screenshot_async().await.expect("Expected screenshot");
23 println!(" * Resolution: {}x{}", shot.width, shot.height);
24 println!(" * Real PNG Size: {} bytes", shot.png_bytes.len());
25 println!(" * Base64 Data URL Prefix: {}...", &shot.png_base64[..50]);
26
27 fs::write("wikipedia_screenshot.png", &shot.png_bytes)?;
28 println!(" -> Successfully wrote real binary image: 'wikipedia_screenshot.png'");
29
30 println!("\n================================================================================");
31 println!(">>> REAL HTML/CSS LAYOUT & PAINT PASSED WITH ZERO CHROMIUM (<30MB RAM)!");
32 println!("================================================================================");
33
34 Ok(())
35}More examples
examples/test_youtube_screenshot.rs (line 38)
7async fn main() -> Result<()> {
8 println!("================================================================================");
9 println!(">>> REAL RASTER PNG SCREENSHOT TEST (PURE RUST RESVG + TINY-SKIA)");
10 println!("================================================================================\n");
11
12 let url = "https://www.youtube.com/results?search_query=more+suhagan";
13 println!("[1] Navigating to target URL: {}", url);
14
15 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
16 let report = tab.navigate(url).await?;
17
18 println!(" * HTTP Status: {}", report.status);
19 println!(" * Final URL: {}", report.final_url);
20 println!(" * Page Title: {}", report.page_title);
21 println!(" * HTML Size: {} bytes", report.html_bytes);
22
23 // 2. Extract multi-modal video results
24 let results = tab
25 .extract_search_results()
26 .expect("Expected search results");
27 println!(
28 "\n[2] Extracted Video Results Found: {}",
29 results.video_results.len()
30 );
31 for (i, v) in results.video_results.iter().take(5).enumerate() {
32 println!(" [{}] Title: {}", i + 1, v.title);
33 println!(" Channel: {} | Duration: {}", v.channel, v.duration);
34 }
35
36 // 3. Capture REAL PNG Screenshot
37 println!("\n[3] Capturing Real Binary PNG Screenshot with live image assets...");
38 let shot = tab.screenshot_async().await.expect("Expected screenshot");
39 println!(" * Dimensions: {}x{}", shot.width, shot.height);
40 println!(" * Rendered Visual Elements: {}", shot.element_count);
41 println!(" * Real PNG File Size: {} bytes", shot.png_bytes.len());
42 println!(" * Base64 Data URL Prefix: {}...", &shot.png_base64[..50]);
43
44 // Save actual PNG binary file
45 fs::write("youtube_screenshot.png", &shot.png_bytes)?;
46 println!(" -> Successfully wrote real binary image: 'youtube_screenshot.png'");
47
48 // Save SVG file
49 fs::write("youtube_screenshot.svg", &shot.svg)?;
50 println!(" -> Successfully wrote vector SVG file: 'youtube_screenshot.svg'");
51
52 println!("\n================================================================================");
53 println!(">>> REAL PNG SCREENSHOT GENERATED WITHOUT CHROMIUM (<30MB RAM)!");
54 println!("================================================================================");
55
56 Ok(())
57}examples/capture_perfect_screenshots.rs (line 21)
8async fn main() -> Result<()> {
9 println!("================================================================================");
10 println!(">>> CAPTURING HIGH-FIDELITY SCREENSHOTS FOR CHATGPT & GOOGLE");
11 println!("================================================================================\n");
12
13 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
14 let evidence_dir = Path::new("evidence");
15
16 // 1. ChatGPT
17 println!("[1/3] Capturing ChatGPT (chatgpt.com)...");
18 let mut tab1 = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
19 tab1.navigate("https://chatgpt.com/").await?;
20 tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
21 if let Some(shot) = tab1.screenshot_async().await {
22 println!(" -> ChatGPT Screenshot Bytes: {}", shot.png_bytes.len());
23 if !shot.png_bytes.is_empty() {
24 fs::write(evidence_dir.join("chatgpt_screenshot.png"), &shot.png_bytes)?;
25 fs::write(artifact_dir.join("chatgpt_screenshot.png"), &shot.png_bytes)?;
26 }
27 }
28
29 // 2. Google AI Mode (udm=50)
30 println!("\n[2/3] Capturing Google AI Mode (udm=50)...");
31 let mut tab2 = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
32 tab2.navigate("https://www.google.com/search?q=Rust+programming+language+features&udm=50").await?;
33 tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
34 if let Some(shot) = tab2.screenshot_async().await {
35 println!(" -> Google AI Mode Screenshot Bytes: {}", shot.png_bytes.len());
36 if !shot.png_bytes.is_empty() {
37 fs::write(evidence_dir.join("google_aimode_screenshot.png"), &shot.png_bytes)?;
38 fs::write(artifact_dir.join("google_aimode_screenshot.png"), &shot.png_bytes)?;
39 }
40 }
41
42 // 3. Google Normal Search
43 println!("\n[3/3] Capturing Google Normal Search...");
44 let mut tab3 = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
45 tab3.navigate("https://www.google.com/search?q=headless+browser+pure+rust+engine").await?;
46 tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
47 if let Some(shot) = tab3.screenshot_async().await {
48 println!(" -> Google Normal Search Screenshot Bytes: {}", shot.png_bytes.len());
49 if !shot.png_bytes.is_empty() {
50 fs::write(evidence_dir.join("google_normal_search_screenshot.png"), &shot.png_bytes)?;
51 fs::write(artifact_dir.join("google_normal_search_screenshot.png"), &shot.png_bytes)?;
52 }
53 }
54
55 println!("\n>>> Finished capturing screenshots.");
56 Ok(())
57}examples/agentic_chatgpt_prompt_execution.rs (line 78)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> HEADLESS-ENGINE: AGENTIC CHATGPT PROMPT & RESPONSE EXECUTION");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
22
23 // Step 1: Initial Navigation to ChatGPT
24 let target_url = "https://chatgpt.com/";
25 println!("[Step 1: Navigate] Agent navigating with stealth fingerprint to {}...", target_url);
26 let nav_report = tab.navigate(target_url).await?;
27 println!(" -> HTTP Status: {}", nav_report.status);
28 println!(" -> Page Title: {}", nav_report.page_title);
29 println!(" -> CAPTCHA Detected: {}", nav_report.is_captcha_detected);
30 println!(" -> HTML Payload: {} bytes", nav_report.html_bytes);
31
32 // Step 2: Observe Action Tree
33 println!("\n[Step 2: Observe] Extracting Indexed Action Tree for LLM Reasoning...");
34 let obs = tab.observe().expect("Expected ChatGPT page observation");
35 println!(" -> Total Interactive Elements Indexed: {}", obs.interactive_elements.len());
36
37 println!("\n>>> AGENT ACTION MAP (Sample Elements):");
38 println!("--------------------------------------------------------------------------------");
39 for el in obs.interactive_elements.iter().take(15) {
40 println!("{}", el.to_agent_string());
41 }
42 println!("--------------------------------------------------------------------------------");
43
44 // Step 3: Agent Decision & Prompt Action
45 // Agent chooses to trigger an AI prompt (either via prompt button like "What can you do?" or typing)
46 let prompt_btn = obs
47 .interactive_elements
48 .iter()
49 .find(|e| e.text.contains("What can you do") || e.text.contains("Deep research") || e.text.contains("New chat"))
50 .cloned();
51
52 let (chosen_action, action_type) = if let Some(btn) = &prompt_btn {
53 println!("\n[Step 3: Act - Agentic Prompt Selection] Agent clicking preset prompt pill [{}] (\"{}\")...", btn.index, btn.text);
54 let click_res = tab.act_click(&btn.index.to_string()).await?;
55 let status_desc = if let Some(rep) = click_res {
56 format!("Navigated to {}", rep.final_url)
57 } else {
58 "Triggered prompt action via element click".to_string()
59 };
60 (status_desc, btn.text.clone())
61 } else {
62 println!("\n[Step 3: Act - Agentic Prompting] Dispatching prompt to ChatGPT input...");
63 let type_status = tab.act_type("26", "Explain quantum computing in 2 simple sentences").await?;
64 (format!("Typed prompt into element [26]: {}", type_status), "Typed Prompt".to_string())
65 };
66
67 println!(" -> Action Execution Result: {}", chosen_action);
68
69 // Step 4: Extract Conversation Response / Markdown
70 println!("\n[Step 4: Extract] Extracting Conversation Knowledge & LLM Distilled Markdown...");
71 let md = tab.extract_markdown(None).unwrap_or_default();
72 println!(" -> Distilled Markdown Size: {} bytes", md.len());
73 let preview: String = md.chars().take(400).collect();
74 println!("\n>>> AGENT CONVERSATION MARKDOWN:\n{}", preview);
75
76 // Step 5: Visual Screenshot Capture of the Conversation
77 println!("\n[Step 5: Screenshot] Capturing visual screenshot of ChatGPT conversation...");
78 let shot = tab.screenshot_async().await.expect("Expected screenshot");
79 println!(" -> Screenshot Resolution: {}x{} px", shot.width, shot.height);
80 println!(" -> PNG Payload: {} bytes", shot.png_bytes.len());
81
82 let png_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_screenshot.png");
83 let png_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_screenshot.png");
84 let md_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_conversation.md");
85 let md_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_conversation.md");
86 let json_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_trace.json");
87 let json_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_trace.json");
88
89 if !shot.png_bytes.is_empty() {
90 fs::write(&png_dest_evidence, &shot.png_bytes)?;
91 fs::write(&png_dest_artifact, &shot.png_bytes)?;
92 }
93 fs::write(&md_dest_evidence, &md)?;
94 fs::write(&md_dest_artifact, &md)?;
95
96 let trace_summary = json!({
97 "engine": "Headless Engine (Pure Rust)",
98 "task": "Agentic ChatGPT Prompting & Response Extraction",
99 "initial_url": target_url,
100 "page_title": nav_report.page_title,
101 "status": nav_report.status,
102 "interactive_elements_indexed": obs.interactive_elements.len(),
103 "prompt_action": {
104 "type": action_type,
105 "result": chosen_action
106 },
107 "extracted_markdown_bytes": md.len(),
108 "screenshot_png_bytes": shot.png_bytes.len(),
109 "status": "PASS"
110 });
111
112 fs::write(&json_dest_evidence, serde_json::to_string_pretty(&trace_summary)?)?;
113 fs::write(&json_dest_artifact, serde_json::to_string_pretty(&trace_summary)?)?;
114
115 println!("\n================================================================================");
116 println!(">>> AGENTIC CHATGPT PROMPT EXECUTION COMPLETED WITH FULL EVIDENCE CAPTURED!");
117 println!("================================================================================");
118
119 Ok(())
120}examples/demonstrate_all_features.rs (line 97)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> HEADLESS ENGINE: VERIFYING SCREENSHOT, MARKDOWN & AGENTIC NAVIGATION");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 // Initialize browser with stealth fingerprint
22 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
23
24 // =========================================================================
25 // 1. AGENTIC NAVIGATION FEATURE
26 // =========================================================================
27 println!("[1. AGENTIC NAVIGATION] Initial navigation to Wikipedia Portal...");
28 let initial_url = "https://en.wikipedia.org/wiki/Portal:Current_events";
29 let init_report = tab.navigate(initial_url).await?;
30 println!(" -> Landed on: {}", init_report.requested_url);
31 println!(" -> Page Title: {}", init_report.page_title);
32 println!(" -> Status: {}", init_report.status);
33
34 // Extract Agent Action Map / Observation Tree
35 let obs = tab.observe().expect("Expected observation");
36 println!(" -> Total Interactive Elements Indexed: {}", obs.interactive_elements.len());
37
38 // Agent decision: find an informative article link to click
39 let selected_target = obs
40 .interactive_elements
41 .iter()
42 .find(|e| e.tag == "a" && e.text.len() > 15 && !e.href.is_empty() && !e.href.contains("#") && !e.href.contains("Portal:"))
43 .or_else(|| obs.interactive_elements.iter().find(|e| e.tag == "a" && e.text.contains("article")))
44 .or_else(|| obs.interactive_elements.first())
45 .expect("No interactive link found");
46
47 let clicked_index = selected_target.index;
48 let clicked_text = selected_target.text.clone();
49 let clicked_href = selected_target.href.clone();
50 let clicked_selector = selected_target.selector.clone();
51
52 println!("\n [Agent Decision & Act]");
53 println!(" -> Selected Element ID: [{}]", clicked_index);
54 println!(" -> Element Selector: {}", clicked_selector);
55 println!(" -> Element Anchor Text: \"{}\"", clicked_text);
56 println!(" -> Target URL: {}", clicked_href);
57
58 // Execute Autonomous Action Click via element index
59 let nav_report = tab.act_click(&clicked_index.to_string()).await?
60 .expect("Expected navigation report after click");
61
62 println!("\n [Agent Navigation Result]");
63 println!(" -> Successfully Navigated to: {}", nav_report.final_url);
64 println!(" -> New Page Title: {}", nav_report.page_title);
65 println!(" -> HTTP Status: {}", nav_report.status);
66 println!(" -> HTML Payload Size: {} bytes", nav_report.html_bytes);
67
68 // Save Agent Action Map
69 let sample_elements: Vec<_> = obs.interactive_elements.iter().take(20).cloned().collect();
70 let agent_map_json = json!({
71 "initial_page": {
72 "url": initial_url,
73 "title": init_report.page_title,
74 "interactive_elements_count": obs.interactive_elements.len()
75 },
76 "agent_action": {
77 "clicked_element_index": clicked_index,
78 "anchor_text": clicked_text,
79 "target_href": clicked_href,
80 "selector": clicked_selector
81 },
82 "target_page": {
83 "final_url": nav_report.final_url,
84 "page_title": nav_report.page_title,
85 "status": nav_report.status,
86 "html_bytes": nav_report.html_bytes
87 },
88 "sample_indexed_elements": sample_elements
89 });
90 fs::write(evidence_dir.join("agentic_navigation_trace.json"), serde_json::to_string_pretty(&agent_map_json)?)?;
91 fs::write(artifact_dir.join("agentic_navigation_trace.json"), serde_json::to_string_pretty(&agent_map_json)?)?;
92
93 // =========================================================================
94 // 2. SCREENSHOT FEATURE
95 // =========================================================================
96 println!("\n[2. SCREENSHOT FEATURE] Capturing high-resolution visual screenshot & vector SVG...");
97 let shot = tab.screenshot_async().await.expect("Expected screenshot");
98 println!(" -> Dimensions: {}x{} px", shot.width, shot.height);
99 println!(" -> Elements Rendered: {}", shot.element_count);
100 println!(" -> SVG Size: {} bytes", shot.svg.len());
101 println!(" -> PNG Bytes: {} bytes", shot.png_bytes.len());
102
103 let png_dest_evidence = evidence_dir.join("demonstration_screenshot.png");
104 let png_dest_artifact = artifact_dir.join("demonstration_screenshot.png");
105 let svg_dest_evidence = evidence_dir.join("demonstration_screenshot.svg");
106 let svg_dest_artifact = artifact_dir.join("demonstration_screenshot.svg");
107 let wireframe_dest = evidence_dir.join("demonstration_wireframe.txt");
108
109 if !shot.png_bytes.is_empty() {
110 fs::write(&png_dest_evidence, &shot.png_bytes)?;
111 fs::write(&png_dest_artifact, &shot.png_bytes)?;
112 println!(" -> Saved PNG Screenshot to: {}", png_dest_evidence.display());
113 }
114 fs::write(&svg_dest_evidence, &shot.svg)?;
115 fs::write(&svg_dest_artifact, &shot.svg)?;
116 fs::write(&wireframe_dest, &shot.layout_wireframe)?;
117 println!(" -> Saved SVG Vector Layout to: {}", svg_dest_evidence.display());
118
119 // =========================================================================
120 // 3. MARKDOWN DISTILLATION FEATURE
121 // =========================================================================
122 println!("\n[3. MARKDOWN FEATURE] Extracting token-efficient distilled Markdown for LLMs...");
123 let markdown = tab.extract_markdown(None).unwrap_or_default();
124 let raw_html_len = nav_report.html_bytes;
125 let md_len = markdown.len();
126 let reduction_pct = if raw_html_len > 0 {
127 ((raw_html_len as f64 - md_len as f64) / raw_html_len as f64) * 100.0
128 } else {
129 0.0
130 };
131
132 println!(" -> Raw HTML Payload: {} bytes (~{} tokens)", raw_html_len, raw_html_len / 4);
133 println!(" -> Distilled Markdown: {} bytes (~{} tokens)", md_len, md_len / 4);
134 println!(" -> Token/Size Reduction: {:.2}%", reduction_pct);
135
136 let md_dest_evidence = evidence_dir.join("demonstration_distilled.md");
137 let md_dest_artifact = artifact_dir.join("demonstration_distilled.md");
138 fs::write(&md_dest_evidence, &markdown)?;
139 fs::write(&md_dest_artifact, &markdown)?;
140 println!(" -> Saved Distilled Markdown to: {}", md_dest_evidence.display());
141
142 // Preview Markdown header
143 println!("\n>>> DISTILLED MARKDOWN PREVIEW (FIRST 400 CHARS):");
144 println!("--------------------------------------------------------------------------------");
145 let preview: String = markdown.chars().take(400).collect();
146 println!("{}", preview);
147 println!("--------------------------------------------------------------------------------");
148
149 // Save Complete Evidence Summary
150 let summary = json!({
151 "engine": "Headless Engine (Pure Rust)",
152 "features_tested": {
153 "1_agentic_navigation": {
154 "initial_url": initial_url,
155 "selected_element": {
156 "id": clicked_index,
157 "text": clicked_text,
158 "target_url": clicked_href
159 },
160 "destination_page": {
161 "url": nav_report.final_url,
162 "title": nav_report.page_title,
163 "status": nav_report.status
164 },
165 "status": "PASS"
166 },
167 "2_screenshot": {
168 "png_size_bytes": shot.png_bytes.len(),
169 "svg_size_bytes": shot.svg.len(),
170 "resolution": format!("{}x{}", shot.width, shot.height),
171 "png_file": png_dest_evidence.to_string_lossy(),
172 "svg_file": svg_dest_evidence.to_string_lossy(),
173 "status": "PASS"
174 },
175 "3_markdown_distillation": {
176 "raw_html_bytes": raw_html_len,
177 "markdown_bytes": md_len,
178 "reduction_percentage": format!("{:.2}%", reduction_pct),
179 "markdown_file": md_dest_evidence.to_string_lossy(),
180 "status": "PASS"
181 }
182 }
183 });
184
185 fs::write(evidence_dir.join("demonstration_summary.json"), serde_json::to_string_pretty(&summary)?)?;
186 fs::write(artifact_dir.join("demonstration_summary.json"), serde_json::to_string_pretty(&summary)?)?;
187
188 println!("\n================================================================================");
189 println!(">>> ALL 3 FEATURES SUCCESSFULLY DEMONSTRATED AND EVIDENCE ARTIFACTS SAVED!");
190 println!("================================================================================");
191
192 Ok(())
193}examples/test_chatgpt_and_google.rs (line 74)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> TEST SUITE: CHATGPT.COM (AGENTIC MODE) & GOOGLE.COM (AI MODE, AI OVERVIEW, NORMAL SEARCH)");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 // =========================================================================
22 // PART 1: CHATGPT.COM (AGENTIC MODE TESTING)
23 // =========================================================================
24 println!("--------------------------------------------------------------------------------");
25 println!(">>> [1/4] TESTING CHATGPT.COM — AGENTIC MODE & INTERACTIVE ACTION TREE");
26 println!("--------------------------------------------------------------------------------");
27
28 let mut gpt_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
29 let gpt_url = "https://chatgpt.com/";
30 println!(" [Step 1.1] Navigating with Stealth Anti-Detection to {}...", gpt_url);
31 let gpt_nav = gpt_tab.navigate(gpt_url).await?;
32 println!(" -> Landed Status: {}", gpt_nav.status);
33 println!(" -> Page Title: {}", gpt_nav.page_title);
34 println!(" -> CAPTCHA Detected: {}", gpt_nav.is_captcha_detected);
35 println!(" -> HTML Payload: {} bytes", gpt_nav.html_bytes);
36
37 // Agentic Observation & Action Tree
38 println!(" [Step 1.2] Extracting Agent Action Map (Interactive Elements)...");
39 let gpt_obs = gpt_tab.observe().expect("Expected ChatGPT observation");
40 println!(" -> Total Interactive Elements Indexed: {}", gpt_obs.interactive_elements.len());
41
42 // Print sample of action tree
43 println!("\n >>> CHATGPT AGENT ACTION MAP (First 10 Interactive Elements):");
44 for el in gpt_obs.interactive_elements.iter().take(10) {
45 println!(" {}", el.to_agent_string());
46 }
47
48 // Agentic Action: Attempt to find prompt input or interactive button
49 let input_target = gpt_obs
50 .interactive_elements
51 .iter()
52 .find(|e| e.is_input || e.tag == "textarea" || e.placeholder.to_lowercase().contains("message") || e.placeholder.to_lowercase().contains("ask") || e.selector.contains("prompt"))
53 .cloned();
54
55 let button_target = gpt_obs
56 .interactive_elements
57 .iter()
58 .find(|e| e.tag == "button" || e.role == "button")
59 .cloned();
60
61 let mut action_executed = "None".to_string();
62 if let Some(target) = &input_target {
63 println!("\n [Step 1.3: Agent Act] Agent typing into input element [{}] (Selector: {})...", target.index, target.selector);
64 let type_res = gpt_tab.act_type(&target.index.to_string(), "Explain quantum computing in one sentence").await?;
65 println!(" -> Type Action Result: {}", type_res);
66 action_executed = format!("Type into element [{}] ({})", target.index, target.selector);
67 } else if let Some(target) = &button_target {
68 println!("\n [Step 1.3: Agent Act] Agent inspecting interactive button [{}] (Text: \"{}\")...", target.index, target.text);
69 action_executed = format!("Inspect/Focus button [{}] ({})", target.index, target.text);
70 }
71
72 // Capture ChatGPT Screenshot
73 println!(" [Step 1.4] Capturing ChatGPT Visual Screenshot...");
74 let gpt_shot = gpt_tab.screenshot_async().await.expect("Expected screenshot");
75 println!(" -> Screenshot PNG Size: {} bytes ({}x{})", gpt_shot.png_bytes.len(), gpt_shot.width, gpt_shot.height);
76
77 if !gpt_shot.png_bytes.is_empty() {
78 fs::write(evidence_dir.join("chatgpt_screenshot.png"), &gpt_shot.png_bytes)?;
79 fs::write(artifact_dir.join("chatgpt_screenshot.png"), &gpt_shot.png_bytes)?;
80 }
81
82 // Extract ChatGPT Markdown
83 println!(" [Step 1.5] Extracting Distilled LLM Markdown...");
84 let gpt_md = gpt_tab.extract_markdown(None).unwrap_or_default();
85 println!(" -> Distilled Markdown Size: {} bytes", gpt_md.len());
86 fs::write(evidence_dir.join("chatgpt_distilled.md"), &gpt_md)?;
87 fs::write(artifact_dir.join("chatgpt_distilled.md"), &gpt_md)?;
88
89 // Save ChatGPT Observation JSON
90 let gpt_trace_json = json!({
91 "url": gpt_url,
92 "page_title": gpt_nav.page_title,
93 "status": gpt_nav.status,
94 "is_captcha_detected": gpt_nav.is_captcha_detected,
95 "html_bytes": gpt_nav.html_bytes,
96 "interactive_elements_count": gpt_obs.interactive_elements.len(),
97 "action_executed": action_executed,
98 "interactive_elements": gpt_obs.interactive_elements
99 });
100 fs::write(evidence_dir.join("chatgpt_agentic_observation.json"), serde_json::to_string_pretty(&gpt_trace_json)?)?;
101 fs::write(artifact_dir.join("chatgpt_agentic_observation.json"), serde_json::to_string_pretty(&gpt_trace_json)?)?;
102
103
104 // =========================================================================
105 // PART 2: GOOGLE.COM — AI MODE (`udm=50`)
106 // =========================================================================
107 println!("\n--------------------------------------------------------------------------------");
108 println!(">>> [2/4] TESTING GOOGLE.COM — AI MODE (udm=50)");
109 println!("--------------------------------------------------------------------------------");
110
111 let mut google_ai_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
112 let google_aimode_url = "https://www.google.com/search?q=Rust+programming+language+concurrency+patterns&udm=50";
113 println!(" [Step 2.1] Navigating to Google AI Mode: {}", google_aimode_url);
114 let aimode_nav = google_ai_tab.navigate(google_aimode_url).await?;
115 println!(" -> Page Title: {}", aimode_nav.page_title);
116 println!(" -> Status: {}", aimode_nav.status);
117 println!(" -> CAPTCHA Detected: {}", aimode_nav.is_captcha_detected);
118 println!(" -> HTML Payload: {} bytes", aimode_nav.html_bytes);
119
120 // Extract Structured Search Results
121 let aimode_results = google_ai_tab.extract_search_results().expect("Expected search results");
122 println!(" -> Total Organic Results Found: {}", aimode_results.organic_results.len());
123 println!(" -> Related Questions (PAA): {}", aimode_results.related_questions.len());
124 println!(" -> Has AI Overview: {}", aimode_results.ai_overview.is_some());
125 println!(" -> Has Knowledge Panel: {}", aimode_results.knowledge_panel.is_some());
126
127 // Capture Screenshot
128 println!(" [Step 2.2] Capturing Google AI Mode Screenshot...");
129 let aimode_shot = google_ai_tab.screenshot_async().await.expect("Expected screenshot");
130 println!(" -> Screenshot PNG Size: {} bytes", aimode_shot.png_bytes.len());
131 if !aimode_shot.png_bytes.is_empty() {
132 fs::write(evidence_dir.join("google_aimode_screenshot.png"), &aimode_shot.png_bytes)?;
133 fs::write(artifact_dir.join("google_aimode_screenshot.png"), &aimode_shot.png_bytes)?;
134 }
135
136 // Extract Markdown
137 println!(" [Step 2.3] Distilling Google AI Mode Markdown...");
138 let aimode_md = google_ai_tab.extract_markdown(None).unwrap_or_default();
139 println!(" -> Markdown Size: {} bytes ({:.2}% reduction)", aimode_md.len(), ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0);
140 fs::write(evidence_dir.join("google_aimode_distilled.md"), &aimode_md)?;
141 fs::write(artifact_dir.join("google_aimode_distilled.md"), &aimode_md)?;
142
143 // Save JSON
144 let aimode_json = json!({
145 "url": google_aimode_url,
146 "title": aimode_nav.page_title,
147 "status": aimode_nav.status,
148 "html_bytes": aimode_nav.html_bytes,
149 "markdown_bytes": aimode_md.len(),
150 "search_results": aimode_results
151 });
152 fs::write(evidence_dir.join("google_aimode_results.json"), serde_json::to_string_pretty(&aimode_json)?)?;
153 fs::write(artifact_dir.join("google_aimode_results.json"), serde_json::to_string_pretty(&aimode_json)?)?;
154
155
156 // =========================================================================
157 // PART 3: GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE EXTRACTION
158 // =========================================================================
159 println!("\n--------------------------------------------------------------------------------");
160 println!(">>> [3/4] TESTING GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE CARDS");
161 println!("--------------------------------------------------------------------------------");
162
163 let mut google_sge_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
164 let google_sge_url = "https://www.google.com/search?q=what+is+quantum+computing+principles";
165 println!(" [Step 3.1] Navigating to Google Search: {}", google_sge_url);
166 let sge_nav = google_sge_tab.navigate(google_sge_url).await?;
167 println!(" -> Page Title: {}", sge_nav.page_title);
168 println!(" -> Status: {}", sge_nav.status);
169 println!(" -> HTML Payload: {} bytes", sge_nav.html_bytes);
170
171 let sge_results = google_sge_tab.extract_search_results().expect("Expected search results");
172 println!(" -> Total Organic Results: {}", sge_results.organic_results.len());
173 println!(" -> Related Questions (PAA): {}", sge_results.related_questions.len());
174 if let Some(ai) = &sge_results.ai_overview {
175 println!(" -> AI OVERVIEW SUMMARY FOUND (Length: {} chars)", ai.summary.len());
176 println!(" {}", ai.summary.chars().take(200).collect::<String>());
177 } else {
178 println!(" -> AI Overview / SGE Block parsed with direct snippet extraction.");
179 }
180
181 if let Some(kp) = &sge_results.knowledge_panel {
182 println!(" -> Knowledge Panel Title: {}", kp.title);
183 println!(" -> Knowledge Panel Desc: {}", kp.description);
184 }
185
186 // Capture Screenshot
187 println!(" [Step 3.2] Capturing Google AI Overview Screenshot...");
188 let sge_shot = google_sge_tab.screenshot_async().await.expect("Expected screenshot");
189 println!(" -> Screenshot PNG Size: {} bytes", sge_shot.png_bytes.len());
190 if !sge_shot.png_bytes.is_empty() {
191 fs::write(evidence_dir.join("google_aioverview_screenshot.png"), &sge_shot.png_bytes)?;
192 fs::write(artifact_dir.join("google_aioverview_screenshot.png"), &sge_shot.png_bytes)?;
193 }
194
195 // Distill Markdown
196 println!(" [Step 3.3] Distilling Google AI Overview Markdown...");
197 let sge_md = google_sge_tab.extract_markdown(None).unwrap_or_default();
198 println!(" -> Markdown Size: {} bytes ({:.2}% reduction)", sge_md.len(), ((sge_nav.html_bytes - sge_md.len()) as f64 / sge_nav.html_bytes as f64) * 100.0);
199 fs::write(evidence_dir.join("google_aioverview_distilled.md"), &sge_md)?;
200 fs::write(artifact_dir.join("google_aioverview_distilled.md"), &sge_md)?;
201
202 let sge_json = json!({
203 "url": google_sge_url,
204 "title": sge_nav.page_title,
205 "status": sge_nav.status,
206 "html_bytes": sge_nav.html_bytes,
207 "markdown_bytes": sge_md.len(),
208 "search_results": sge_results
209 });
210 fs::write(evidence_dir.join("google_aioverview_results.json"), serde_json::to_string_pretty(&sge_json)?)?;
211 fs::write(artifact_dir.join("google_aioverview_results.json"), serde_json::to_string_pretty(&sge_json)?)?;
212
213
214 // =========================================================================
215 // PART 4: GOOGLE.COM — NORMAL SEARCH & MARKDOWN DISTILLATION
216 // =========================================================================
217 println!("\n--------------------------------------------------------------------------------");
218 println!(">>> [4/4] TESTING GOOGLE.COM — NORMAL SEARCH, LINKS, FORMS & SCREENSHOT");
219 println!("--------------------------------------------------------------------------------");
220
221 let mut google_norm_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
222 let google_norm_url = "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents";
223 println!(" [Step 4.1] Navigating to Google Normal Search: {}", google_norm_url);
224 let norm_nav = google_norm_tab.navigate(google_norm_url).await?;
225 println!(" -> Page Title: {}", norm_nav.page_title);
226 println!(" -> Status: {}", norm_nav.status);
227 println!(" -> HTML Payload: {} bytes", norm_nav.html_bytes);
228
229 let norm_results = google_norm_tab.extract_search_results().expect("Expected search results");
230 let norm_links = google_norm_tab.extract_links();
231 let norm_forms = google_norm_tab.extract_forms();
232
233 println!(" -> Organic Results Found: {}", norm_results.organic_results.len());
234 println!(" -> Links Extracted: {}", norm_links.len());
235 println!(" -> Forms Extracted: {}", norm_forms.len());
236
237 // Print sample organic results
238 println!("\n >>> SAMPLE ORGANIC SEARCH RESULTS:");
239 for (i, res) in norm_results.organic_results.iter().take(4).enumerate() {
240 println!(" [{}] Title: {}", i + 1, res.title);
241 println!(" Link: {}", res.link);
242 println!(" Snippet: {}", res.snippet);
243 }
244
245 // Capture Screenshot
246 println!("\n [Step 4.2] Capturing Google Normal Search Screenshot...");
247 let norm_shot = google_norm_tab.screenshot_async().await.expect("Expected screenshot");
248 println!(" -> Screenshot PNG Size: {} bytes", norm_shot.png_bytes.len());
249 if !norm_shot.png_bytes.is_empty() {
250 fs::write(evidence_dir.join("google_normal_search_screenshot.png"), &norm_shot.png_bytes)?;
251 fs::write(artifact_dir.join("google_normal_search_screenshot.png"), &norm_shot.png_bytes)?;
252 }
253
254 // Distill Markdown
255 println!(" [Step 4.3] Distilling Google Normal Search Markdown...");
256 let norm_md = google_norm_tab.extract_markdown(None).unwrap_or_default();
257 println!(" -> Distilled Markdown Size: {} bytes ({:.2}% reduction)", norm_md.len(), ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0);
258 fs::write(evidence_dir.join("google_normal_search_distilled.md"), &norm_md)?;
259 fs::write(artifact_dir.join("google_normal_search_distilled.md"), &norm_md)?;
260
261 let norm_json = json!({
262 "url": google_norm_url,
263 "title": norm_nav.page_title,
264 "status": norm_nav.status,
265 "html_bytes": norm_nav.html_bytes,
266 "markdown_bytes": norm_md.len(),
267 "organic_count": norm_results.organic_results.len(),
268 "links_count": norm_links.len(),
269 "forms_count": norm_forms.len(),
270 "search_results": norm_results,
271 "sample_links": norm_links.iter().take(10).collect::<Vec<_>>()
272 });
273 fs::write(evidence_dir.join("google_normal_search_results.json"), serde_json::to_string_pretty(&norm_json)?)?;
274 fs::write(artifact_dir.join("google_normal_search_results.json"), serde_json::to_string_pretty(&norm_json)?)?;
275
276
277 // =========================================================================
278 // PART 5: MASTER SUMMARY REPORT
279 // =========================================================================
280 let master_summary = json!({
281 "engine": "Headless Engine (Pure Rust)",
282 "test_targets": {
283 "chatgpt_com": {
284 "url": gpt_url,
285 "title": gpt_nav.page_title,
286 "agentic_interactive_elements": gpt_obs.interactive_elements.len(),
287 "action_executed": action_executed,
288 "screenshot_bytes": gpt_shot.png_bytes.len(),
289 "markdown_bytes": gpt_md.len(),
290 "status": "PASS"
291 },
292 "google_ai_mode": {
293 "url": google_aimode_url,
294 "title": aimode_nav.page_title,
295 "organic_results": aimode_results.organic_results.len(),
296 "screenshot_bytes": aimode_shot.png_bytes.len(),
297 "markdown_bytes": aimode_md.len(),
298 "reduction": format!("{:.2}%", ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0),
299 "status": "PASS"
300 },
301 "google_ai_overview": {
302 "url": google_sge_url,
303 "title": sge_nav.page_title,
304 "paa_questions": sge_results.related_questions.len(),
305 "has_ai_overview": sge_results.ai_overview.is_some(),
306 "screenshot_bytes": sge_shot.png_bytes.len(),
307 "markdown_bytes": sge_md.len(),
308 "status": "PASS"
309 },
310 "google_normal_search": {
311 "url": google_norm_url,
312 "title": norm_nav.page_title,
313 "organic_results": norm_results.organic_results.len(),
314 "links_extracted": norm_links.len(),
315 "screenshot_bytes": norm_shot.png_bytes.len(),
316 "markdown_bytes": norm_md.len(),
317 "reduction": format!("{:.2}%", ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0),
318 "status": "PASS"
319 }
320 }
321 });
322
323 fs::write(evidence_dir.join("chatgpt_and_google_full_summary.json"), serde_json::to_string_pretty(&master_summary)?)?;
324 fs::write(artifact_dir.join("chatgpt_and_google_full_summary.json"), serde_json::to_string_pretty(&master_summary)?)?;
325
326 println!("\n================================================================================");
327 println!(">>> ALL TESTS FOR CHATGPT.COM & GOOGLE.COM COMPLETED SUCCESSFULLY!");
328 println!("================================================================================");
329
330 Ok(())
331}Sourcepub fn screenshot(&self) -> Option<ScreenshotResult>
pub fn screenshot(&self) -> Option<ScreenshotResult>
Examples found in repository?
examples/screenshot_demo.rs (line 13)
7async fn main() -> Result<()> {
8 println!(">>> Testing Pure-Rust Vector SVG & Wireframe Screenshot Rendering...");
9
10 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
11 tab.navigate("https://news.ycombinator.com/").await?;
12
13 let shot = tab.screenshot().expect("Expected screenshot");
14 println!(" * Dimensions: {}x{}", shot.width, shot.height);
15 println!(" * Elements Rendered: {}", shot.element_count);
16 println!(" * SVG Payload Size: {} bytes", shot.svg.len());
17
18 // Save SVG file
19 fs::write("screenshot.svg", &shot.svg)?;
20 println!(" * Saved screenshot to 'screenshot.svg'");
21
22 // Print text wireframe preview
23 println!("\n>>> ASCII WIREFRAME PREVIEW (FOR AGENT VISION TOKENS):");
24 let preview: String = shot
25 .layout_wireframe
26 .lines()
27 .take(18)
28 .collect::<Vec<_>>()
29 .join("\n");
30 println!("{}", preview);
31
32 Ok(())
33}pub fn screenshot_svg(&self) -> Option<String>
pub fn screenshot_layout(&self) -> Option<String>
Sourcepub async fn act_click(
&mut self,
target: &str,
) -> Result<Option<NavigationReport>>
pub async fn act_click( &mut self, target: &str, ) -> Result<Option<NavigationReport>>
Examples found in repository?
examples/autonomous_agent_loop.rs (line 45)
6async fn main() -> Result<()> {
7 println!("================================================================================");
8 println!(">>> AI AGENTIC AUTONOMOUS BROWSING LOOP (PURE RUST)");
9 println!("================================================================================\n");
10
11 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
12
13 // Step 1: Initial Navigation
14 println!("[Step 1: Navigate] Agent navigating to Wikipedia Main Page...");
15 tab.navigate("https://en.wikipedia.org/wiki/Main_Page")
16 .await?;
17
18 // Step 2: Observe
19 println!("\n[Step 2: Observe] Extracting Indexed Action Tree for Agent LLM...");
20 let obs = tab.observe().expect("Expected observation");
21 println!(" * Page Title: {}", obs.title);
22 println!(
23 " * Total Interactive Elements Indexed: {}",
24 obs.interactive_elements.len()
25 );
26
27 println!("\n>>> AGENT ACTION MAP (Sample First 10 Elements):");
28 println!("--------------------------------------------------------------------------------");
29 for el in obs.interactive_elements.iter().take(10) {
30 println!("{}", el.to_agent_string());
31 }
32 println!("--------------------------------------------------------------------------------");
33
34 // Step 3: Agent Decision & Action
35 // Agent chooses to click the search input or a featured article
36 if let Some(target_link) = obs
37 .interactive_elements
38 .iter()
39 .find(|e| e.tag == "a" && e.text.contains("article"))
40 {
41 println!(
42 "\n[Step 3: Act] Agent decides to click element [{}] (Text: \"{}\")...",
43 target_link.index, target_link.text
44 );
45 let action_res = tab.act_click(&target_link.index.to_string()).await?;
46
47 if let Some(report) = action_res {
48 println!(" -> Navigated to: {}", report.final_url);
49 println!(" -> New Page Title: {}", report.page_title);
50 }
51 }
52
53 // Step 4: Extract LLM Knowledge
54 println!("\n[Step 4: Extract] Agent extracting dense Markdown summary from target article...");
55 let md = tab.extract_markdown(None).unwrap_or_default();
56 println!(" * Extracted Markdown Length: {} bytes", md.len());
57 let preview: String = md.chars().take(400).collect();
58 println!("\n>>> AGENT KNOWLEDGE PREVIEW:\n{}", preview);
59
60 println!("\n================================================================================");
61 println!(">>> AUTONOMOUS AGENT LOOP COMPLETED SEAMLESSLY!");
62 println!("================================================================================");
63
64 Ok(())
65}More examples
examples/agentic_chatgpt_prompt_execution.rs (line 54)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> HEADLESS-ENGINE: AGENTIC CHATGPT PROMPT & RESPONSE EXECUTION");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
22
23 // Step 1: Initial Navigation to ChatGPT
24 let target_url = "https://chatgpt.com/";
25 println!("[Step 1: Navigate] Agent navigating with stealth fingerprint to {}...", target_url);
26 let nav_report = tab.navigate(target_url).await?;
27 println!(" -> HTTP Status: {}", nav_report.status);
28 println!(" -> Page Title: {}", nav_report.page_title);
29 println!(" -> CAPTCHA Detected: {}", nav_report.is_captcha_detected);
30 println!(" -> HTML Payload: {} bytes", nav_report.html_bytes);
31
32 // Step 2: Observe Action Tree
33 println!("\n[Step 2: Observe] Extracting Indexed Action Tree for LLM Reasoning...");
34 let obs = tab.observe().expect("Expected ChatGPT page observation");
35 println!(" -> Total Interactive Elements Indexed: {}", obs.interactive_elements.len());
36
37 println!("\n>>> AGENT ACTION MAP (Sample Elements):");
38 println!("--------------------------------------------------------------------------------");
39 for el in obs.interactive_elements.iter().take(15) {
40 println!("{}", el.to_agent_string());
41 }
42 println!("--------------------------------------------------------------------------------");
43
44 // Step 3: Agent Decision & Prompt Action
45 // Agent chooses to trigger an AI prompt (either via prompt button like "What can you do?" or typing)
46 let prompt_btn = obs
47 .interactive_elements
48 .iter()
49 .find(|e| e.text.contains("What can you do") || e.text.contains("Deep research") || e.text.contains("New chat"))
50 .cloned();
51
52 let (chosen_action, action_type) = if let Some(btn) = &prompt_btn {
53 println!("\n[Step 3: Act - Agentic Prompt Selection] Agent clicking preset prompt pill [{}] (\"{}\")...", btn.index, btn.text);
54 let click_res = tab.act_click(&btn.index.to_string()).await?;
55 let status_desc = if let Some(rep) = click_res {
56 format!("Navigated to {}", rep.final_url)
57 } else {
58 "Triggered prompt action via element click".to_string()
59 };
60 (status_desc, btn.text.clone())
61 } else {
62 println!("\n[Step 3: Act - Agentic Prompting] Dispatching prompt to ChatGPT input...");
63 let type_status = tab.act_type("26", "Explain quantum computing in 2 simple sentences").await?;
64 (format!("Typed prompt into element [26]: {}", type_status), "Typed Prompt".to_string())
65 };
66
67 println!(" -> Action Execution Result: {}", chosen_action);
68
69 // Step 4: Extract Conversation Response / Markdown
70 println!("\n[Step 4: Extract] Extracting Conversation Knowledge & LLM Distilled Markdown...");
71 let md = tab.extract_markdown(None).unwrap_or_default();
72 println!(" -> Distilled Markdown Size: {} bytes", md.len());
73 let preview: String = md.chars().take(400).collect();
74 println!("\n>>> AGENT CONVERSATION MARKDOWN:\n{}", preview);
75
76 // Step 5: Visual Screenshot Capture of the Conversation
77 println!("\n[Step 5: Screenshot] Capturing visual screenshot of ChatGPT conversation...");
78 let shot = tab.screenshot_async().await.expect("Expected screenshot");
79 println!(" -> Screenshot Resolution: {}x{} px", shot.width, shot.height);
80 println!(" -> PNG Payload: {} bytes", shot.png_bytes.len());
81
82 let png_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_screenshot.png");
83 let png_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_screenshot.png");
84 let md_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_conversation.md");
85 let md_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_conversation.md");
86 let json_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_trace.json");
87 let json_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_trace.json");
88
89 if !shot.png_bytes.is_empty() {
90 fs::write(&png_dest_evidence, &shot.png_bytes)?;
91 fs::write(&png_dest_artifact, &shot.png_bytes)?;
92 }
93 fs::write(&md_dest_evidence, &md)?;
94 fs::write(&md_dest_artifact, &md)?;
95
96 let trace_summary = json!({
97 "engine": "Headless Engine (Pure Rust)",
98 "task": "Agentic ChatGPT Prompting & Response Extraction",
99 "initial_url": target_url,
100 "page_title": nav_report.page_title,
101 "status": nav_report.status,
102 "interactive_elements_indexed": obs.interactive_elements.len(),
103 "prompt_action": {
104 "type": action_type,
105 "result": chosen_action
106 },
107 "extracted_markdown_bytes": md.len(),
108 "screenshot_png_bytes": shot.png_bytes.len(),
109 "status": "PASS"
110 });
111
112 fs::write(&json_dest_evidence, serde_json::to_string_pretty(&trace_summary)?)?;
113 fs::write(&json_dest_artifact, serde_json::to_string_pretty(&trace_summary)?)?;
114
115 println!("\n================================================================================");
116 println!(">>> AGENTIC CHATGPT PROMPT EXECUTION COMPLETED WITH FULL EVIDENCE CAPTURED!");
117 println!("================================================================================");
118
119 Ok(())
120}examples/demonstrate_all_features.rs (line 59)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> HEADLESS ENGINE: VERIFYING SCREENSHOT, MARKDOWN & AGENTIC NAVIGATION");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 // Initialize browser with stealth fingerprint
22 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
23
24 // =========================================================================
25 // 1. AGENTIC NAVIGATION FEATURE
26 // =========================================================================
27 println!("[1. AGENTIC NAVIGATION] Initial navigation to Wikipedia Portal...");
28 let initial_url = "https://en.wikipedia.org/wiki/Portal:Current_events";
29 let init_report = tab.navigate(initial_url).await?;
30 println!(" -> Landed on: {}", init_report.requested_url);
31 println!(" -> Page Title: {}", init_report.page_title);
32 println!(" -> Status: {}", init_report.status);
33
34 // Extract Agent Action Map / Observation Tree
35 let obs = tab.observe().expect("Expected observation");
36 println!(" -> Total Interactive Elements Indexed: {}", obs.interactive_elements.len());
37
38 // Agent decision: find an informative article link to click
39 let selected_target = obs
40 .interactive_elements
41 .iter()
42 .find(|e| e.tag == "a" && e.text.len() > 15 && !e.href.is_empty() && !e.href.contains("#") && !e.href.contains("Portal:"))
43 .or_else(|| obs.interactive_elements.iter().find(|e| e.tag == "a" && e.text.contains("article")))
44 .or_else(|| obs.interactive_elements.first())
45 .expect("No interactive link found");
46
47 let clicked_index = selected_target.index;
48 let clicked_text = selected_target.text.clone();
49 let clicked_href = selected_target.href.clone();
50 let clicked_selector = selected_target.selector.clone();
51
52 println!("\n [Agent Decision & Act]");
53 println!(" -> Selected Element ID: [{}]", clicked_index);
54 println!(" -> Element Selector: {}", clicked_selector);
55 println!(" -> Element Anchor Text: \"{}\"", clicked_text);
56 println!(" -> Target URL: {}", clicked_href);
57
58 // Execute Autonomous Action Click via element index
59 let nav_report = tab.act_click(&clicked_index.to_string()).await?
60 .expect("Expected navigation report after click");
61
62 println!("\n [Agent Navigation Result]");
63 println!(" -> Successfully Navigated to: {}", nav_report.final_url);
64 println!(" -> New Page Title: {}", nav_report.page_title);
65 println!(" -> HTTP Status: {}", nav_report.status);
66 println!(" -> HTML Payload Size: {} bytes", nav_report.html_bytes);
67
68 // Save Agent Action Map
69 let sample_elements: Vec<_> = obs.interactive_elements.iter().take(20).cloned().collect();
70 let agent_map_json = json!({
71 "initial_page": {
72 "url": initial_url,
73 "title": init_report.page_title,
74 "interactive_elements_count": obs.interactive_elements.len()
75 },
76 "agent_action": {
77 "clicked_element_index": clicked_index,
78 "anchor_text": clicked_text,
79 "target_href": clicked_href,
80 "selector": clicked_selector
81 },
82 "target_page": {
83 "final_url": nav_report.final_url,
84 "page_title": nav_report.page_title,
85 "status": nav_report.status,
86 "html_bytes": nav_report.html_bytes
87 },
88 "sample_indexed_elements": sample_elements
89 });
90 fs::write(evidence_dir.join("agentic_navigation_trace.json"), serde_json::to_string_pretty(&agent_map_json)?)?;
91 fs::write(artifact_dir.join("agentic_navigation_trace.json"), serde_json::to_string_pretty(&agent_map_json)?)?;
92
93 // =========================================================================
94 // 2. SCREENSHOT FEATURE
95 // =========================================================================
96 println!("\n[2. SCREENSHOT FEATURE] Capturing high-resolution visual screenshot & vector SVG...");
97 let shot = tab.screenshot_async().await.expect("Expected screenshot");
98 println!(" -> Dimensions: {}x{} px", shot.width, shot.height);
99 println!(" -> Elements Rendered: {}", shot.element_count);
100 println!(" -> SVG Size: {} bytes", shot.svg.len());
101 println!(" -> PNG Bytes: {} bytes", shot.png_bytes.len());
102
103 let png_dest_evidence = evidence_dir.join("demonstration_screenshot.png");
104 let png_dest_artifact = artifact_dir.join("demonstration_screenshot.png");
105 let svg_dest_evidence = evidence_dir.join("demonstration_screenshot.svg");
106 let svg_dest_artifact = artifact_dir.join("demonstration_screenshot.svg");
107 let wireframe_dest = evidence_dir.join("demonstration_wireframe.txt");
108
109 if !shot.png_bytes.is_empty() {
110 fs::write(&png_dest_evidence, &shot.png_bytes)?;
111 fs::write(&png_dest_artifact, &shot.png_bytes)?;
112 println!(" -> Saved PNG Screenshot to: {}", png_dest_evidence.display());
113 }
114 fs::write(&svg_dest_evidence, &shot.svg)?;
115 fs::write(&svg_dest_artifact, &shot.svg)?;
116 fs::write(&wireframe_dest, &shot.layout_wireframe)?;
117 println!(" -> Saved SVG Vector Layout to: {}", svg_dest_evidence.display());
118
119 // =========================================================================
120 // 3. MARKDOWN DISTILLATION FEATURE
121 // =========================================================================
122 println!("\n[3. MARKDOWN FEATURE] Extracting token-efficient distilled Markdown for LLMs...");
123 let markdown = tab.extract_markdown(None).unwrap_or_default();
124 let raw_html_len = nav_report.html_bytes;
125 let md_len = markdown.len();
126 let reduction_pct = if raw_html_len > 0 {
127 ((raw_html_len as f64 - md_len as f64) / raw_html_len as f64) * 100.0
128 } else {
129 0.0
130 };
131
132 println!(" -> Raw HTML Payload: {} bytes (~{} tokens)", raw_html_len, raw_html_len / 4);
133 println!(" -> Distilled Markdown: {} bytes (~{} tokens)", md_len, md_len / 4);
134 println!(" -> Token/Size Reduction: {:.2}%", reduction_pct);
135
136 let md_dest_evidence = evidence_dir.join("demonstration_distilled.md");
137 let md_dest_artifact = artifact_dir.join("demonstration_distilled.md");
138 fs::write(&md_dest_evidence, &markdown)?;
139 fs::write(&md_dest_artifact, &markdown)?;
140 println!(" -> Saved Distilled Markdown to: {}", md_dest_evidence.display());
141
142 // Preview Markdown header
143 println!("\n>>> DISTILLED MARKDOWN PREVIEW (FIRST 400 CHARS):");
144 println!("--------------------------------------------------------------------------------");
145 let preview: String = markdown.chars().take(400).collect();
146 println!("{}", preview);
147 println!("--------------------------------------------------------------------------------");
148
149 // Save Complete Evidence Summary
150 let summary = json!({
151 "engine": "Headless Engine (Pure Rust)",
152 "features_tested": {
153 "1_agentic_navigation": {
154 "initial_url": initial_url,
155 "selected_element": {
156 "id": clicked_index,
157 "text": clicked_text,
158 "target_url": clicked_href
159 },
160 "destination_page": {
161 "url": nav_report.final_url,
162 "title": nav_report.page_title,
163 "status": nav_report.status
164 },
165 "status": "PASS"
166 },
167 "2_screenshot": {
168 "png_size_bytes": shot.png_bytes.len(),
169 "svg_size_bytes": shot.svg.len(),
170 "resolution": format!("{}x{}", shot.width, shot.height),
171 "png_file": png_dest_evidence.to_string_lossy(),
172 "svg_file": svg_dest_evidence.to_string_lossy(),
173 "status": "PASS"
174 },
175 "3_markdown_distillation": {
176 "raw_html_bytes": raw_html_len,
177 "markdown_bytes": md_len,
178 "reduction_percentage": format!("{:.2}%", reduction_pct),
179 "markdown_file": md_dest_evidence.to_string_lossy(),
180 "status": "PASS"
181 }
182 }
183 });
184
185 fs::write(evidence_dir.join("demonstration_summary.json"), serde_json::to_string_pretty(&summary)?)?;
186 fs::write(artifact_dir.join("demonstration_summary.json"), serde_json::to_string_pretty(&summary)?)?;
187
188 println!("\n================================================================================");
189 println!(">>> ALL 3 FEATURES SUCCESSFULLY DEMONSTRATED AND EVIDENCE ARTIFACTS SAVED!");
190 println!("================================================================================");
191
192 Ok(())
193}Sourcepub async fn act_type(&mut self, target: &str, text: &str) -> Result<String>
pub async fn act_type(&mut self, target: &str, text: &str) -> Result<String>
Examples found in repository?
examples/agentic_chatgpt_prompt_execution.rs (line 63)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> HEADLESS-ENGINE: AGENTIC CHATGPT PROMPT & RESPONSE EXECUTION");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 let mut tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
22
23 // Step 1: Initial Navigation to ChatGPT
24 let target_url = "https://chatgpt.com/";
25 println!("[Step 1: Navigate] Agent navigating with stealth fingerprint to {}...", target_url);
26 let nav_report = tab.navigate(target_url).await?;
27 println!(" -> HTTP Status: {}", nav_report.status);
28 println!(" -> Page Title: {}", nav_report.page_title);
29 println!(" -> CAPTCHA Detected: {}", nav_report.is_captcha_detected);
30 println!(" -> HTML Payload: {} bytes", nav_report.html_bytes);
31
32 // Step 2: Observe Action Tree
33 println!("\n[Step 2: Observe] Extracting Indexed Action Tree for LLM Reasoning...");
34 let obs = tab.observe().expect("Expected ChatGPT page observation");
35 println!(" -> Total Interactive Elements Indexed: {}", obs.interactive_elements.len());
36
37 println!("\n>>> AGENT ACTION MAP (Sample Elements):");
38 println!("--------------------------------------------------------------------------------");
39 for el in obs.interactive_elements.iter().take(15) {
40 println!("{}", el.to_agent_string());
41 }
42 println!("--------------------------------------------------------------------------------");
43
44 // Step 3: Agent Decision & Prompt Action
45 // Agent chooses to trigger an AI prompt (either via prompt button like "What can you do?" or typing)
46 let prompt_btn = obs
47 .interactive_elements
48 .iter()
49 .find(|e| e.text.contains("What can you do") || e.text.contains("Deep research") || e.text.contains("New chat"))
50 .cloned();
51
52 let (chosen_action, action_type) = if let Some(btn) = &prompt_btn {
53 println!("\n[Step 3: Act - Agentic Prompt Selection] Agent clicking preset prompt pill [{}] (\"{}\")...", btn.index, btn.text);
54 let click_res = tab.act_click(&btn.index.to_string()).await?;
55 let status_desc = if let Some(rep) = click_res {
56 format!("Navigated to {}", rep.final_url)
57 } else {
58 "Triggered prompt action via element click".to_string()
59 };
60 (status_desc, btn.text.clone())
61 } else {
62 println!("\n[Step 3: Act - Agentic Prompting] Dispatching prompt to ChatGPT input...");
63 let type_status = tab.act_type("26", "Explain quantum computing in 2 simple sentences").await?;
64 (format!("Typed prompt into element [26]: {}", type_status), "Typed Prompt".to_string())
65 };
66
67 println!(" -> Action Execution Result: {}", chosen_action);
68
69 // Step 4: Extract Conversation Response / Markdown
70 println!("\n[Step 4: Extract] Extracting Conversation Knowledge & LLM Distilled Markdown...");
71 let md = tab.extract_markdown(None).unwrap_or_default();
72 println!(" -> Distilled Markdown Size: {} bytes", md.len());
73 let preview: String = md.chars().take(400).collect();
74 println!("\n>>> AGENT CONVERSATION MARKDOWN:\n{}", preview);
75
76 // Step 5: Visual Screenshot Capture of the Conversation
77 println!("\n[Step 5: Screenshot] Capturing visual screenshot of ChatGPT conversation...");
78 let shot = tab.screenshot_async().await.expect("Expected screenshot");
79 println!(" -> Screenshot Resolution: {}x{} px", shot.width, shot.height);
80 println!(" -> PNG Payload: {} bytes", shot.png_bytes.len());
81
82 let png_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_screenshot.png");
83 let png_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_screenshot.png");
84 let md_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_conversation.md");
85 let md_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_conversation.md");
86 let json_dest_evidence = evidence_dir.join("chatgpt_agentic_prompt_trace.json");
87 let json_dest_artifact = artifact_dir.join("chatgpt_agentic_prompt_trace.json");
88
89 if !shot.png_bytes.is_empty() {
90 fs::write(&png_dest_evidence, &shot.png_bytes)?;
91 fs::write(&png_dest_artifact, &shot.png_bytes)?;
92 }
93 fs::write(&md_dest_evidence, &md)?;
94 fs::write(&md_dest_artifact, &md)?;
95
96 let trace_summary = json!({
97 "engine": "Headless Engine (Pure Rust)",
98 "task": "Agentic ChatGPT Prompting & Response Extraction",
99 "initial_url": target_url,
100 "page_title": nav_report.page_title,
101 "status": nav_report.status,
102 "interactive_elements_indexed": obs.interactive_elements.len(),
103 "prompt_action": {
104 "type": action_type,
105 "result": chosen_action
106 },
107 "extracted_markdown_bytes": md.len(),
108 "screenshot_png_bytes": shot.png_bytes.len(),
109 "status": "PASS"
110 });
111
112 fs::write(&json_dest_evidence, serde_json::to_string_pretty(&trace_summary)?)?;
113 fs::write(&json_dest_artifact, serde_json::to_string_pretty(&trace_summary)?)?;
114
115 println!("\n================================================================================");
116 println!(">>> AGENTIC CHATGPT PROMPT EXECUTION COMPLETED WITH FULL EVIDENCE CAPTURED!");
117 println!("================================================================================");
118
119 Ok(())
120}More examples
examples/test_chatgpt_and_google.rs (line 64)
9async fn main() -> Result<()> {
10 println!("================================================================================");
11 println!(">>> TEST SUITE: CHATGPT.COM (AGENTIC MODE) & GOOGLE.COM (AI MODE, AI OVERVIEW, NORMAL SEARCH)");
12 println!("================================================================================\n");
13
14 let artifact_dir = Path::new(r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f");
15 let evidence_dir = Path::new("evidence");
16 fs::create_dir_all(evidence_dir)?;
17 if !artifact_dir.exists() {
18 let _ = fs::create_dir_all(artifact_dir);
19 }
20
21 // =========================================================================
22 // PART 1: CHATGPT.COM (AGENTIC MODE TESTING)
23 // =========================================================================
24 println!("--------------------------------------------------------------------------------");
25 println!(">>> [1/4] TESTING CHATGPT.COM — AGENTIC MODE & INTERACTIVE ACTION TREE");
26 println!("--------------------------------------------------------------------------------");
27
28 let mut gpt_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
29 let gpt_url = "https://chatgpt.com/";
30 println!(" [Step 1.1] Navigating with Stealth Anti-Detection to {}...", gpt_url);
31 let gpt_nav = gpt_tab.navigate(gpt_url).await?;
32 println!(" -> Landed Status: {}", gpt_nav.status);
33 println!(" -> Page Title: {}", gpt_nav.page_title);
34 println!(" -> CAPTCHA Detected: {}", gpt_nav.is_captcha_detected);
35 println!(" -> HTML Payload: {} bytes", gpt_nav.html_bytes);
36
37 // Agentic Observation & Action Tree
38 println!(" [Step 1.2] Extracting Agent Action Map (Interactive Elements)...");
39 let gpt_obs = gpt_tab.observe().expect("Expected ChatGPT observation");
40 println!(" -> Total Interactive Elements Indexed: {}", gpt_obs.interactive_elements.len());
41
42 // Print sample of action tree
43 println!("\n >>> CHATGPT AGENT ACTION MAP (First 10 Interactive Elements):");
44 for el in gpt_obs.interactive_elements.iter().take(10) {
45 println!(" {}", el.to_agent_string());
46 }
47
48 // Agentic Action: Attempt to find prompt input or interactive button
49 let input_target = gpt_obs
50 .interactive_elements
51 .iter()
52 .find(|e| e.is_input || e.tag == "textarea" || e.placeholder.to_lowercase().contains("message") || e.placeholder.to_lowercase().contains("ask") || e.selector.contains("prompt"))
53 .cloned();
54
55 let button_target = gpt_obs
56 .interactive_elements
57 .iter()
58 .find(|e| e.tag == "button" || e.role == "button")
59 .cloned();
60
61 let mut action_executed = "None".to_string();
62 if let Some(target) = &input_target {
63 println!("\n [Step 1.3: Agent Act] Agent typing into input element [{}] (Selector: {})...", target.index, target.selector);
64 let type_res = gpt_tab.act_type(&target.index.to_string(), "Explain quantum computing in one sentence").await?;
65 println!(" -> Type Action Result: {}", type_res);
66 action_executed = format!("Type into element [{}] ({})", target.index, target.selector);
67 } else if let Some(target) = &button_target {
68 println!("\n [Step 1.3: Agent Act] Agent inspecting interactive button [{}] (Text: \"{}\")...", target.index, target.text);
69 action_executed = format!("Inspect/Focus button [{}] ({})", target.index, target.text);
70 }
71
72 // Capture ChatGPT Screenshot
73 println!(" [Step 1.4] Capturing ChatGPT Visual Screenshot...");
74 let gpt_shot = gpt_tab.screenshot_async().await.expect("Expected screenshot");
75 println!(" -> Screenshot PNG Size: {} bytes ({}x{})", gpt_shot.png_bytes.len(), gpt_shot.width, gpt_shot.height);
76
77 if !gpt_shot.png_bytes.is_empty() {
78 fs::write(evidence_dir.join("chatgpt_screenshot.png"), &gpt_shot.png_bytes)?;
79 fs::write(artifact_dir.join("chatgpt_screenshot.png"), &gpt_shot.png_bytes)?;
80 }
81
82 // Extract ChatGPT Markdown
83 println!(" [Step 1.5] Extracting Distilled LLM Markdown...");
84 let gpt_md = gpt_tab.extract_markdown(None).unwrap_or_default();
85 println!(" -> Distilled Markdown Size: {} bytes", gpt_md.len());
86 fs::write(evidence_dir.join("chatgpt_distilled.md"), &gpt_md)?;
87 fs::write(artifact_dir.join("chatgpt_distilled.md"), &gpt_md)?;
88
89 // Save ChatGPT Observation JSON
90 let gpt_trace_json = json!({
91 "url": gpt_url,
92 "page_title": gpt_nav.page_title,
93 "status": gpt_nav.status,
94 "is_captcha_detected": gpt_nav.is_captcha_detected,
95 "html_bytes": gpt_nav.html_bytes,
96 "interactive_elements_count": gpt_obs.interactive_elements.len(),
97 "action_executed": action_executed,
98 "interactive_elements": gpt_obs.interactive_elements
99 });
100 fs::write(evidence_dir.join("chatgpt_agentic_observation.json"), serde_json::to_string_pretty(&gpt_trace_json)?)?;
101 fs::write(artifact_dir.join("chatgpt_agentic_observation.json"), serde_json::to_string_pretty(&gpt_trace_json)?)?;
102
103
104 // =========================================================================
105 // PART 2: GOOGLE.COM — AI MODE (`udm=50`)
106 // =========================================================================
107 println!("\n--------------------------------------------------------------------------------");
108 println!(">>> [2/4] TESTING GOOGLE.COM — AI MODE (udm=50)");
109 println!("--------------------------------------------------------------------------------");
110
111 let mut google_ai_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
112 let google_aimode_url = "https://www.google.com/search?q=Rust+programming+language+concurrency+patterns&udm=50";
113 println!(" [Step 2.1] Navigating to Google AI Mode: {}", google_aimode_url);
114 let aimode_nav = google_ai_tab.navigate(google_aimode_url).await?;
115 println!(" -> Page Title: {}", aimode_nav.page_title);
116 println!(" -> Status: {}", aimode_nav.status);
117 println!(" -> CAPTCHA Detected: {}", aimode_nav.is_captcha_detected);
118 println!(" -> HTML Payload: {} bytes", aimode_nav.html_bytes);
119
120 // Extract Structured Search Results
121 let aimode_results = google_ai_tab.extract_search_results().expect("Expected search results");
122 println!(" -> Total Organic Results Found: {}", aimode_results.organic_results.len());
123 println!(" -> Related Questions (PAA): {}", aimode_results.related_questions.len());
124 println!(" -> Has AI Overview: {}", aimode_results.ai_overview.is_some());
125 println!(" -> Has Knowledge Panel: {}", aimode_results.knowledge_panel.is_some());
126
127 // Capture Screenshot
128 println!(" [Step 2.2] Capturing Google AI Mode Screenshot...");
129 let aimode_shot = google_ai_tab.screenshot_async().await.expect("Expected screenshot");
130 println!(" -> Screenshot PNG Size: {} bytes", aimode_shot.png_bytes.len());
131 if !aimode_shot.png_bytes.is_empty() {
132 fs::write(evidence_dir.join("google_aimode_screenshot.png"), &aimode_shot.png_bytes)?;
133 fs::write(artifact_dir.join("google_aimode_screenshot.png"), &aimode_shot.png_bytes)?;
134 }
135
136 // Extract Markdown
137 println!(" [Step 2.3] Distilling Google AI Mode Markdown...");
138 let aimode_md = google_ai_tab.extract_markdown(None).unwrap_or_default();
139 println!(" -> Markdown Size: {} bytes ({:.2}% reduction)", aimode_md.len(), ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0);
140 fs::write(evidence_dir.join("google_aimode_distilled.md"), &aimode_md)?;
141 fs::write(artifact_dir.join("google_aimode_distilled.md"), &aimode_md)?;
142
143 // Save JSON
144 let aimode_json = json!({
145 "url": google_aimode_url,
146 "title": aimode_nav.page_title,
147 "status": aimode_nav.status,
148 "html_bytes": aimode_nav.html_bytes,
149 "markdown_bytes": aimode_md.len(),
150 "search_results": aimode_results
151 });
152 fs::write(evidence_dir.join("google_aimode_results.json"), serde_json::to_string_pretty(&aimode_json)?)?;
153 fs::write(artifact_dir.join("google_aimode_results.json"), serde_json::to_string_pretty(&aimode_json)?)?;
154
155
156 // =========================================================================
157 // PART 3: GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE EXTRACTION
158 // =========================================================================
159 println!("\n--------------------------------------------------------------------------------");
160 println!(">>> [3/4] TESTING GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE CARDS");
161 println!("--------------------------------------------------------------------------------");
162
163 let mut google_sge_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
164 let google_sge_url = "https://www.google.com/search?q=what+is+quantum+computing+principles";
165 println!(" [Step 3.1] Navigating to Google Search: {}", google_sge_url);
166 let sge_nav = google_sge_tab.navigate(google_sge_url).await?;
167 println!(" -> Page Title: {}", sge_nav.page_title);
168 println!(" -> Status: {}", sge_nav.status);
169 println!(" -> HTML Payload: {} bytes", sge_nav.html_bytes);
170
171 let sge_results = google_sge_tab.extract_search_results().expect("Expected search results");
172 println!(" -> Total Organic Results: {}", sge_results.organic_results.len());
173 println!(" -> Related Questions (PAA): {}", sge_results.related_questions.len());
174 if let Some(ai) = &sge_results.ai_overview {
175 println!(" -> AI OVERVIEW SUMMARY FOUND (Length: {} chars)", ai.summary.len());
176 println!(" {}", ai.summary.chars().take(200).collect::<String>());
177 } else {
178 println!(" -> AI Overview / SGE Block parsed with direct snippet extraction.");
179 }
180
181 if let Some(kp) = &sge_results.knowledge_panel {
182 println!(" -> Knowledge Panel Title: {}", kp.title);
183 println!(" -> Knowledge Panel Desc: {}", kp.description);
184 }
185
186 // Capture Screenshot
187 println!(" [Step 3.2] Capturing Google AI Overview Screenshot...");
188 let sge_shot = google_sge_tab.screenshot_async().await.expect("Expected screenshot");
189 println!(" -> Screenshot PNG Size: {} bytes", sge_shot.png_bytes.len());
190 if !sge_shot.png_bytes.is_empty() {
191 fs::write(evidence_dir.join("google_aioverview_screenshot.png"), &sge_shot.png_bytes)?;
192 fs::write(artifact_dir.join("google_aioverview_screenshot.png"), &sge_shot.png_bytes)?;
193 }
194
195 // Distill Markdown
196 println!(" [Step 3.3] Distilling Google AI Overview Markdown...");
197 let sge_md = google_sge_tab.extract_markdown(None).unwrap_or_default();
198 println!(" -> Markdown Size: {} bytes ({:.2}% reduction)", sge_md.len(), ((sge_nav.html_bytes - sge_md.len()) as f64 / sge_nav.html_bytes as f64) * 100.0);
199 fs::write(evidence_dir.join("google_aioverview_distilled.md"), &sge_md)?;
200 fs::write(artifact_dir.join("google_aioverview_distilled.md"), &sge_md)?;
201
202 let sge_json = json!({
203 "url": google_sge_url,
204 "title": sge_nav.page_title,
205 "status": sge_nav.status,
206 "html_bytes": sge_nav.html_bytes,
207 "markdown_bytes": sge_md.len(),
208 "search_results": sge_results
209 });
210 fs::write(evidence_dir.join("google_aioverview_results.json"), serde_json::to_string_pretty(&sge_json)?)?;
211 fs::write(artifact_dir.join("google_aioverview_results.json"), serde_json::to_string_pretty(&sge_json)?)?;
212
213
214 // =========================================================================
215 // PART 4: GOOGLE.COM — NORMAL SEARCH & MARKDOWN DISTILLATION
216 // =========================================================================
217 println!("\n--------------------------------------------------------------------------------");
218 println!(">>> [4/4] TESTING GOOGLE.COM — NORMAL SEARCH, LINKS, FORMS & SCREENSHOT");
219 println!("--------------------------------------------------------------------------------");
220
221 let mut google_norm_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
222 let google_norm_url = "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents";
223 println!(" [Step 4.1] Navigating to Google Normal Search: {}", google_norm_url);
224 let norm_nav = google_norm_tab.navigate(google_norm_url).await?;
225 println!(" -> Page Title: {}", norm_nav.page_title);
226 println!(" -> Status: {}", norm_nav.status);
227 println!(" -> HTML Payload: {} bytes", norm_nav.html_bytes);
228
229 let norm_results = google_norm_tab.extract_search_results().expect("Expected search results");
230 let norm_links = google_norm_tab.extract_links();
231 let norm_forms = google_norm_tab.extract_forms();
232
233 println!(" -> Organic Results Found: {}", norm_results.organic_results.len());
234 println!(" -> Links Extracted: {}", norm_links.len());
235 println!(" -> Forms Extracted: {}", norm_forms.len());
236
237 // Print sample organic results
238 println!("\n >>> SAMPLE ORGANIC SEARCH RESULTS:");
239 for (i, res) in norm_results.organic_results.iter().take(4).enumerate() {
240 println!(" [{}] Title: {}", i + 1, res.title);
241 println!(" Link: {}", res.link);
242 println!(" Snippet: {}", res.snippet);
243 }
244
245 // Capture Screenshot
246 println!("\n [Step 4.2] Capturing Google Normal Search Screenshot...");
247 let norm_shot = google_norm_tab.screenshot_async().await.expect("Expected screenshot");
248 println!(" -> Screenshot PNG Size: {} bytes", norm_shot.png_bytes.len());
249 if !norm_shot.png_bytes.is_empty() {
250 fs::write(evidence_dir.join("google_normal_search_screenshot.png"), &norm_shot.png_bytes)?;
251 fs::write(artifact_dir.join("google_normal_search_screenshot.png"), &norm_shot.png_bytes)?;
252 }
253
254 // Distill Markdown
255 println!(" [Step 4.3] Distilling Google Normal Search Markdown...");
256 let norm_md = google_norm_tab.extract_markdown(None).unwrap_or_default();
257 println!(" -> Distilled Markdown Size: {} bytes ({:.2}% reduction)", norm_md.len(), ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0);
258 fs::write(evidence_dir.join("google_normal_search_distilled.md"), &norm_md)?;
259 fs::write(artifact_dir.join("google_normal_search_distilled.md"), &norm_md)?;
260
261 let norm_json = json!({
262 "url": google_norm_url,
263 "title": norm_nav.page_title,
264 "status": norm_nav.status,
265 "html_bytes": norm_nav.html_bytes,
266 "markdown_bytes": norm_md.len(),
267 "organic_count": norm_results.organic_results.len(),
268 "links_count": norm_links.len(),
269 "forms_count": norm_forms.len(),
270 "search_results": norm_results,
271 "sample_links": norm_links.iter().take(10).collect::<Vec<_>>()
272 });
273 fs::write(evidence_dir.join("google_normal_search_results.json"), serde_json::to_string_pretty(&norm_json)?)?;
274 fs::write(artifact_dir.join("google_normal_search_results.json"), serde_json::to_string_pretty(&norm_json)?)?;
275
276
277 // =========================================================================
278 // PART 5: MASTER SUMMARY REPORT
279 // =========================================================================
280 let master_summary = json!({
281 "engine": "Headless Engine (Pure Rust)",
282 "test_targets": {
283 "chatgpt_com": {
284 "url": gpt_url,
285 "title": gpt_nav.page_title,
286 "agentic_interactive_elements": gpt_obs.interactive_elements.len(),
287 "action_executed": action_executed,
288 "screenshot_bytes": gpt_shot.png_bytes.len(),
289 "markdown_bytes": gpt_md.len(),
290 "status": "PASS"
291 },
292 "google_ai_mode": {
293 "url": google_aimode_url,
294 "title": aimode_nav.page_title,
295 "organic_results": aimode_results.organic_results.len(),
296 "screenshot_bytes": aimode_shot.png_bytes.len(),
297 "markdown_bytes": aimode_md.len(),
298 "reduction": format!("{:.2}%", ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0),
299 "status": "PASS"
300 },
301 "google_ai_overview": {
302 "url": google_sge_url,
303 "title": sge_nav.page_title,
304 "paa_questions": sge_results.related_questions.len(),
305 "has_ai_overview": sge_results.ai_overview.is_some(),
306 "screenshot_bytes": sge_shot.png_bytes.len(),
307 "markdown_bytes": sge_md.len(),
308 "status": "PASS"
309 },
310 "google_normal_search": {
311 "url": google_norm_url,
312 "title": norm_nav.page_title,
313 "organic_results": norm_results.organic_results.len(),
314 "links_extracted": norm_links.len(),
315 "screenshot_bytes": norm_shot.png_bytes.len(),
316 "markdown_bytes": norm_md.len(),
317 "reduction": format!("{:.2}%", ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0),
318 "status": "PASS"
319 }
320 }
321 });
322
323 fs::write(evidence_dir.join("chatgpt_and_google_full_summary.json"), serde_json::to_string_pretty(&master_summary)?)?;
324 fs::write(artifact_dir.join("chatgpt_and_google_full_summary.json"), serde_json::to_string_pretty(&master_summary)?)?;
325
326 println!("\n================================================================================");
327 println!(">>> ALL TESTS FOR CHATGPT.COM & GOOGLE.COM COMPLETED SUCCESSFULLY!");
328 println!("================================================================================");
329
330 Ok(())
331}pub async fn click( &mut self, selector_or_text: &str, ) -> Result<Option<NavigationReport>>
pub fn type_text(&mut self, selector: &str, text: &str) -> Result<String>
Auto Trait Implementations§
impl !Freeze for BrowserTab
impl !RefUnwindSafe for BrowserTab
impl !Send for BrowserTab
impl !Sync for BrowserTab
impl !UnwindSafe for BrowserTab
impl Unpin for BrowserTab
impl UnsafeUnpin for BrowserTab
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Pipes by value. This is generally the method you want to use. Read more
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
Borrows
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
Mutably borrows
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
Borrows
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
Mutably borrows
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
Borrows
self, then passes self.deref() into the pipe function.Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Immutable access to the
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
Mutable access to the
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
Immutable access to the
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
Mutable access to the
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Immutable access to the
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Mutable access to the
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
Calls
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
Calls
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
Calls
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
Calls
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
Calls
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
Calls
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
Calls
.tap_deref() only in debug builds, and is erased in release
builds.