export { Sandbox } from "../../worker/sandbox";
import runtime, {
PersonalAgent as FixturePersonalAgent,
Conversation as FixtureConversation,
} from "./think-worker";
import type { Env } from "../../worker/personal-agent";
import type { BrowserBinding } from "agents/browser";
import { createBrowserSession } from "agents/browser";
import { getAgentByName } from "agents";
import { browserRace } from "./browser-races";
const sessions: { id: string; deleted: boolean }[] = [];
const requests: string[] = [];
let failDeletes = 0;
let delayCreate = 0;
const dynamicHtml = `
Initial titleLoading`;
const originalFetch = globalThis.fetch;
globalThis.fetch = ((input: RequestInfo | URL, init?: RequestInit) => {
const url = new URL(
typeof input === "string"
? input
: input instanceof URL
? input.href
: input.url,
);
return url.hostname === "browser.fixture.example.com"
? Promise.resolve(
new Response(dynamicHtml, { headers: { "content-type": "text/html" } }),
)
: originalFetch(input, init);
}) as typeof fetch;
function fixtureBrowser(browser: BrowserBinding): BrowserBinding {
return {
async fetch(input, init) {
if (init?.method === "DELETE" && failDeletes-- > 0)
return new Response(null, { status: 503 });
const response = await browser.fetch(input, init);
if (init?.method === "POST") {
const { sessionId } = (await response.clone().json()) as {
sessionId: string;
};
sessions.push({ id: sessionId, deleted: false });
if (delayCreate)
await new Promise((resolve) => setTimeout(resolve, delayCreate));
}
if (init?.method === "DELETE") {
const found = sessions.find(
(session) => session.id === String(input).split("/").at(-1),
);
if (found && (response.ok || response.status === 404))
found.deleted = true;
}
if (response.webSocket) {
const socket = response.webSocket;
const send = socket.send.bind(socket);
const paused = new Map();
socket.addEventListener("message", (message) => {
const event = JSON.parse(String(message.data));
if (event.method === "Fetch.requestPaused") {
paused.set(event.params.requestId, event.params.request.url);
requests.push(event.params.request.url);
}
});
socket.send = (message) => {
const command = JSON.parse(String(message));
if (command.method === "Fetch.continueRequest") {
const url = new URL(paused.get(command.params.requestId)!);
if (url.hostname === "browser.fixture.example.com") {
const path = url.pathname;
const body =
path === "/follow"
? "Followed sourceFollow-up evidence"
: path === "/large"
? "" +
"🐟".repeat(12_000) +
""
: path === "/slow"
? "Waiting"
: dynamicHtml;
command.method = "Fetch.fulfillRequest";
command.params = {
requestId: command.params.requestId,
responseCode:
path === "/private" ? 302 : path === "/error" ? 429 : 200,
responseHeaders: [
{ name: "content-type", value: "text/html; charset=utf-8" },
...(path === "/private"
? [{ name: "location", value: "http://127.0.0.1/secret" }]
: []),
],
body: btoa(
String.fromCharCode(...new TextEncoder().encode(body)),
),
};
}
}
send(JSON.stringify(command));
};
}
return response;
},
};
}
export class PersonalAgent extends FixturePersonalAgent {
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, { ...env, BROWSER: fixtureBrowser(env.BROWSER) as Fetcher });
}
inspectBrowsers() {
return this.sql`SELECT * FROM flarebot_browser_leases`;
}
async seedBrowser(conversationId: string, ms: number) {
const { sessionId } = await createBrowserSession(this.env.BROWSER, {
keepAliveMs: 60_000,
});
await this.registerResearchBrowser(
conversationId,
sessionId,
Date.now() + ms,
);
return sessionId;
}
}
export class Conversation extends FixtureConversation {
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, { ...env, BROWSER: fixtureBrowser(env.BROWSER) as Fetcher });
}
}
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext,
) {
const url = new URL(request.url);
if (url.pathname === "/__fixture/browser-probe") {
const response = await env.BROWSER.fetch(
`https://localhost/v1/devtools/browser/${url.searchParams.get("id")}/json/list`,
);
return Response.json({ status: response.status });
}
if (url.pathname === "/__fixture/browser-status") {
const parent = await getAgentByName(env.PersonalAgent, "personal");
return Response.json({
sessions,
requests,
leases: await (parent as unknown as PersonalAgent).inspectBrowsers(),
});
}
if (url.pathname === "/__fixture/browser-fault") {
failDeletes = Number(url.searchParams.get("deletes") ?? 0);
delayCreate = Number(url.searchParams.get("create") ?? 0);
return new Response("ok");
}
if (url.pathname === "/__fixture/browser-seed") {
const parent = await getAgentByName(env.PersonalAgent, "personal");
return Response.json(
await (parent as unknown as PersonalAgent).seedBrowser(
url.searchParams.get("id")!,
Number(url.searchParams.get("ms")),
),
);
}
if (url.pathname === "/__fixture/browser-race")
return Response.json(
await browserRace(url.searchParams.get("scenario")!),
);
return runtime.fetch(request, env, ctx);
},
};