Q4 Planning Follow-up
| To | sarah.chen@company.com |
Hi Sarah, Thanks for joining the planning meeting today. I've attached the updated timeline. Best, Alex
| To | sarah.chen@company.com |
Hi Sarah, Thanks for joining the planning meeting today. I've attached the updated timeline. Best, Alex
import { MessageDraft } from "@/components/tool-ui/message-draft";export function Example() { return ( <MessageDraft id="message-draft-example" channel="email" subject="Q4 Planning Follow-up" to={["sarah.chen@company.com"]} body={`Hi Sarah,Thanks for joining the planning meeting today. I've attached the updated timeline.Best,Alex`} onSend={() => console.log("Sent")} onCancel={() => console.log("Cancelled")} /> );}Review messages before the AI sends them on your behalf
Cancel within a configurable window after clicking Send
Email and Slack with channel-specific metadata display
Compact confirmation after send or cancel
The component supports multiple channel types, each with its own metadata fields.
Shows subject line, To/CC/BCC recipients, and message body.
| To | finance@company.com |
| Cc | manager@company.com |
Hi team, I've compiled the department requests. Key changes: - Engineering: +15% for infrastructure - Marketing: Flat (reallocating to digital) Please review by Friday. Thanks, Dana
<MessageDraft id="email-example" channel="email" subject="Re: Q4 Budget Review" to={["finance@company.com"]} cc={["manager@company.com"]} body="..." onSend={() => sendEmail()} onCancel={() => console.log("Cancelled")}/>Shows channel or DM target with the Slack icon.
Shipped v2.4.1 to production: - Fixed auth token refresh bug - Improved search latency by 40% Monitoring dashboards look good.
Hey Alex, just wanted to check in on the API integration. Are we still on track for the Thursday demo?
After clicking Send, there's a grace period where the user can undo:
The grace period is configurable via undoGracePeriod (in milliseconds).
When outcome is set, the component renders a compact receipt showing the result. This is useful for displaying the outcome in conversation history.
| To | hiring@company.com |
Thank you for the interview...
Copy components/tool-ui/message-draft and the shared directory into your project. The shared folder contains utilities used by all Tool UI components. The tool-ui directory should sit alongside your shadcn ui directory.
This component requires the following shadcn/ui components:
pnpm dlx shadcn@latest add button separator"use client";import { makeAssistantTool } from "@assistant-ui/react";import { MessageDraft, MessageDraftErrorBoundary, parseSerializableMessageDraft, SerializableMessageDraftSchema, type SerializableMessageDraft, type MessageDraftOutcome,} from "@/components/tool-ui/message-draft";export const MessageDraftTool = makeAssistantTool< SerializableMessageDraft, MessageDraftOutcome>({ toolName: "draftMessage", description: "Draft a message for the user to review before sending.", parameters: SerializableMessageDraftSchema, render: ({ args, result, addResult, toolCallId }) => { // Wait for channel to determine which fields are required if (!(args as any)?.channel || !(args as any)?.body) return null; const draft = parseSerializableMessageDraft({ ...args, id: (args as any)?.id ?? `message-draft-${toolCallId}`, }); return ( <MessageDraftErrorBoundary> {result !== undefined ? ( <MessageDraft {...draft} outcome={result} /> ) : ( <MessageDraft {...draft} onSend={async () => { // Perform actual send logic here await sendMessage(draft); addResult("sent"); }} onCancel={() => addResult("cancelled")} /> )} </MessageDraftErrorBoundary> ); },});Mount <MessageDraftTool /> under <AssistantRuntimeProvider> to register the tool and its UI.
Prop
Type
Prop
Type
Prop
Type
article with aria-labelledby for the draft contentTab to move between buttonsEnter or Space to activate focused buttonEscape triggers cancel while in review statearia-live="polite"role="status" for screen reader announcements