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
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.3.0"
".": "0.4.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-e96507dd78e76fccc77ba7fb09704da127ead6f4d73ea854e9b2150e90787ff4.yml
openapi_spec_hash: 0c2548b8fdd6de6789b19123e69609c1
config_hash: c3abb41dbe698d59b3bf12f393013d54
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-f7d6b6489159f611a2bfdc267ce0a6fc0455bed1ffa0c310044baaa5d8381b9b.yml
openapi_spec_hash: cd88d8068abfde8382da0bed674e440c
config_hash: 5c69fb596588b8ace08203858518c149
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 0.4.0 (2025-12-19)

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

### Features

* **api:** manual updates ([c93a988](https://github.com/browserbase/stagehand-ruby/commit/c93a988374918f841643a84145b3008970b665a7))


### Bug Fixes

* issue where json.parse errors when receiving HTTP 204 with nobody ([fc3e31e](https://github.com/browserbase/stagehand-ruby/commit/fc3e31e00944a7fdf89e367e281bc0510847d15e))

## 0.3.0 (2025-12-17)

Full Changelog: [v0.2.0...v0.3.0](https://github.com/browserbase/stagehand-ruby/compare/v0.2.0...v0.3.0)
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.3.0)
stagehand (0.4.0)
connection_pool

GEM
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ To use this gem, install via Bundler by adding the following to your application
<!-- x-release-please-start-version -->

```ruby
gem "stagehand", "~> 0.3.0"
gem "stagehand", "~> 0.4.0"
```

<!-- x-release-please-end -->
Expand Down
3 changes: 3 additions & 0 deletions lib/stagehand.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
require_relative "stagehand/internal/type/hash_of"
require_relative "stagehand/internal/type/base_model"
require_relative "stagehand/internal/type/base_page"
require_relative "stagehand/internal/type/base_stream"
require_relative "stagehand/internal/type/request_parameters"
require_relative "stagehand/internal"
require_relative "stagehand/request_options"
Expand All @@ -52,6 +53,7 @@
require_relative "stagehand/internal/transport/base_client"
require_relative "stagehand/internal/transport/pooled_net_requester"
require_relative "stagehand/client"
require_relative "stagehand/internal/stream"
require_relative "stagehand/models/action"
require_relative "stagehand/models/model_config"
require_relative "stagehand/models/session_act_params"
Expand All @@ -68,5 +70,6 @@
require_relative "stagehand/models/session_observe_response"
require_relative "stagehand/models/session_start_params"
require_relative "stagehand/models/session_start_response"
require_relative "stagehand/models/stream_event"
require_relative "stagehand/models"
require_relative "stagehand/resources/sessions"
56 changes: 56 additions & 0 deletions lib/stagehand/internal/stream.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# frozen_string_literal: true

module Stagehand
module Internal
# @generic Elem
#
# @example
# stream.each do |event|
# puts(event)
# end
class Stream
include Stagehand::Internal::Type::BaseStream

# @api private
#
# @return [Enumerable<generic<Elem>>]
private def iterator
# rubocop:disable Metrics/BlockLength
@iterator ||= Stagehand::Internal::Util.chain_fused(@stream) do |y|
consume = false

@stream.each do |msg|
next if consume

case msg
in {data: String => data} if data.start_with?("finished")
consume = true
next
in {data: String => data} if data.start_with?("error")
decoded = Kernel.then do
JSON.parse(data, symbolize_names: true)
rescue JSON::ParserError
data
end
err = Stagehand::Errors::APIStatusError.for(
url: @url,
status: @status,
headers: @headers,
body: decoded,
request: nil,
response: @response
)
raise err
in {event: nil, data: String => data}
decoded = JSON.parse(data, symbolize_names: true)
unwrapped = Stagehand::Internal::Util.dig(decoded, @unwrap)
y << Stagehand::Internal::Type::Converter.coerce(@model, unwrapped)
else
end
end
end
# rubocop:enable Metrics/BlockLength
end
end
end
end
4 changes: 3 additions & 1 deletion lib/stagehand/internal/transport/base_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,9 @@ def inspect
)
),
page: T.nilable(T::Class[Stagehand::Internal::Type::BasePage[Stagehand::Internal::Type::BaseModel]]),
stream: T.nilable(T::Class[T.anything]),
stream: T.nilable(
T::Class[Stagehand::Internal::Type::BaseStream[T.anything, Stagehand::Internal::Type::BaseModel]]
),
model: T.nilable(Stagehand::Internal::Type::Converter::Input),
options: T.nilable(Stagehand::RequestOptions::OrHash)
}
Expand Down
83 changes: 83 additions & 0 deletions lib/stagehand/internal/type/base_stream.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# frozen_string_literal: true

module Stagehand
module Internal
module Type
# @api private
#
# @generic Elem
#
# This module provides a base implementation for streaming responses in the SDK.
#
# @see https://rubyapi.org/3.2/o/enumerable
module BaseStream
include Enumerable

# @return [Integer]
attr_reader :status

# @return [Hash{String=>String}]
attr_reader :headers

# @api public
#
# @return [void]
def close = Stagehand::Internal::Util.close_fused!(@iterator)

# @api private
#
# @return [Enumerable<generic<Elem>>]
private def iterator = (raise NotImplementedError)

# @api public
#
# @param blk [Proc]
#
# @yieldparam [generic<Elem>]
# @return [void]
def each(&blk)
unless block_given?
raise ArgumentError.new("A block must be given to ##{__method__}")
end
@iterator.each(&blk)
end

# @api public
#
# @return [Enumerator<generic<Elem>>]
def to_enum = @iterator

alias_method :enum_for, :to_enum

# @api private
#
# @param model [Class, Stagehand::Internal::Type::Converter]
# @param url [URI::Generic]
# @param status [Integer]
# @param headers [Hash{String=>String}]
# @param response [Net::HTTPResponse]
# @param unwrap [Symbol, Integer, Array<Symbol, Integer>, Proc]
# @param stream [Enumerable<Object>]
def initialize(model:, url:, status:, headers:, response:, unwrap:, stream:)
@model = model
@url = url
@status = status
@headers = headers
@response = response
@unwrap = unwrap
@stream = stream
@iterator = iterator
end

# @api private
#
# @return [String]
def inspect
model = Stagehand::Internal::Type::Converter.inspect(@model, depth: 1)

"#<#{self.class}[#{model}]:0x#{object_id.to_s(16)}>"
end
end
end
end
end
9 changes: 7 additions & 2 deletions lib/stagehand/internal/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,8 @@ def force_charset!(content_type, text:)
def decode_content(headers, stream:, suppress_error: false)
case (content_type = headers["content-type"])
in Stagehand::Internal::Util::JSON_CONTENT
json = stream.to_a.join
return nil if (json = stream.to_a.join).empty?

begin
JSON.parse(json, symbolize_names: true)
rescue JSON::ParserError => e
Expand All @@ -667,7 +668,11 @@ def decode_content(headers, stream:, suppress_error: false)
in Stagehand::Internal::Util::JSONL_CONTENT
lines = decode_lines(stream)
chain_fused(lines) do |y|
lines.each { y << JSON.parse(_1, symbolize_names: true) }
lines.each do
next if _1.empty?

y << JSON.parse(_1, symbolize_names: true)
end
end
in %r{^text/event-stream}
lines = decode_lines(stream)
Expand Down
2 changes: 2 additions & 0 deletions lib/stagehand/models.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,6 @@ module Stagehand
SessionObserveParams = Stagehand::Models::SessionObserveParams

SessionStartParams = Stagehand::Models::SessionStartParams

StreamEvent = Stagehand::Models::StreamEvent
end
47 changes: 6 additions & 41 deletions lib/stagehand/models/session_act_params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
module Stagehand
module Models
# @see Stagehand::Resources::Sessions#act
#
# @see Stagehand::Resources::Sessions#act_streaming
class SessionActParams < Stagehand::Internal::Type::BaseModel
extend Stagehand::Internal::Type::RequestParameters::Converter
include Stagehand::Internal::Type::RequestParameters

# @!attribute input
# Natural language instruction or Action object
#
# @return [String, Stagehand::Models::SessionActParams::Input::ActionInput]
# @return [String, Stagehand::Models::Action]
required :input, union: -> { Stagehand::SessionActParams::Input }

# @!attribute frame_id
Expand Down Expand Up @@ -49,7 +51,7 @@ class SessionActParams < Stagehand::Internal::Type::BaseModel
optional :x_stream_response, enum: -> { Stagehand::SessionActParams::XStreamResponse }

# @!method initialize(input:, frame_id: nil, options: nil, x_language: nil, x_sdk_version: nil, x_sent_at: nil, x_stream_response: nil, request_options: {})
# @param input [String, Stagehand::Models::SessionActParams::Input::ActionInput] Natural language instruction or Action object
# @param input [String, Stagehand::Models::Action] Natural language instruction or Action object
#
# @param frame_id [String] Target frame ID for the action
#
Expand All @@ -72,47 +74,10 @@ module Input
variant String

# Action object returned by observe and used by act
variant -> { Stagehand::SessionActParams::Input::ActionInput }

class ActionInput < Stagehand::Internal::Type::BaseModel
# @!attribute description
# Human-readable description of the action
#
# @return [String]
required :description, String

# @!attribute selector
# CSS selector or XPath for the element
#
# @return [String]
required :selector, String

# @!attribute arguments
# Arguments to pass to the method
#
# @return [Array<String>, nil]
optional :arguments, Stagehand::Internal::Type::ArrayOf[String]

# @!attribute method_
# The method to execute (click, fill, etc.)
#
# @return [String, nil]
optional :method_, String, api_name: :method

# @!method initialize(description:, selector:, arguments: nil, method_: nil)
# Action object returned by observe and used by act
#
# @param description [String] Human-readable description of the action
#
# @param selector [String] CSS selector or XPath for the element
#
# @param arguments [Array<String>] Arguments to pass to the method
#
# @param method_ [String] The method to execute (click, fill, etc.)
end
variant -> { Stagehand::Action }

# @!method self.variants
# @return [Array(String, Stagehand::Models::SessionActParams::Input::ActionInput)]
# @return [Array(String, Stagehand::Models::Action)]
end

class Options < Stagehand::Internal::Type::BaseModel
Expand Down
2 changes: 2 additions & 0 deletions lib/stagehand/models/session_act_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module Stagehand
module Models
# @see Stagehand::Resources::Sessions#act
#
# @see Stagehand::Resources::Sessions#act_streaming
class SessionActResponse < Stagehand::Internal::Type::BaseModel
# @!attribute data
#
Expand Down
2 changes: 2 additions & 0 deletions lib/stagehand/models/session_execute_params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module Stagehand
module Models
# @see Stagehand::Resources::Sessions#execute
#
# @see Stagehand::Resources::Sessions#execute_streaming
class SessionExecuteParams < Stagehand::Internal::Type::BaseModel
extend Stagehand::Internal::Type::RequestParameters::Converter
include Stagehand::Internal::Type::RequestParameters
Expand Down
2 changes: 2 additions & 0 deletions lib/stagehand/models/session_execute_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module Stagehand
module Models
# @see Stagehand::Resources::Sessions#execute
#
# @see Stagehand::Resources::Sessions#execute_streaming
class SessionExecuteResponse < Stagehand::Internal::Type::BaseModel
# @!attribute data
#
Expand Down
2 changes: 2 additions & 0 deletions lib/stagehand/models/session_extract_params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module Stagehand
module Models
# @see Stagehand::Resources::Sessions#extract
#
# @see Stagehand::Resources::Sessions#extract_streaming
class SessionExtractParams < Stagehand::Internal::Type::BaseModel
extend Stagehand::Internal::Type::RequestParameters::Converter
include Stagehand::Internal::Type::RequestParameters
Expand Down
2 changes: 2 additions & 0 deletions lib/stagehand/models/session_extract_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module Stagehand
module Models
# @see Stagehand::Resources::Sessions#extract
#
# @see Stagehand::Resources::Sessions#extract_streaming
class SessionExtractResponse < Stagehand::Internal::Type::BaseModel
# @!attribute data
#
Expand Down
Loading
Loading