class RubyLLM::Browser::Act

One host-approved browser action. Disabled unless the host configures an {ApprovalStore} and issues a matching single-use {Approval}. Currently simulation-only: {Engine} refuses all non-fake Act backends until the required same-session/target approval protocol is implemented.

‘Act` is opt-in and must never be registered by default. Two gates protect it:

  1. RubyLLM’s ‘requires_approval` pauses the tool call, and this class’s instance approval resolver reads the host {ApprovalStore} — a side-effect-free read, because RubyLLM may call the resolver several times. A bare ‘Chat#approve` records no host approval and therefore dispatches nothing.

  2. Immediately before dispatch, the {Engine} re-normalizes the action against policy and atomically consumes the approval exactly once, bound to this actor, run, URL, page revision and exact action digest. A replayed, expired, revoked, cross-actor or stale-page approval denies without dispatching.

Purchases, posts, account changes, credential entry and access-control bypass stay outside the allowed set even with a broad approval. A provider timeout after dispatch is an ‘unknown` outcome that requires a new explicit decision, never an automatic retry.

Public Instance Methods

approval_resolver() click to toggle source

The instance-level resolver so it can read this tool’s host {ApprovalStore}.

It only reads: it never consumes an approval and never dispatches. Returning ‘true` merely lets the call proceed to {Engine#act}, which performs the authoritative, atomic, fully-bound check immediately before dispatch.

# File lib/ruby_llm/browser/tools/act.rb, line 70
def approval_resolver
  lambda do |tool_call|
    approve?(tool_call.arguments)
  end
end
execute(url:, approval_id:, method:, selector:, description: nil, arguments: nil) click to toggle source
# File lib/ruby_llm/browser/tools/act.rb, line 50
def execute(url:, approval_id:, method:, selector:, description: nil, arguments: nil)
  report("Checking an approved browser action")
  action = {
    "method" => method,
    "selector" => selector,
    "description" => description,
    "arguments" => Array(arguments).map(&:to_s)
  }
  engine.act(url: url, approval_id: approval_id, action: action).to_h
rescue Error => e
  failure(e)
rescue StandardError
  unexpected_failure
end