Vanilla Breeze

ai-chat

On-device chat via Chrome's LanguageModel API. Optionally page-aware via a context selector. Provider-neutral inline endpoint and external deep-link fallbacks.

Overview

An on-device chat component built on <chat-window> + <chat-input>. Without a context attribute, behaves as a general assistant. With context="", the targeted region's text is folded into the system prompt so the model can answer questions about the surrounding article — no retrieval plumbing required.

The configured providers (local Chrome LanguageModel, your endpoint, your fallback-url) are surfaced as options in the chat-window header's model select. Users can see what's running and switch on the fly. Auto-selection prefers local → endpoint → deep-link; unavailable options stay disabled.

Page-aware mode

Add context="#some-selector" and the component reads that region's text on session creation, prepending it to the system prompt under a clear [PAGE CONTENT] delimiter. A ribbon shows character / token counts and warns if the selection exceeds Gemini Nano's window.

System prompt and starters

Long system prompts go in <template data-role="system">. The system attribute wins if both are set.

Starter chips come from <template data-role="starters">, one prompt per line. They render as a chip row under the ribbon and disappear once the conversation has any messages (CSS :has() handles the toggle).

Inline endpoint fallback

Configure endpoint="…" to route through a server you control when on-device AI isn't available. The component sends { prompt, content, mode: "chat" } as JSON; the server streams text/plain chunks back (or returns one-shot application/json). The chat UI is identical regardless of provider.

Wire format documented in AI page-tools v1, §C.

External deep-link fallback

Configure fallback-url="…" and the Send button opens the configured URL in a new tab when neither on-device AI nor an inline endpoint is configured. The current draft message is folded into the deep-link {prompt} so the external tool picks up where the user left off.

State and events

Lifecycle on data-state: checking, ready, downloading, streaming, error, unavailable. Provider switching emits chat-window:model-change from the inner chat-window — listen there to react to in-page provider swaps.