ruby_llm-browser 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -0
- data/CONTRIBUTING.md +8 -1
- data/README.md +25 -96
- data/docs/API.md +5 -172
- data/docs/RAILS.md +5 -162
- data/docs/README.md +23 -12
- data/docs/RELEASE_ACTION_PLAN.md +28 -13
- data/docs/RELEASE_AUDIT.md +19 -0
- data/docs/RELEASING.md +24 -12
- data/docs/SECURITY_MODEL.md +1 -1
- data/docs/WORK.md +22 -0
- data/docs/_advanced/development-and-testing.md +107 -0
- data/docs/_advanced/live-backend-qualification.md +5 -0
- data/docs/_advanced/rails-integration.md +147 -29
- data/docs/_advanced/result-delivery.md +119 -0
- data/docs/_config.yml +8 -4
- data/docs/_core_features/diagnostics.md +68 -0
- data/docs/_core_features/inspect-extract.md +18 -2
- data/docs/_data/navigation.yml +2 -0
- data/docs/_getting_started/getting-started.md +11 -1
- data/docs/_getting_started/overview.md +3 -0
- data/docs/_getting_started/whats-new-in-0-3.md +48 -0
- data/docs/_plugins/versioned_docs.rb +3 -3
- data/docs/_reference/api-and-configuration.md +203 -0
- data/docs/_reference/api-reference.md +3 -2
- data/docs/_reference/release-history.md +3 -1
- data/docs/_reference/roadmap.md +171 -0
- data/docs/_reference/upgrading.md +48 -14
- data/docs/_reference/whats-new-in-0-2.md +46 -0
- data/docs/index.md +2 -3
- data/examples/plain_ruby.rb +7 -4
- data/examples/rails_results.rb +141 -0
- data/lib/ruby_llm/browser/doctor.rb +25 -10
- data/lib/ruby_llm/browser/rails/operation_job.rb +16 -4
- data/lib/ruby_llm/browser/rails/result_delivery_error.rb +22 -0
- data/lib/ruby_llm/browser/rails.rb +16 -0
- data/lib/ruby_llm/browser/result.rb +3 -3
- data/lib/ruby_llm/browser/version.rb +1 -1
- data/lib/ruby_llm/browser.rb +11 -0
- metadata +11 -2
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Rails Result Delivery
|
|
4
|
+
nav_order: 2
|
|
5
|
+
description: Persist sanitized background results in your application and recover delivery separately from browser cleanup.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# {{ page.title }}
|
|
9
|
+
|
|
10
|
+
{{ page.description }}
|
|
11
|
+
|
|
12
|
+
After reading this guide, you will know:
|
|
13
|
+
|
|
14
|
+
- How to receive a background operation's bounded result.
|
|
15
|
+
- How to store and authorize results in your application.
|
|
16
|
+
- How to recover delivery without repeating browser work.
|
|
17
|
+
|
|
18
|
+
## Persist a Result
|
|
19
|
+
|
|
20
|
+
Configure the optional Rails adapter and its context factory first. See
|
|
21
|
+
[Rails jobs and recovery]({% link _advanced/rails-integration.md %}). Register a trusted
|
|
22
|
+
callback in your initializer:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
RubyLLM::Browser::Rails.result_delivery = lambda do |operation:, result:|
|
|
26
|
+
# Your host service persists result.to_h with operation.id, actor_id and run_id.
|
|
27
|
+
BrowserResults.persist(operation: operation, payload: result.to_h)
|
|
28
|
+
end
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`BrowserResults` is your application service. It is not a gem class. The callback
|
|
32
|
+
receives an immutable `Operation` snapshot and the core's sanitized, bounded `Result`.
|
|
33
|
+
Persist `result.to_h` or `result.to_json`, rather than the operation object, which
|
|
34
|
+
contains a provider session ID for trusted bookkeeping.
|
|
35
|
+
|
|
36
|
+
The callback runs synchronously in the worker after the engine attempts cleanup and
|
|
37
|
+
before the job returns. It receives successful, truncated, error, unknown, and
|
|
38
|
+
cleanup-pending results. Preflight exceptions have no `Result` and do not invoke it.
|
|
39
|
+
Cancellation or a changed fence detected after execution suppresses delivery. A
|
|
40
|
+
missing, already started, or terminal operation does not invoke it either.
|
|
41
|
+
|
|
42
|
+
The default is `nil`, which preserves the existing job return behavior. Setting the
|
|
43
|
+
hook to a non-callable value raises `InvalidInput`. Callback return values are ignored;
|
|
44
|
+
raise an exception if persistence fails.
|
|
45
|
+
|
|
46
|
+
## Keep Storage and Access in the Host
|
|
47
|
+
|
|
48
|
+
Run the disposable, offline host example:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
bundle exec ruby examples/rails_results.rb
|
|
52
|
+
# RESULT_AFTER_WORKER_EXIT_PASS
|
|
53
|
+
# SCOPED_READS_PASS
|
|
54
|
+
# IDEMPOTENT_WRITE_PASS
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
It writes a serialized Active Job to a temporary file, executes it in a separate
|
|
58
|
+
worker, waits for exit, and reads the schema-checked extraction from SQLite. Repeating
|
|
59
|
+
the job in another worker starts no browser session. The example's host table accepts
|
|
60
|
+
identical repeated writes and rejects conflicting bodies or actor/run identities.
|
|
61
|
+
Its file queue holds one job and is for demonstration; use a durable queue in your
|
|
62
|
+
application. The temporary database and queue file are removed on completion. Read
|
|
63
|
+
[the example source](https://github.com/yorzi/ruby_llm-browser/blob/main/examples/rails_results.rb).
|
|
64
|
+
|
|
65
|
+
Use a unique operation ID for idempotent writes. Repeating a write of the same result
|
|
66
|
+
should succeed; reject a conflicting body or actor/run identity. Retrieve with the
|
|
67
|
+
authenticated actor and run in the database query. Never use model-supplied actor IDs
|
|
68
|
+
as authorization. Recheck host revocation and retention rules when serving a result.
|
|
69
|
+
|
|
70
|
+
The gem creates no result table and adds no migrations. Keep results in your host's
|
|
71
|
+
database or durable storage. Do not rely on an Active Job return value or in-memory
|
|
72
|
+
callback state after a worker exits.
|
|
73
|
+
|
|
74
|
+
An `ok` extraction passed the pinned schema before redaction and bounding. A truncated
|
|
75
|
+
result can contain a preview instead of the original schema shape. Treat all page
|
|
76
|
+
content as untrusted. Store failures too, without interpreting `cleanup_pending` or
|
|
77
|
+
`unknown` as success. A stored result describes that attempt; a later reaper changes
|
|
78
|
+
session state, not the historical result body.
|
|
79
|
+
|
|
80
|
+
## Recover Delivery Separately
|
|
81
|
+
|
|
82
|
+
If the callback raises, the job raises `RubyLLM::Browser::Rails::ResultDeliveryError`
|
|
83
|
+
with code `RESULT_DELIVERY_FAILED`. The original callback exception is not chained,
|
|
84
|
+
so automatic job logs cannot print its potentially sensitive message. The error
|
|
85
|
+
exposes `operation` and `result` to trusted, in-process host recovery code:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
# Inside host code that catches ResultDeliveryError while these objects still exist:
|
|
89
|
+
RubyLLM::Browser::Rails.result_delivery.call(
|
|
90
|
+
operation: error.operation, result: error.result
|
|
91
|
+
)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This retries only your callback. Reauthorize recovery in the host. Keep external side
|
|
95
|
+
effects idempotent and persist the result before sending notifications. For durable
|
|
96
|
+
notification retries, write the result and a host outbox entry in one transaction.
|
|
97
|
+
An exception object does not survive worker exit as durable result storage.
|
|
98
|
+
|
|
99
|
+
A failed callback does not change the operation's session state or error code. Queue
|
|
100
|
+
redelivery of `OperationJob` does not repeat a started browser operation and does not
|
|
101
|
+
redeliver its result. Keep delivery failures visible in your job monitoring; retrying
|
|
102
|
+
the browser job is not a result-recovery mechanism.
|
|
103
|
+
|
|
104
|
+
There is no atomic transaction across provider execution, operation bookkeeping, and
|
|
105
|
+
host persistence. A process crash after execution but before persistence can lose the
|
|
106
|
+
result. The hook offers one automatic delivery attempt, not guaranteed or exactly-once
|
|
107
|
+
delivery. If host storage is unavailable, a recovery handler must save the retained
|
|
108
|
+
result to a separate durable destination before it exits. Never recover a lost result
|
|
109
|
+
by replaying an uncertain browser operation automatically.
|
|
110
|
+
|
|
111
|
+
Cancellation can race after the worker's final check. If your host forbids storing a
|
|
112
|
+
result after revocation, enforce that rule in the persistence transaction as well as
|
|
113
|
+
at read time. A callback failure must not clear cancellation, pending cleanup, or quota.
|
|
114
|
+
|
|
115
|
+
## Next Steps
|
|
116
|
+
|
|
117
|
+
Read [the API reference]({% link _reference/api-and-configuration.md %}) for result
|
|
118
|
+
fields and [Rails jobs and recovery]({% link _advanced/rails-integration.md %}) for
|
|
119
|
+
cancellation and reaper behavior.
|
data/docs/_config.yml
CHANGED
|
@@ -94,16 +94,20 @@ exclude:
|
|
|
94
94
|
- Gemfile
|
|
95
95
|
- Gemfile.lock
|
|
96
96
|
- README.md
|
|
97
|
+
- API.md
|
|
98
|
+
- RAILS.md
|
|
97
99
|
- RELEASE_ACTION_PLAN.md
|
|
98
100
|
- SPEC_BASELINE.md
|
|
99
101
|
- WORK.md
|
|
102
|
+
- evidence
|
|
100
103
|
|
|
101
104
|
# The language of code examples; `project-docs` uses it for new pages.
|
|
102
105
|
code_language: ruby
|
|
103
106
|
|
|
104
107
|
# Values that change between releases. Pages read them as {{ site.version }}
|
|
105
|
-
# and {{ site.examples.NAME }}.
|
|
106
|
-
# reads
|
|
107
|
-
released:
|
|
108
|
-
version: "0.
|
|
108
|
+
# and {{ site.examples.NAME }}. Candidates remain unreleased; the docs builder
|
|
109
|
+
# reads stable docs from the latest release tag and main under /next/.
|
|
110
|
+
released: true
|
|
111
|
+
version: "0.3.0"
|
|
112
|
+
stable_version: "0.3.0"
|
|
109
113
|
examples: {}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Checking Configuration
|
|
4
|
+
nav_order: 5
|
|
5
|
+
description: Diagnose the configured backend without opening a session or making a provider request.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# {{ page.title }}
|
|
9
|
+
|
|
10
|
+
{{ page.description }}
|
|
11
|
+
|
|
12
|
+
After reading this guide, you will know:
|
|
13
|
+
|
|
14
|
+
- How to check offline configuration without provider credentials.
|
|
15
|
+
- Which checks apply to each backend.
|
|
16
|
+
- Why a local pass cannot qualify a live deployment.
|
|
17
|
+
|
|
18
|
+
## Check an Offline Backend
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
require "ruby_llm/browser"
|
|
22
|
+
|
|
23
|
+
report = RubyLLM::Browser::Doctor.new(backend: RubyLLM::Browser::FakeBackend.new).report
|
|
24
|
+
puts report[:mode] # => offline
|
|
25
|
+
puts report[:ok] # => true
|
|
26
|
+
puts report[:summary]
|
|
27
|
+
# => configuration checks passed; live provider guarantees are not verified
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Doctor checks RubyLLM compatibility and the fake backend's capabilities. It does not
|
|
31
|
+
load the Stagehand SDK, inspect provider credentials or endpoint overrides, or open a
|
|
32
|
+
session. You do not need provider credentials to run offline checks.
|
|
33
|
+
|
|
34
|
+
## Interpret the Report
|
|
35
|
+
|
|
36
|
+
Use `ok` to decide whether configuration checks passed. Use `mode` to identify which
|
|
37
|
+
backend the report describes, not whether that backend is supported. The existing
|
|
38
|
+
`summary` and `checks` fields remain available. Each check has `name`, `status`, and
|
|
39
|
+
`detail`; statuses are `pass`, `warn`, `info`, or `fail`. Any failure makes `ok` false.
|
|
40
|
+
|
|
41
|
+
| Mode | Meaning | Checks |
|
|
42
|
+
| --- | --- | --- |
|
|
43
|
+
| `offline` | FakeBackend with fake server mode | RubyLLM and backend capabilities; no provider environment or SDK checks |
|
|
44
|
+
| `live` | Stagehand or another non-offline backend | RubyLLM and backend capabilities; Stagehand also checks its SDK and environment |
|
|
45
|
+
| `unconfigured` | No backend supplied | RubyLLM and a failed backend/egress check |
|
|
46
|
+
|
|
47
|
+
A custom backend does not depend on Stagehand diagnostics. Its capability checks
|
|
48
|
+
still enforce unverified egress, an unpinned local server, and unapproved custom-header
|
|
49
|
+
capabilities as failures. A backend's enforced-egress assertion is not independent
|
|
50
|
+
evidence of its deployment behavior.
|
|
51
|
+
|
|
52
|
+
## Diagnose Stagehand Without Calling It
|
|
53
|
+
|
|
54
|
+
Pass your host-created Stagehand backend to `Doctor.new(backend:)`. It reports `live`
|
|
55
|
+
mode and a failed `egress_isolation` check because the built-in adapter is unsupported.
|
|
56
|
+
Having an installed SDK or environment credentials cannot enable live operations.
|
|
57
|
+
|
|
58
|
+
Stagehand diagnostics report the SDK version, endpoint override names, and credential
|
|
59
|
+
presence in the supplied environment without printing values. These observations do
|
|
60
|
+
not configure the backend or replace explicit constructor credentials. Doctor never
|
|
61
|
+
calls the provider to test credentials, billing, egress, or session cleanup.
|
|
62
|
+
|
|
63
|
+
## Next Steps
|
|
64
|
+
|
|
65
|
+
- Read [live-backend qualification]({% link _advanced/live-backend-qualification.md %})
|
|
66
|
+
for the deployment evidence needed before live use.
|
|
67
|
+
- Use [development and testing]({% link _advanced/development-and-testing.md %}) to
|
|
68
|
+
exercise diagnostics in the offline browser workbench.
|
|
@@ -41,8 +41,7 @@ schema = {
|
|
|
41
41
|
"required" => [ "title" ], "additionalProperties" => false
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
inspect_tool = RubyLLM::Browser
|
|
45
|
-
extract_tool = RubyLLM::Browser::Extract.new(context: context, schema: schema)
|
|
44
|
+
inspect_tool, extract_tool = RubyLLM::Browser.tools(context: context, schema: schema)
|
|
46
45
|
|
|
47
46
|
puts inspect_tool.execute(url: "https://docs.example.com/")[:status] # => ok
|
|
48
47
|
puts extract_tool.execute(url: "https://docs.example.com/")[:data] # => {"title"=>"Example"}
|
|
@@ -54,6 +53,23 @@ instances on a configured RubyLLM chat. The host should select the context and s
|
|
|
54
53
|
the model supplies only the URL, optional instruction, and an optional positive
|
|
55
54
|
`max_bytes` limit.
|
|
56
55
|
|
|
56
|
+
## Register the Read-only Pair
|
|
57
|
+
|
|
58
|
+
Once your host has a context and schema, register both tools in one call:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
chat.with_tools(*RubyLLM::Browser.tools(context: context, schema: schema))
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The factory returns fresh Inspect and Extract instances in that order. Both use the
|
|
65
|
+
same context; Extract keeps its own immutable schema copy. It never includes Act,
|
|
66
|
+
loads credentials, or starts an operation. A missing context or schema is rejected
|
|
67
|
+
by the existing constructors. Schema contents are checked by policy when Extract
|
|
68
|
+
runs, before a session starts.
|
|
69
|
+
|
|
70
|
+
You can still construct either tool separately with `Inspect.new(context:)` or
|
|
71
|
+
`Extract.new(context:, schema:)`. That remains useful when a chat needs only one tool.
|
|
72
|
+
|
|
57
73
|
## Inspect a Page
|
|
58
74
|
|
|
59
75
|
`Inspect` navigates to one approved URL and asks the backend for observations. It does
|
data/docs/_data/navigation.yml
CHANGED
|
@@ -18,7 +18,16 @@ After reading this guide, you will know:
|
|
|
18
18
|
|
|
19
19
|
## Installation
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
{% if site.docs_unreleased %}This guide follows `main` at source version `{{ site.version }}`.
|
|
22
|
+
Install the default branch to use the APIs documented here:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
bundle add ruby_llm-browser --git https://github.com/yorzi/ruby_llm-browser --branch main
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The latest stable release is `{{ site.stable_version }}`; select its documentation
|
|
29
|
+
from the version menu before installing that release.
|
|
30
|
+
{% else %}The stable release is `{{ site.version }}`. Add it to your Gemfile:
|
|
22
31
|
|
|
23
32
|
```ruby
|
|
24
33
|
gem "ruby_llm-browser", "~> {{ site.version }}"
|
|
@@ -29,6 +38,7 @@ For unreleased development changes, install the default branch instead:
|
|
|
29
38
|
```sh
|
|
30
39
|
bundle add ruby_llm-browser --git https://github.com/yorzi/ruby_llm-browser --branch main
|
|
31
40
|
```
|
|
41
|
+
{% endif %}
|
|
32
42
|
|
|
33
43
|
Use Ruby 3.2 or later. The gem supports RubyLLM `>= 2.0, < 3` and pins Stagehand to the
|
|
34
44
|
3.21.x series. Rails is optional and is not loaded by the core entry point. See
|
|
@@ -50,3 +50,6 @@ does not click or submit forms.
|
|
|
50
50
|
* [Getting Started]({% link _getting_started/getting-started.md %}) - install and run the offline example.
|
|
51
51
|
* [Configuration]({% link _getting_started/configuration.md %}) - choose host-owned defaults.
|
|
52
52
|
* [API and configuration reference]({% link _reference/api-reference.md %}) - see options, statuses, and result fields.
|
|
53
|
+
|
|
54
|
+
Read [Rails Result Delivery]({% link _advanced/result-delivery.md %}) to persist a
|
|
55
|
+
background result in host storage and recover delivery separately from session cleanup.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: What's New in 0.3
|
|
4
|
+
redirect_from:
|
|
5
|
+
- /whats-new/
|
|
6
|
+
nav_order: 4
|
|
7
|
+
description: Deliver Rails background results to host storage without repeating browser work on delivery failure.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# {{ page.title }}
|
|
11
|
+
|
|
12
|
+
{{ page.description }}
|
|
13
|
+
|
|
14
|
+
After reading this guide, you will know:
|
|
15
|
+
|
|
16
|
+
- How to persist the result of a background operation.
|
|
17
|
+
- Which delivery failures your application must recover.
|
|
18
|
+
- Which capabilities remain unsupported.
|
|
19
|
+
|
|
20
|
+
## Rails Result Delivery
|
|
21
|
+
|
|
22
|
+
Register a host callback to receive each eligible job's sanitized `Result` after
|
|
23
|
+
execution and cleanup:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
RubyLLM::Browser::Rails.result_delivery = lambda do |operation:, result:|
|
|
27
|
+
BrowserResults.persist(operation: operation, payload: result.to_h)
|
|
28
|
+
end
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Your application supplies `BrowserResults`, storage, access checks, retention, and
|
|
32
|
+
idempotent recovery. The gem adds no database tables or runtime dependencies. Read
|
|
33
|
+
[Rails Result Delivery]({% link _advanced/result-delivery.md %}) for the contract.
|
|
34
|
+
|
|
35
|
+
Run `bundle exec ruby examples/rails_results.rb` for a disposable SQLite host example.
|
|
36
|
+
It executes a serialized job in a separate process, waits for the worker to exit,
|
|
37
|
+
then verifies result retrieval, actor/run isolation, and idempotent persistence.
|
|
38
|
+
|
|
39
|
+
## Delivery Failure Is Separate from Cleanup
|
|
40
|
+
|
|
41
|
+
A callback failure raises `Rails::ResultDeliveryError` with the retained operation and
|
|
42
|
+
result. It does not change session state. A duplicate browser job does not rerun the
|
|
43
|
+
operation or redeliver the result. Recover host delivery using the retained result;
|
|
44
|
+
do not enqueue a new browser operation to recover persistence.
|
|
45
|
+
|
|
46
|
+
The hook cannot guarantee delivery across worker crashes. Stagehand and live Act remain
|
|
47
|
+
unsupported. Review [the roadmap]({% link _reference/roadmap.md %}) for live-backend
|
|
48
|
+
qualification and the remaining 1.0 requirements.
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
# while _config.yml says `released: false`. Pages use it to show the install
|
|
7
7
|
# command for the default branch. A build of a release tag is never
|
|
8
8
|
# unreleased, even when that tag forgot to set `released: true`.
|
|
9
|
-
# - A
|
|
9
|
+
# - A stable or archive build takes `version` from _data/versions.yml, which
|
|
10
10
|
# bin/prepare_versions.rb fills in from the tag, so a tag that forgot to bump
|
|
11
|
-
# `version` still shows the right install command.
|
|
11
|
+
# `version` still shows the right install command. Next keeps its source version.
|
|
12
12
|
# - An absolute canonical_url on this site becomes a path, so the theme adds
|
|
13
13
|
# this build's base path (/next/, /v1/) and the page stays in its own
|
|
14
14
|
# build's llms.txt and sitemap.
|
|
@@ -22,7 +22,7 @@ Jekyll::Hooks.register :site, :post_read, priority: :high do |site|
|
|
|
22
22
|
else
|
|
23
23
|
site.config['docs_unreleased'] = [ 'next', 'Next (unreleased)' ].include?(current)
|
|
24
24
|
release = versions['release'].to_s
|
|
25
|
-
site.config['version'] = release unless release.empty?
|
|
25
|
+
site.config['version'] = release unless release.empty? || site.config['docs_unreleased']
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
origin = site.config['url'].to_s.delete_suffix('/')
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: API and Configuration
|
|
4
|
+
nav_order: 3
|
|
5
|
+
permalink: /api-and-configuration/
|
|
6
|
+
description: Configure trusted host objects and interpret bounded untrusted results.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# API and configuration
|
|
10
|
+
|
|
11
|
+
Configure trusted host objects and interpret bounded, untrusted results.
|
|
12
|
+
|
|
13
|
+
After reading this guide, you will know:
|
|
14
|
+
|
|
15
|
+
- How to register read-only tools.
|
|
16
|
+
- Which inputs belong to the host and which belong to the model.
|
|
17
|
+
- How to configure budgets, schemas, backends, and error handling.
|
|
18
|
+
|
|
19
|
+
## Creating a context
|
|
20
|
+
|
|
21
|
+
Use the complete offline example in [Getting Started]({% link _getting_started/getting-started.md %}). `Context.new` requires:
|
|
22
|
+
|
|
23
|
+
| Keyword | Type and meaning |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `actor_id`, `run_id` | Nonempty strings from authenticated host records. Convert numeric database IDs with `to_s`. |
|
|
26
|
+
| `backend` | A `Backend` instance. Use `FakeBackend` for offline tests. |
|
|
27
|
+
| `source_policy` | A host-created `Policy`. |
|
|
28
|
+
| `operation_store` | An `OperationStore`; durable storage is required across restarts or workers. |
|
|
29
|
+
| `approval_store` | Optional `ApprovalStore`, needed only for experimental Act. |
|
|
30
|
+
| `budget` | Optional `Budget`; defaults listed below. |
|
|
31
|
+
| `clock` | Optional callable returning a UTC `Time`. |
|
|
32
|
+
| `logger` | Optional host logger. Do not enable raw provider or tool payload logging. |
|
|
33
|
+
| `consent` | Optional host consent record. The gem records its presence; it does not collect or authenticate consent. |
|
|
34
|
+
| `metadata` | Optional host metadata. Never supply credentials here. |
|
|
35
|
+
|
|
36
|
+
The host must reauthorize actor/run access when building a context, including background
|
|
37
|
+
jobs. Passing IDs alone is not authentication. The model must never choose a backend,
|
|
38
|
+
credential, schema, source allowlist, consent record, or budget.
|
|
39
|
+
|
|
40
|
+
## Registering tools
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
chat.with_tools(*RubyLLM::Browser.tools(context: context, schema: schema))
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`Browser.tools` returns fresh Inspect and Extract instances in that order, sharing
|
|
47
|
+
the supplied context. It never includes Act or dispatches an operation. You can also
|
|
48
|
+
construct either tool separately with `Inspect.new(context:)` and
|
|
49
|
+
`Extract.new(context:, schema:)`. Constructors reject missing host bindings; schema
|
|
50
|
+
contents are validated by policy when Extract runs, before a session starts.
|
|
51
|
+
|
|
52
|
+
Both tools expose `url`, optional `instruction`, and optional positive integer
|
|
53
|
+
`max_bytes`. `max_bytes` can only tighten the policy and operation ceilings.
|
|
54
|
+
`Extract` takes its schema in the constructor, not in model arguments.
|
|
55
|
+
|
|
56
|
+
`Inspect` returns **candidate interactions**, not a screenshot or arbitrary page dump.
|
|
57
|
+
Neither read-only tool dispatches candidates automatically. Pages may still run scripts
|
|
58
|
+
and initiate requests; read-only does not mean browsing has no external effects.
|
|
59
|
+
|
|
60
|
+
`Tool#execute` and RubyLLM `Tool#call` return a Hash. If you need a `Result` object, use:
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
engine = RubyLLM::Browser::Engine.new(context: context)
|
|
64
|
+
result = engine.inspect(url: url)
|
|
65
|
+
result = engine.extract(url: url, schema: schema, instruction: "Find the title")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The optional `operation:` Engine keyword accepts a host-reserved operation with the
|
|
69
|
+
same actor/run and budget. Starting it is an atomic reserved-to-starting claim. It is
|
|
70
|
+
not a resume or retry API for active, unknown, or closed operations.
|
|
71
|
+
|
|
72
|
+
## Source policy
|
|
73
|
+
|
|
74
|
+
`Policy.new(allowed_hosts: [...])` accepts exact hosts and `*.example.com` subdomains.
|
|
75
|
+
A wildcard does not allow the bare domain. Defaults are HTTP/HTTPS and ports 80/443.
|
|
76
|
+
Keep `verify_dns: true`; `resolver:` is injectable for offline fixtures.
|
|
77
|
+
|
|
78
|
+
Other options are `allowed_schemes`, `allowed_ports`, `max_result_bytes` (65,536),
|
|
79
|
+
`max_schema_depth` (8), `max_schema_properties` (64 root properties), and
|
|
80
|
+
`max_schema_bytes` (16,384). Browser-side enforcement must also cover explicitly
|
|
81
|
+
approved asset origins, redirects, frames, popups, WebSockets, and subresources.
|
|
82
|
+
|
|
83
|
+
## Extraction schemas
|
|
84
|
+
|
|
85
|
+
Schemas must be bounded object JSON Schemas, passed as a Hash, JSON object string, or
|
|
86
|
+
an object/class supporting `to_json_schema`. Supported keywords are `type`,
|
|
87
|
+
`description`, `properties`, `required`, `items`, `enum`, `additionalProperties`,
|
|
88
|
+
`title`, `minimum`, `maximum`, `minLength`, `maxLength`, `minItems`, `maxItems`,
|
|
89
|
+
`format`, and `default`. Remote references and arbitrary schema extensions are refused.
|
|
90
|
+
|
|
91
|
+
Use `required` and `additionalProperties: false` when an exact shape matters. Provider
|
|
92
|
+
data must satisfy the schema before redaction or truncation. Invalid data returns
|
|
93
|
+
`PROVIDER_ERROR`; it is not returned as a successful extraction. A truncated preview
|
|
94
|
+
or redacted field need not retain the original schema's type. Always check the status.
|
|
95
|
+
|
|
96
|
+
## Results and errors
|
|
97
|
+
|
|
98
|
+
`Result` copies and freezes its strings and nested data. This includes operation ID,
|
|
99
|
+
error code and error message; changes to constructor inputs cannot alter a retained
|
|
100
|
+
result. Duplicate a returned string if host code needs to edit it.
|
|
101
|
+
|
|
102
|
+
`Result#to_h` contains symbol keys: `status`, `operation_id`, `final_url`,
|
|
103
|
+
`captured_at` (UTC ISO 8601), `locator`, `digest`, `truncated`, `data`, and optional
|
|
104
|
+
`error: { code:, message: }`. Locator/data objects use string keys. JSON encodes all
|
|
105
|
+
keys as strings. Credential-like query values are redacted in URL provenance.
|
|
106
|
+
|
|
107
|
+
Statuses are `ok`, `truncated`, `error`, `unknown`, and `cleanup_pending`.
|
|
108
|
+
`Result#ok?` accepts `ok` and `truncated`; it makes no factual verification claim.
|
|
109
|
+
`digest` is SHA-256 of canonical JSON of the returned, sanitized data. Very small byte
|
|
110
|
+
limits can produce an empty string or scalar preview; `truncated` is authoritative.
|
|
111
|
+
|
|
112
|
+
Engine preflight denials raise typed errors. Tools convert them into error Hashes.
|
|
113
|
+
After a session starts, the Engine attempts cleanup and returns a failure result.
|
|
114
|
+
Cleanup failure can supersede the original result with `cleanup_pending`; inspect the
|
|
115
|
+
durable operation's `error_code` and arrange host review for unknown effects.
|
|
116
|
+
|
|
117
|
+
Safe error codes: `INVALID_INPUT`, `NOT_AUTHORIZED`, `UNSUPPORTED_SECURITY_CAPABILITY`,
|
|
118
|
+
`BUDGET_EXHAUSTED`, `SESSION_UNKNOWN`, `CLEANUP_PENDING`, `APPROVAL_REQUIRED`,
|
|
119
|
+
`APPROVAL_STALE`, and `PROVIDER_ERROR`.
|
|
120
|
+
|
|
121
|
+
## Budgets
|
|
122
|
+
|
|
123
|
+
`Budget.new` defaults to `max_seconds: 60`, `max_steps: 12`, `max_bytes: 262_144`,
|
|
124
|
+
`max_concurrent: 1`, and `max_cost_usd: nil`.
|
|
125
|
+
|
|
126
|
+
`RubyLLM::Browser.configure` sets process defaults for `default_budget`,
|
|
127
|
+
`max_result_bytes`, `clock`, and `logger`. New contexts/policies use those defaults;
|
|
128
|
+
existing objects do not change. `configuration.backend` is only a reserved host slot:
|
|
129
|
+
contexts always require an explicitly supplied backend and never use a fallback.
|
|
130
|
+
|
|
131
|
+
- Steps count navigation, observation, extraction, and action calls, not start/cleanup.
|
|
132
|
+
- Bytes count retained sanitized result data, not all bytes the remote browser receives.
|
|
133
|
+
- Wall-clock checks refuse new calls after expiry. Stagehand request timeouts are bounded
|
|
134
|
+
by remaining time. Cleanup has a separate timeout and may outlive this budget.
|
|
135
|
+
- Concurrency is scoped to the actor across runs. Unknown/pending cleanup holds a slot.
|
|
136
|
+
- `max_cost_usd` is **advisory only**. There is no cost ledger or provider hard spending
|
|
137
|
+
cap in this release. Enforce billing limits in the provider/host.
|
|
138
|
+
|
|
139
|
+
## Stagehand backend status
|
|
140
|
+
|
|
141
|
+
`StagehandBackend` is unsupported for live operations in this release. It always reports
|
|
142
|
+
`egress_isolation: :unverified` and `act_supported?: false`. `Engine` refuses it before
|
|
143
|
+
the first provider request, and direct start, navigation, observation, extraction, and
|
|
144
|
+
Act calls also fail closed. No constructor option or injected client enables live use.
|
|
145
|
+
|
|
146
|
+
The adapter remains in the source for future qualification. Its client pins credentials
|
|
147
|
+
and base URL, disables retries, self-healing, CAPTCHA solving, session recording and
|
|
148
|
+
session logging, and requests a provider timeout. These controls do not prove egress,
|
|
149
|
+
TTL, billing, final-URL reporting, or cleanup. `end_session` sends no request in this
|
|
150
|
+
release and returns `false`; the operation remains `cleanup_pending`.
|
|
151
|
+
|
|
152
|
+
The constructor accepts `server: :remote`, `base_url:`, `timeout: 60.0`,
|
|
153
|
+
`custom_headers_approved: false`, `env: ENV`, and an injected `client:` for internal
|
|
154
|
+
contract tests. A future live implementation must verify all relevant environment
|
|
155
|
+
settings, egress across every browser request path, TTL and closure status, and provider
|
|
156
|
+
billing controls before it can advertise support.
|
|
157
|
+
|
|
158
|
+
## Configuration diagnostics
|
|
159
|
+
|
|
160
|
+
For diagnostics without network requests, use `Doctor.new(backend:).report`. It
|
|
161
|
+
returns `mode`, `ok`, `summary`, and `checks`. See
|
|
162
|
+
[Checking Configuration]({% link _core_features/diagnostics.md %}) for the backend-specific checks.
|
|
163
|
+
|
|
164
|
+
## Dependency security floors
|
|
165
|
+
|
|
166
|
+
Old Ruby installations can supply vulnerable default gems even when a developer's
|
|
167
|
+
lockfile audit passes. Runtime requirements explicitly exclude those versions:
|
|
168
|
+
`cgi >= 0.4.2, < 1`, `resolv >= 0.7.2, < 1`, `uri >= 1.0.4, < 2`, and
|
|
169
|
+
`zlib >= 3.2.3, < 4`. A fresh install may build native extensions for these gems.
|
|
170
|
+
Use a supported, patched Ruby interpreter as well; these floors do not patch Ruby or
|
|
171
|
+
system libraries. Audit the versions actually activated by your application, including
|
|
172
|
+
default gems, not just a development lockfile.
|
|
173
|
+
|
|
174
|
+
## Experimental Act
|
|
175
|
+
|
|
176
|
+
`Act.new(context:)` declares RubyLLM `requires_approval`. Its arguments are `url`,
|
|
177
|
+
`approval_id`, `method`, `selector`, optional `description`, and optional `arguments`.
|
|
178
|
+
The resolver reads the host store without consuming. Consumption immediately before
|
|
179
|
+
dispatch checks actor/run, exact URL/action digest, expiry, and any supplied
|
|
180
|
+
page/operation/session bindings. Revocation and consumption are atomic in the stores.
|
|
181
|
+
|
|
182
|
+
**Do not use this as a production authorization protocol yet.** Bindings are currently
|
|
183
|
+
optional; a candidate-list digest is not a DOM/target revision, and each Engine action
|
|
184
|
+
opens a fresh session. The same-session host approval flow required by the specification
|
|
185
|
+
is deferred to a later version. The Engine refuses all non-fake Act calls before starting
|
|
186
|
+
a session. Selector/description keyword filters are defense in depth, not semantic proof
|
|
187
|
+
that a click is harmless. The Stagehand adapter does not support Act in this release.
|
|
188
|
+
|
|
189
|
+
## Rails Result Delivery
|
|
190
|
+
|
|
191
|
+
After `require "ruby_llm/browser/rails"`, set `Rails.result_delivery` to a callable
|
|
192
|
+
accepting `operation:` and `result:`, or `nil` to disable it. `Rails.reset!` clears the
|
|
193
|
+
hook. The callback runs synchronously after execution and cleanup. Return values are
|
|
194
|
+
ignored; exceptions become `Rails::ResultDeliveryError` (`RESULT_DELIVERY_FAILED`),
|
|
195
|
+
which exposes `operation` and `result` to trusted recovery code. These objects are
|
|
196
|
+
not automatically persisted. Duplicate browser jobs do not retry delivery. Read
|
|
197
|
+
[Rails Result Delivery]({% link _advanced/result-delivery.md %}) for storage, access,
|
|
198
|
+
cancellation, and crash boundaries.
|
|
199
|
+
|
|
200
|
+
## Next steps
|
|
201
|
+
|
|
202
|
+
- Read [Rails integration]({% link _advanced/rails-integration.md %}) for durable workers and recovery.
|
|
203
|
+
- Read [security boundaries]({% link SECURITY_MODEL.md %}) before qualifying a live backend.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
layout: default
|
|
3
3
|
title: API Reference
|
|
4
|
-
nav_order:
|
|
4
|
+
nav_order: 4
|
|
5
5
|
guide: false
|
|
6
6
|
description: Find the RubyLLM::Browser classes for tools, policy, results, backends, and Rails jobs.
|
|
7
7
|
---
|
|
@@ -20,10 +20,11 @@ The [generated RDoc reference]({{ '/api/' | relative_url }}) documents classes a
|
|
|
20
20
|
| Simulate one host-approved action offline | `Act`, `Approval`, `ApprovalStore` |
|
|
21
21
|
| Read a bounded result | `Result` |
|
|
22
22
|
| Use an offline backend | `FakeBackend` |
|
|
23
|
+
| Diagnose configuration without dispatch | `Doctor` ([guide]({% link _core_features/diagnostics.md %})) |
|
|
23
24
|
| Adapt the Stagehand Ruby SDK | `StagehandBackend`, `Capabilities`, `Doctor` |
|
|
24
25
|
| Persist operation or approval state | `OperationStore`, `ApprovalStore` and their implementations |
|
|
25
26
|
| Run Rails background jobs and cleanup | `RubyLLM::Browser::Rails::OperationJob`, `Reaper` |
|
|
26
27
|
|
|
27
|
-
Start with [Getting Started]({% link _getting_started/getting-started.md %}) for a runnable offline example. The [API and configuration guide]({% link
|
|
28
|
+
Start with [Getting Started]({% link _getting_started/getting-started.md %}) for a runnable offline example. The [API and configuration guide]({% link _reference/api-and-configuration.md %}) explains inputs, results, limits, and errors.
|
|
28
29
|
|
|
29
30
|
The reference is generated from source comments. Build it locally with `docs/bin/build-api.sh tmp/api`.
|
|
@@ -11,13 +11,15 @@ description: Follow release tags and their documentation for RubyLLM::Browser.
|
|
|
11
11
|
{{ page.description }}
|
|
12
12
|
{: .fs-6 .fw-300 }
|
|
13
13
|
|
|
14
|
-
{% if site.docs_unreleased %}The current source build follows `main`. The latest stable release is `
|
|
14
|
+
{% if site.docs_unreleased %}The current source build follows `main`. The latest stable release is `{{ site.stable_version }}`.
|
|
15
15
|
{% else %}This documentation describes the `{{ site.version }}` release. Use the tag and
|
|
16
16
|
release notes to identify the exact source for this version.
|
|
17
17
|
{% endif %}
|
|
18
18
|
|
|
19
19
|
| Release | Date | Highlights |
|
|
20
20
|
| --- | --- | --- |
|
|
21
|
+
| [0.3.0]({% link _getting_started/whats-new-in-0-3.md %}) | 2026-10-19 | Opt-in Rails result delivery, durable host example, recovery and upgrade verification |
|
|
22
|
+
| [0.2.0]({% link _reference/whats-new-in-0-2.md %}) | 2026-10-19 | Read-only tool factory, backend-aware Doctor, and agent development/browser verification |
|
|
21
23
|
| [0.1.0](https://github.com/yorzi/ruby_llm-browser/releases/tag/v0.1.0) | 2026-10-18 | Offline read-only Inspect and Extract, Rails adapter, and Act simulation; live Stagehand and live Act are unsupported |
|
|
22
24
|
|
|
23
25
|
For changes to existing applications, follow [Upgrading]({% link _reference/upgrading.md %}).
|