ruby_llm-browser 0.1.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 +7 -0
- data/CHANGELOG.md +61 -0
- data/CODE_OF_CONDUCT.md +11 -0
- data/CONTRIBUTING.md +42 -0
- data/LICENSE.txt +21 -0
- data/NOTICE.md +92 -0
- data/README.md +139 -0
- data/SECURITY.md +46 -0
- data/docs/API.md +177 -0
- data/docs/CNAME +1 -0
- data/docs/RAILS.md +167 -0
- data/docs/README.md +16 -0
- data/docs/RELEASE_ACTION_PLAN.md +81 -0
- data/docs/RELEASE_AUDIT.md +158 -0
- data/docs/RELEASING.md +131 -0
- data/docs/SECURITY_MODEL.md +117 -0
- data/docs/SPEC_BASELINE.md +107 -0
- data/docs/WORK.md +260 -0
- data/docs/_advanced/live-backend-qualification.md +74 -0
- data/docs/_advanced/rails-integration.md +56 -0
- data/docs/_config.yml +109 -0
- data/docs/_core_features/inspect-extract.md +91 -0
- data/docs/_core_features/offline-act.md +110 -0
- data/docs/_core_features/operation-lifecycle.md +63 -0
- data/docs/_core_features/source-policy.md +61 -0
- data/docs/_data/navigation.yml +12 -0
- data/docs/_data/sidebar.yml +8 -0
- data/docs/_data/social_links.yml +3 -0
- data/docs/_getting_started/configuration.md +68 -0
- data/docs/_getting_started/getting-started.md +77 -0
- data/docs/_getting_started/overview.md +52 -0
- data/docs/_plugins/versioned_docs.rb +46 -0
- data/docs/_reference/api-reference.md +29 -0
- data/docs/_reference/release-history.md +23 -0
- data/docs/_reference/upgrading.md +33 -0
- data/docs/bin/build-api.sh +23 -0
- data/docs/bin/build.sh +161 -0
- data/docs/bin/export-api-markdown.rb +53 -0
- data/docs/bin/link_versions.rb +54 -0
- data/docs/bin/postprocess_api_seo.rb +129 -0
- data/docs/bin/prepare_versions.rb +40 -0
- data/docs/bin/serve.sh +12 -0
- data/docs/bin/versions.yml +14 -0
- data/docs/index.md +82 -0
- data/examples/plain_ruby.rb +34 -0
- data/examples/rails_adapter.rb +47 -0
- data/lib/generators/ruby_llm/browser/install_generator.rb +29 -0
- data/lib/generators/ruby_llm/browser/templates/create_ruby_llm_browser_tables.rb.tt +60 -0
- data/lib/ruby_llm/browser/approval.rb +128 -0
- data/lib/ruby_llm/browser/approval_store.rb +38 -0
- data/lib/ruby_llm/browser/backend.rb +99 -0
- data/lib/ruby_llm/browser/budget.rb +90 -0
- data/lib/ruby_llm/browser/capabilities.rb +76 -0
- data/lib/ruby_llm/browser/configuration.rb +74 -0
- data/lib/ruby_llm/browser/context.rb +117 -0
- data/lib/ruby_llm/browser/doctor.rb +134 -0
- data/lib/ruby_llm/browser/engine.rb +326 -0
- data/lib/ruby_llm/browser/errors.rb +86 -0
- data/lib/ruby_llm/browser/fake_backend.rb +134 -0
- data/lib/ruby_llm/browser/immutable.rb +19 -0
- data/lib/ruby_llm/browser/in_memory_approval_store.rb +67 -0
- data/lib/ruby_llm/browser/in_memory_operation_store.rb +174 -0
- data/lib/ruby_llm/browser/operation.rb +218 -0
- data/lib/ruby_llm/browser/operation_store.rb +92 -0
- data/lib/ruby_llm/browser/policy.rb +298 -0
- data/lib/ruby_llm/browser/rails/active_record_approval_store.rb +72 -0
- data/lib/ruby_llm/browser/rails/active_record_operation_store.rb +231 -0
- data/lib/ruby_llm/browser/rails/actor_record.rb +13 -0
- data/lib/ruby_llm/browser/rails/approval_record.rb +49 -0
- data/lib/ruby_llm/browser/rails/operation_job.rb +163 -0
- data/lib/ruby_llm/browser/rails/operation_record.rb +56 -0
- data/lib/ruby_llm/browser/rails/reaper.rb +117 -0
- data/lib/ruby_llm/browser/rails/schema.rb +81 -0
- data/lib/ruby_llm/browser/rails.rb +79 -0
- data/lib/ruby_llm/browser/redactor.rb +159 -0
- data/lib/ruby_llm/browser/result.rb +102 -0
- data/lib/ruby_llm/browser/stagehand_backend.rb +332 -0
- data/lib/ruby_llm/browser/tool.rb +70 -0
- data/lib/ruby_llm/browser/tools/act.rb +91 -0
- data/lib/ruby_llm/browser/tools/extract.rb +60 -0
- data/lib/ruby_llm/browser/tools/inspect.rb +38 -0
- data/lib/ruby_llm/browser/url_guard.rb +253 -0
- data/lib/ruby_llm/browser/version.rb +9 -0
- data/lib/ruby_llm/browser.rb +79 -0
- metadata +267 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: e6184d0ab1ce52e3a77ed427ff4e083790a7d573a51b5ea07ddffeab034b356e
|
|
4
|
+
data.tar.gz: c08d7fd335590fa99341551ce77ca6a8f8ec61662b3e63903308f56ea9ff05d6
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 3f671bfe311dea830346ce657373b81f514c227eac636576f76fb962a4690a0e688fecb476d36ef83a288d02cdc28e0bd2f8fece092b00cd8925e57cae6b3509
|
|
7
|
+
data.tar.gz: 0f11137930c35dc67cf7642db5152864fa5b101bb957bba24edeab974279c66f33e728766bb5005c29bb331b37989f09edbbaee70f461acf419ea31db9b4a209
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project aims to
|
|
5
|
+
follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-10-18
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Atomic start claims, actor quota locking, payload-bound idempotency, exact fence/state
|
|
12
|
+
checks, cancellation quota retention, and cleanup after post-start persistence errors.
|
|
13
|
+
- Reaper fencing before cleanup and recovery of known sessions without a correlation API.
|
|
14
|
+
- Host/operation output ceilings, UTF-8/escaped-JSON bounds, retained byte accounting,
|
|
15
|
+
malformed schema handling, and provider extraction schema validation.
|
|
16
|
+
- Defensive policy/approval/schema copies, safer progress/errors/provenance, and suppressed
|
|
17
|
+
Active Job argument logging.
|
|
18
|
+
- Real-clock durable timestamp round-trips and effective process budget/result defaults.
|
|
19
|
+
- Stagehand response validation, explicit disabled self-healing/CAPTCHA solving/recording,
|
|
20
|
+
environment-drift rejection, remaining-time timeouts, and no guessed final URL.
|
|
21
|
+
- Rails install generator namespace, README API errors, shipped documentation/examples,
|
|
22
|
+
and RubyLLM 2.0/2.1 public-API compatibility tests.
|
|
23
|
+
|
|
24
|
+
### Security
|
|
25
|
+
|
|
26
|
+
- Require patched CGI, DNS resolver, URI and zlib versions instead of accepting old
|
|
27
|
+
vulnerable default gems on a clean Ruby installation.
|
|
28
|
+
- The first-release scope is offline read-only. Stagehand remains unsupported until
|
|
29
|
+
provider egress and confirmed cleanup are qualified; no live calls were made. Full live
|
|
30
|
+
Act is deferred to a later version, while offline Act simulation remains available.
|
|
31
|
+
- See `docs/RELEASE_AUDIT.md` for findings, mitigations and residual limits.
|
|
32
|
+
|
|
33
|
+
The first implementation milestone. Everything below is proven offline against the fake
|
|
34
|
+
backend and an in-memory SQLite database; **no live browser provider call has been run**,
|
|
35
|
+
and mocked tests never establish remote egress isolation, TTL or billing limits.
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- Plain-Ruby Gem core (`require "ruby_llm/browser"`) with a manual require chain, no Rails
|
|
40
|
+
and no provider credentials loaded on require.
|
|
41
|
+
- Read-only `RubyLLM::Browser::Inspect` and `Extract` tools; `Extract` takes a
|
|
42
|
+
host-pinned schema instead of a model-supplied one.
|
|
43
|
+
- Simulation-only `RubyLLM::Browser::Act` (never registered by default) with a read-only RubyLLM
|
|
44
|
+
approval resolver and an atomic, digest-bound, single-use approval consumed in `execute`.
|
|
45
|
+
- Source policy: URL normalization with userinfo/scheme/port and ambiguous-IP rejection,
|
|
46
|
+
allowlist matching, and fail-closed egress qualification that returns
|
|
47
|
+
`UNSUPPORTED_SECURITY_CAPABILITY` before any session when a backend cannot prove
|
|
48
|
+
browser-side egress isolation.
|
|
49
|
+
- Durable operation lifecycle (`reserved → starting → active → closing → closed`, plus
|
|
50
|
+
`unknown` / `cleanup_pending` / `cancelled`), fencing and per-actor concurrency budgets,
|
|
51
|
+
with in-memory and ActiveRecord stores.
|
|
52
|
+
- Official Stagehand Ruby SDK adapter (loaded lazily) that passes every client argument
|
|
53
|
+
explicitly, sets `max_retries: 0` on effectful calls, drops `cdp_url`, and reports honest
|
|
54
|
+
capabilities.
|
|
55
|
+
- Bounded, sanitized `Result` with provenance, plus a redactor that strips secrets,
|
|
56
|
+
cookies and DevTools URLs.
|
|
57
|
+
- Read-only preflight `Doctor`.
|
|
58
|
+
- Optional Rails 8 adapter (`require "ruby_llm/browser/rails"`): ActiveRecord operation and
|
|
59
|
+
approval stores, a scoped Active Job with fence/cancel handling, a cleanup reaper, a
|
|
60
|
+
canonical schema module and an install generator with migration.
|
|
61
|
+
- Offline examples, documentation and an FR evidence ledger (`docs/WORK.md`).
|
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Contributor Code of Conduct
|
|
2
|
+
|
|
3
|
+
This project follows the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
|
|
4
|
+
|
|
5
|
+
Be respectful, assume good faith, and keep discussions focused on the work. Harassment,
|
|
6
|
+
discrimination, doxxing and disclosure of other people's data or credentials are not
|
|
7
|
+
acceptable. Maintainers may edit, lock or remove contributions and comments that violate
|
|
8
|
+
this code, and may ban contributors for repeated or severe violations.
|
|
9
|
+
|
|
10
|
+
Report concerns privately to the maintainer listed in the gemspec. Reports are handled
|
|
11
|
+
confidentially.
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Contributing to ruby_llm-browser
|
|
2
|
+
|
|
3
|
+
Thanks for helping. This is an unofficial community extension for
|
|
4
|
+
[RubyLLM](https://rubyllm.com), not an official RubyLLM project.
|
|
5
|
+
|
|
6
|
+
## Ground rules
|
|
7
|
+
|
|
8
|
+
1. **Fail closed.** Anything that touches URLs, egress, sessions, approvals, budgets or
|
|
9
|
+
secrets must default to deny and must be provable by a test.
|
|
10
|
+
2. **No new unsafe surface.** No arbitrary JS/shell, no credential or cookie scraping,
|
|
11
|
+
no CAPTCHA/age/access bypass, no purchases, posting or account changes, and no
|
|
12
|
+
second browser engine.
|
|
13
|
+
3. **Offline by default.** CI must never make a paid provider call. Use the fake backend
|
|
14
|
+
or an injected client. Live tests are opt-in and owner-authorized.
|
|
15
|
+
4. **Say what is not proven.** Distinguish PASS from NOT RUN. Mocked egress proves the
|
|
16
|
+
Gem's logic, never a provider's network isolation.
|
|
17
|
+
|
|
18
|
+
## Development
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bin/setup # bundle install
|
|
22
|
+
bundle exec rake # specs + rubocop
|
|
23
|
+
bundle exec rspec # specs only
|
|
24
|
+
bundle exec bundle-audit check --update
|
|
25
|
+
bundle exec rubocop -A # autocorrect style
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Changing behaviour
|
|
29
|
+
|
|
30
|
+
- Add a failing spec first, including the negative/denial case.
|
|
31
|
+
- Update `CHANGELOG.md` under `Unreleased`.
|
|
32
|
+
- Update `docs/SECURITY_MODEL.md` or `README.md` if a boundary or public API moved.
|
|
33
|
+
- Keep runnable examples and the package's local links green in
|
|
34
|
+
`spec/integration/documentation_spec.rb`.
|
|
35
|
+
- Run both alternate bundles in `gemfiles/` when changing Tool or Rails integration.
|
|
36
|
+
- Keep the Gem core loadable without Rails: `ruby -e 'require "ruby_llm/browser"'` must
|
|
37
|
+
not load `rails`, `active_job` or open any browser session.
|
|
38
|
+
|
|
39
|
+
## Pull requests
|
|
40
|
+
|
|
41
|
+
Keep commits small and focused. Explain the security impact of the change, list the
|
|
42
|
+
tests you ran, and note anything you could not verify. Maintainers control releases.
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andy Wang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/NOTICE.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
`ruby_llm-browser` is MIT licensed (see `LICENSE.txt`). It declares separate runtime
|
|
4
|
+
dependencies; no upstream source code is vendored in this Gem. The inventory below covers
|
|
5
|
+
the 26 runtime dependency gems resolved in the local lockfile on 2026-10-18 and matches
|
|
6
|
+
their exact installed gemspec license metadata. Stagehand has no license metadata in its
|
|
7
|
+
published gem, so its MIT license is tied to the pinned upstream source tag below.
|
|
8
|
+
|
|
9
|
+
This is a point-in-time technical inventory, not legal advice or trademark, affiliation,
|
|
10
|
+
account-ownership, or publication clearance. Version ranges can resolve different
|
|
11
|
+
versions later; recheck the exact artifact before distribution.
|
|
12
|
+
|
|
13
|
+
## RubyLLM (`ruby_llm`)
|
|
14
|
+
|
|
15
|
+
- License: MIT
|
|
16
|
+
- Source: <https://github.com/crmne/ruby_llm>
|
|
17
|
+
- Used for: the `RubyLLM::Tool` protocol and the chat tool-execution loop.
|
|
18
|
+
|
|
19
|
+
## Stagehand Ruby SDK (`stagehand`)
|
|
20
|
+
|
|
21
|
+
- License: MIT, as declared in the repository `LICENSE` file, "Copyright 2026 stagehand"
|
|
22
|
+
(`https://github.com/browserbase/stagehand-ruby/blob/v3.21.0/LICENSE`).
|
|
23
|
+
- Source tag: `v3.21.0` (commit `b389c6e3ca7e4a5f9d46511082a6466d37163e17`).
|
|
24
|
+
- Used for: the reference browser REST client behind
|
|
25
|
+
`RubyLLM::Browser::StagehandBackend`.
|
|
26
|
+
- Note: the published `stagehand` gem ships without license metadata and without the
|
|
27
|
+
`LICENSE` file, so this notice cites the repository license at the pinned tag. Pin
|
|
28
|
+
the exact version and checksum in your `Gemfile.lock`.
|
|
29
|
+
|
|
30
|
+
## Point-in-time runtime inventory (2026-10-18)
|
|
31
|
+
|
|
32
|
+
Resolved locally on Ruby 3.3.5 with RubyLLM 2.1.1. Every dependency row was matched to
|
|
33
|
+
the local lockfile version and installed gemspec license metadata. RubyGems version links
|
|
34
|
+
identify the exact distributed releases; Stagehand's pinned-source exception is noted
|
|
35
|
+
above. Rails/Active Record/Active Job and sqlite3 are host/test dependencies and are not
|
|
36
|
+
part of this Gem's runtime dependency graph.
|
|
37
|
+
|
|
38
|
+
| Dependency | Version | Declared license(s) | RubyGems version record |
|
|
39
|
+
| --- | --- | --- | --- |
|
|
40
|
+
| [`ruby_llm`](https://rubygems.org/gems/ruby_llm/versions/2.1.1) | 2.1.1 | MIT | [RubyGems version](https://rubygems.org/gems/ruby_llm/versions/2.1.1) |
|
|
41
|
+
| [`stagehand`](https://rubygems.org/gems/stagehand/versions/3.21.0) | 3.21.0 | No gem metadata; pinned source MIT text below | [RubyGems version](https://rubygems.org/gems/stagehand/versions/3.21.0) |
|
|
42
|
+
| [`json_schemer`](https://rubygems.org/gems/json_schemer/versions/2.5.0) | 2.5.0 | MIT | [RubyGems version](https://rubygems.org/gems/json_schemer/versions/2.5.0) |
|
|
43
|
+
| [`hana`](https://rubygems.org/gems/hana/versions/1.3.7) | 1.3.7 | MIT | [RubyGems version](https://rubygems.org/gems/hana/versions/1.3.7) |
|
|
44
|
+
| [`simpleidn`](https://rubygems.org/gems/simpleidn/versions/0.3.0) | 0.3.0 | MIT | [RubyGems version](https://rubygems.org/gems/simpleidn/versions/0.3.0) |
|
|
45
|
+
| [`regexp_parser`](https://rubygems.org/gems/regexp_parser/versions/2.13.1) | 2.13.1 | MIT | [RubyGems version](https://rubygems.org/gems/regexp_parser/versions/2.13.1) |
|
|
46
|
+
| [`schematist`](https://rubygems.org/gems/schematist/versions/1.1.0) | 1.1.0 | MIT | [RubyGems version](https://rubygems.org/gems/schematist/versions/1.1.0) |
|
|
47
|
+
| [`zeitwerk`](https://rubygems.org/gems/zeitwerk/versions/2.8.3) | 2.8.3 | MIT | [RubyGems version](https://rubygems.org/gems/zeitwerk/versions/2.8.3) |
|
|
48
|
+
| [`connection_pool`](https://rubygems.org/gems/connection_pool/versions/3.0.2) | 3.0.2 | MIT | [RubyGems version](https://rubygems.org/gems/connection_pool/versions/3.0.2) |
|
|
49
|
+
| [`faraday`](https://rubygems.org/gems/faraday/versions/2.15.0) | 2.15.0 | MIT | [RubyGems version](https://rubygems.org/gems/faraday/versions/2.15.0) |
|
|
50
|
+
| [`faraday-net_http`](https://rubygems.org/gems/faraday-net_http/versions/3.5.0) | 3.5.0 | MIT | [RubyGems version](https://rubygems.org/gems/faraday-net_http/versions/3.5.0) |
|
|
51
|
+
| [`faraday-multipart`](https://rubygems.org/gems/faraday-multipart/versions/1.2.0) | 1.2.0 | MIT | [RubyGems version](https://rubygems.org/gems/faraday-multipart/versions/1.2.0) |
|
|
52
|
+
| [`faraday-retry`](https://rubygems.org/gems/faraday-retry/versions/2.4.0) | 2.4.0 | MIT | [RubyGems version](https://rubygems.org/gems/faraday-retry/versions/2.4.0) |
|
|
53
|
+
| [`multipart-post`](https://rubygems.org/gems/multipart-post/versions/2.4.1) | 2.4.1 | MIT | [RubyGems version](https://rubygems.org/gems/multipart-post/versions/2.4.1) |
|
|
54
|
+
| [`marcel`](https://rubygems.org/gems/marcel/versions/2.1.0) | 2.1.0 | MIT / Apache-2.0 | [RubyGems version](https://rubygems.org/gems/marcel/versions/2.1.0) |
|
|
55
|
+
| [`base64`](https://rubygems.org/gems/base64/versions/0.3.0) | 0.3.0 | Ruby / BSD-2-Clause | [RubyGems version](https://rubygems.org/gems/base64/versions/0.3.0) |
|
|
56
|
+
| [`bigdecimal`](https://rubygems.org/gems/bigdecimal/versions/4.1.3) | 4.1.3 | Ruby / BSD-2-Clause | [RubyGems version](https://rubygems.org/gems/bigdecimal/versions/4.1.3) |
|
|
57
|
+
| [`cgi`](https://rubygems.org/gems/cgi/versions/0.5.2) | 0.5.2 | Ruby / BSD-2-Clause | [RubyGems version](https://rubygems.org/gems/cgi/versions/0.5.2) |
|
|
58
|
+
| [`json`](https://rubygems.org/gems/json/versions/3.1.0) | 3.1.0 | Ruby | [RubyGems version](https://rubygems.org/gems/json/versions/3.1.0) |
|
|
59
|
+
| [`logger`](https://rubygems.org/gems/logger/versions/1.7.0) | 1.7.0 | Ruby / BSD-2-Clause | [RubyGems version](https://rubygems.org/gems/logger/versions/1.7.0) |
|
|
60
|
+
| [`net-http`](https://rubygems.org/gems/net-http/versions/0.10.0) | 0.10.0 | Ruby / BSD-2-Clause | [RubyGems version](https://rubygems.org/gems/net-http/versions/0.10.0) |
|
|
61
|
+
| [`net-protocol`](https://rubygems.org/gems/net-protocol/versions/0.4.0) | 0.4.0 | Ruby / BSD-2-Clause | [RubyGems version](https://rubygems.org/gems/net-protocol/versions/0.4.0) |
|
|
62
|
+
| [`timeout`](https://rubygems.org/gems/timeout/versions/0.6.1) | 0.6.1 | Ruby / BSD-2-Clause | [RubyGems version](https://rubygems.org/gems/timeout/versions/0.6.1) |
|
|
63
|
+
| [`uri`](https://rubygems.org/gems/uri/versions/1.1.2) | 1.1.2 | Ruby / BSD-2-Clause | [RubyGems version](https://rubygems.org/gems/uri/versions/1.1.2) |
|
|
64
|
+
| [`resolv`](https://rubygems.org/gems/resolv/versions/0.8.1) | 0.8.1 | Ruby / BSD-2-Clause | [RubyGems version](https://rubygems.org/gems/resolv/versions/0.8.1) |
|
|
65
|
+
| [`zlib`](https://rubygems.org/gems/zlib/versions/3.2.4) | 3.2.4 | Ruby / BSD-2-Clause | [RubyGems version](https://rubygems.org/gems/zlib/versions/3.2.4) |
|
|
66
|
+
|
|
67
|
+
Rails/Active Record/Active Job are optional host dependencies (MIT); sqlite3 is a test/
|
|
68
|
+
host adapter (BSD-3-Clause). Development-only dependencies are not gem runtime requirements.
|
|
69
|
+
|
|
70
|
+
## Stagehand pinned source license text
|
|
71
|
+
|
|
72
|
+
Source: <https://github.com/browserbase/stagehand-ruby/blob/v3.21.0/LICENSE>, fetched
|
|
73
|
+
2026-10-18. Included because the published Stagehand 3.21.0 gem omits the license file.
|
|
74
|
+
|
|
75
|
+
Copyright 2026 stagehand
|
|
76
|
+
|
|
77
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
78
|
+
software and associated documentation files (the "Software"), to deal in the Software
|
|
79
|
+
without restriction, including without limitation the rights to use, copy, modify,
|
|
80
|
+
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
|
81
|
+
permit persons to whom the Software is furnished to do so, subject to the following
|
|
82
|
+
conditions:
|
|
83
|
+
|
|
84
|
+
The above copyright notice and this permission notice shall be included in all copies
|
|
85
|
+
or substantial portions of the Software.
|
|
86
|
+
|
|
87
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
88
|
+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
89
|
+
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
90
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
91
|
+
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
92
|
+
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# ruby_llm-browser
|
|
2
|
+
|
|
3
|
+
An **unofficial community extension** for [RubyLLM](https://rubyllm.com), with an
|
|
4
|
+
experimental adapter for the official [Stagehand Ruby SDK](https://github.com/browserbase/stagehand-ruby).
|
|
5
|
+
It provides read-only `Inspect` and schema-pinned `Extract` tools, operation bookkeeping,
|
|
6
|
+
and an optional Rails 8 adapter. It does not implement a browser engine.
|
|
7
|
+
|
|
8
|
+
The first release supports the offline `FakeBackend` only. `StagehandBackend` is present
|
|
9
|
+
for future qualification, but it refuses live operations until browser-side egress and
|
|
10
|
+
provider cleanup are qualified.
|
|
11
|
+
|
|
12
|
+
> **Version 0.1.0 is the offline-only first release.** The built-in Stagehand backend
|
|
13
|
+
> is unsupported, and the full live Act approval protocol is deferred. No live provider
|
|
14
|
+
> calls were made. See the [release audit](docs/RELEASE_AUDIT.md). This project is not
|
|
15
|
+
> maintained or endorsed by RubyLLM or Browserbase.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
Add the gem to your application's Gemfile:
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
gem "ruby_llm-browser", "~> 0.1.0"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The core requires Ruby 3.2+, RubyLLM `>= 2.0, < 3`, `json_schemer ~> 2.5`, and
|
|
26
|
+
`stagehand ~> 3.21.0`, plus patched DNS/URL/CGI/compression gems (see the
|
|
27
|
+
[dependency reference](docs/API.md)). Requiring `ruby_llm/browser` loads neither Rails nor the Stagehand
|
|
28
|
+
client, discovers no provider credentials, and opens no browser session.
|
|
29
|
+
|
|
30
|
+
## Try it offline
|
|
31
|
+
|
|
32
|
+
This complete example makes no network request and requires no API key:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
# smoke-test: offline
|
|
36
|
+
require "ruby_llm/browser"
|
|
37
|
+
|
|
38
|
+
# Fake DNS is only for this offline demonstration. Production uses real DNS.
|
|
39
|
+
class OfflineResolver
|
|
40
|
+
def getaddresses(_host) = [ "93.184.216.34" ]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context = RubyLLM::Browser::Context.new(
|
|
44
|
+
actor_id: "demo-actor", run_id: "demo-run",
|
|
45
|
+
backend: RubyLLM::Browser::FakeBackend.new,
|
|
46
|
+
source_policy: RubyLLM::Browser::Policy.new(
|
|
47
|
+
allowed_hosts: [ "docs.example.com" ], resolver: OfflineResolver.new
|
|
48
|
+
),
|
|
49
|
+
operation_store: RubyLLM::Browser::InMemoryOperationStore.new
|
|
50
|
+
)
|
|
51
|
+
schema = {
|
|
52
|
+
"type" => "object",
|
|
53
|
+
"properties" => { "title" => { "type" => "string" } },
|
|
54
|
+
"required" => [ "title" ], "additionalProperties" => false
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
inspect_tool = RubyLLM::Browser::Inspect.new(context: context)
|
|
58
|
+
extract_tool = RubyLLM::Browser::Extract.new(context: context, schema: schema)
|
|
59
|
+
puts inspect_tool.execute(url: "https://docs.example.com/")[:status] # => ok
|
|
60
|
+
puts extract_tool.execute(url: "https://docs.example.com/")[:data] # => {"title"=>"Example"}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Register these instances on your configured RubyLLM chat with
|
|
64
|
+
`chat.with_tools(inspect_tool, extract_tool)`. Never register `Act` by default.
|
|
65
|
+
The host supplies authenticated **string** actor/run IDs, authorization, consent,
|
|
66
|
+
the pinned extraction schema, budgets, and the backend.
|
|
67
|
+
|
|
68
|
+
The tools return a **Hash**, not a `Result` object. Direct `Engine` calls return a
|
|
69
|
+
`Result`. Check `status` and `error`; page data is untrusted evidence, not verified truth.
|
|
70
|
+
|
|
71
|
+
## Safety boundaries
|
|
72
|
+
|
|
73
|
+
- URL policy checks hosts, schemes, ports, and public DNS/IP addresses. It cannot
|
|
74
|
+
sandbox a remote browser or control page-triggered requests.
|
|
75
|
+
- No built-in live backend is supported in this release. `StagehandBackend` always
|
|
76
|
+
reports egress as unverified and refuses live operations. A host assertion cannot
|
|
77
|
+
enable it.
|
|
78
|
+
- The model cannot increase the host's output limit. Results are redacted, schema-checked
|
|
79
|
+
for extraction, and bounded by the policy and remaining operation bytes.
|
|
80
|
+
- A durable operation is claimed before start. Duplicate jobs cannot start it again.
|
|
81
|
+
SDK retries are disabled; uncertain outcomes are never automatically replayed.
|
|
82
|
+
- Cancellation fences workers but cannot undo an in-flight request. Dispatched operations
|
|
83
|
+
retain quota until cleanup is confirmed. Run a reaper independently of job workers.
|
|
84
|
+
- `max_cost_usd` is advisory metadata, not an enforced billing cap. Provider timeouts and
|
|
85
|
+
cleanup are also not a promise of zero future charges.
|
|
86
|
+
- `Act` is an offline simulation only. The full same-session live approval protocol is
|
|
87
|
+
deferred to a later version. Candidate-list hashes and selector keyword filters are
|
|
88
|
+
not proof of target identity or action safety.
|
|
89
|
+
|
|
90
|
+
## Rails integration
|
|
91
|
+
|
|
92
|
+
Add Rails 8's `activerecord` and `activejob` to your host application, then opt in:
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
require "ruby_llm/browser/rails"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
bin/rails generate ruby_llm:browser:install
|
|
100
|
+
bin/rails db:migrate
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The adapter provides durable operation/approval stores, actor-scoped jobs, cancellation,
|
|
104
|
+
and a reaper. Follow the [Rails guide](docs/RAILS.md) for the context factory, matching
|
|
105
|
+
budgets, status access, scheduling, and upgrading an earlier development database.
|
|
106
|
+
Only SQLite concurrency is tested locally; PostgreSQL requires its own qualification.
|
|
107
|
+
|
|
108
|
+
## Documentation
|
|
109
|
+
|
|
110
|
+
- [Documentation website](https://rubyllm-browser.wangyaodi.com) (GitHub Pages)
|
|
111
|
+
- [Documentation index](docs/README.md)
|
|
112
|
+
- [API, configuration, and result reference](docs/API.md)
|
|
113
|
+
- [Rails jobs and recovery](docs/RAILS.md)
|
|
114
|
+
- [Security model and live qualification](docs/SECURITY_MODEL.md)
|
|
115
|
+
- [Compatibility and release checklist](docs/RELEASING.md)
|
|
116
|
+
- [Audit findings and unresolved blockers](docs/RELEASE_AUDIT.md)
|
|
117
|
+
- [Requirement evidence](docs/WORK.md)
|
|
118
|
+
- [Offline scripts](examples/)
|
|
119
|
+
|
|
120
|
+
These documents and examples are included in the built gem.
|
|
121
|
+
|
|
122
|
+
## Development
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
bin/setup
|
|
126
|
+
bundle exec rake
|
|
127
|
+
bundle exec bundle-audit check --update
|
|
128
|
+
bundle exec ruby examples/plain_ruby.rb
|
|
129
|
+
bundle exec ruby examples/rails_adapter.rb
|
|
130
|
+
bundle exec rake build
|
|
131
|
+
bundle exec ruby bin/verify-package --rails --audit
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Tests block unmocked network requests. No paid live call or RubyGems publication is part
|
|
135
|
+
of the default workflow. See [contributing](CONTRIBUTING.md).
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT. See [LICENSE.txt](LICENSE.txt) and [third-party notices](NOTICE.md).
|
data/SECURITY.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Report security issues privately via GitHub Security Advisories on
|
|
6
|
+
<https://github.com/yorzi/ruby_llm-browser> ("Report a vulnerability"), or by email
|
|
7
|
+
to the maintainer listed in the gemspec. Please do not open a public issue for a
|
|
8
|
+
suspected vulnerability.
|
|
9
|
+
|
|
10
|
+
Include: affected version, a minimal reproduction, the impact you observed, and
|
|
11
|
+
whether secrets, cross-actor data, browser sessions or provider billing are involved.
|
|
12
|
+
We aim to acknowledge within a few days and to publish a fix and advisory once a
|
|
13
|
+
patch is available. Never include real credentials, cookies, `cdp_url` values or
|
|
14
|
+
private page payloads in a report; use synthetic fixtures.
|
|
15
|
+
|
|
16
|
+
## Security model in one page
|
|
17
|
+
|
|
18
|
+
- **Untrusted everything external.** Model output and page text are untrusted data.
|
|
19
|
+
They can never change tool policy, grant permissions or authorize actions.
|
|
20
|
+
- **Default deny.** Only hosts you allow explicitly, over `http`/`https`, on approved
|
|
21
|
+
ports, are reachable. Loopback, private, link-local, multicast and cloud-metadata
|
|
22
|
+
addresses are rejected, including IPv6 and IPv4-mapped forms.
|
|
23
|
+
- **Fail closed on egress.** Ruby-side URL checks cannot prove what a *remote* browser
|
|
24
|
+
does. `Policy#egress_qualified?` must be satisfied by the backend before a session
|
|
25
|
+
starts; otherwise the Gem raises `UNSUPPORTED_SECURITY_CAPABILITY` and never
|
|
26
|
+
contacts a provider.
|
|
27
|
+
- **Effectful retries are off.** Session creation, navigation, `act` and `end_` are
|
|
28
|
+
issued with `max_retries: 0`. Unknown outcomes stay `unknown` /
|
|
29
|
+
`cleanup_pending` and are never silently retried into a second session or a
|
|
30
|
+
duplicated action.
|
|
31
|
+
- **Reduce secret exposure.** Credential-like fields, known secret literals and
|
|
32
|
+
`cdp_url` endpoints are redacted; this is not a general PII/page-secret detector.
|
|
33
|
+
Avoid authenticated/private browsing and raw payload logging. SDK client arguments are passed
|
|
34
|
+
explicitly; the Gem never reads SDK environment defaults for credentials or base
|
|
35
|
+
URLs, and refuses to start when `STAGEHAND_CUSTOM_HEADERS` is set unless the host
|
|
36
|
+
approved it.
|
|
37
|
+
- **Live Act is disabled.** `RubyLLM::Browser::Act` is never registered by default,
|
|
38
|
+
and the Engine refuses non-fake action backends. Offline single-use approval tests
|
|
39
|
+
do not establish the missing same-session/target authorization protocol. Purchases,
|
|
40
|
+
posting, account changes and access-control bypass remain unsupported.
|
|
41
|
+
|
|
42
|
+
## Scope of guarantees
|
|
43
|
+
|
|
44
|
+
Mocked or fake backends demonstrate the Gem's API logic only. They do not prove
|
|
45
|
+
provider-side network egress isolation, provider TTL enforcement or billing limits.
|
|
46
|
+
See `docs/SECURITY_MODEL.md` and `docs/SPEC_BASELINE.md` for the full, honest status.
|
data/docs/API.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: API and Configuration
|
|
4
|
+
permalink: /api-and-configuration/
|
|
5
|
+
description: Configure trusted host objects and interpret bounded untrusted results.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# API and configuration
|
|
9
|
+
|
|
10
|
+
Configure trusted host objects and interpret bounded, untrusted results.
|
|
11
|
+
|
|
12
|
+
After reading this guide, you will know:
|
|
13
|
+
|
|
14
|
+
- How to register read-only tools.
|
|
15
|
+
- Which inputs belong to the host and which belong to the model.
|
|
16
|
+
- How to configure budgets, schemas, backends, and error handling.
|
|
17
|
+
|
|
18
|
+
## Creating a context
|
|
19
|
+
|
|
20
|
+
Use the complete offline example in [Getting Started]({% link _getting_started/getting-started.md %}). `Context.new` requires:
|
|
21
|
+
|
|
22
|
+
| Keyword | Type and meaning |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `actor_id`, `run_id` | Nonempty strings from authenticated host records. Convert numeric database IDs with `to_s`. |
|
|
25
|
+
| `backend` | A `Backend` instance. Use `FakeBackend` for offline tests. |
|
|
26
|
+
| `source_policy` | A host-created `Policy`. |
|
|
27
|
+
| `operation_store` | An `OperationStore`; durable storage is required across restarts or workers. |
|
|
28
|
+
| `approval_store` | Optional `ApprovalStore`, needed only for experimental Act. |
|
|
29
|
+
| `budget` | Optional `Budget`; defaults listed below. |
|
|
30
|
+
| `clock` | Optional callable returning a UTC `Time`. |
|
|
31
|
+
| `logger` | Optional host logger. Do not enable raw provider or tool payload logging. |
|
|
32
|
+
| `consent` | Optional host consent record. The gem records its presence; it does not collect or authenticate consent. |
|
|
33
|
+
| `metadata` | Optional host metadata. Never supply credentials here. |
|
|
34
|
+
|
|
35
|
+
The host must reauthorize actor/run access when building a context, including background
|
|
36
|
+
jobs. Passing IDs alone is not authentication. The model must never choose a backend,
|
|
37
|
+
credential, schema, source allowlist, consent record, or budget.
|
|
38
|
+
|
|
39
|
+
## Registering tools
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
inspect_tool = RubyLLM::Browser::Inspect.new(context: context)
|
|
43
|
+
extract_tool = RubyLLM::Browser::Extract.new(context: context, schema: schema)
|
|
44
|
+
chat.with_tools(inspect_tool, extract_tool)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Both tools expose `url`, optional `instruction`, and optional positive integer
|
|
48
|
+
`max_bytes`. `max_bytes` can only tighten the policy and operation ceilings.
|
|
49
|
+
`Extract` takes its schema in the constructor, not in model arguments.
|
|
50
|
+
|
|
51
|
+
`Inspect` returns **candidate interactions**, not a screenshot or arbitrary page dump.
|
|
52
|
+
Neither read-only tool dispatches candidates automatically. Pages may still run scripts
|
|
53
|
+
and initiate requests; read-only does not mean browsing has no external effects.
|
|
54
|
+
|
|
55
|
+
`Tool#execute` and RubyLLM `Tool#call` return a Hash. If you need a `Result` object, use:
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
engine = RubyLLM::Browser::Engine.new(context: context)
|
|
59
|
+
result = engine.inspect(url: url)
|
|
60
|
+
result = engine.extract(url: url, schema: schema, instruction: "Find the title")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The optional `operation:` Engine keyword accepts a host-reserved operation with the
|
|
64
|
+
same actor/run and budget. Starting it is an atomic reserved-to-starting claim. It is
|
|
65
|
+
not a resume or retry API for active, unknown, or closed operations.
|
|
66
|
+
|
|
67
|
+
## Source policy
|
|
68
|
+
|
|
69
|
+
`Policy.new(allowed_hosts: [...])` accepts exact hosts and `*.example.com` subdomains.
|
|
70
|
+
A wildcard does not allow the bare domain. Defaults are HTTP/HTTPS and ports 80/443.
|
|
71
|
+
Keep `verify_dns: true`; `resolver:` is injectable for offline fixtures.
|
|
72
|
+
|
|
73
|
+
Other options are `allowed_schemes`, `allowed_ports`, `max_result_bytes` (65,536),
|
|
74
|
+
`max_schema_depth` (8), `max_schema_properties` (64 root properties), and
|
|
75
|
+
`max_schema_bytes` (16,384). Browser-side enforcement must also cover explicitly
|
|
76
|
+
approved asset origins, redirects, frames, popups, WebSockets, and subresources.
|
|
77
|
+
|
|
78
|
+
## Extraction schemas
|
|
79
|
+
|
|
80
|
+
Schemas must be bounded object JSON Schemas, passed as a Hash, JSON object string, or
|
|
81
|
+
an object/class supporting `to_json_schema`. Supported keywords are `type`,
|
|
82
|
+
`description`, `properties`, `required`, `items`, `enum`, `additionalProperties`,
|
|
83
|
+
`title`, `minimum`, `maximum`, `minLength`, `maxLength`, `minItems`, `maxItems`,
|
|
84
|
+
`format`, and `default`. Remote references and arbitrary schema extensions are refused.
|
|
85
|
+
|
|
86
|
+
Use `required` and `additionalProperties: false` when an exact shape matters. Provider
|
|
87
|
+
data must satisfy the schema before redaction or truncation. Invalid data returns
|
|
88
|
+
`PROVIDER_ERROR`; it is not returned as a successful extraction. A truncated preview
|
|
89
|
+
or redacted field need not retain the original schema's type. Always check the status.
|
|
90
|
+
|
|
91
|
+
## Results and errors
|
|
92
|
+
|
|
93
|
+
`Result#to_h` contains symbol keys: `status`, `operation_id`, `final_url`,
|
|
94
|
+
`captured_at` (UTC ISO 8601), `locator`, `digest`, `truncated`, `data`, and optional
|
|
95
|
+
`error: { code:, message: }`. Locator/data objects use string keys. JSON encodes all
|
|
96
|
+
keys as strings. Credential-like query values are redacted in URL provenance.
|
|
97
|
+
|
|
98
|
+
Statuses are `ok`, `truncated`, `error`, `unknown`, and `cleanup_pending`.
|
|
99
|
+
`Result#ok?` accepts `ok` and `truncated`; it makes no factual verification claim.
|
|
100
|
+
`digest` is SHA-256 of canonical JSON of the returned, sanitized data. Very small byte
|
|
101
|
+
limits can produce an empty string or scalar preview; `truncated` is authoritative.
|
|
102
|
+
|
|
103
|
+
Engine preflight denials raise typed errors. Tools convert them into error Hashes.
|
|
104
|
+
After a session starts, the Engine attempts cleanup and returns a failure result.
|
|
105
|
+
Cleanup failure can supersede the original result with `cleanup_pending`; inspect the
|
|
106
|
+
durable operation's `error_code` and arrange host review for unknown effects.
|
|
107
|
+
|
|
108
|
+
Safe error codes: `INVALID_INPUT`, `NOT_AUTHORIZED`, `UNSUPPORTED_SECURITY_CAPABILITY`,
|
|
109
|
+
`BUDGET_EXHAUSTED`, `SESSION_UNKNOWN`, `CLEANUP_PENDING`, `APPROVAL_REQUIRED`,
|
|
110
|
+
`APPROVAL_STALE`, and `PROVIDER_ERROR`.
|
|
111
|
+
|
|
112
|
+
## Budgets
|
|
113
|
+
|
|
114
|
+
`Budget.new` defaults to `max_seconds: 60`, `max_steps: 12`, `max_bytes: 262_144`,
|
|
115
|
+
`max_concurrent: 1`, and `max_cost_usd: nil`.
|
|
116
|
+
|
|
117
|
+
`RubyLLM::Browser.configure` sets process defaults for `default_budget`,
|
|
118
|
+
`max_result_bytes`, `clock`, and `logger`. New contexts/policies use those defaults;
|
|
119
|
+
existing objects do not change. `configuration.backend` is only a reserved host slot:
|
|
120
|
+
contexts always require an explicitly supplied backend and never use a fallback.
|
|
121
|
+
|
|
122
|
+
- Steps count navigation, observation, extraction, and action calls, not start/cleanup.
|
|
123
|
+
- Bytes count retained sanitized result data, not all bytes the remote browser receives.
|
|
124
|
+
- Wall-clock checks refuse new calls after expiry. Stagehand request timeouts are bounded
|
|
125
|
+
by remaining time. Cleanup has a separate timeout and may outlive this budget.
|
|
126
|
+
- Concurrency is scoped to the actor across runs. Unknown/pending cleanup holds a slot.
|
|
127
|
+
- `max_cost_usd` is **advisory only**. There is no cost ledger or provider hard spending
|
|
128
|
+
cap in this release. Enforce billing limits in the provider/host.
|
|
129
|
+
|
|
130
|
+
## Stagehand backend status
|
|
131
|
+
|
|
132
|
+
`StagehandBackend` is unsupported for live operations in this release. It always reports
|
|
133
|
+
`egress_isolation: :unverified` and `act_supported?: false`. `Engine` refuses it before
|
|
134
|
+
the first provider request, and direct start, navigation, observation, extraction, and
|
|
135
|
+
Act calls also fail closed. No constructor option or injected client enables live use.
|
|
136
|
+
|
|
137
|
+
The adapter remains in the source for future qualification. Its client pins credentials
|
|
138
|
+
and base URL, disables retries, self-healing, CAPTCHA solving, session recording and
|
|
139
|
+
session logging, and requests a provider timeout. These controls do not prove egress,
|
|
140
|
+
TTL, billing, final-URL reporting, or cleanup. `end_session` sends no request in this
|
|
141
|
+
release and returns `false`; the operation remains `cleanup_pending`.
|
|
142
|
+
|
|
143
|
+
The constructor accepts `server: :remote`, `base_url:`, `timeout: 60.0`,
|
|
144
|
+
`custom_headers_approved: false`, `env: ENV`, and an injected `client:` for internal
|
|
145
|
+
contract tests. A future live implementation must verify all relevant environment
|
|
146
|
+
settings, egress across every browser request path, TTL and closure status, and provider
|
|
147
|
+
billing controls before it can advertise support.
|
|
148
|
+
|
|
149
|
+
## Dependency security floors
|
|
150
|
+
|
|
151
|
+
Old Ruby installations can supply vulnerable default gems even when a developer's
|
|
152
|
+
lockfile audit passes. Runtime requirements explicitly exclude those versions:
|
|
153
|
+
`cgi >= 0.4.2, < 1`, `resolv >= 0.7.2, < 1`, `uri >= 1.0.4, < 2`, and
|
|
154
|
+
`zlib >= 3.2.3, < 4`. A fresh install may build native extensions for these gems.
|
|
155
|
+
Use a supported, patched Ruby interpreter as well; these floors do not patch Ruby or
|
|
156
|
+
system libraries. Audit the versions actually activated by your application, including
|
|
157
|
+
default gems, not just a development lockfile.
|
|
158
|
+
|
|
159
|
+
## Experimental Act
|
|
160
|
+
|
|
161
|
+
`Act.new(context:)` declares RubyLLM `requires_approval`. Its arguments are `url`,
|
|
162
|
+
`approval_id`, `method`, `selector`, optional `description`, and optional `arguments`.
|
|
163
|
+
The resolver reads the host store without consuming. Consumption immediately before
|
|
164
|
+
dispatch checks actor/run, exact URL/action digest, expiry, and any supplied
|
|
165
|
+
page/operation/session bindings. Revocation and consumption are atomic in the stores.
|
|
166
|
+
|
|
167
|
+
**Do not use this as a production authorization protocol yet.** Bindings are currently
|
|
168
|
+
optional; a candidate-list digest is not a DOM/target revision, and each Engine action
|
|
169
|
+
opens a fresh session. The same-session host approval flow required by the specification
|
|
170
|
+
is deferred to a later version. The Engine refuses all non-fake Act calls before starting
|
|
171
|
+
a session. Selector/description keyword filters are defense in depth, not semantic proof
|
|
172
|
+
that a click is harmless. The Stagehand adapter does not support Act in this release.
|
|
173
|
+
|
|
174
|
+
## Next steps
|
|
175
|
+
|
|
176
|
+
- Read [Rails integration]({% link RAILS.md %}) for durable workers and recovery.
|
|
177
|
+
- Read [security boundaries]({% link SECURITY_MODEL.md %}) before qualifying a live backend.
|
data/docs/CNAME
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rubyllm-browser.wangyaodi.com
|