Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/publish-gem.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This workflow is triggered when a GitHub release is created.
# It can also be run manually to re-publish to rubygems.org in case it failed for some reason.
# You can run this workflow by navigating to https://www.github.com/browserbase/stagehand-ruby/actions/workflows/publish-gem.yml
name: Publish Gem
on:
workflow_dispatch:

release:
types: [published]

jobs:
publish:
name: publish
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: false
- run: |-
bundle install

- name: Publish to RubyGems.org
run: |
bash ./bin/publish-gem
env:
# `RUBYGEMS_HOST` is only required for private gem repositories, not https://rubygems.org
RUBYGEMS_HOST: ${{ secrets.STAGEHAND_RUBYGEMS_HOST || secrets.RUBYGEMS_HOST }}
GEM_HOST_API_KEY: ${{ secrets.STAGEHAND_GEM_HOST_API_KEY || secrets.GEM_HOST_API_KEY }}
22 changes: 22 additions & 0 deletions .github/workflows/release-doctor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Release Doctor
on:
pull_request:
branches:
- main
workflow_dispatch:

jobs:
release_doctor:
name: release doctor
runs-on: ubuntu-latest
if: github.repository == 'browserbase/stagehand-ruby' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')

steps:
- uses: actions/checkout@v4

- name: Check release environment
run: |
bash ./bin/check-release-environment
env:
RUBYGEMS_HOST: ${{ secrets.STAGEHAND_RUBYGEMS_HOST || secrets.RUBYGEMS_HOST }}
GEM_HOST_API_KEY: ${{ secrets.STAGEHAND_GEM_HOST_API_KEY || secrets.GEM_HOST_API_KEY }}
3 changes: 3 additions & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
".": "0.1.0"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 7
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml
openapi_spec_hash: efb79934e1dc63763dd4e8493b825273
config_hash: 5f3345d1d825e49f896f3b0e493e6938
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-2c88c6d890406ff8a5f1bca692264fb9af4bc4fe64df0986e06d3386fc6d6fcb.yml
openapi_spec_hash: dc6ea17f8152708dc0a390c7f86b1a5d
config_hash: b01f15c540ab2c92808c2bba96368631
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Changelog

## 0.1.0 (2025-12-16)

Full Changelog: [v0.0.1...v0.1.0](https://github.com/browserbase/stagehand-ruby/compare/v0.0.1...v0.1.0)

### Features

* **api:** manual updates ([5deaf8f](https://github.com/browserbase/stagehand-ruby/commit/5deaf8ff2011a2808dcfe66ef14470029bb3590e))
* **api:** manual updates ([87ce5f3](https://github.com/browserbase/stagehand-ruby/commit/87ce5f320056fb34770be2f0c87985960e995e92))
* **api:** manual updates ([2a8b9e7](https://github.com/browserbase/stagehand-ruby/commit/2a8b9e7d219360a5e783c650fc7c9544a9a6fbb5))
* **api:** manual updates ([0bcedba](https://github.com/browserbase/stagehand-ruby/commit/0bcedbaf26918822abdc958e6020f68b263ffee0))
* **api:** manual updates ([8355d5e](https://github.com/browserbase/stagehand-ruby/commit/8355d5e6b83f6c31f6494f771fba51b6e31023e7))
* **api:** manual updates ([655f517](https://github.com/browserbase/stagehand-ruby/commit/655f51718008b4c512eed1ce65660dae80039e49))
* **api:** tweak branding and fix some config fields ([c48f36e](https://github.com/browserbase/stagehand-ruby/commit/c48f36e307aafd9a2d6ac59d9857be789f29eaa1))


### Chores

* configure new SDK language ([3be44a3](https://github.com/browserbase/stagehand-ruby/commit/3be44a344d5bc49e7c2e16129c2b24db175f4eb6))
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ If you’d like to use the repository from source, you can either install from g
To install via git in your `Gemfile`:

```ruby
gem "stagehand", git: "https://www.github.com/stainless-sdks/stagehand-ruby"
gem "stagehand", git: "https://www.github.com/browserbase/stagehand-ruby"
```

Alternatively, reference local copy of the repo:

```bash
$ git clone -- 'https://www.github.com/stainless-sdks/stagehand-ruby' '<path-to-repo>'
$ git clone -- 'https://www.github.com/browserbase/stagehand-ruby' '<path-to-repo>'
```

```ruby
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GIT
PATH
remote: .
specs:
stagehand (0.0.1)
stagehand (0.1.0)
connection_pool

GEM
Expand Down
49 changes: 33 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,42 @@
# Stagehand Ruby API library

The Stagehand Ruby library provides convenient access to the Stagehand REST API from any Ruby 3.2.0+ application. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [see below](https://github.com/stainless-sdks/stagehand-ruby#Sorbet) for usage with Sorbet. The standard library's `net/http` is used as the HTTP transport, with connection pooling via the `connection_pool` gem.
The Stagehand Ruby library provides convenient access to the Stagehand REST API from any Ruby 3.2.0+ application. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [see below](https://github.com/browserbase/stagehand-ruby#Sorbet) for usage with Sorbet. The standard library's `net/http` is used as the HTTP transport, with connection pooling via the `connection_pool` gem.

It is generated with [Stainless](https://www.stainless.com/).

## Documentation

Documentation for releases of this gem can be found [on RubyDoc](https://gemdocs.org/gems/stagehand).

The REST API documentation can be found on [browserbase.com](https://browserbase.com).
The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev).

## Installation

To use this gem, install via Bundler by adding the following to your application's `Gemfile`:

<!-- x-release-please-start-version -->

```ruby
gem "stagehand", "~> 0.0.1"
gem "stagehand", "~> 0.1.0"
```

<!-- x-release-please-end -->

## Usage

```ruby
require "bundler/setup"
require "stagehand"

stagehand = Stagehand::Client.new(
api_key: ENV["STAGEHAND_API_KEY"], # This is the default and can be omitted
environment: "environment_1" # defaults to "production"
browserbase_api_key: ENV["BROWSERBASE_API_KEY"], # This is the default and can be omitted
browserbase_project_id: ENV["BROWSERBASE_PROJECT_ID"], # This is the default and can be omitted
model_api_key: ENV["MODEL_API_KEY"] # This is the default and can be omitted
)

response = stagehand.sessions.start(env: "LOCAL")
response = stagehand.sessions.act("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", input: "click the first link on the page")

puts(response.available)
puts(response.actions)
```

### Handling errors
Expand All @@ -40,7 +45,10 @@ When the library is unable to connect to the API, or if the API returns a non-su

```ruby
begin
session = stagehand.sessions.start(env: "LOCAL")
session = stagehand.sessions.start(
browserbase_api_key: "BROWSERBASE_API_KEY",
browserbase_project_id: "BROWSERBASE_PROJECT_ID"
)
rescue Stagehand::Errors::APIConnectionError => e
puts("The server could not be reached")
puts(e.cause) # an underlying Exception, likely raised within `net/http`
Expand Down Expand Up @@ -83,7 +91,11 @@ stagehand = Stagehand::Client.new(
)

# Or, configure per-request:
stagehand.sessions.start(env: "LOCAL", request_options: {max_retries: 5})
stagehand.sessions.start(
browserbase_api_key: "BROWSERBASE_API_KEY",
browserbase_project_id: "BROWSERBASE_PROJECT_ID",
request_options: {max_retries: 5}
)
```

### Timeouts
Expand All @@ -97,7 +109,11 @@ stagehand = Stagehand::Client.new(
)

# Or, configure per-request:
stagehand.sessions.start(env: "LOCAL", request_options: {timeout: 5})
stagehand.sessions.start(
browserbase_api_key: "BROWSERBASE_API_KEY",
browserbase_project_id: "BROWSERBASE_PROJECT_ID",
request_options: {timeout: 5}
)
```

On timeout, `Stagehand::Errors::APITimeoutError` is raised.
Expand Down Expand Up @@ -129,7 +145,8 @@ Note: the `extra_` parameters of the same name overrides the documented paramete
```ruby
response =
stagehand.sessions.start(
env: "LOCAL",
browserbase_api_key: "BROWSERBASE_API_KEY",
browserbase_project_id: "BROWSERBASE_PROJECT_ID",
request_options: {
extra_query: {my_query_parameter: value},
extra_body: {my_body_parameter: value},
Expand Down Expand Up @@ -175,18 +192,18 @@ This library provides comprehensive [RBI](https://sorbet.org/docs/rbi) definitio
You can provide typesafe request parameters like so:

```ruby
stagehand.sessions.start(env: "LOCAL")
stagehand.sessions.act("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", input: "click the first link on the page")
```

Or, equivalently:

```ruby
# Hashes work, but are not typesafe:
stagehand.sessions.start(env: "LOCAL")
stagehand.sessions.act("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", input: "click the first link on the page")

# You can also splat a full Params class:
params = Stagehand::SessionStartParams.new(env: "LOCAL")
stagehand.sessions.start(**params)
params = Stagehand::SessionActParams.new(input: "click the first link on the page")
stagehand.sessions.act("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", **params)
```

### Enums
Expand Down Expand Up @@ -229,4 +246,4 @@ Ruby 3.2.0 or higher.

## Contributing

See [the contributing documentation](https://github.com/stainless-sdks/stagehand-ruby/tree/main/CONTRIBUTING.md).
See [the contributing documentation](https://github.com/browserbase/stagehand-ruby/tree/main/CONTRIBUTING.md).
21 changes: 21 additions & 0 deletions bin/check-release-environment
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash

errors=()

if [ -z "${GEM_HOST_API_KEY}" ]; then
errors+=("The GEM_HOST_API_KEY secret has not been set. Please set it in either this repository's secrets or your organization secrets")
fi

lenErrors=${#errors[@]}

if [[ lenErrors -gt 0 ]]; then
echo -e "Found the following errors in the release environment:\n"

for error in "${errors[@]}"; do
echo -e "- $error\n"
done

exit 1
fi

echo "The environment is ready to push releases!"
74 changes: 53 additions & 21 deletions lib/stagehand/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@ class Client < Stagehand::Internal::Transport::BaseClient
# Default max retry delay in seconds.
DEFAULT_MAX_RETRY_DELAY = 8.0

# rubocop:disable Style/MutableConstant
# @type [Hash{Symbol=>String}]
ENVIRONMENTS =
{production: "http://localhost:3000/v1", environment_1: "https://api.stagehand.browserbase.com/v1"}
# rubocop:enable Style/MutableConstant
# Your [Browserbase API Key](https://www.browserbase.com/settings)
# @return [String]
attr_reader :browserbase_api_key

# @return [String, nil]
attr_reader :api_key
# Your [Browserbase Project ID](https://www.browserbase.com/settings)
# @return [String]
attr_reader :browserbase_project_id

# Your LLM provider API key (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.)
# @return [String]
attr_reader :model_api_key

# @return [Stagehand::Resources::Sessions]
attr_reader :sessions
Expand All @@ -31,21 +34,40 @@ class Client < Stagehand::Internal::Transport::BaseClient
#
# @return [Hash{String=>String}]
private def auth_headers
return {} if @api_key.nil?
{**bb_api_key_auth, **bb_project_id_auth, **llm_model_api_key_auth}
end

{"authorization" => "Bearer #{@api_key}"}
# @api private
#
# @return [Hash{String=>String}]
private def bb_api_key_auth
{"x-bb-api-key" => @browserbase_api_key}
end

# Creates and returns a new client for interacting with the API.
# @api private
#
# @param api_key [String, nil] Defaults to `ENV["STAGEHAND_API_KEY"]`
# @return [Hash{String=>String}]
private def bb_project_id_auth
{"x-bb-project-id" => @browserbase_project_id}
end

# @api private
#
# @param environment [:production, :environment_1, nil] Specifies the environment to use for the API.
# @return [Hash{String=>String}]
private def llm_model_api_key_auth
{"x-model-api-key" => @model_api_key}
end

# Creates and returns a new client for interacting with the API.
#
# Each environment maps to a different base URL:
# @param browserbase_api_key [String, nil] Your [Browserbase API Key](https://www.browserbase.com/settings) Defaults to
# `ENV["BROWSERBASE_API_KEY"]`
#
# - `production` corresponds to `http://localhost:3000/v1`
# - `environment_1` corresponds to `https://api.stagehand.browserbase.com/v1`
# @param browserbase_project_id [String, nil] Your [Browserbase Project ID](https://www.browserbase.com/settings) Defaults to
# `ENV["BROWSERBASE_PROJECT_ID"]`
#
# @param model_api_key [String, nil] Your LLM provider API key (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.)
# Defaults to `ENV["MODEL_API_KEY"]`
#
# @param base_url [String, nil] Override the default base URL for the API, e.g.,
# `"https://api.example.com/v2/"`. Defaults to `ENV["STAGEHAND_BASE_URL"]`
Expand All @@ -58,20 +80,30 @@ class Client < Stagehand::Internal::Transport::BaseClient
#
# @param max_retry_delay [Float]
def initialize(
api_key: ENV["STAGEHAND_API_KEY"],
environment: nil,
browserbase_api_key: ENV["BROWSERBASE_API_KEY"],
browserbase_project_id: ENV["BROWSERBASE_PROJECT_ID"],
model_api_key: ENV["MODEL_API_KEY"],
base_url: ENV["STAGEHAND_BASE_URL"],
max_retries: self.class::DEFAULT_MAX_RETRIES,
timeout: self.class::DEFAULT_TIMEOUT_IN_SECONDS,
initial_retry_delay: self.class::DEFAULT_INITIAL_RETRY_DELAY,
max_retry_delay: self.class::DEFAULT_MAX_RETRY_DELAY
)
base_url ||= Stagehand::Client::ENVIRONMENTS.fetch(environment&.to_sym || :production) do
message = "environment must be one of #{Stagehand::Client::ENVIRONMENTS.keys}, got #{environment}"
raise ArgumentError.new(message)
base_url ||= "https://api.stagehand.browserbase.com/v1"

if browserbase_api_key.nil?
raise ArgumentError.new("browserbase_api_key is required, and can be set via environ: \"BROWSERBASE_API_KEY\"")
end
if browserbase_project_id.nil?
raise ArgumentError.new("browserbase_project_id is required, and can be set via environ: \"BROWSERBASE_PROJECT_ID\"")
end
if model_api_key.nil?
raise ArgumentError.new("model_api_key is required, and can be set via environ: \"MODEL_API_KEY\"")
end

@api_key = api_key&.to_s
@browserbase_api_key = browserbase_api_key.to_s
@browserbase_project_id = browserbase_project_id.to_s
@model_api_key = model_api_key.to_s

super(
base_url: base_url,
Expand Down
2 changes: 1 addition & 1 deletion lib/stagehand/internal/type/union.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module Type
# case session_extract_response
# when Stagehand::Models::SessionExtractResponse::Extraction
# puts(session_extract_response.extraction)
# when Stagehand::Models::SessionExtractResponse::UnionMember1Map
# when Stagehand::Models::SessionExtractResponse::CustomMap
# # ...
# else
# puts(session_extract_response)
Expand Down
Loading
Loading