ruby_llm-browser 0.1.0 → 0.2.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 +15 -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 +22 -12
- data/docs/RELEASE_ACTION_PLAN.md +28 -13
- data/docs/RELEASE_AUDIT.md +19 -0
- data/docs/RELEASING.md +13 -6
- data/docs/SECURITY_MODEL.md +1 -1
- data/docs/WORK.md +22 -0
- data/docs/_advanced/development-and-testing.md +100 -0
- data/docs/_advanced/live-backend-qualification.md +5 -0
- data/docs/_advanced/rails-integration.md +143 -29
- 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/whats-new-in-0-2.md +47 -0
- data/docs/_plugins/versioned_docs.rb +3 -3
- data/docs/_reference/api-and-configuration.md +188 -0
- data/docs/_reference/api-reference.md +3 -2
- data/docs/_reference/release-history.md +2 -1
- data/docs/_reference/roadmap.md +163 -0
- data/docs/_reference/upgrading.md +44 -13
- data/docs/index.md +2 -3
- data/examples/plain_ruby.rb +7 -4
- data/lib/ruby_llm/browser/doctor.rb +25 -10
- data/lib/ruby_llm/browser/version.rb +1 -1
- data/lib/ruby_llm/browser.rb +11 -0
- metadata +6 -1
data/docs/RELEASE_ACTION_PLAN.md
CHANGED
|
@@ -7,26 +7,41 @@ llms: false
|
|
|
7
7
|
|
|
8
8
|
# Release action plan
|
|
9
9
|
|
|
10
|
+
This is the historical 0.1.0 release record. Use the
|
|
11
|
+
[roadmap to 1.0]({% link _reference/roadmap.md %}) for upcoming development.
|
|
12
|
+
|
|
10
13
|
The owner selected the offline-only first release as `0.1.0`, authorized its publication,
|
|
11
|
-
and requested tag-based release automation.
|
|
12
|
-
and
|
|
14
|
+
and requested tag-based release automation. Version `0.1.0` is published. This plan records
|
|
15
|
+
the outcome and preserves the live-provider limits for future work.
|
|
13
16
|
|
|
14
17
|
## Current position
|
|
15
18
|
|
|
16
|
-
- Hardening baseline: `0ec34d4`.
|
|
17
|
-
- Expanded remote CI
|
|
19
|
+
- Hardening baseline: `0ec34d4`; release workflow fix: `8f0e8e7`.
|
|
20
|
+
- Expanded remote CI passed before release. Tagged verification and publication passed in
|
|
21
|
+
[release run 39110148539](https://github.com/yorzi/ruby_llm-browser/actions/runs/39110148539).
|
|
22
|
+
- RubyGems lists [ruby_llm-browser 0.1.0](https://rubygems.org/gems/ruby_llm-browser).
|
|
23
|
+
Publication used the registered trusted publisher for `yorzi/ruby_llm-browser`,
|
|
24
|
+
`.github/workflows/release.yml`, and environment `release`; MFA publication is recorded.
|
|
25
|
+
- The [GitHub Release](https://github.com/yorzi/ruby_llm-browser/releases/tag/v0.1.0)
|
|
26
|
+
includes the gem and `SHA256SUMS`. The gem SHA-256 is
|
|
27
|
+
`0159bf5b4d50fc1a5d129ce8e6d8235ff9a5181704d5e8168c2facb429808ed3`.
|
|
28
|
+
- The post-release Pages build passed in
|
|
29
|
+
[Docs run 39110265391](https://github.com/yorzi/ruby_llm-browser/actions/runs/39110265391).
|
|
30
|
+
The [custom-domain docs site]({% link index.md %}) shows `0.1.0 (stable)`.
|
|
31
|
+
- The first publish attempt failed before upload because the action's optional
|
|
32
|
+
experimental attestation patch activated Ruby's default zlib before Bundler. The
|
|
33
|
+
unpublished tag was moved to a fix that disables that patch; OIDC publication remains.
|
|
18
34
|
- Owner decision on 2026-10-18: first release is read-only; defer live Act and mark the
|
|
19
35
|
built-in Stagehand backend unsupported until egress and cleanup are qualified.
|
|
20
36
|
- No live provider calls are authorized or were run for this decision.
|
|
21
37
|
- Independent H1 and owner H2 are complete for exact candidate Q
|
|
22
38
|
`22d488987517b10dcd96d2713ed3d47e8818b36b`. H2 approves handoff, not RubyGems publication.
|
|
23
|
-
- The
|
|
24
|
-
|
|
25
|
-
matches installed gemspec metadata; Stagehand is covered by its pinned source
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
`release` environment.
|
|
39
|
+
- The pre-release exact-name check returned 404 on 2026-10-18; it did not reserve the
|
|
40
|
+
name. Version `0.1.0` is now registered on RubyGems. The resolved 26-gem runtime license
|
|
41
|
+
inventory matches installed gemspec metadata; Stagehand is covered by its pinned source
|
|
42
|
+
MIT text.
|
|
43
|
+
- The owner instructed publication separately from H2's handoff approval. The gem requires
|
|
44
|
+
MFA, and RubyGems records the successful publication as MFA-protected.
|
|
30
45
|
|
|
31
46
|
## Release scope
|
|
32
47
|
|
|
@@ -42,9 +57,9 @@ exact Q `22d488987517b10dcd96d2713ed3d47e8818b36b`; the approved Specs candidate
|
|
|
42
57
|
| --- | --- | --- |
|
|
43
58
|
| Release scope / Act | H2 approved the read-only scope and KPI proposal against exact Q. Live Act remains a later-version feature. | Keep the Stagehand adapter disabled and preserve the H2 decision in release docs. |
|
|
44
59
|
| Provider qualification | No live call is authorized for the first release. A later live release needs a named deployment and approval of data-processing/billing owners. | Record the unsupported egress and cleanup guarantees. Do not use a host assertion as qualification. |
|
|
45
|
-
| Name and account | The owner authorized publication as `ruby_llm-browser`;
|
|
60
|
+
| Name and account | The owner authorized publication as `ruby_llm-browser`; version `0.1.0` is registered and MFA-protected. | Use the existing trusted publisher for future tags; do not add a long-lived RubyGems API key to GitHub. |
|
|
46
61
|
| Formal approval | H1 and H2 are complete for exact Q; C/R registration and implementation baseline receipt remain pending. | Preserve the historical approval. Do not represent H2 as RubyGems authorization; the owner's later release instruction supplies that authorization. |
|
|
47
|
-
| Publication |
|
|
62
|
+
| Publication | Version `0.1.0` is published under tag `v0.1.0`; GitHub Release assets and stable Pages are live. | For each later version, align gem/docs/changelog metadata and push the matching tag. The release workflow verifies tests, advisories and package contents before OIDC publishing; Docs deploys after success. |
|
|
48
63
|
|
|
49
64
|
## Provider questions to resolve before live tests
|
|
50
65
|
|
data/docs/RELEASE_AUDIT.md
CHANGED
|
@@ -156,3 +156,22 @@ does not authorize provider calls, make Stagehand supported, or implement live A
|
|
|
156
156
|
approved Specs Q remains identified by its historical candidate label `0.3.0-draft`.
|
|
157
157
|
RubyGems publication and GitHub Pages deployment results are recorded separately from
|
|
158
158
|
this pre-release audit snapshot.
|
|
159
|
+
|
|
160
|
+
## Publication outcome (2026-10-18)
|
|
161
|
+
|
|
162
|
+
The owner authorized publishing the offline-only `0.1.0` package after the earlier audit
|
|
163
|
+
snapshot. The RubyGems trusted publisher is registered for repository `yorzi/ruby_llm-browser`,
|
|
164
|
+
workflow `release.yml`, and environment `release`. The corrected tagged workflow
|
|
165
|
+
[39110148539](https://github.com/yorzi/ruby_llm-browser/actions/runs/39110148539) passed
|
|
166
|
+
tagged-package verification and published the gem with GitHub OIDC. RubyGems lists
|
|
167
|
+
[version 0.1.0](https://rubygems.org/gems/ruby_llm-browser), published with MFA metadata;
|
|
168
|
+
the [GitHub Release](https://github.com/yorzi/ruby_llm-browser/releases/tag/v0.1.0)
|
|
169
|
+
contains the gem and checksum. The custom-domain [documentation site]({% link index.md %})
|
|
170
|
+
is deployed and shows `0.1.0 (stable)`.
|
|
171
|
+
|
|
172
|
+
The first tag run, [39109944660](https://github.com/yorzi/ruby_llm-browser/actions/runs/39109944660),
|
|
173
|
+
failed before upload because the action's optional experimental attestation patch loaded
|
|
174
|
+
RubyGems before Bundler and activated Ruby's default zlib. The unpublished tag was moved
|
|
175
|
+
to a workflow fix that disables that optional patch; OIDC publishing remains active.
|
|
176
|
+
This release does not close provider qualification: no live egress, TTL, billing, or
|
|
177
|
+
cleanup calls were made. Stagehand remains unsupported, and full live Act remains deferred.
|
data/docs/RELEASING.md
CHANGED
|
@@ -47,6 +47,7 @@ BUNDLE_GEMFILE=gemfiles/rails_8_0.gemfile bundle install
|
|
|
47
47
|
BUNDLE_GEMFILE=gemfiles/rails_8_0.gemfile bundle exec rspec
|
|
48
48
|
|
|
49
49
|
bundle exec rake build
|
|
50
|
+
bin/verify-release --candidate # for unreleased development candidates
|
|
50
51
|
bundle exec ruby bin/verify-package --rails --audit
|
|
51
52
|
```
|
|
52
53
|
|
|
@@ -101,10 +102,16 @@ made for `0.1.0`.
|
|
|
101
102
|
## Releasing a version
|
|
102
103
|
|
|
103
104
|
For a later version, update the gem version in `lib/ruby_llm/browser/version.rb` and the
|
|
104
|
-
documentation version in `docs/_config.yml` to the same value. Keep `released: false`
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
documentation version in `docs/_config.yml` to the same value. Keep `released: false`
|
|
106
|
+
while preparing a candidate. Set it to `true` and update `stable_version` when the
|
|
107
|
+
owner authorizes a release. The documentation builder uses release tags
|
|
108
|
+
for the stable site and builds the working tree under `/next/`. Add a matching release
|
|
109
|
+
entry to `CHANGELOG.md` and `docs/_reference/release-history.md`.
|
|
110
|
+
|
|
111
|
+
During candidate development, keep changes under `Unreleased` in the changelog and
|
|
112
|
+
run `bin/verify-release --candidate`. Before tagging, move them to a dated release
|
|
113
|
+
section and run `bin/verify-release` without that flag. The tag workflow requires
|
|
114
|
+
released metadata; local candidate verification cannot enable publication.
|
|
108
115
|
|
|
109
116
|
Run the checks above, review the package contents and push the completed commit to
|
|
110
117
|
`main`. Then create and push a matching tag, for example `v0.2.0` for gem version
|
|
@@ -127,5 +134,5 @@ workflow `release.yml`, and environment `release` before the first tag.
|
|
|
127
134
|
## Next steps
|
|
128
135
|
|
|
129
136
|
- Review the requirement evidence in the source repository's `docs/WORK.md` and the [remaining audit findings]({% link RELEASE_AUDIT.md %}).
|
|
130
|
-
- Follow the
|
|
131
|
-
|
|
137
|
+
- Follow the [roadmap to 1.0]({% link _reference/roadmap.md %}) for proposed version scope.
|
|
138
|
+
The source repository's `docs/RELEASE_ACTION_PLAN.md` preserves the 0.1.0 release record.
|
data/docs/SECURITY_MODEL.md
CHANGED
|
@@ -113,5 +113,5 @@ qualification. Cleanup and TTL are best-effort, and cost values are advisory.
|
|
|
113
113
|
|
|
114
114
|
## Next steps
|
|
115
115
|
|
|
116
|
-
- Follow [Rails recovery]({% link
|
|
116
|
+
- Follow [Rails recovery]({% link _advanced/rails-integration.md %}) to schedule cleanup and protect status access.
|
|
117
117
|
- Review [the release audit]({% link RELEASE_AUDIT.md %}) for evidence and remaining blockers.
|
data/docs/WORK.md
CHANGED
|
@@ -242,6 +242,28 @@ the tag's stable documentation only after that release workflow succeeds. The fi
|
|
|
242
242
|
is pushed only after the trusted publisher is registered for this repository and the
|
|
243
243
|
`release.yml` workflow under the `release` GitHub environment.
|
|
244
244
|
|
|
245
|
+
### 0.1.0 publication receipt (2026-10-18)
|
|
246
|
+
|
|
247
|
+
The first tagged workflow run failed before the gem upload because the action's optional
|
|
248
|
+
experimental attestation patch loaded RubyGems before Bundler and activated Ruby 3.3's
|
|
249
|
+
default zlib instead of the locked patched zlib. No gem was published by that attempt.
|
|
250
|
+
The release action now has attestations disabled; trusted OIDC publishing remains enabled.
|
|
251
|
+
The unpublished `v0.1.0` tag was moved to the workflow-fix commit before retrying.
|
|
252
|
+
|
|
253
|
+
| Check | Result |
|
|
254
|
+
| --- | --- |
|
|
255
|
+
| Tagged release workflow | PASS: [run 39110148539](https://github.com/yorzi/ruby_llm-browser/actions/runs/39110148539); tagged package verification and RubyGems publish jobs succeeded |
|
|
256
|
+
| RubyGems | PASS: [ruby_llm-browser 0.1.0](https://rubygems.org/gems/ruby_llm-browser); published by `yorzi/ruby_llm-browser` via `.github/workflows/release.yml` and `release` environment; MFA publication is recorded |
|
|
257
|
+
| Gem SHA-256 | `0159bf5b4d50fc1a5d129ce8e6d8235ff9a5181704d5e8168c2facb429808ed3` |
|
|
258
|
+
| GitHub Release | PASS: [v0.1.0](https://github.com/yorzi/ruby_llm-browser/releases/tag/v0.1.0) contains the `.gem` file and `SHA256SUMS` |
|
|
259
|
+
| Documentation Pages | PASS: [run 39110265391](https://github.com/yorzi/ruby_llm-browser/actions/runs/39110265391); the [custom-domain docs site]({% link index.md %}) shows `0.1.0 (stable)` |
|
|
260
|
+
| Live provider egress, TTL, billing and cleanup | NOT RUN; Stagehand remains unsupported until provider qualification |
|
|
261
|
+
| Full live Act protocol | NOT IMPLEMENTED; offline simulation only, deferred to a later version |
|
|
262
|
+
|
|
263
|
+
The published gem metadata reports MFA publication. No long-lived RubyGems API key was
|
|
264
|
+
added to GitHub; the release workflow uses the registered trusted publisher and GitHub
|
|
265
|
+
OIDC. The first failed run was [39109944660](https://github.com/yorzi/ruby_llm-browser/actions/runs/39109944660).
|
|
266
|
+
|
|
245
267
|
## Commit log
|
|
246
268
|
|
|
247
269
|
Small, meaningful commits land one piece at a time. See `git log` for the authoritative
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Development and Testing
|
|
4
|
+
nav_order: 3
|
|
5
|
+
description: Verify changes with offline contracts, installed packages, and a local browser workbench.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# {{ page.title }}
|
|
9
|
+
|
|
10
|
+
{{ page.description }}
|
|
11
|
+
|
|
12
|
+
After reading this guide, you will know:
|
|
13
|
+
|
|
14
|
+
- How to run the local verification loop.
|
|
15
|
+
- How to review browser behavior and retain fixture screenshots.
|
|
16
|
+
- What offline, browser, and installed-package checks establish.
|
|
17
|
+
|
|
18
|
+
## Run the Offline Checks
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
bin/setup
|
|
22
|
+
bin/check
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Start a behavior change with a focused failing spec. Implement the smallest public
|
|
26
|
+
contract, update its guide, then run `bin/check`. The command runs specs and RuboCop,
|
|
27
|
+
the RubyLLM 2.0 and Rails 8.0 alternate bundles, and the plain-Ruby and Rails examples.
|
|
28
|
+
Install each alternate bundle first if needed. Database suites run sequentially.
|
|
29
|
+
RuboCop uses the writable `tmp/rubocop` cache. Default tests block unmocked HTTP.
|
|
30
|
+
|
|
31
|
+
Commit each completed change with its docs and checks. Keep the next work item in the
|
|
32
|
+
[roadmap]({% link _reference/roadmap.md %}); do not create a second task ledger.
|
|
33
|
+
|
|
34
|
+
## Review the Offline Workbench
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
BUNDLE_GEMFILE=gemfiles/browser.gemfile bundle install
|
|
38
|
+
bin/workbench
|
|
39
|
+
# Open http://127.0.0.1:4024, then Ctrl-C to stop.
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The single fixture in `dev/workbench.rb` runs the real Ruby tools with FakeBackend,
|
|
43
|
+
a deterministic resolver, and an in-memory operation store. Inspect and Extract show
|
|
44
|
+
their returned hashes and fake start/cleanup counts. Enter an unapproved host to
|
|
45
|
+
exercise a denial, run offline Doctor, or check that Stagehand remains blocked. The
|
|
46
|
+
Stagehand diagnostic uses synthetic fixture credentials and never calls the provider.
|
|
47
|
+
|
|
48
|
+
The host serves local HTML and CSS, escapes returned content, requires a form token,
|
|
49
|
+
and accepts loopback Host values only. It is a development fixture, not a production
|
|
50
|
+
controller or a new public gem API. It does not load the requested page or use provider
|
|
51
|
+
credentials. The fixture and browser libraries are excluded from the gem.
|
|
52
|
+
|
|
53
|
+
## Run Browser Tests
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
bin/check-browser
|
|
57
|
+
# Or include browser tests after the offline checks:
|
|
58
|
+
bin/check --browser
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Use installed Chrome. `CHROME_BIN` can select its binary; `CHROMEDRIVER` can select an
|
|
62
|
+
installed matching driver to avoid Selenium Manager's driver resolution. Screenshots
|
|
63
|
+
go into the printed, ignored `tmp/browser/` directory. The runner fails if tests fail
|
|
64
|
+
or no screenshot is produced. CI retains fixture screenshots for seven days.
|
|
65
|
+
|
|
66
|
+
Browser scenarios cover inspect/extract, denial before dispatch, keyboard recovery at
|
|
67
|
+
a 390px device viewport, and offline/blocked-Stagehand Doctor output. Capture screenshots before closing the
|
|
68
|
+
active session, including on assertion failures. Inspect failure artifacts before
|
|
69
|
+
retrying. Screenshots support visual review; assertions establish the expected behavior.
|
|
70
|
+
|
|
71
|
+
The Puma host and Selenium port probe bind loopback. Browser test HTTP clients allow
|
|
72
|
+
loopback only; this is not a Chrome network firewall. No live provider request is part
|
|
73
|
+
of this suite. Tests close their driver sessions, and Puma ends with the test process.
|
|
74
|
+
Stop manual previews and verify no task-owned service remains after your review.
|
|
75
|
+
|
|
76
|
+
## Verify a Candidate Package
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
bin/check --browser --package
|
|
80
|
+
bin/verify-release --candidate
|
|
81
|
+
docs/bin/build.sh
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The package option builds the gem and runs `bin/verify-package --rails --audit`. It
|
|
85
|
+
installs into an empty GEM_HOME outside the checkout, resolves dependencies from the
|
|
86
|
+
registry, runs shipped examples, tests the generated migration, and audits the activated
|
|
87
|
+
runtime. Refresh the advisory database first with `bundle exec bundle-audit check --update`.
|
|
88
|
+
Package verification needs registry access; offline test success cannot replace it.
|
|
89
|
+
|
|
90
|
+
`bin/verify-release --candidate` checks version alignment, the Unreleased changelog,
|
|
91
|
+
the unreleased docs flag, and package exclusions. Without `--candidate`, it requires
|
|
92
|
+
released docs and a dated changelog; the tag workflow never passes the candidate flag.
|
|
93
|
+
The install verifier copies the input artifact before testing and prints that snapshot's
|
|
94
|
+
SHA-256. A later build cannot replace the file under verification.
|
|
95
|
+
|
|
96
|
+
Record the exact artifact hash, dependency versions, checks, and not-run boundaries in
|
|
97
|
+
the candidate validation note. Local browser tests prove fixture application wiring.
|
|
98
|
+
They do not establish real provider egress, session TTL, cleanup, billing, external
|
|
99
|
+
adoption, remote CI success, or publication. Follow the
|
|
100
|
+
[release checklist]({% link RELEASING.md %}) before releasing.
|
|
@@ -34,6 +34,11 @@ built-in Stagehand backend as unsupported: `egress_isolation` remains `:unverifi
|
|
|
34
34
|
the Engine refuses to start a session. The host cannot override this status with a
|
|
35
35
|
constructor option. A custom backend must enforce its own browser-side network boundary.
|
|
36
36
|
|
|
37
|
+
The fake report has `mode: :offline` and skips provider credential and SDK checks.
|
|
38
|
+
Stagehand reports `mode: :live` even though it remains unsupported; mode describes
|
|
39
|
+
the backend, not its qualification. See [Checking Configuration]({% link _core_features/diagnostics.md %})
|
|
40
|
+
for the report fields and checks applied to each backend.
|
|
41
|
+
|
|
37
42
|
Browserbase's documented [Allowed Domains feature](https://docs.browserbase.com/platform/browser/security/allowed-domains)
|
|
38
43
|
applies to top-frame navigations. It does not block iframe or subresource requests such
|
|
39
44
|
as scripts, images, and XHR. That setting alone cannot qualify provider egress. Any future
|
|
@@ -1,56 +1,170 @@
|
|
|
1
1
|
---
|
|
2
2
|
layout: default
|
|
3
|
-
title:
|
|
3
|
+
title: Rails Jobs and Recovery
|
|
4
4
|
nav_order: 1
|
|
5
|
-
|
|
5
|
+
redirect_from:
|
|
6
|
+
- /RAILS/
|
|
7
|
+
description: Run bounded read-only operations with durable state and independently scheduled cleanup.
|
|
6
8
|
---
|
|
7
9
|
|
|
8
|
-
#
|
|
10
|
+
# Rails jobs and recovery
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
{: .fs-6 .fw-300 }
|
|
12
|
+
Run bounded read-only operations with durable state and independently scheduled cleanup.
|
|
12
13
|
|
|
13
14
|
After reading this guide, you will know:
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
- How to install the adapter's tables.
|
|
17
|
+
- How to build a freshly authorized job context with matching budgets.
|
|
18
|
+
- How to inspect status, cancel work, and recover orphaned sessions.
|
|
18
19
|
|
|
19
|
-
##
|
|
20
|
+
## Installing the adapter
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
Your application supplies Rails 8, Active Record, Active Job, and a database adapter.
|
|
23
|
+
They are not runtime dependencies of the plain-Ruby gem.
|
|
23
24
|
|
|
24
25
|
```ruby
|
|
25
26
|
require "ruby_llm/browser/rails"
|
|
26
27
|
```
|
|
27
28
|
|
|
28
|
-
```
|
|
29
|
+
```bash
|
|
29
30
|
bin/rails generate ruby_llm:browser:install
|
|
30
31
|
bin/rails db:migrate
|
|
31
32
|
```
|
|
32
33
|
|
|
33
|
-
The generator creates
|
|
34
|
-
|
|
34
|
+
The generator creates operations, approvals, and per-actor reservation-lock tables.
|
|
35
|
+
SQLite and PostgreSQL are accepted by the store, but only SQLite concurrency is tested
|
|
36
|
+
locally. MySQL is not supported by this adapter's partial indexes/locking contract.
|
|
37
|
+
Use a database timeout appropriate to your workload. Database lock failures fail closed;
|
|
38
|
+
they must not be handled by retrying a browser call with a new operation ID.
|
|
35
39
|
|
|
36
|
-
|
|
40
|
+
`Schema.create!` is for disposable fixtures, not production migrations or schema upgrades.
|
|
41
|
+
The [offline Rails example](https://github.com/yorzi/ruby_llm-browser/blob/main/examples/rails_adapter.rb) requires no full Rails app.
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
run authorization, and use the same operation store and budget limits as the reservation.
|
|
40
|
-
Never put provider credentials or authorization decisions in model arguments or job
|
|
41
|
-
payloads. Protect queue storage because URLs, instructions, and schemas are persisted.
|
|
43
|
+
## Configuring the trusted context factory
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
```ruby
|
|
46
|
+
# config/initializers/ruby_llm_browser.rb
|
|
47
|
+
require "ruby_llm/browser/rails"
|
|
48
|
+
|
|
49
|
+
browser_budget = RubyLLM::Browser::Budget.new(max_seconds: 30, max_steps: 6)
|
|
50
|
+
RubyLLM::Browser::Rails.context_factory = lambda do |actor_id:, run_id:|
|
|
51
|
+
# Resolve authenticated host records and recheck authorization, consent and revocation.
|
|
52
|
+
# Build policy/backend from those records, never from job or model-supplied credentials.
|
|
53
|
+
RubyLLM::Browser::Context.new(
|
|
54
|
+
actor_id: actor_id, run_id: run_id,
|
|
55
|
+
backend: qualified_backend, source_policy: policy,
|
|
56
|
+
operation_store: RubyLLM::Browser::Rails.operation_store,
|
|
57
|
+
budget: browser_budget
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`qualified_backend` and `policy` above are host objects, not global APIs supplied by the
|
|
63
|
+
gem. The factory must use the **same operation-store instance and budget limits** as
|
|
64
|
+
the queued reservation. Construct different budgets per run only from trusted records
|
|
65
|
+
that the factory can retrieve again. An optional approval store does not enable Act in
|
|
66
|
+
jobs; `OperationJob` accepts only `inspect` and `extract`.
|
|
67
|
+
|
|
68
|
+
## Enqueuing a read-only operation
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
operation = RubyLLM::Browser::Rails::OperationJob.enqueue(
|
|
72
|
+
actor_id: current_user.id.to_s, run_id: research_run.id.to_s,
|
|
73
|
+
kind: :inspect, url: "https://docs.example.com/",
|
|
74
|
+
budget: browser_budget, idempotency_key: "research-#{research_run.id}"
|
|
75
|
+
)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
For extraction, pass `kind: :extract` and a host-pinned JSON `schema:`. Optional
|
|
79
|
+
`instruction:` and `max_bytes:` have the same meaning as on the tools.
|
|
80
|
+
|
|
81
|
+
One actor/run/key identifies one exact payload and budget. A changed payload using the
|
|
82
|
+
same key is rejected. Repeated enqueue calls may add duplicate queue deliveries, but
|
|
83
|
+
they attach to the same durable operation. Starting is atomically claimed once. A job
|
|
84
|
+
that sees a started, unknown, pending-cleanup, or terminal operation cannot start it
|
|
85
|
+
again. No automatic browser retry is configured.
|
|
86
|
+
|
|
87
|
+
Reservation and queue insertion are separate transactions. If enqueueing fails, retain
|
|
88
|
+
the returned operation identity when available and use the same idempotency key after
|
|
89
|
+
investigation. Schedule the reaper to reclaim expired reservations that never started.
|
|
44
90
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
91
|
+
Configure `RubyLLM::Browser::Rails.job_queue = :browser` if you need a separate queue.
|
|
92
|
+
Jobs suppress argument logging, but queues still persist URLs, instructions and schemas.
|
|
93
|
+
Protect queue access, storage, retention and encryption in the host application.
|
|
94
|
+
|
|
95
|
+
## Reading status and progress
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
store = RubyLLM::Browser::Rails.operation_store
|
|
99
|
+
operation = store.fetch!(operation_id)
|
|
100
|
+
# Authorize this read against the authenticated actor/run before returning anything.
|
|
101
|
+
summary = operation.summary
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`summary` omits provider session IDs and budget internals. It reports state, steps,
|
|
105
|
+
bytes, fence, timestamps, error code and cancellation flag. It is coarse progress,
|
|
106
|
+
not a percentage-complete promise. No result body is durably stored by the job; the
|
|
107
|
+
host must explicitly implement authorized result storage/delivery if needed. Do not
|
|
108
|
+
rely on an Active Job return value after asynchronous execution.
|
|
109
|
+
|
|
110
|
+
The stores are trusted server APIs, not tenant-safe controllers. They expose unscoped
|
|
111
|
+
fetch/sweep methods for workers; never expose them directly to model arguments or HTTP.
|
|
112
|
+
Tool progress callbacks are feature-detected on RubyLLM 2.1+, and contain no raw URL.
|
|
113
|
+
|
|
114
|
+
## Cancelling and reaping
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
store.cancel(operation_id, actor_id: current_user.id.to_s,
|
|
118
|
+
run_id: research_run.id.to_s, now: Time.now.utc)
|
|
119
|
+
RubyLLM::Browser::Rails::Reaper.new(backend: qualified_backend).sweep
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Cancellation of a never-started reservation is terminal immediately. Otherwise it sets
|
|
123
|
+
`cancel_requested`, fences stale workers, and remains `cleanup_pending` with quota held.
|
|
124
|
+
It cannot undo an in-flight provider request. A returned session ID is persisted even
|
|
125
|
+
if cancellation raced with session creation.
|
|
126
|
+
|
|
127
|
+
Run a reaper regularly in an independent scheduler, not only in the operation worker's
|
|
128
|
+
ensure block. A reaper fences workers **before** reconciliation/cleanup, tries to end
|
|
129
|
+
known sessions even when provider reconciliation is unavailable, and reports `failed`
|
|
130
|
+
rather than claiming a database write succeeded. `ttl_seconds:` is an optional positive
|
|
131
|
+
idle threshold, not proof that the provider's billable session has expired.
|
|
132
|
+
|
|
133
|
+
Stagehand exposes no correlation endpoint here. An unknown start without a session ID
|
|
134
|
+
remains unknown and holds quota until the host supplies provider-confirmed evidence.
|
|
135
|
+
Alert on unknown/pending/failed entries. Never free quota just because enough local time
|
|
136
|
+
passed. An unknown action outcome remains in the result/error code even if session
|
|
137
|
+
cleanup succeeds; do not replay it.
|
|
138
|
+
|
|
139
|
+
One reaper/backend instance must cover only operations belonging to that provider
|
|
140
|
+
configuration. The current table has no backend credential-configuration binding.
|
|
141
|
+
Multi-provider/multi-credential deployments need a host-scoped store or a future schema
|
|
142
|
+
extension before a global sweep is safe.
|
|
143
|
+
|
|
144
|
+
## Upgrading an earlier development snapshot
|
|
145
|
+
|
|
146
|
+
If you installed the generator from an earlier development snapshot, preserve your data
|
|
147
|
+
and add an explicit migration for these new fields instead of rerunning `create_table`
|
|
148
|
+
or dropping the database:
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
class HardenBrowserBookkeeping < ActiveRecord::Migration[8.1]
|
|
152
|
+
def change
|
|
153
|
+
create_table :ruby_llm_browser_actors, id: :string do |t|
|
|
154
|
+
t.integer :sequence, null: false, default: 0
|
|
155
|
+
end
|
|
156
|
+
add_column :ruby_llm_browser_operations, :cancel_requested, :boolean, default: false, null: false
|
|
157
|
+
add_column :ruby_llm_browser_operations, :request_digest, :string
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
```
|
|
49
161
|
|
|
50
|
-
|
|
51
|
-
|
|
162
|
+
Adapt this migration if any additions already exist. Drain workers during the upgrade.
|
|
163
|
+
Legacy rows without request digests are not payload-bound, so do not reuse their
|
|
164
|
+
idempotency keys for new work. Inspect earlier terminal cancellations for sessions that
|
|
165
|
+
may not have been confirmed closed before reclaiming them.
|
|
52
166
|
|
|
53
|
-
## Next
|
|
167
|
+
## Next steps
|
|
54
168
|
|
|
55
|
-
|
|
56
|
-
|
|
169
|
+
- Review [the API]({% link _reference/api-and-configuration.md %}) for result interpretation and budget semantics.
|
|
170
|
+
- Review [release blockers]({% link RELEASE_AUDIT.md %}) before production deployment.
|
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.2.0"
|
|
112
|
+
stable_version: "0.2.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
|