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
7 changes: 1 addition & 6 deletions browser-use-node/src/generated/v4/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1110,12 +1110,7 @@ export interface components {
* @default minimax-m3
* @enum {string}
*/
// POST-GEN PATCH: "kimi-k3" and "claude-fable-5" omitted on purpose —
// live in the API but not public yet. openapi-typescript re-adds them
// from the spec on every regen, so re-apply this after `task gen:types`
// until the backend advertises a public model subset. (The API still
// accepts them; this only hides them from the SDK type.)
model: "glm-5.2" | "grok-4.5" | "minimax-m3" | "claude-opus-4.7" | "claude-opus-4.8" | "claude-sonnet-5" | "gpt-5.5" | "gpt-5.6" | "gemini-3.5-flash" | "gemini-3.1-pro" | "gemini-3-flash";
model: "glm-5.2" | "grok-4.5" | "kimi-k3" | "minimax-m3" | "claude-opus-4.7" | "claude-opus-4.8" | "claude-opus-5" | "claude-fable-5" | "claude-sonnet-5" | "gpt-5.5" | "gpt-5.6" | "gemini-3.5-flash" | "gemini-3.1-pro" | "gemini-3-flash";
/** Sessionid */
sessionId?: string | null;
/** Workspaceid */
Expand Down
8 changes: 6 additions & 2 deletions browser-use-node/src/v4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ export type { BrowserUseOptions } from "./v4/client.js";
export { BrowserUseError } from "./core/errors.js";

export { Runs } from "./v4/resources/runs.js";
export type { RunListParams, RunEventsParams, WaitOptions } from "./v4/resources/runs.js";
export type {
RunCreateRequest,
RunListParams,
RunEventsParams,
WaitOptions,
} from "./v4/resources/runs.js";

export { Sessions } from "./v4/resources/sessions.js";
export type { SessionListParams } from "./v4/resources/sessions.js";
Expand All @@ -19,7 +24,6 @@ import type { components } from "./generated/v4/types.js";
type S = components["schemas"];

// Run models
export type RunCreateRequest = S["RunCreateRequest"];
export type RunCreateResponse = S["RunCreateResponse"];
export type RunSummary = S["RunSummary"];
export type RunStatusResponse = S["RunStatusResponse"];
Expand Down
6 changes: 5 additions & 1 deletion browser-use-node/src/v4/resources/runs.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import type { HttpClient } from "../../core/http.js";
import type { components } from "../../generated/v4/types.js";

type RunCreateRequest = components["schemas"]["RunCreateRequest"];
type GeneratedRunCreateRequest = components["schemas"]["RunCreateRequest"];
export type RunCreateRequest = Omit<GeneratedRunCreateRequest, "model"> & {
/** Defaults to minimax-m3 when omitted. */
model?: GeneratedRunCreateRequest["model"];
};
type RunCreateResponse = components["schemas"]["RunCreateResponse"];
type RunSummary = components["schemas"]["RunSummary"];
type RunStatusResponse = components["schemas"]["RunStatusResponse"];
Expand Down
5 changes: 5 additions & 0 deletions browser-use-node/src/v4/resources/sessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ export class Sessions {
return this.http.get<SessionInfo>(`/sessions/${sessionId}`);
}

/** Immediately purge all data for a session. Available to ZDR projects only. */
purge(sessionId: string): Promise<void> {
return this.http.post<void>(`/sessions/${sessionId}/purge`);
}

/**
* Send a message to the session. Runs as the next turn when the session is
* busy; set `interrupt: true` to cancel the active run so the message runs
Expand Down
31 changes: 31 additions & 0 deletions browser-use-node/tests/v4.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
import { Runs } from "../src/v4/resources/runs.js";
import { Sessions } from "../src/v4/resources/sessions.js";
import { Workspaces } from "../src/v4/resources/workspaces.js";
import type { RunCreateRequest } from "../src/v4.js";

const RUN_ID = "00000000-0000-0000-0000-000000000001";
const SESSION_ID = "00000000-0000-0000-0000-000000000002";
Expand All @@ -32,6 +33,25 @@ function runSummary(status: string) {
}

describe("v4 runs.waitForCompletion", () => {
it("creates a run without requiring the API-defaulted model", async () => {
const http = {
post: vi.fn(async () => ({
id: RUN_ID,
sessionId: SESSION_ID,
workspaceId: WORKSPACE_ID,
status: "queued",
})),
};
const runs = new Runs(http as any);
const request: RunCreateRequest = { task: "Find the top HN post" };

await runs.create(request);

expect(http.post).toHaveBeenCalledWith("/runs", {
task: "Find the top HN post",
});
});

it("polls status until terminal, then fetches the full run once", async () => {
const statuses = ["queued", "running", "completed"];
let statusCalls = 0;
Expand Down Expand Up @@ -163,6 +183,17 @@ describe("v4 sessions queue", () => {
expect(msg.status).toBe("pending");
});

it("purges a session through the ZDR endpoint", async () => {
const http = {
post: vi.fn(async () => undefined),
};
const sessions = new Sessions(http as any);

await sessions.purge(SESSION_ID);

expect(http.post).toHaveBeenCalledWith(`/sessions/${SESSION_ID}/purge`);
});

it("lists pending queued messages", async () => {
const http = {
get: vi.fn(async () => ({ queue: [queuedMessage] })),
Expand Down
1 change: 1 addition & 0 deletions browser-use-node/tests/vibe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ function v4EndpointToSdkMethod(
// Sessions + queue
if (method === "get" && path === "/sessions") return { resource: "sessions", method: "list" };
if (method === "get" && path === "/sessions/{session_id}") return { resource: "sessions", method: "get" };
if (method === "post" && path === "/sessions/{session_id}/purge") return { resource: "sessions", method: "purge" };
if (method === "post" && path === "/sessions/{session_id}/queue") return { resource: "sessions", method: "sendMessage" };
if (method === "get" && path === "/sessions/{session_id}/queue") return { resource: "sessions", method: "queue" };
if (method === "delete" && path === "/sessions/{session_id}/queue/{message_id}") return { resource: "sessions", method: "removeMessage" };
Expand Down
10 changes: 4 additions & 6 deletions browser-use-python/src/browser_use_sdk/generated/v4/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,17 +657,15 @@ class RunBrowserSettings(BaseModel):
)


# POST-GEN PATCH: kimi-k3 and claude-fable-5 are omitted on purpose — they are
# live in the API but not public yet. datamodel-codegen re-adds them from the
# spec on every regen, so this must be re-applied after `task gen:types` until
# the backend advertises a public model subset. (The API still accepts them;
# this only hides them from the SDK enum.)
class Model(Enum):
glm_5_2 = 'glm-5.2'
grok_4_5 = 'grok-4.5'
kimi_k3 = 'kimi-k3'
minimax_m3 = 'minimax-m3'
claude_opus_4_7 = 'claude-opus-4.7'
claude_opus_4_8 = 'claude-opus-4.8'
claude_opus_5 = 'claude-opus-5'
claude_fable_5 = 'claude-fable-5'
claude_sonnet_5 = 'claude-sonnet-5'
gpt_5_5 = 'gpt-5.5'
gpt_5_6 = 'gpt-5.6'
Expand Down Expand Up @@ -812,7 +810,7 @@ class ValidationError(BaseModel):


class Name2(RootModel[str]):
root: str = Field(..., max_length=255, title='Name')
root: str = Field(..., max_length=100, title='Name')


class WorkspaceCreateRequest(BaseModel):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ def get(self, session_id: str | UUID) -> SessionInfo:
self._http.request("GET", f"/sessions/{session_id}")
)

def purge(self, session_id: str | UUID) -> None:
"""Immediately purge all session data. Available to ZDR projects only."""
self._http.request("POST", f"/sessions/{session_id}/purge")

def send_message(
self,
session_id: str | UUID,
Expand Down Expand Up @@ -120,6 +124,10 @@ async def get(self, session_id: str | UUID) -> SessionInfo:
await self._http.request("GET", f"/sessions/{session_id}")
)

async def purge(self, session_id: str | UUID) -> None:
"""Immediately purge all session data. Available to ZDR projects only."""
await self._http.request("POST", f"/sessions/{session_id}/purge")

async def send_message(
self,
session_id: str | UUID,
Expand Down
9 changes: 9 additions & 0 deletions browser-use-python/tests/test_v4.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,15 @@ def test_sessions_send_message() -> None:
assert msg.status.value == "pending"


def test_sessions_purge() -> None:
http = FakeSyncHttp([{}])
sessions = Sessions(http) # type: ignore[arg-type]

sessions.purge(SESSION_ID)

assert http.calls[0][:2] == ("POST", f"/sessions/{SESSION_ID}/purge")


def test_sessions_queue_list() -> None:
http = FakeSyncHttp([{"queue": [_queued_message()]}])
sessions = Sessions(http) # type: ignore[arg-type]
Expand Down
1 change: 1 addition & 0 deletions browser-use-python/tests/test_vibe.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ def _load_spec(path: Path) -> Dict[str, Any]:
# sessions + queue
("get", "/sessions"): ("sessions", "list"),
("get", "/sessions/{session_id}"): ("sessions", "get"),
("post", "/sessions/{session_id}/purge"): ("sessions", "purge"),
("post", "/sessions/{session_id}/queue"): ("sessions", "send_message"),
("get", "/sessions/{session_id}/queue"): ("sessions", "queue"),
("delete", "/sessions/{session_id}/queue/{message_id}"): ("sessions", "remove_message"),
Expand Down
Loading