Message actions
The row of buttons under a message — copy, retry, edit, feedback, details — on when your app can answer them, in the order you choose.
<!-- In your app: import { aparteGlobalConfig } from '@aparte/core'. -->
<aparte-chat-bubble message-id="u1" data-role="user" name="You" content="Write a one-line release note."></aparte-chat-bubble>
<aparte-chat-bubble message-id="a1" data-role="assistant" name="Assistant" content="0.19.2 fixes the sidebar drawer and the menu check mark."></aparte-chat-bubble>
<script>
// Copy works on its own. Retry and edit need something that re-sends and rewrites
// (AparteClient does both), and feedback needs a listener: declare what your app handles.
const { aparteGlobalConfig } = window.aparte;
aparteGlobalConfig.setBubbleActions({ retry: true, edit: true, feedback: true });
document.addEventListener('aparte-feedback', (e) => console.log('feedback', e.detail));
</script>Every message can carry a row of actions. Copy is on by default, because the library can do it
alone. The others only ask: retry and edit need something that re-sends and rewrites the
conversation, feedback and details need a listener. So they stay off until your app says it
handles them, with aparteGlobalConfig.setBubbleActions(), and a button never sits there
answering to nobody.
AparteClient handles retry and edit for you, so with the client running,
setBubbleActions({ retry: true, edit: true }) is all it takes.
Variants
Section titled “Variants”In an order of your own
Section titled “In an order of your own”<aparte-chat-bubble message-id="u1" data-role="user" name="You" content="Write a one-line release note."></aparte-chat-bubble>
<aparte-chat-bubble message-id="a1" data-role="assistant" name="Assistant" content="0.19.2 fixes the sidebar drawer and the menu check mark."></aparte-chat-bubble>
<script>
// A list per role replaces the flags for that role: these buttons, in this order.
window.aparte.aparteGlobalConfig.setBubbleActions({
user: ['edit', 'copy'],
assistant: ['thumbUp', 'thumbDown', 'copy', 'retry'],
});
</script>A list for a role replaces the flags for that role: those buttons, in that order. Naming a button in the list is the opt-in.
Token usage behind a details button
Section titled “Token usage behind a details button”<aparte-chat-bubble message-id="a1" data-role="assistant" name="Assistant" content="0.19.2 fixes the sidebar drawer and the menu check mark."></aparte-chat-bubble>
<script>
const { aparteGlobalConfig } = window.aparte;
// The info button appears only on a message that carries usage, and only asks:
// the popover with the numbers is your app's.
aparteGlobalConfig.setBubbleActions({ info: true });
document.querySelector('aparte-chat-bubble').setUsage({ inputTokens: 412, outputTokens: 38, durationMs: 1260 });
document.addEventListener('aparte-message-info', (e) => console.log('show the stats for', e.detail));
</script>The details button appears only on a message that carries usage, and it only emits
aparte-message-info: the popover with the numbers is yours to draw.
import { aparteGlobalConfig } from '@aparte/core';
import type { AparteFeedbackEventDetail } from '@aparte/core';
aparteGlobalConfig.setBubbleActions({ retry: true, edit: true, feedback: true });
document.addEventListener('aparte-feedback', (e) => {
const { messageId, value } = (e as CustomEvent<AparteFeedbackEventDetail>).detail;
void fetch('/api/feedback', { method: 'POST', body: JSON.stringify({ messageId, value }) });
});| Action | Default | Needs |
|---|---|---|
copy | on | nothing |
retry | off | a host that re-sends (AparteClient) |
edit | off | a host that keeps the new text (AparteClient) |
feedback | off | a listener for aparte-feedback |
info | off | a listener for aparte-message-info, and usage on the message |
Accessibility
Section titled “Accessibility”- Each action is a button named from the locale (
copy,retry,edit,feedbackPositive,messageInfo…), so a row of icons still reads as words. - The row is hidden while a reply streams, so nobody copies half an answer.