Browser integration
Browser adapters connect the fx WebAssembly SDK to storage, authentication, command execution, and network requests. Add only the adapters your app needs; adapter methods may be synchronous or asynchronous. createFxTerminal() supports every option on this page, while createFxAgent() supports configStore, sessionStore, and fetch.
Choose an adapter
| Option | Used by | Purpose |
|---|---|---|
configStore | Both | Restore accepted model and mode settings. |
promptHistoryStore | Terminal | Preserve terminal input history. |
sessionStore | Both | Persist conversations. |
openUrl and oauthSessionStore | Terminal | Complete browser device login. |
workspace | Terminal | Add a foreground run_command tool. |
fetch | Both | Control network requests. |
Config store
Use configStore to restore settings such as the active model and mode:
const configStore = {
get(id) {
return localStorage.getItem(`fx.core.config.${id}`)
},
set(id, value) {
localStorage.setItem(`fx.core.config.${id}`, value)
},
}
get(id) returns a string or null. fx calls set(id, value) only after it accepts the new value.
Prompt history store
Use promptHistoryStore to preserve terminal input history across page loads:
type PromptHistoryStore = {
load(
workspaceRoot: string,
limit: number,
): string[] | Promise<string[]>
append(
workspaceRoot: string,
value: string,
timestampMs: number,
):
| void
| 'duplicate'
| 'record_too_large'
| Promise<void | 'duplicate' | 'record_too_large'>
clear(workspaceRoot: string): void | Promise<void>
}
load() returns prompts from oldest to newest. Return duplicate when the latest stored prompt already matches, or record_too_large when the app declines to store it.
Session store
Use sessionStore to persist conversations. Pass args: ['--resume', 'last'] to createFxTerminal() to resume the conversation with the latest updatedAtMs value.
type SessionStore = {
load(id: string):
| { bytes: Uint8Array; revision: string }
| null
| Promise<{ bytes: Uint8Array; revision: string } | null>
commit(
id: string,
bytes: Uint8Array,
expectedRevision: string | undefined,
): { revision: string } | Promise<{ revision: string }>
list():
| Array<{ id: string; updatedAtMs: number }>
| Promise<Array<{ id: string; updatedAtMs: number }>>
remove(id: string): void | Promise<void>
}
Treat bytes as opaque data. commit() receives undefined for the first revision and must return a new revision after every write.
If expectedRevision is stale, throw an error whose code is FX_SESSION_REVISION_CONFLICT. The conflict prevents the stale snapshot from overwriting the current record. createFxAgent() uses an in-memory session store when you do not provide one.
Device login
createFxTerminal() supports browser device login through openUrl and oauthSessionStore:
const terminal = await createFxTerminal({
wasm: './fx-term.wasm',
terminal: terminalAdapter,
openUrl(url) {
return window.open(url, '_blank', 'noopener,noreferrer') !== null
},
oauthSessionStore,
})
Return false from openUrl() when the app cannot open the verification page. fx still prints the URL and verification code in the terminal.
The OAuth store uses the following contract:
type OAuthSessionStore = {
load():
| { bytes: Uint8Array; revision: string }
| null
| Promise<{ bytes: Uint8Array; revision: string } | null>
commit(
bytes: Uint8Array,
expectedRevision: string | undefined,
): { revision: string } | Promise<{ revision: string }>
remove(expectedRevision: string | undefined):
| void
| boolean
| 'missing'
| Promise<void | boolean | 'missing'>
}
Store the OAuth bytes without inspecting or logging them. Return false or missing when there is no record to remove. Reject a stale commit or removal with FX_OAUTH_SESSION_REVISION_CONFLICT.
Browser workspace
The optional workspace adapter adds a foreground run_command tool implemented by your app:
type WorkspaceAdapter = {
info: {
version: 1
root: string
cwd: string
home: string
gitAvailable: false
ephemeral: true
}
permission: 'allow-sandboxed' | 'prompt'
exec(input: {
command: string
cwd: string
signal: AbortSignal
timeoutMs: number
outputLimitBytes: number
}):
| { stdout: string; stderr: string; exitCode: number }
| Promise<{ stdout: string; stderr: string; exitCode: number }>
}
root, cwd, and home must be normalized absolute paths without NUL bytes. Version 1 also requires:
cwdequalsroot.gitAvailableisfalse.ephemeralistrue.permissionisallow-sandboxedorprompt.
exec() returns { stdout, stderr, exitCode }. Commands are limited to 64 KiB of UTF-8, combined output previews to 64 KiB, and execution to 30 seconds. The adapter must stop work when its AbortSignal is cancelled. Without a workspace adapter, the WebAssembly terminal does not expose run_command.
The try page implements this adapter with an in-memory bash environment.
Network requests
The SDK uses globalThis.fetch by default. Pass a fetch function to createFxTerminal() or createFxAgent() when your app needs to proxy requests, add authentication, or apply its own network policy. Browser Cross-Origin Resource Sharing (CORS) and Content Security Policy (CSP) rules still apply.