Skip to content
Open
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
40 changes: 19 additions & 21 deletions docs/cloud/agent/human-in-the-loop.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ icon: hand
---

Use a human checkpoint for approvals, authentication, payments, or review.
After a run stops, get its `live_view_url` from the `browser.ready` event:
Get its `live_view_url` with the SDK's event-wait helper, which follows event
cursors instead of searching only the first page. Wait for the run to stop at
the checkpoint before letting a person interact:

<CodeGroup>
```python Python
Expand All @@ -15,47 +17,43 @@ client = BrowserUse()
run = client.runs.create(
"Open the login page and stop for human review"
)
run = client.runs.wait_for_completion(run.id)

events = client.runs.events(run.id, limit=100)
ready = next(
event for event in events.events
if event.type == "browser.ready"
)
ready = client.runs.wait_for_event(run.id, "browser.ready")
client.runs.wait_for_completion(run.id)
print(ready.data["live_view_url"])

# After the human finishes:
input("Press Enter after finishing the human step...")
next_run = client.runs.create(
"Continue from the current page",
session_id=run.session_id,
)
```
```typescript TypeScript
import { BrowserUse } from "browser-use-sdk/v4";
import * as readline from "node:readline/promises";

const client = new BrowserUse();
const run = await client.runs.create({
task: "Open the login page and stop for human review",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
});
const ready = await client.runs.waitForEvent(run.id, "browser.ready");
await client.runs.waitForCompletion(run.id);
console.log(ready.data.live_view_url);

const events = await client.runs.events(run.id, {
limit: 100,
});
const ready = events.events.find(
(event) => event.type === "browser.ready",
);
console.log(ready?.data.live_view_url);

// After the human finishes:
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
await rl.question("Press Enter after finishing the human step...");
rl.close();
const nextRun = await client.runs.create({
task: "Continue from the current page",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
sessionId: run.sessionId,
});
```
</CodeGroup>

The same session preserves the conversation and workspace and reuses the live
browser while it is available. Treat live-view URLs as credentials.
browser while it is available. Complete the human step before that browser
expires. In a web app, replace the terminal prompt with an explicit Continue
control. Treat live-view URLs as credentials.
12 changes: 8 additions & 4 deletions docs/cloud/agent/scripts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ first = client.runs.create(
proof/run-2.json. Confirm both outputs have a fresh fetched_at value and
five stories. Add scripts/README.md with the command to run it again.
""",
model="grok-4.5",
model="gpt-5.6-luna",
model_params={"reasoning": {"effort": "xhigh"}},
workspace_id=workspace.id,
)
client.runs.wait_for_completion(first.id)
Expand Down Expand Up @@ -87,7 +88,8 @@ const first = await client.runs.create({
proof/run-2.json. Confirm both outputs have a fresh fetched_at value and
five stories. Add scripts/README.md with the command to run it again.
`,
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
workspaceId: workspace.id,
});
await client.runs.waitForCompletion(first.id);
Expand Down Expand Up @@ -119,7 +121,8 @@ later = client.runs.create(
has five stories. If the script fails or the result is malformed, inspect
the live page and repair the saved script before returning the new result.
""",
model="grok-4.5",
model="gpt-5.6-luna",
model_params={"reasoning": {"effort": "xhigh"}},
workspace_id=workspace_id,
)
result = client.runs.wait_for_completion(later.id)
Expand All @@ -138,7 +141,8 @@ const later = await client.runs.create({
has five stories. If the script fails or the result is malformed, inspect
the live page and repair the saved script before returning the new result.
`,
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
workspaceId,
});
const result = await client.runs.waitForCompletion(later.id);
Expand Down
6 changes: 4 additions & 2 deletions docs/cloud/agent/sessions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ print(result.result)
```typescript TypeScript
const first = await client.runs.create({
task: "Open Hacker News",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
});
await client.runs.waitForCompletion(first.id);

const followUp = await client.runs.create({
task: "Now summarize the top story",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
sessionId: first.sessionId,
});
const result = await client.runs.waitForCompletion(followUp.id);
Expand Down
3 changes: 2 additions & 1 deletion docs/cloud/agent/structured-output.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ const Story = z.object({

const run = await client.runs.create({
task: 'Find the top HN story. Return only {"title":"...","points":0}.',
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
});
const result = await client.runs.waitForCompletion(run.id);
const story = Story.parse(JSON.parse(result.result ?? "{}"));
Expand Down
3 changes: 2 additions & 1 deletion docs/cloud/agent/workspaces.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ await client.workspaces.upload(

const run = await client.runs.create({
task: "Find everyone in the CSV who works at Google",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
workspaceId: workspace.id,
});
```
Expand Down
6 changes: 4 additions & 2 deletions docs/cloud/browser/live-preview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import { BrowserUse } from "browser-use-sdk/v4";
const client = new BrowserUse();
const run = await client.runs.create({
task: "Find the top Hacker News story",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
});
const ready = await client.runs.waitForEvent(run.id, "browser.ready", { interval: 3_000 });
console.log(ready.data.live_view_url);
Expand Down Expand Up @@ -121,7 +122,8 @@ run = client.runs.create(
```typescript TypeScript
const run = await client.runs.create({
task: "Test the checkout flow",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
browserSettings: { proxyCountryCode: "us", record: true },
});
```
Expand Down
9 changes: 6 additions & 3 deletions docs/cloud/browser/proxies.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ import { BrowserUse } from "browser-use-sdk/v4";
const client = new BrowserUse();
const run = await client.runs.create({
task: "Get the iPhone 16 price on amazon.de",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
browserSettings: { proxyCountryCode: "de" },
});
```
Expand All @@ -73,7 +74,8 @@ run = client.runs.create(
```typescript TypeScript
const run = await client.runs.create({
task: "Test my staging site",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
browserSettings: { proxyCountryCode: null },
});
```
Expand Down Expand Up @@ -145,7 +147,8 @@ run = client.runs.create(
```typescript TypeScript
const run = await client.runs.create({
task: "Check the account dashboard",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
browserSettings: {
proxyCountryCode: "us",
customProxy: {
Expand Down
17 changes: 14 additions & 3 deletions docs/cloud/guides/2fa.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ run = client.runs.create(
```typescript TypeScript
const run = await client.runs.create({
task: "Download my latest invoice",
model: "grok-4.5",
model: "gpt-5.6-luna",
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
modelParams: { reasoning: { effort: "xhigh" } },
browserSettings: {
profileId: "YOUR_PROFILE_ID",
proxyCountryCode: "us",
Expand All @@ -43,7 +44,10 @@ the code. Then continue with the same session:
first = client.runs.create(
"Open the login page and stop at the 2FA prompt",
)
ready = client.runs.wait_for_event(first.id, "browser.ready")
client.runs.wait_for_completion(first.id)
print(ready.data["live_view_url"])
input("Press Enter after entering the 2FA code...")

next_run = client.runs.create(
"Continue after login and download the invoice",
Expand All @@ -53,13 +57,20 @@ next_run = client.runs.create(
```typescript TypeScript
const first = await client.runs.create({
task: "Open the login page and stop at the 2FA prompt",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
});
const ready = await client.runs.waitForEvent(first.id, "browser.ready");
await client.runs.waitForCompletion(first.id);
console.log(ready.data.live_view_url);
await new Promise((resolve) => {

@cubic-dev-ai cubic-dev-ai Bot Sep 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: After the human presses Enter, this promise resolves but nothing pauses or closes process.stdin. Attaching the data listener put it into flowing mode, so a TTY stdin never ends and a copy-pasted script that finishes after nextRun = await client.runs.create(...) lingers at a blank prompt instead of exiting. This also diverges from the shipped pattern in human-in-the-loop.mdx, which uses readline/promises with rl.question(...) then rl.close() to relinquish stdin. Mirror that pattern here.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/cloud/guides/2fa.mdx, line 66:

<comment>After the human presses Enter, this promise resolves but nothing pauses or closes `process.stdin`. Attaching the `data` listener put it into flowing mode, so a TTY stdin never ends and a copy-pasted script that finishes after `nextRun = await client.runs.create(...)` lingers at a blank prompt instead of exiting. This also diverges from the shipped pattern in human-in-the-loop.mdx, which uses `readline/promises` with `rl.question(...)` then `rl.close()` to relinquish stdin. Mirror that pattern here.</comment>

<file context>
@@ -57,7 +60,12 @@ const first = await client.runs.create({
+const ready = await client.runs.waitForEvent(first.id, "browser.ready");
 await client.runs.waitForCompletion(first.id);
+console.log(ready.data.live_view_url);
+await new Promise((resolve) => {
+  process.stdin.once("data", resolve);
+});
</file context>
Fix with cubic

process.stdin.once("data", resolve);
});

const nextRun = await client.runs.create({
task: "Continue after login and download the invoice",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
sessionId: first.sessionId,
});
```
Expand Down
3 changes: 2 additions & 1 deletion docs/cloud/guides/authentication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ import { BrowserUse } from "browser-use-sdk/v4";
const client = new BrowserUse();
const run = await client.runs.create({
task: "Open my account dashboard and summarize it",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
browserSettings: {
profileId: "YOUR_PROFILE_ID",
proxyCountryCode: "us",
Expand Down
3 changes: 2 additions & 1 deletion docs/cloud/guides/profile-sync.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ import { BrowserUse } from "browser-use-sdk/v4";
const client = new BrowserUse();
const run = await client.runs.create({
task: "Check my LinkedIn messages",
model: "grok-4.5",
model: "gpt-5.6-luna",
modelParams: { reasoning: { effort: "xhigh" } },
browserSettings: {
profileId: "YOUR_PROFILE_ID",
proxyCountryCode: "us",
Expand Down