@aquera/nile-ai-elements
v0.0.5
Published
AI webcomponents for nile following open-wc recommendations
Keywords
Readme
<nile-ai-elements>
AI-focused web components for Nile, following the open-wc recommendation. Built with Lit and styled with the Nile / NxtGen (--ng-*) design tokens.
Components
| Tag | Description |
| --- | --- |
| <nile-ai-chat-bubble> | A chat bubble for an AI conversation (user / ai roles, agent header, reasoning pill, loader). Driven by a single data object. |
| <nile-ai-token-stream> | Reveals text token-by-token (typewriter style) with jitter, looping, a caret, and live API streaming. |
| <nile-wibbling-spinner> | A whimsical text spinner: a rotating glyph + a (re-rolling) verb + optional info. |
| <nile-ai-chat> | A scrollable conversation thread — lays out bubbles, autoscrolls to the latest, with header / footer / empty slots. Emits nile-scroll-state. |
| <nile-ai-prompt-input> | A chat composer: auto-growing textarea + send / stop button, Enter-to-send. Emits nile-submit, nile-input, nile-stop. |
| <nile-ai-prompt> | A rich composer: auto-growing textarea + toolbar (add-context, model picker, mic, send). The + button can open a customizable attachment menu (default "Add photos or files") via attach-menu / attachItems. Speech-to-text dictation via the Web Speech API with a live mic waveform. Emits nile-submit, nile-change, nile-model-change, nile-add-context, nile-attach, nile-voice*, nile-stop. |
| <nile-ai-prompts> | A predefined set of clickable prompt suggestions (icon / label / description), with nesting, a title, vertical / wrap layouts and fade-in. Emits nile-item-click. |
| <nile-ai-message-actions> | A per-message toolbar (copy / regenerate / like / dislike). Emits nile-action. |
| <nile-ai-suggestion> | A horizontal row of clickable suggestion pills — predefined prompts a user can tap to send to an LLM. Scrolls when it overflows, or wraps with wrap; supports plain strings or { label, value, icon, disabled } items. Emits nile-suggestion-click. |
| <nile-ai-attachments> | Displays file attachments and source documents with grid / inline / list layouts, automatic media-type detection, previews, and an optional remove affordance. Emits nile-remove, nile-item-click. |
| <nile-ai-image> | Renders an AI-generated image from the AI SDK — accepts an Experimental_GeneratedImage (base64 / uint8Array + mediaType) or a plain src, assembles the data: URL, and shows a loading shimmer then an error fallback. Emits nile-load, nile-error. |
| <nile-ai-citation> | An inline citation pill that reveals source details on hover / click; multiple sources become a carousel. Emits nile-toggle, nile-navigate, nile-source-click. |
| <nile-ai-checkpoint> | A marker between messages that lets the user restore the chat back to that point (bookmark icon + restore trigger + separator). Emits nile-restore. |
| <nile-ai-context> | Visualizes an LLM context-window's usage — a circular percentage ring that reveals a token / cost breakdown (input / output / reasoning / cache) on hover or click. Emits nile-toggle. |
| <nile-ai-temperature> | A reasoning-effort slider modeled on a coding agent's /effort menu — hover to preview a tier, click to commit. Emits nile-change. |
| <nile-ai-status> | A compact status pill (pending / active / running / done / error). |
| <nile-ai-reasoning> | A collapsible chain-of-thought panel; streaming-aware. Emits nile-toggle. |
| <nile-ai-tool-call> | A card for an agent tool / function invocation (name, status, args, collapsible result). Emits nile-toggle. |
| <nile-ai-confirmation> | A tool-approval card: shows an approval prompt with Approve / Reject actions while pending, then an accepted or rejected confirmation once resolved (driven by state + approved). Emits nile-respond, nile-approve, nile-reject. |
| <nile-ai-steps> | A vertical timeline of agent steps with per-step status markers. When more steps are appended than maxVisible (default 3), older steps slide out the top while new ones slide in, keeping only the trailing window on screen. |
| <nile-ai-plan> | A collapsible card showing an AI-generated execution plan — titled/described content sections (headings, prose, bullet lists) with a footer call-to-action; streaming-aware. Emits nile-toggle, nile-action. |
| <nile-ai-queue> | A queue of messages / todos in collapsible sections — per-item status indicator, content/description, image & file attachments, and hover-revealed actions. Emits nile-toggle, nile-action, nile-item-click. |
| <nile-ai-sources> | A collapsible disclosure listing the grounding sources a model used ("Used N sources") — each a link with a leading icon, title (falling back to the hostname) and optional description, opening in a new tab. Emits nile-toggle, nile-source-click. |
| <nile-ai-schema-display> | Visualizes a REST API endpoint — a color-coded HTTP method, the path (with highlighted {path} params), an optional description, and collapsible sections for parameters and request / response body schemas. Types and required render as badges; nested object / array properties expand and collapse in place. Emits nile-toggle. |
| <nile-ai-test-results> | A test-suite run report — pass/fail/skip counts with a proportional progress bar, plus collapsible suites whose failed tests reveal an expandable error message and stack trace. Summary counts are computed from the suites when omitted. Emits nile-toggle, nile-error-toggle. |
Installation
npm i @aquera/nile-ai-elementsUsage
<script type="module">
import '@aquera/nile-ai-elements/nile-ai-chat-bubble';
import '@aquera/nile-ai-elements/nile-ai-token-stream';
import '@aquera/nile-ai-elements/nile-wibbling-spinner';
</script>// Chat bubble — configured via a single data object
const bubble = document.createElement('nile-ai-chat-bubble');
bubble.data = {
role: 'ai',
agent: 'Synthetica',
thinking: 'reasoning',
loading: true,
message: 'Q3 churn is bleeding from your SMB cohort.',
};
// Token stream — typewriter reveal, also drivable from a backend stream
const stream = document.createElement('nile-ai-token-stream');
stream.text = 'Q3 churn is bleeding from your SMB cohort…';
stream.loop = true;
// stream.streamFrom((await fetch('/api/chat')).body); // live API streaming
// Wibbling spinner — rotating glyph + re-rolling verb + live info
const spinner = document.createElement('nile-wibbling-spinner');
spinner.verbInterval = 1500;Wiring up a chat
<script type="module">
import '@aquera/nile-ai-elements/nile-ai-chat';
import '@aquera/nile-ai-elements/nile-ai-prompt-input';
</script>
<nile-ai-chat id="chat" style="height: 480px;">
<nile-ai-prompt-input slot="footer" placeholder="Ask anything…"></nile-ai-prompt-input>
<div slot="empty">Start the conversation 👋</div>
</nile-ai-chat>const chat = document.getElementById('chat');
const composer = chat.querySelector('nile-ai-prompt-input');
composer.addEventListener('nile-submit', e => {
// append the user's message
const userBubble = document.createElement('nile-ai-chat-bubble');
userBubble.data = { role: 'user', message: e.detail.value };
chat.insertBefore(userBubble, null);
// …then stream the AI reply into a nile-ai-chat-bubble / nile-ai-token-stream
});Rich composer (<nile-ai-prompt>)
A fuller composer with a toolbar: an "add context" button, a model dropdown, a mic, and a send button. The mic uses the browser's Web Speech API to dictate straight into the field, showing a live mic waveform while it listens.
<script type="module">
import '@aquera/nile-ai-elements/nile-ai-prompt';
</script>
<nile-ai-prompt
id="composer"
placeholder="Paste a tweet, get a landing page…"
default-model="Claude Sonnet 4.6"
></nile-ai-prompt>const composer = document.getElementById('composer');
composer.models = ['Claude Sonnet 4.6', 'Claude Opus 4.8', 'Claude Haiku 4.5'];
composer.addEventListener('nile-submit', e => {
console.log('send', e.detail.value, 'with model', e.detail.model);
});
composer.addEventListener('nile-model-change', e => console.log('model →', e.detail.model));
// Attachment menu: set `attach-menu` so the + opens a menu instead of emitting
// `nile-add-context`. Defaults to a single "Add photos or files" option.
composer.attachMenu = true;
// Pass your own items to customize the menu (id is reported as `source`;
// `picksFiles` opens the native file picker):
composer.attachItems = [
{ id: 'files', label: 'Add photos or files', icon: 'ng-image', picksFiles: true },
{ id: 'screenshot', label: 'Take screenshot', icon: 'ng-monitor' },
];
composer.addEventListener('nile-attach', e => {
if (e.detail.source === 'files') console.log('files:', e.detail.files);
else console.log('custom action:', e.detail.source);
});
// Speech-to-text: spoken words are appended to the field as you talk.
composer.addEventListener('nile-voice-result', e => console.log(e.detail.transcript, e.detail.isFinal));
composer.addEventListener('nile-voice-end', e => console.log('dictation done:', e.detail.value));
// Optional toolbar extra (e.g. a keyboard hint), rendered before the mic + send:
// <span slot="toolbar-extras">⌘↵ to send</span>Key options: value / defaultValue, placeholder, rows, models /
model / defaultModel, submitOnCmdEnter (default true), speechLang,
attach-menu / attachItems / accept, and
hide-add-context / hide-model / hide-voice / hide-send. Everything is
also settable at once via the data object.
Prompt suggestions (<nile-ai-prompts>)
A predefined list of clickable starter prompts — handy for an empty chat state.
<script type="module">
import '@aquera/nile-ai-elements/nile-ai-prompts';
</script>
<nile-ai-prompts id="suggestions" wrap fade-in></nile-ai-prompts>const suggestions = document.getElementById('suggestions');
suggestions.title = '✨ How can I help you today?';
suggestions.items = [
{ key: 'ignite', icon: 'ng-sparkles', label: 'Ignite an idea', description: 'Brainstorm names and angles' },
{ key: 'write', icon: 'ng-pen-line', label: 'Draft copy', description: 'Turn a tweet into a landing page' },
// nested children render indented beneath their parent
{ key: 'analytics', icon: 'ng-rocket', label: 'Analytics', children: [
{ key: 'churn', label: 'Summarize Q3 churn by cohort' },
] },
];
suggestions.addEventListener('nile-item-click', e => {
// seed the composer with the chosen prompt
composer.value = e.detail.data.label;
composer.focus();
});icon accepts a nile-glyph name (e.g. ng-sparkles) or any other string
(e.g. an emoji). Layout is controlled with vertical and wrap; fade-in /
fade-in-left add a staggered entrance.
Suggestion pills (<nile-ai-suggestion>)
A horizontal row of tappable suggestions — the follow-up chips that sit under a
chat answer. The row scrolls when it overflows; add wrap to flow onto
multiple lines instead.
<script type="module">
import '@aquera/nile-ai-elements/nile-ai-suggestion';
</script>
<nile-ai-suggestion id="followups"></nile-ai-suggestion>const followups = document.getElementById('followups');
// Plain strings — the simplest form.
followups.suggestions = [
'Summarize Q3 churn by cohort',
'Which segment is bleeding the most?',
'Draft a recovery plan',
];
// …or richer items with an icon, a distinct emitted value, or a disabled state.
followups.suggestions = [
{ label: 'Ignite an idea', icon: 'ng-sparkles' },
{ label: 'Explain code', icon: 'ng-code', value: 'explain:code' },
{ label: 'Generate an image', icon: 'ng-image', disabled: true },
];
followups.addEventListener('nile-suggestion-click', e => {
// e.detail.suggestion is the item's `value` (or its label), e.detail.item the full item
sendMessage({ text: e.detail.suggestion });
});Agent transparency
// Tool call — name, status, args + (collapsible) result
const tool = document.createElement('nile-ai-tool-call');
tool.data = { name: 'search_web', status: 'running', args: { query: 'Q3 churn' } };
// Reasoning — collapsible chain-of-thought, streaming-aware
const reasoning = document.createElement('nile-ai-reasoning');
reasoning.data = { loading: true, open: true };
// Steps — a vertical agent timeline
const steps = document.createElement('nile-ai-steps');
steps.data = {
steps: [{ label: 'Plan' }, { label: 'Search the web' }, { label: 'Synthesize answer' }],
activeIndex: 1,
// Only the trailing 3 steps stay mounted; older ones slide out as new
// ones are appended (set 0 to disable windowing and show every step).
maxVisible: 3,
};Queue (<nile-ai-queue>)
A queue of messages / todos grouped into collapsible sections. Each item shows a status indicator, content + optional description, image / file attachments, and action buttons revealed on hover.
<script type="module">
import '@aquera/nile-ai-elements/nile-ai-queue';
</script>
<nile-ai-queue id="queue"></nile-ai-queue>const queue = document.getElementById('queue');
queue.data = {
sections: [
{
id: 'queued',
label: 'Queued',
icon: 'ng-list',
// count defaults to items.length; defaultOpen defaults to true
items: [
{
id: 'q1',
content: 'Summarize Q3 churn by cohort',
description: 'Waiting to run',
attachments: [
{ type: 'image', url: '/cohort.png', filename: 'cohort.png' },
{ filename: 'report.pdf', mediaType: 'application/pdf' },
],
actions: [
{ id: 'run', icon: 'ng-play', label: 'Run now' },
{ id: 'remove', icon: 'ng-x', label: 'Remove' },
],
},
],
},
{
id: 'completed',
label: 'Completed',
icon: 'ng-circle-check',
defaultOpen: false,
items: [{ id: 'c1', content: 'Pull subscription events', completed: true }],
},
],
};
queue.addEventListener('nile-toggle', e => console.log(e.detail.id, e.detail.open));
queue.addEventListener('nile-action', e =>
console.log('action', e.detail.actionId, 'on', e.detail.itemId)
);
queue.addEventListener('nile-item-click', e => console.log('item', e.detail.itemId));Sources (<nile-ai-sources>)
A collapsible disclosure listing the grounding sources a model used. The trigger reads "Used N sources"; each source is a link (title falling back to the hostname) that opens in a new tab.
<script type="module">
import '@aquera/nile-ai-elements/nile-ai-sources';
</script>
<nile-ai-sources id="sources"></nile-ai-sources>const sources = document.getElementById('sources');
sources.data = {
open: false, // collapsed by default; omit `label` for the "Used N sources" default
sources: [
{
href: 'https://en.wikipedia.org/wiki/Revenue_retention',
title: 'Net revenue retention — Wikipedia',
description: 'Definition and benchmarks',
},
// title falls back to the hostname when omitted
{ href: 'https://stripe.com/docs/billing' },
],
};
sources.addEventListener('nile-toggle', e => console.log('open →', e.detail.open));
sources.addEventListener('nile-source-click', e =>
// e.detail: { index, source, url }
console.log('opened source', e.detail.index, e.detail.url)
);Schema display (<nile-ai-schema-display>)
Documents a single REST API endpoint: a color-coded method badge (GET / POST /
PUT / PATCH / DELETE), the path with highlighted {path} parameters, an optional
description, and collapsible Parameters, Request Body and Response Body
sections. Body properties nest recursively — object types expand their
properties, array types descend into their items.
<script type="module">
import '@aquera/nile-ai-elements/nile-ai-schema-display';
</script>
<nile-ai-schema-display id="schema"></nile-ai-schema-display>const schema = document.getElementById('schema');
schema.data = {
method: 'GET',
path: '/v1/users/{id}/orders',
description: 'List the orders belonging to a single user.',
parameters: [
{ name: 'id', type: 'string', in: 'path', required: true },
{ name: 'limit', type: 'integer', in: 'query' },
],
responseBody: [
{
name: 'orders',
type: 'array',
required: true,
// arrays descend into `items`; objects expand `properties`
items: {
name: 'order',
type: 'object',
properties: [
{ name: 'id', type: 'string', required: true },
{ name: 'total', type: 'number', required: true },
],
},
},
{ name: 'nextCursor', type: 'string' },
],
};
schema.addEventListener('nile-toggle', e =>
// e.detail: { section: 'parameters' | 'request' | 'response', open }
console.log(e.detail.section, '→', e.detail.open)
);Test results (<nile-ai-test-results>)
Reports a test-suite run: a header with passed / failed / skipped counts, a total
and an optional duration, a proportional progress bar, and collapsible suites.
Each test row shows its status icon, name and duration; a failed test with an
error reveals an expandable message and stack trace. The summary is computed
from the suites when not supplied, and a suite's status is derived from its tests.
<script type="module">
import '@aquera/nile-ai-elements/nile-ai-test-results';
</script>
<nile-ai-test-results id="results"></nile-ai-test-results>const results = document.getElementById('results');
results.data = {
// summary is optional — omit it and the counts are computed from `suites`
summary: { passed: 5, failed: 1, skipped: 1, total: 7, duration: 1840 },
suites: [
{
id: 'billing',
name: 'billing.spec.ts',
defaultOpen: true,
tests: [
{ name: 'charges the card on renewal', status: 'passed', duration: 120 },
{
name: 'prorates a mid-cycle upgrade',
status: 'failed',
duration: 88,
error: {
message: 'Expected 41.50 but received 40.00',
stack: 'AssertionError: ...\n at proratePlan (billing.ts:212:14)',
},
},
],
},
],
};
results.addEventListener('nile-toggle', e =>
// e.detail: { id, open }
console.log('suite', e.detail.id, '→', e.detail.open)
);
results.addEventListener('nile-error-toggle', e =>
// e.detail: { suiteId, testIndex, open }
console.log('error', e.detail.suiteId, '→', e.detail.open)
);Confirmation (<nile-ai-confirmation>)
Gates a tool / function call behind user approval. While the request is pending
(state: 'approval-requested') it shows the prompt with Approve / Reject
buttons; once the response resolves (approval-responded, output-denied or
output-available) it renders an accepted or rejected confirmation based on
approved. Use the title / default / accepted / rejected / actions slots
to override any part.
<script type="module">
import '@aquera/nile-ai-elements/nile-ai-confirmation';
</script>
<nile-ai-confirmation id="confirm"></nile-ai-confirmation>const confirm = document.getElementById('confirm');
confirm.data = {
approvalId: 'call_123',
state: 'approval-requested',
heading: 'Delete file?',
request: 'This tool wants to delete /tmp/example.txt. Do you approve?',
acceptedText: 'You approved this tool execution',
rejectedText: 'You rejected this tool execution',
};
confirm.addEventListener('nile-respond', e => {
// e.detail: { id, approved }
console.log(e.detail.id, '→', e.detail.approved);
// reflect the decision back into the card
confirm.data = { ...confirm.data, state: 'output-available', approved: e.detail.approved };
});The components consume the Nile / NxtGen design tokens (
--ng-*). Make sure the NxtGen stylesheet from@aquera/nileis loaded on the page so colors, spacing and typography resolve correctly.<nile-ai-chat-bubble>also depends on@aquera/nile-glyphfor its icons.
Linting and formatting
To scan the project for linting and formatting errors, run
npm run lintTo automatically fix linting and formatting errors, run
npm run formatTesting with Web Test Runner
To execute a single test run:
npm run testTo run the tests in watch mode, run
npm run test:watchTooling configs
For most of the tools, the configuration is in the package.json to reduce the amount of files in your project.
If you customize the configuration a lot, you can consider moving them to individual files.
Local Demo with web-dev-server
npm startTo run a local development server that serves the basic demo located in demo/index.html.
Release Notes
In this section, you can find the updates for each release of nile-ai-elements. It's a good practice to maintain detailed release notes to help users and developers understand what changes have been made from one version to another and how these changes might affect their projects.
Version 0.0.5 (July 06, 2026)
- Nile AI Steps: Added a
maxVisibleproperty (UIF-1290)
Version 0.0.4 (July 01, 2026)
- Nile AI Confirmation: Added new component — a tool-approval card that shows an Approve / Reject prompt while pending and an accepted / rejected confirmation once resolved, driven by
state+approved. Slots fortitle/ request /accepted/rejected/actions. Emitsnile-respond({ id, approved }), plusnile-approve/nile-reject. (UIF-1284) - Nile AI Schema Display: Added new component — visualizes a REST API endpoint with a color-coded method badge, highlighted
{path}params, and collapsible Parameters / Request Body / Response Body sections. Types andrequiredrender as badges, and nestedobject/arrayproperties expand and collapse in place. Emitsnile-toggle. - Nile AI Test Results: Added new component — a test-suite run report with passed / failed / skipped counts, a proportional progress bar, and collapsible suites whose failed tests reveal an expandable message and stack trace. Emits
nile-toggle,nile-error-toggle.
Version 0.0.3 (June 30, 2026)
- Nile AI Queue: Added new component — a queue of messages / todos grouped into collapsible sections (
Queued/Completedetc.), each item with a status indicator, content + description, image / file attachments, and hover-revealed action buttons. Data-driven viasections. Emitsnile-toggle,nile-action,nile-item-click. (UIF-1282) - Nile AI Sources: Added new component — a collapsible "Used N sources" disclosure listing the grounding sources a model used; each is a link with a leading icon, a title (falling back to the hostname) and an optional description, opening in a new tab. Emits
nile-toggle,nile-source-click. - Nile AI Suggestion: Added new component — a horizontal row of clickable suggestion pills (the follow-up chips under an answer); scrolls on overflow or wraps with
wrap; accepts plain strings or{ label, value, icon, disabled }items. Emitsnile-suggestion-clickwith{ suggestion, item }. - Nile AI Prompt: The + button can now open a customizable attachment menu instead of emitting
nile-add-context. Setattach-menufor the default "Add photos or files" option, or passattachItems({ id, label, icon?, picksFiles? }) to define your own;acceptfilters the file picker. Emitsnile-attachwith{ source, files? }.
Version 0.0.2 (June 19, 2026)
- Nile AI Chat: Added new component — scrollable conversation thread with autoscroll, "scroll to latest", and
header/footer/emptyslots; optionaldata.messagesrendering. Emitsnile-scroll-state. (UIF-1279) - Nile AI Prompt Input: Added new composer component — auto-growing textarea, send / stop button, Enter-to-send (Shift+Enter newline),
prefix/suffix/footerslots. Emitsnile-submit,nile-input,nile-stop. - Nile AI Prompt: Added new rich composer — auto-growing textarea with a toolbar (add-context, model dropdown, mic, send),
data-object config, controlled/uncontrolledvalue&model, and atoolbar-extrasslot. Speech-to-text dictation via the Web Speech API with a live mic waveform; submit on Cmd/Ctrl+Enter. Emitsnile-submit,nile-change,nile-model-change,nile-add-context,nile-voice/nile-voice-start/nile-voice-result/nile-voice-end/nile-voice-error, andnile-stop. - Nile AI Prompts: Added new component — a predefined set of clickable prompt suggestions (icon / label / description) with nested children, a
title,vertical/wraplayouts andfade-in/fade-in-leftentrances. Modeled on Ant Design X's Prompts. Emitsnile-item-click. - Nile AI Message Actions: Added new component — per-message toolbar (copy / regenerate / like / dislike) with clipboard copy. Emits
nile-action. - Nile AI Status: Added new component — compact status pill (
pending/active/running/done/error). - Nile AI Reasoning: Added new component — collapsible, streaming-aware chain-of-thought panel. Emits
nile-toggle. - Nile AI Tool Call: Added new component — agent tool / function invocation card (name, status, args, collapsible result). Emits
nile-toggle. - Nile AI Steps: Added new component — vertical agent timeline with per-step status markers.
Version 0.0.1 (June 17, 2026)
- Nile AI Chat Bubble: Added new component —
user/airoles, agent header, reasoning pill with loader, and a singledata-object API. (UIF-1269) - Nile AI Token Stream: Added new component — token-by-token text reveal with jitter, looping, blinking caret, and live API streaming (
append,finish,streamFrom).(UIF-1269) - Nile Wibbling Spinner: Added new component — rotating glyph, re-rolling verb pool, and stateful parenthetical info.(UIF-1269)
- Initial release of the
@aquera/nile-ai-elementspackage (build tooling, dev server, and tests mirroring@aquera/nile-elements).(UIF-1269)
