Skip to main content

elizaos_browser/
plugin.rs

1use crate::actions::{
2    browser_click, browser_extract, browser_navigate, browser_screenshot, browser_select,
3    browser_type,
4};
5use crate::providers::get_browser_state;
6use crate::services::BrowserService;
7use crate::types::{ActionResult, BrowserConfig};
8use std::env;
9use std::sync::Arc;
10use tracing::info;
11
12pub struct BrowserPlugin {
13    pub name: String,
14    pub description: String,
15    pub config: BrowserConfig,
16    pub service: Option<Arc<BrowserService>>,
17}
18
19impl BrowserPlugin {
20    pub fn new(config: BrowserConfig) -> Self {
21        Self {
22            name: "plugin-browser".to_string(),
23            description: "Browser automation plugin".to_string(),
24            config,
25            service: None,
26        }
27    }
28
29    pub async fn init(&mut self) -> Result<(), String> {
30        info!("Initializing browser automation plugin");
31
32        self.config = BrowserConfig {
33            headless: env::var("BROWSER_HEADLESS")
34                .map(|v| v.to_lowercase() == "true")
35                .unwrap_or(true),
36            browserbase_api_key: env::var("BROWSERBASE_API_KEY").ok(),
37            browserbase_project_id: env::var("BROWSERBASE_PROJECT_ID").ok(),
38            openai_api_key: env::var("OPENAI_API_KEY").ok(),
39            anthropic_api_key: env::var("ANTHROPIC_API_KEY").ok(),
40            ollama_base_url: env::var("OLLAMA_BASE_URL").ok(),
41            ollama_model: env::var("OLLAMA_MODEL").ok(),
42            capsolver_api_key: env::var("CAPSOLVER_API_KEY").ok(),
43            server_port: env::var("BROWSER_SERVER_PORT")
44                .ok()
45                .and_then(|v| v.parse().ok())
46                .unwrap_or(3456),
47        };
48
49        let service = BrowserService::new(self.config.clone());
50        service.start().await?;
51        self.service = Some(Arc::new(service));
52
53        info!("Browser plugin initialized successfully");
54        Ok(())
55    }
56
57    pub async fn stop(&mut self) {
58        info!("Stopping browser automation plugin");
59        if let Some(service) = &self.service {
60            service.stop().await;
61        }
62        self.service = None;
63    }
64
65    pub async fn handle_action(
66        &self,
67        action_name: &str,
68        message: &str,
69    ) -> Result<ActionResult, String> {
70        let service = self
71            .service
72            .as_ref()
73            .ok_or("Browser service not initialized")?;
74
75        match action_name {
76            "BROWSER_NAVIGATE" => Ok(browser_navigate(Arc::clone(service), message).await),
77            "BROWSER_CLICK" => Ok(browser_click(Arc::clone(service), message).await),
78            "BROWSER_TYPE" => Ok(browser_type(Arc::clone(service), message).await),
79            "BROWSER_SELECT" => Ok(browser_select(Arc::clone(service), message).await),
80            "BROWSER_EXTRACT" => Ok(browser_extract(Arc::clone(service), message).await),
81            "BROWSER_SCREENSHOT" => Ok(browser_screenshot(Arc::clone(service), message).await),
82            _ => Err(format!("Unknown action: {}", action_name)),
83        }
84    }
85
86    pub async fn get_provider(&self, provider_name: &str) -> Result<serde_json::Value, String> {
87        let service = self
88            .service
89            .as_ref()
90            .ok_or("Browser service not initialized")?;
91
92        match provider_name {
93            "BROWSER_STATE" => {
94                let result = get_browser_state(Arc::clone(service)).await;
95                Ok(serde_json::json!({
96                    "text": result.text,
97                    "values": result.values,
98                    "data": result.data,
99                }))
100            }
101            _ => Err(format!("Unknown provider: {}", provider_name)),
102        }
103    }
104}
105
106pub fn create_browser_plugin(config: Option<BrowserConfig>) -> BrowserPlugin {
107    BrowserPlugin::new(config.unwrap_or_default())
108}