Skip to content

Commit 8ed1980

Browse files
monadoidstainless-app[bot]
authored andcommitted
STG-1293: add local server multiregion example
1 parent 817b78d commit 8ed1980

File tree

1 file changed

+161
-0
lines changed

1 file changed

+161
-0
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
require "bundler/setup"
5+
require "stagehand"
6+
7+
require_relative "env"
8+
ExampleEnv.load!
9+
browserbase_api_key = ENV["BROWSERBASE_API_KEY"].to_s
10+
browserbase_project_id = ENV["BROWSERBASE_PROJECT_ID"].to_s
11+
model_key = ENV["MODEL_API_KEY"].to_s
12+
13+
missing = []
14+
missing << "BROWSERBASE_API_KEY" if browserbase_api_key.empty?
15+
missing << "BROWSERBASE_PROJECT_ID" if browserbase_project_id.empty?
16+
missing << "MODEL_API_KEY" if model_key.empty?
17+
18+
unless missing.empty?
19+
warn "Set #{missing.join(', ')} to run the local server + multiregion Browserbase example."
20+
exit 1
21+
end
22+
23+
client = Stagehand::Client.new(
24+
browserbase_api_key: browserbase_api_key,
25+
browserbase_project_id: browserbase_project_id,
26+
model_api_key: model_key,
27+
server: "local"
28+
)
29+
30+
def print_stream_event(label, event)
31+
case event.type
32+
when :log
33+
puts("[#{label}] log: #{event.data.message}")
34+
when :system
35+
status = event.data.status
36+
if event.data.respond_to?(:error) && event.data.error
37+
puts("[#{label}] system #{status}: #{event.data.error}")
38+
elsif event.data.respond_to?(:result) && !event.data.result.nil?
39+
puts("[#{label}] system #{status}: #{event.data.result}")
40+
else
41+
puts("[#{label}] system #{status}")
42+
end
43+
else
44+
puts("[#{label}] event: #{event.inspect}")
45+
end
46+
end
47+
48+
def stream_with_result(label, stream)
49+
puts("#{label} stream:")
50+
result = nil
51+
stream.each do |event|
52+
print_stream_event(label, event)
53+
if event.type == :system && event.data.respond_to?(:result) && !event.data.result.nil?
54+
result = event.data.result
55+
end
56+
if event.type == :system && event.data.respond_to?(:status) && event.data.status == :error
57+
error_message = event.data.respond_to?(:error) && event.data.error ? event.data.error : "unknown error"
58+
raise("#{label} stream error: #{error_message}")
59+
end
60+
end
61+
result
62+
end
63+
64+
session_id = nil
65+
66+
begin
67+
start_response = client.sessions.start(
68+
model_name: "anthropic/claude-sonnet-4-6",
69+
browser: {type: :browserbase},
70+
browserbase_session_create_params: {
71+
region: Stagehand::SessionStartParams::BrowserbaseSessionCreateParams::Region::EU_CENTRAL_1
72+
}
73+
)
74+
session_id = start_response.data.session_id
75+
puts("Session started: #{session_id}")
76+
77+
client.sessions.navigate(session_id, url: "https://news.ycombinator.com")
78+
puts("Navigated to Hacker News")
79+
80+
observe_stream = client.sessions.observe_streaming(
81+
session_id,
82+
instruction: "find the link to view comments for the top post"
83+
)
84+
85+
observe_result = stream_with_result("Observe", observe_stream)
86+
actions = observe_result || []
87+
puts("Found #{actions.length} possible actions")
88+
89+
action = actions.first
90+
unless action
91+
warn("No actions found")
92+
exit(1)
93+
end
94+
95+
puts("Acting on: #{action.description}")
96+
97+
act_stream = client.sessions.act_streaming(
98+
session_id,
99+
input: action.to_h.merge(method: "click")
100+
)
101+
act_result = stream_with_result("Act", act_stream)
102+
act_message = act_result.is_a?(Hash) ? (act_result[:message] || act_result["message"]) : act_result
103+
puts("Act completed: #{act_message}")
104+
105+
extract_stream = client.sessions.extract_streaming(
106+
session_id,
107+
instruction: "extract the text of the top comment on this page",
108+
schema: {
109+
type: "object",
110+
properties: {
111+
comment_text: {
112+
type: "string",
113+
description: "The text content of the top comment"
114+
},
115+
author: {
116+
type: "string",
117+
description: "The username of the comment author"
118+
}
119+
},
120+
required: ["comment_text"]
121+
}
122+
)
123+
extract_result = stream_with_result("Extract", extract_stream)
124+
puts("Extracted data: #{extract_result}")
125+
126+
extracted_data = extract_result
127+
author = extracted_data.is_a?(Hash) ? extracted_data[:author] : nil
128+
author ||= "unknown"
129+
puts("Looking up profile for author: #{author}")
130+
131+
instruction = [
132+
"Find any personal website, GitHub, or LinkedIn for the Hacker News user '#{author}'.",
133+
"Click their username to open the profile and look for shared links."
134+
].join(" ")
135+
136+
execute_stream = client.sessions.execute_streaming(
137+
session_id,
138+
execute_options: {
139+
instruction: instruction,
140+
max_steps: 15
141+
},
142+
agent_config: {
143+
model: Stagehand::ModelConfig.new(
144+
model_name: "anthropic/claude-opus-4-6",
145+
api_key: model_key
146+
),
147+
cua: false
148+
}
149+
)
150+
151+
execute_result = stream_with_result("Execute", execute_stream)
152+
execute_message = execute_result.is_a?(Hash) ? (execute_result[:message] || execute_result["message"]) : execute_result
153+
execute_success = execute_result.is_a?(Hash) ? (execute_result[:success] || execute_result["success"]) : nil
154+
execute_actions = execute_result.is_a?(Hash) ? (execute_result[:actions] || execute_result["actions"]) : nil
155+
puts("Agent completed: #{execute_message}")
156+
puts("Agent success: #{execute_success}")
157+
puts("Agent actions taken: #{execute_actions&.length || 0}")
158+
ensure
159+
client.sessions.end_(session_id) if session_id
160+
client.close
161+
end

0 commit comments

Comments
 (0)