Skip to content

Session lifecycle

Built-in AI sessions run on-device models. Creating a session can take seconds and can trigger a model download. Every live session holds model memory until the tab closes.

Chrome’s Built-in AI dos and don’ts turns that cost into three rules: prepare the model at a reasonable time, reuse sessions instead of re-creating them, and destroy sessions you no longer need. This guide shows how the SDK covers each rule and which parts your application controls.

Every task package keeps a bounded LRU cache of warm native sessions, keyed by the session-affecting options. Calls with the same configuration reuse the warm session and skip the cold start. ask() in Prompt goes further: it keeps one warm base session and runs each call on a fresh clone, so unrelated prompts never share context.

This covers the reuse rule by default. The remaining two rules need one signal only your application has: user intent.

The SDK cannot know when a user is about to use an AI feature. Your application does: a panel opens, a field gains focus, a pointer hovers the action. prepare<Noun>(options) starts native session creation at that moment, before any input exists.

import { prepareSummarizer, summarize } from "@web-ai-sdk/summarizer";
// The user opened the summary panel: warm the session now.
const summarizerModel = prepareSummarizer({ language: "en", type: "key-points" });
// The user clicked: the matching call reuses the prepared session.
const result = await summarize({
input: articleText,
language: "en",
type: "key-points",
});
// The user closed the panel: destroy the session and free its memory.
summarizerModel.release();

Reuse happens when the prepare options match the session-affecting options of the later call. A mismatch is never an error; the call creates its own session lazily, as it would without preparation.

Do not prepare on module import or page load. Preparation can download a model and holds memory, so it needs real intent behind it.

prepare returns a lease: { ready: Promise<void>; release(): void }. Call release() when the user leaves the feature. The session is destroyed as soon as it is safe, which frees the model memory instead of waiting for the tab to close.

release() is idempotent, so wiring it to more than one teardown path is safe:

const translatorModel = prepareTranslator({ sourceLanguage: "en", targetLanguage: "es" });
closeButton.addEventListener("click", () => {
translationPanel.hidden = true;
translatorModel.release();
});

Safety rules the SDK enforces for you:

  • Multiple prepares for one configuration share one native session. Each caller holds its own lease.
  • Releasing one lease never destroys a session that another lease or an in-flight call still uses. The final release destroys it exactly once.
  • Releasing before creation settles destroys the session after creation succeeds.
  • Sessions with active leases never fall out of the LRU cache.
  • Preparing one configuration cannot release or reuse another configuration.

ready resolves when the native session exists. Use it to switch UI states: enable the action, or hide a “downloading model” hint. prepare never throws synchronously; a missing API or a failed creation rejects ready with the package’s typed unavailability error.

const translatorModel = prepareTranslator({ sourceLanguage: "en", targetLanguage: "fr" });
translatorModel.ready
.then(() => showReadyState())
.catch(() => showFallback());

Failure is a real path. Chrome refuses some downloads without a user gesture, storage can be full, and a device can be unsupported. A failed preparation leaves the cache, so a later prepare retries cleanly.

The React hooks need no extra wiring. Hold a lease in an effect; the hook’s matching call reuses the warm session, and unmount releases it.

usePrompt runs on demand, which makes the payoff visible: the model warms while the panel is open, so the first ask() starts instantly.

import { useEffect } from "react";
import { prepareLanguageModel } from "@web-ai-sdk/prompt";
import { usePrompt } from "@web-ai-sdk/prompt/react";
const SYSTEM_PROMPT = "Answer in one short paragraph.";
export function AnswerPanel() {
// Hold a lease for the panel's lifetime. Unmount releases the base session.
useEffect(() => {
const languageModel = prepareLanguageModel({ systemPrompt: SYSTEM_PROMPT });
return languageModel.release;
}, []);
// ask() clones from the warm base; no second create.
const { status, output, ask } = usePrompt({ systemPrompt: SYSTEM_PROMPT });
if (status === "unavailable") return null;
return (
<section>
<button
onClick={() => ask("Why is the sky blue?")}
disabled={status === "loading" || status === "streaming"}
>
Ask
</button>
{output ? <p>{output}</p> : null}
</section>
);
}

Leases are shared, so you can also prepare earlier, for example in the hover handler of the button that mounts this panel. Releasing that earlier lease cannot destroy the session while the panel still holds its own.

useSession is the one exception: it wraps createSession(), which creates a caller-owned session outside the warm cache. It manages its own lifecycle, so prepareLanguageModel does not warm it.

Package Prepare Lease type
@web-ai-sdk/prompt prepareLanguageModel LanguageModelLease
@web-ai-sdk/summarizer prepareSummarizer SummarizerLease
@web-ai-sdk/translator prepareTranslator TranslatorLease
@web-ai-sdk/detector prepareLanguageDetector LanguageDetectorLease
@web-ai-sdk/writer prepareWriter WriterLease
@web-ai-sdk/rewriter prepareRewriter RewriterLease
@web-ai-sdk/proofreader prepareProofreader ProofreaderLease

Each package README documents its session-affecting option fields. Prompt’s createSession() stays outside this system; it always creates a caller-owned session you destroy yourself.

Every package also exports configure<Noun>Cache({ max }), clear<Noun>Sessions(), and clear<Noun>Session(options) for direct cache control. Clearing detaches sessions pinned by a lease or an in-flight call and destroys them when the last pin drops.