Attention-aware announcements
Opt into attention policy and add host-owned Auto, Normal, and Quiet controls to an existing React interface.
Opt in at both layers
Core attention filtering is disabled by default. Set
policy.attention.enabled: true to enable it. Its default quietWhen is
["background"]; add "reading-history" or "away" only when appropriate for
your host interface.
The React provider's separate attentionPolicy prop opts into forwarding
browser observations to the runtime. It does not enable core filtering by
itself. A runtime supplied through runtime must already have its policy
configured; provider policy props do not reconfigure a borrowed runtime.
The provider renders no visible controls. Connect your existing interface, then add an optional quiet toggle. With core attention disabled, the effective mode remains normal.
Enable attention policy
Follow the React setup, then import A11yProvider from
@generative-a11y/react and wrap your existing interface. Keep the default
system clock for production.
<A11yProvider attentionPolicy policy={{ attention: { enabled: true } }}>
<YourExistingInterface />
</A11yProvider>Connect your existing elements
In your client module, import useAttentionRefs from @generative-a11y/react.
Call it inside a component under the provider to obtain callback refs for the
composer, conversation, and newest response. Attach those refs to your existing
elements to observe focus and visibility; keep your content and styling.
const { composerRef, conversationRef, newestResponseRef } = useAttentionRefs();
return (
<>
<div ref={conversationRef}>
<article ref={newestResponseRef}>{response}</article>
</div>
<textarea ref={composerRef} />
</>
);Here, response is your application's existing response content. These bindings
provide browser observations, not proof that someone is reading.
Add controls where they fit
Import useAttentionControl from @generative-a11y/react in your client
module, then call it inside a component under the provider. Connect
setOverride to your own settings or controls. For example, a quiet toggle:
const { state, setOverride } = useAttentionControl();
return (
<button
type="button"
aria-pressed={state.override === "quiet"}
onClick={() => setOverride(state.override === "quiet" ? "auto" : "quiet")}
>
Quiet announcements
</button>
);setOverride("normal") explicitly restores normal delivery regardless of
observations. setOverride("auto") follows attention policy again.
state.observed reports browser evidence; state.effective reports the
resulting normal or quiet mode.
Understand what quiet suppresses
Quiet suppresses all response text, including full text announcements, and routine response/tool/run/step starts and tool/step progress. It preserves terminal, failure, interaction, connection, citation, and retry notices only when the underlying policy already enables them. It does not turn on categories disabled by the base policy.
There is no backlog on return. Text observed while quiet is discarded for announcements while your host keeps rendering it normally. Sentence and paragraph strategies discard the unit crossing the attention boundary and resume at a fresh unit. A response that lost text during quiet mode is not replayed in full by the completion strategy. This is more than a reduction in detail: users can miss response content in announcements and must be able to read the host's retained response.
Browser attention is a heuristic. The observer checks actual intersection of your registered newest response, along with available focus and visibility evidence. Intersection is not proof of a screen reader's virtual cursor location or reading position. Missing evidence remains unknown. Ordinary streaming, attention changes, and routine statuses never move focus.
Ownership and delivery
The provider owns and disposes its internally created runtime, DOM delivery, and stores when unmounted. An externally supplied runtime or store is borrowed: its creator must dispose it after consumers detach.
Provider live regions are placed at body level, outside nested conversation semantics. Keep your existing visible response and composer, and attach the public ref bindings shown above. Do not add another live region around the transcript: the provider handles delivery.
Without React, use bindAttention({ runtime, attentionStore }) from
@generative-a11y/dom. It forwards the initial snapshot and subsequent changes.
Dispose the binding to unsubscribe and send an unknown observation; it owns
neither runtime nor store. Competing bindings to the same runtime are rejected.
See DOM attention, core policy, and
React hooks.
Deterministic runtime tests and browser DOM checks establish filtering, cleanup, and focus behavior in those environments. They do not prove actual assistive-technology output. Manually test supported browser and screen-reader combinations, including quiet/resume, background return, history navigation, tool failure, approval, and explicit overrides.
Accessibility model and architecture
Follow an AI lifecycle event through the framework-independent runtime, scheduling policy, and DOM delivery that produce paced screen-reader updates.
Localized announcements
Connect your existing translations to runtime notices while keeping answer language, host UI, and lifecycle evidence independent.