pub struct BrowserTools { /* private fields */ }Implementations§
Source§impl BrowserTools
impl BrowserTools
Sourcepub fn new(root: PathBuf) -> Self
pub fn new(root: PathBuf) -> Self
The agent’s browser — the persistent profile an assistant run drives.
Sourcepub fn standing_session(root: PathBuf) -> Self
pub fn standing_session(root: PathBuf) -> Self
The drawer’s standing session, on its own persistent profile.
Sourcepub fn daemon_host_connectivity(
state: &Arc<ServerState>,
) -> Arc<dyn HostConnectivity> ⓘ
pub fn daemon_host_connectivity( state: &Arc<ServerState>, ) -> Arc<dyn HostConnectivity> ⓘ
Build a HostConnectivity backed by state’s live session set —
the in-daemon producer’s probe (assistant_start and anything else
that builds an AssistantRuntime inside the daemon). Install it via
Self::set_host_connectivity right after build_assistant_runtime
returns, before the run can reach its first browse call.
Sourcepub fn set_host_connectivity(&self, probe: Arc<dyn HostConnectivity>)
pub fn set_host_connectivity(&self, probe: Arc<dyn HostConnectivity>)
Install the probe used to decide headless vs headed at launch, and to
notice a host disconnecting mid-run for the sign-in fallback.
OnceLock-backed: every production caller installs this exactly
once, before any browse call can possibly fire, so a second call
(unreachable in practice) is a silent no-op rather than a panic.
Sourcepub fn set_signin_attention(
&self,
attention: Arc<dyn SignInAttention>,
conversation_id: Option<String>,
)
pub fn set_signin_attention( &self, attention: Arc<dyn SignInAttention>, conversation_id: Option<String>, )
Install the operator-attention sink for this browser, under the
conversation key it is registered as (None = the standing session).
OnceLock-backed for the same reason as
Self::set_host_connectivity: every production caller installs this
exactly once, before the run can reach a browse call, so a second call
is a silent no-op rather than a panic.
Sourcepub fn tool_defs(&self) -> Vec<Value>
pub fn tool_defs(&self) -> Vec<Value>
Advertised whenever a Chromium is plausibly launchable. Deliberately not probing by launching a browser at prompt-build time — that would pay the cost the lazy launch exists to avoid, on every session.
Sourcepub fn subscribe_changes(&self) -> Receiver<u64>
pub fn subscribe_changes(&self) -> Receiver<u64>
A signal that fires whenever the presentation may have changed — a
control-state transition, or a browser launching. The browser.view.*
fan-out awaits this and only then calls Self::presentation, whose
live tab refresh costs a CDP round trip per open tab.
Sourcepub async fn subscribe_frames(&self) -> (FrameReceiver, Instant)
pub async fn subscribe_frames(&self) -> (FrameReceiver, Instant)
Live screencast frames for a human watching the drawer. Never gated by the blackout — that is the whole point of it (the person driving keeps seeing the page; the model does not). Capture starts on the first subscription and stops when the last one is dropped.
Sourcepub async fn release_frames(&self)
pub async fn release_frames(&self)
Drop consumers whose receiver has gone away, stopping CDP capture if that was the last one. Called when the last drawer subscriber leaves, so a browser nobody is watching stops paying for a screencast without waiting for a frame to arrive and notice.
Sourcepub async fn control_status(&self) -> ControlStatus
pub async fn control_status(&self) -> ControlStatus
The cheap read of who is driving — no CDP, unlike
Self::presentation, which refreshes the tab list. This is what
the input path consults on every call.
Sourcepub async fn subscribe_tabs(&self) -> Option<Receiver<TabsSnapshot>>
pub async fn subscribe_tabs(&self) -> Option<Receiver<TabsSnapshot>>
Tab open/close/switch/nav-state notifications from the live browser,
or None when none has launched yet.
Sourcepub async fn presentation(&self) -> Presentation
pub async fn presentation(&self) -> Presentation
The presentation snapshot — tabs (live-refreshed from the browser
when one exists), control owner, current action, pending sign-in,
blackout, and a monotonic revision. What the browser.view.* RPC
surface serializes.
Sourcepub async fn take_control(&self) -> (Presentation, Vec<ControlEffect>)
pub async fn take_control(&self) -> (Presentation, Vec<ControlEffect>)
User presses “Take control” in the drawer.
Sourcepub async fn hand_back(&self) -> (Presentation, Vec<ControlEffect>)
pub async fn hand_back(&self) -> (Presentation, Vec<ControlEffect>)
User presses “Hand back to CAR” — also resolves a pending sign-in,
if one is up (see ControlState::apply).
Sourcepub async fn note_run_ended(&self) -> (Presentation, Vec<ControlEffect>)
pub async fn note_run_ended(&self) -> (Presentation, Vec<ControlEffect>)
The run this browser was attached to has ended: no ceremony, the user’s browser again. Nothing in this crate calls this yet — the daemon owns “when does a run end” (see the R6 note in the task brief), this is the seam it hooks into.
Sourcepub async fn note_user_input(&self)
pub async fn note_user_input(&self)
A person drove this browser. See ControlState::user_engaged — this is
what a sign-in timeout consults before deciding it may end their
window.
Sourcepub async fn control_holder_disconnected(
&self,
) -> (Presentation, Vec<ControlEffect>)
pub async fn control_holder_disconnected( &self, ) -> (Presentation, Vec<ControlEffect>)
The connection holding user control dropped. Nothing in this crate detects that condition yet (it lives at the transport layer); this is the seam a later task hooks a real disconnect signal into.
Sourcepub async fn grace_period_expired(&self) -> (Presentation, Vec<ControlEffect>)
pub async fn grace_period_expired(&self) -> (Presentation, Vec<ControlEffect>)
The grace period started by control_holder_disconnected elapsed.
Nothing in this crate owns the actual clock yet (see
ControlEffect::StartGracePeriod’s doc comment); this is the seam.
Navigate the active tab. This is the one input that may LAUNCH the browser: the standing session starts empty and comes to life on the user’s first navigation (controller ruling R6), without attaching an agent.
pub async fn user_click(&self, x: f64, y: f64) -> Result<(), String>
pub async fn user_type(&self, text: &str) -> Result<(), String>
Sourcepub async fn user_paste(&self, text: &str) -> Result<(), String>
pub async fn user_paste(&self, text: &str) -> Result<(), String>
Paste text at the caret, replacing the selection.
The host reads its OWN pasteboard and sends the string, because a synthesised ⌘V cannot work: the clipboard belongs to the browser, not the page, and CDP’s injected key events have no access to it.
pub async fn user_keypress( &self, key: &str, modifiers: &[Modifier], ) -> Result<(), String>
pub async fn user_scroll(&self, delta_y: i32) -> Result<(), String>
Sourcepub async fn user_go_back(&self) -> Result<(), String>
pub async fn user_go_back(&self) -> Result<(), String>
The nav bar’s Back button. Drives Chromium’s real session history via CDP — a synthesised ⌘← keystroke does not, because the shortcut is browser chrome the input domain never reaches.
Sourcepub async fn user_go_forward(&self) -> Result<(), String>
pub async fn user_go_forward(&self) -> Result<(), String>
The nav bar’s Forward button.
Sourcepub async fn user_reload(&self) -> Result<(), String>
pub async fn user_reload(&self) -> Result<(), String>
The nav bar’s Reload button. Errors on the empty state through
Self::live_backend, like every other input that needs a page to
act on.
pub async fn user_tab_open(&self) -> Result<TabId, String>
pub async fn user_tab_close(&self, id: TabId) -> Result<(), String>
pub async fn user_tab_switch(&self, id: TabId) -> Result<(), String>
Sourcepub async fn resolve_tab(&self, wire_id: &str) -> Result<TabId, String>
pub async fn resolve_tab(&self, wire_id: &str) -> Result<TabId, String>
Resolve a wire tab id (TabId’s own Display form, e.g. tab-3)
against the open tabs. TabId is deliberately opaque outside
car-browser — matching on the rendered id is what keeps it that way,
and it makes a stale id from a closed tab a clean error rather than
an operation on some other tab.
Trait Implementations§
Source§impl ToolExecutor for BrowserTools
impl ToolExecutor for BrowserTools
fn execute<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
tool: &'life1 str,
params: &'life2 Value,
) -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§fn execute_with_action<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
tool: &'life1 str,
params: &'life2 Value,
_action_id: &'life3 str,
_timeout_ms: Option<u64>,
) -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
fn execute_with_action<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
tool: &'life1 str,
params: &'life2 Value,
_action_id: &'life3 str,
_timeout_ms: Option<u64>,
) -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
Source§fn execute_with_action_in_session<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
tool: &'life1 str,
params: &'life2 Value,
action_id: &'life3 str,
timeout_ms: Option<u64>,
_session_id: Option<&'life4 str>,
_attempt: u32,
) -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Self: 'async_trait,
fn execute_with_action_in_session<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
tool: &'life1 str,
params: &'life2 Value,
action_id: &'life3 str,
timeout_ms: Option<u64>,
_session_id: Option<&'life4 str>,
_attempt: u32,
) -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Self: 'async_trait,
Source§fn execute_with_action_state_in_session<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'async_trait>(
&'life0 self,
tool: &'life1 str,
params: &'life2 Value,
action_id: &'life3 str,
timeout_ms: Option<u64>,
session_id: Option<&'life4 str>,
attempt: u32,
_expected_effects: &'life5 HashMap<String, Value>,
_return_schema: Option<&'life6 Value>,
) -> Pin<Box<dyn Future<Output = Result<ToolExecution, String>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
'life5: 'async_trait,
'life6: 'async_trait,
Self: 'async_trait,
fn execute_with_action_state_in_session<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'async_trait>(
&'life0 self,
tool: &'life1 str,
params: &'life2 Value,
action_id: &'life3 str,
timeout_ms: Option<u64>,
session_id: Option<&'life4 str>,
attempt: u32,
_expected_effects: &'life5 HashMap<String, Value>,
_return_schema: Option<&'life6 Value>,
) -> Pin<Box<dyn Future<Output = Result<ToolExecution, String>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
'life5: 'async_trait,
'life6: 'async_trait,
Self: 'async_trait,
Source§fn execute_classified<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'async_trait>(
&'life0 self,
tool: &'life1 str,
params: &'life2 Value,
action_id: &'life3 str,
timeout_ms: Option<u64>,
session_id: Option<&'life4 str>,
attempt: u32,
expected_effects: &'life5 HashMap<String, Value>,
return_schema: Option<&'life6 Value>,
) -> Pin<Box<dyn Future<Output = Result<ToolExecution, ToolFailure>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
'life5: 'async_trait,
'life6: 'async_trait,
Self: 'async_trait,
fn execute_classified<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'async_trait>(
&'life0 self,
tool: &'life1 str,
params: &'life2 Value,
action_id: &'life3 str,
timeout_ms: Option<u64>,
session_id: Option<&'life4 str>,
attempt: u32,
expected_effects: &'life5 HashMap<String, Value>,
return_schema: Option<&'life6 Value>,
) -> Pin<Box<dyn Future<Output = Result<ToolExecution, ToolFailure>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
'life5: 'async_trait,
'life6: 'async_trait,
Self: 'async_trait,
Source§fn execute_stream<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
tool: &'life1 str,
_params: &'life2 Value,
_action_id: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<Receiver<ToolStreamChunk>, String>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
fn execute_stream<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
tool: &'life1 str,
_params: &'life2 Value,
_action_id: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<Receiver<ToolStreamChunk>, String>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
car_ir::ToolStreamChunks; the
runtime drains it into the per-runtime handle registry while the
DAG proceeds. End the stream with a terminal chunk (done /
error); dropping the sender without one is reported as failure.
A cooperative executor should stop work when the receiver returned
here is dropped (that’s what cancellation looks like from its side). Read moreAuto Trait Implementations§
impl !Freeze for BrowserTools
impl !RefUnwindSafe for BrowserTools
impl !UnwindSafe for BrowserTools
impl Send for BrowserTools
impl Sync for BrowserTools
impl Unpin for BrowserTools
impl UnsafeUnpin for BrowserTools
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
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> ⓘ
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> ⓘ
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 more