Interface client
Talk to a Chat or Form interface from your own browser UI.
createInterfaceClient is the browser client the hosted pages and the launcher use. It needs no API key: it addresses one interface by its identifier and keeps the visitor's session in a cookie (credentials: "include"). Your site's origin must be in the interface's Allowed origins.
import { createInterfaceClient, ScrydonInterfaceError } from "@scrydon/sdk/interfaces";
const chat = createInterfaceClient({
baseUrl: "https://scrydon.example.com/agentic",
identifier: "<identifier>",
});
const page = await chat.getPage(); // the experience and auth mode
await chat.authenticate("password"); // only for a password-protected interface
const transcript = await chat.getSession(); // the visitor's earlier messages
const controller = new AbortController();
try {
for await (const event of chat.sendMessage("When are you open?", { signal: controller.signal })) {
if (event.type === "message.delta") render(event.text);
}
} catch (error) {
if (error instanceof ScrydonInterfaceError) showNotice(error.code, error.retryAfterSeconds);
}
// A Form interface has its own identifier and its own client.
const form = createInterfaceClient({
baseUrl: "https://scrydon.example.com/agentic",
identifier: "<form identifier>",
});
const result = await form.submitForm({ email: "ada@example.com" });getPage() answers ready (with the experience and whether a password is needed), locked until authenticate succeeds, or unavailable. getSession() returns the visitor's messages and turnsRemaining; it creates no conversation. submitForm(values) returns { status: "replied", message } when a Form Reply answered within the form's reply wait, otherwise { status: "submitted" }.
Events
| Event | Payload |
|---|---|
message.start | messageId, sent as soon as the run is scheduled |
message.delta | text; concatenate deltas (today the whole reply arrives in one) |
message.citations | { documentId, title, snippet }[] |
message.suggestions | string[] |
message.done | messageId, status: "complete" | "fallback" |
error | code: "FAILED" | "UNAVAILABLE" |
Leaving the loop early cancels the stream. The server sends a heartbeat every INTERFACE_HEARTBEAT_INTERVAL_MS (5 seconds). A reply that goes silent for three heartbeat intervals (15 seconds), ends, or breaks without a terminal event is delivered as error with code: "FAILED", so your UI never waits on a reply that will not come.
Nothing bounds the request itself before the reply starts. Pass signal to sendMessage to bound it; aborting the signal rejects with the abort's reason.
Errors
A refusal before the stream opens throws ScrydonInterfaceError with a stable code (RATE_LIMITED, TURN_LIMIT, BUDGET_EXHAUSTED, UNAVAILABLE, UNAUTHORIZED) and retryAfterSeconds, which is set whenever the response carries a Retry-After header: RATE_LIMITED, BUDGET_EXHAUSTED, and an UNAVAILABLE that comes from the rate limiter or the daily budget being unavailable. It is null otherwise. The error also carries the HTTP status (0 when no response could be read). See the Chat trigger.
The client adds codes of its own, listed in INTERFACE_CLIENT_ERROR_CODES: NOT_FOUND, INVALID_INPUT (a form submission whose fields do not fit; details lists them), BAD_REQUEST, PAYLOAD_TOO_LARGE, ORIGIN_NOT_ALLOWED, NETWORK_ERROR and UNEXPECTED_RESPONSE.
NETWORK_ERRORfrom another origin. A page whose origin is missing from the interface's Allowed origins seesNETWORK_ERROR, notORIGIN_NOT_ALLOWED: the refusal carries no cross-origin grant, so the browser hides it. Check the allowed origins first. The same code also covers a real network failure and an unknown identifier, so retry a bounded number of times with backoff.- Do not resubmit a form automatically. After a 502 or 504, or a
NETWORK_ERROR,submitFormmay already have started a run. Ask the visitor before sending the values again.
A runnable example is in examples/interface-chat in the Scrydon repository.