agents
Version:
A home for your AI agents
231 lines (229 loc) • 8.61 kB
TypeScript
import { WorkerEntrypoint } from "cloudflare:workers";
//#region src/browser/internal-hosts.d.ts
/** The most hostnames one browser can have. A Browser Run limit. */
declare const MAX_INTERNAL_HOSTS = 8;
/** A Standard Schema: something that validates a value. */
interface StandardSchemaV1<Input = unknown, Output = Input> {
readonly "~standard": {
readonly version: 1;
readonly vendor: string;
readonly validate: (
value: unknown
) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
readonly types?:
| {
readonly input: Input;
readonly output: Output;
}
| undefined;
};
}
type StandardSchemaResult<Output> =
| {
readonly value: Output;
readonly issues?: undefined;
}
| {
readonly issues: ReadonlyArray<{
readonly message: string;
readonly path?: ReadonlyArray<
| PropertyKey
| {
readonly key: PropertyKey;
}
>;
}>;
};
/** A Standard JSON Schema: something that can describe itself as JSON Schema. */
interface StandardJSONSchemaV1 {
readonly "~standard": {
readonly jsonSchema: {
readonly input: (options: {
readonly target: string;
}) => Record<string, unknown>;
};
};
}
/** A typed schema: validates (Standard Schema) and describes itself (Standard JSON Schema). */
type TypedTargetSchema = StandardSchemaV1 & StandardJSONSchemaV1;
/** A plain JSON Schema object, such as TypeBox output or a hand-written one. */
type JsonSchemaObject = {
readonly [key: string]: unknown;
};
/**
* What the model passes to `browser.assignHost()` for a host. A typed schema (zod
* 4.2+, ArkType, Valibot) types `fetch`'s `target`; a plain JSON Schema
* leaves it `unknown`.
*/
type TargetSchema = TypedTargetSchema | JsonSchemaObject;
/** The value a schema validates to: typed for a Standard Schema, else `unknown`. */
type TargetOf<S> =
S extends StandardSchemaV1<unknown, infer Output> ? Output : unknown;
/** A host served by code in your agent. */
interface InternalHost<S = unknown> {
/** Shown to the model next to the hostname. */
description?: string;
/**
* What the model passes to `browser.assignHost()` to point this host somewhere,
* as a schema. Omit it for a host that always serves the same thing.
*
* The model picks this value, so if part of it becomes a path, URL or
* command in `fetch`, limit it in the schema (an enum, a pattern, a range)
* rather than trusting it.
*/
target?: S & TargetSchema;
/**
* Serves every browser request to this hostname. Runs in your agent, with
* the target the model last assigned (validated by `target`), or
* `undefined` when the host has no `target` schema.
*
* Any http page open in the browser can send requests here, not only
* pages on this host: a page on another internal hostname, or an http
* site the guardrails allow, can POST to `http://preview.internal`. Chrome
* doesn't send `Sec-Fetch-*` headers to http hosts, so if a request has
* side effects, check that its `Origin` is this host.
*
* If it throws, the browser gets a 502 and the error is logged, not shown
* to the page.
*/
fetch: (request: Request, target: TargetOf<S>) => Promise<Response>;
worker?: never;
}
/**
* A host served by a deployed Worker directly, without going through your
* agent: a service binding, or an entrypoint of your own Worker. Not a
* Dynamic Worker or Durable Object stub — Browser Run can't hold those.
*/
interface InternalWorkerHost {
/** Shown to the model next to the hostname. */
description?: string;
/**
* The Worker that serves this hostname: a service binding, or an
* entrypoint of your own Worker. Requests go straight to it, without
* waking your agent.
*
* An entrypoint passed as is (`this.ctx.exports.DocsSite`) is called with
* empty props; to give it props, call it yourself
* (`this.ctx.exports.DocsSite({ props })`). A Durable Object stub doesn't
* type-check: Browser Run accepts one, then resets every request.
*/
worker: Fetcher & {
id?: never;
};
target?: never;
fetch?: never;
}
/** The entrypoint loopback for {@link InternalHostRouter}: `this.ctx.exports.InternalHostRouter`. */
type InternalHostRouterLoopback = (init: {
props: InternalHostRouterProps;
}) => Fetcher;
/**
* `browserRun()`'s `internalHosts`: hostnames only this browser can open.
*
* Fixed when a browser starts. Adding or removing a hostname replaces the
* browser (the model sees `restarted`); changing a host's `fetch`,
* `description` or `target` doesn't. Nor does pointing a `worker` host at
* a different Worker: the running browser keeps the old one until it is
* replaced, so call `browser.close()` after such a change.
*/
interface InternalHostsOptions<S = Record<string, unknown>> {
/**
* Your Worker's {@link InternalHostRouter} export, as
* `this.ctx.exports.InternalHostRouter`. Needed for `fetch` hosts.
*/
router?: InternalHostRouterLoopback;
/**
* At most {@link MAX_INTERNAL_HOSTS} hostnames: bare and lowercase, no
* scheme, port, or path, ending in a suffix that can't be a real site:
* `.internal`, `.test`, `.example` or `.invalid`, like `preview.internal`.
*/
hosts: { [K in keyof S]: InternalHost<S[K]> | InternalWorkerHost };
}
/** One host, as the host API and the model see it. */
interface InternalHostInfo {
/** The hostname, such as `preview.internal`. */
host: string;
/** Where the browser opens it: `http://<host>/`. */
url: string;
description?: string;
/** Whether the model can point it somewhere with `browser.assignHost()`. */
assignable: boolean;
/** The JSON Schema `browser.assignHost()` checks the target against. */
targetSchema?: Record<string, unknown>;
/** The target last assigned, as assigned (before the schema transforms it). */
target?: unknown;
}
/**
* What {@link InternalHostRouter} is given for one hostname: which agent and
* browser own it. Browser Run keeps these for the whole session, across
* redeploys, so they hold names only, never secrets or config.
*/
type InternalHostRouterProps = {
readonly v: 1 /** The agent's class name, as exported from the Worker. */;
readonly className: string /** The agent's name. */;
readonly name: string /** The name of the `Browser` that owns the host. */;
readonly browser: string /** The hostname this route serves. */;
readonly host: string;
};
/**
* One browser request to an internal hostname, as {@link InternalHostRouter}
* hands it to the agent's `fetchInternalHost()`.
*
* `Agent` has `fetchInternalHost()` built in. A plain Durable Object adds it
* and passes the message to its `Browser`:
*
* ```ts
* fetchInternalHost(message: InternalHostMessage) {
* return this.browser.fetchInternalHost(message);
* }
* ```
*/
type InternalHostMessage = {
/** The name of the `Browser` that owns the host. */ readonly browser: string /** The hostname, such as `preview.internal`. */;
readonly host: string /** The browser's request. */;
readonly request: Request;
};
/**
* Carries a browser's requests for an internal hostname to the agent that
* owns it. Export it from your Worker's main module, so
* `this.ctx.exports.InternalHostRouter` exists:
*
* ```ts
* export { InternalHostRouter } from "agents/browser";
* ```
*
* It trusts its props: Browser Run sets them from your routes, but another
* Worker in your account with a service binding to this entrypoint could
* set its own and reach any agent's hosts. That Worker could already call
* your agents directly, so this grants nothing new.
*
* It holds no logic of its own: it calls the agent's `fetchInternalHost()`
* with an {@link InternalHostMessage}, and the agent's `Browser` runs the
* host's `fetch`. `Agent` has `fetchInternalHost()` built in; a plain
* Durable Object adds it (see {@link InternalHostMessage}).
*
* @experimental The API may change before it stabilizes.
*/
declare class InternalHostRouter extends WorkerEntrypoint<
unknown,
InternalHostRouterProps
> {
fetch(request: Request): Promise<Response>;
}
//#endregion
export {
InternalHostRouterLoopback as a,
InternalWorkerHost as c,
TargetOf as d,
TargetSchema as f,
InternalHostRouter as i,
JsonSchemaObject as l,
InternalHostInfo as n,
InternalHostRouterProps as o,
TypedTargetSchema as p,
InternalHostMessage as r,
InternalHostsOptions as s,
InternalHost as t,
MAX_INTERNAL_HOSTS as u
};
//# sourceMappingURL=internal-hosts-Kfp5A392.d.ts.map