import type { AdapterContext, BrowserActKind, BrowserActStep, BrowserProvider, ComputerRef, } from "@rakazo/adapter-kit"; const MAX_BROWSER_ACTIONS = 24; export async function browserNavigateFromTool( browser: BrowserProvider, computer: ComputerRef, context: AdapterContext, args: Record, ) { const url = String(args.url ?? "").trim(); try { const parsed = new URL(url); if (!/^https?:$/.test(parsed.protocol) || parsed.username || parsed.password) { return { error: "An HTTP(S) URL without embedded credentials is required", fallback: "computer_act" as const, }; } const result = await browser.navigate(computer, { url, signal: context.signal }, context); return formatBrowserResult(result); } catch (error) { context.signal.throwIfAborted(); return { error: error instanceof Error ? error.message : String(error), fallback: "computer_act" as const, }; } } export async function browserSnapshotFromTool( browser: BrowserProvider, computer: ComputerRef, context: AdapterContext, args: Record, ) { void args; try { const result = await browser.snapshot(computer, { signal: context.signal }, context); return formatBrowserResult(result); } catch (error) { context.signal.throwIfAborted(); return { error: error instanceof Error ? error.message : String(error), fallback: "computer_act" as const, }; } } export async function browserActFromTool( browser: BrowserProvider, computer: ComputerRef, context: AdapterContext, args: Record, ) { try { const actions = parseBrowserActions(args.actions); const result = await browser.act(computer, { actions, signal: context.signal }, context); return formatBrowserResult(result); } catch (error) { context.signal.throwIfAborted(); return { ok: false, uncertain: true, error: error instanceof Error ? error.message : String(error), fallback: "computer_act" as const, }; } } export function parseBrowserActions(value: unknown): BrowserActStep[] { if (!Array.isArray(value) || value.length === 0) { throw new Error("browser_act requires at least one action"); } if (value.length > MAX_BROWSER_ACTIONS) { throw new Error(`browser_act accepts at most ${MAX_BROWSER_ACTIONS} actions`); } return value.map((raw, index) => { if (!raw || typeof raw !== "object") { throw new Error(`browser_act action ${index} must be an object`); } const action = raw as Record; const kind = String(action.kind ?? "") as BrowserActKind; if (kind !== "click" && kind !== "fill" && kind !== "type") { throw new Error(`browser_act action ${index} has unsupported kind`); } const ref = String(action.ref ?? "").trim(); if (!ref) throw new Error(`browser_act action ${index} requires ref`); if (kind === "fill" || kind === "type") { if (typeof action.text !== "string") { throw new Error(`browser_act ${kind} requires text`); } return { kind, ref, text: String(action.text) }; } return { kind, ref }; }); } function formatBrowserResult(result: T) { if (result.fallback === "computer_act") { return { ...result, note: "Page browser could not complete this step. Inspect the current state before continuing with computer_act if available, otherwise request_takeover. Do not replay completed or uncertain actions.", }; } return result; }