@athenaintel/react 0.60.0 → 0.60.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -2
- package/dist/agent-runtime/src/client-tool-bridge.cjs +20 -2
- package/dist/agent-runtime/src/client-tool-bridge.cjs.map +1 -1
- package/dist/agent-runtime/src/client-tool-bridge.d.ts +9 -4
- package/dist/agent-runtime/src/client-tool-bridge.js +20 -2
- package/dist/agent-runtime/src/client-tool-bridge.js.map +1 -1
- package/dist/agent-runtime/src/client-tools.cjs.map +1 -1
- package/dist/agent-runtime/src/client-tools.d.ts +9 -0
- package/dist/agent-runtime/src/client-tools.js.map +1 -1
- package/dist/chat/AthenaChat.cjs +2 -0
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.js +2 -0
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/StatewireClientToolBridge.cjs +69 -1
- package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
- package/dist/chat/StatewireClientToolBridge.d.ts +14 -1
- package/dist/chat/StatewireClientToolBridge.js +70 -2
- package/dist/chat/StatewireClientToolBridge.js.map +1 -1
- package/dist/chat/StatewireClientToolConsentCard.cjs +65 -0
- package/dist/chat/StatewireClientToolConsentCard.cjs.map +1 -0
- package/dist/chat/StatewireClientToolConsentCard.d.ts +24 -0
- package/dist/chat/StatewireClientToolConsentCard.js +65 -0
- package/dist/chat/StatewireClientToolConsentCard.js.map +1 -0
- package/dist/chat/client-tool-write-consent.cjs +111 -0
- package/dist/chat/client-tool-write-consent.cjs.map +1 -0
- package/dist/chat/client-tool-write-consent.d.ts +71 -0
- package/dist/chat/client-tool-write-consent.js +111 -0
- package/dist/chat/client-tool-write-consent.js.map +1 -0
- package/dist/chat/statewire-client-tools.cjs +30 -5
- package/dist/chat/statewire-client-tools.cjs.map +1 -1
- package/dist/chat/statewire-client-tools.d.ts +34 -2
- package/dist/chat/statewire-client-tools.js +30 -5
- package/dist/chat/statewire-client-tools.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs +13 -0
- package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.d.ts +12 -0
- package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js +13 -0
- package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +2 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.js +3 -2
- package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
- package/dist/chat-ui/mentions/use-asset-icon-app-url.cjs +2 -1
- package/dist/chat-ui/mentions/use-asset-icon-app-url.cjs.map +1 -1
- package/dist/chat-ui/mentions/use-asset-icon-app-url.d.ts +2 -1
- package/dist/chat-ui/mentions/use-asset-icon-app-url.js +2 -1
- package/dist/chat-ui/mentions/use-asset-icon-app-url.js.map +1 -1
- package/dist/chat-ui/statewire.cjs +4 -0
- package/dist/chat-ui/statewire.cjs.map +1 -1
- package/dist/chat-ui/statewire.d.ts +2 -0
- package/dist/chat-ui/statewire.js +4 -0
- package/dist/chat-ui/statewire.js.map +1 -1
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/provider/AthenaProvider.cjs +22 -3
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.d.ts +8 -1
- package/dist/provider/AthenaProvider.js +23 -4
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AthenaChat.js","sources":["../../src/chat/AthenaChat.tsx"],"sourcesContent":["import {\n CHAT_EDIT_UNREACHABLE_LABEL,\n type ChatOutbox,\n type ChatOutboxAttachment,\n isGithubWakeMessage,\n isSubscriptionWakeMessage,\n readRunLive,\n readRuntimeMessageFromSourceMessages,\n readSoleRuntimeMessageKind,\n TASK_TOOL_NAME,\n useChatOutboxReachable,\n useDeepAgentChatOutboxContext,\n useDeepAgentConnection,\n useTurnToolCallsAwaitingApproval,\n autoComposerSendOptions,\n} from '@athenaintel/agent-runtime';\nimport { TiptapText } from './tiptap-text';\nimport { AthenaChatErrorBoundary } from './AthenaChatErrorBoundary';\nimport { StatewireApprovalCard, type StatewireDecisionConfirmer } from './StatewireApprovalCard';\nimport { statewireTypedInterrupts } from './typed-interrupts/StatewireTypedInterruptCard';\nimport { AthenaPlanStrip } from './AthenaPlanStrip';\nimport { StatewireQueuedMessages } from './StatewireQueuedMessages';\nimport { StatewireConnectionBanner, StatewireErrorBanner } from './statewire-banners';\nimport { AthenaChatModeMenu } from '../catalog/chat-pickers';\nimport { NEEDS_CONNECTION } from '@athenaintel/agent-runtime/offline-status';\nimport { StatewireRunRefusalNotice } from './StatewireRunRefusalNotice';\nimport { WaitingOnYouBanner } from './WaitingOnYouBanner';\nimport type { ThreadDriverSurface } from '@athenaintel/agent-runtime/thread-driver';\nimport { DrivingOnChip } from './DrivingOnChip';\nimport { OfflineSnapshotBanner } from '../offline/offline-history';\nimport { WakeMarkerMessage } from '../chat-ui/messages/wake-marker';\nimport { RuntimeMessageCard } from '../chat-ui/messages/runtime-message';\nimport { ToolFallback, ToolFallbackAppearanceProvider } from '../tools/tool-fallback';\nimport { AppendDocumentToolUI } from '../tools/append-document-tool-ui';\nimport { ReadAssetToolUI } from '../tools/read-asset-tool-ui';\nimport { isSdkInlineTool } from '../tools/inline-tools';\nimport { SubagentTaskToolUI } from '../tools/subagent-task-tool-ui';\nimport { TOOL_UI_REGISTRY } from '../tools/tool-uis';\nimport { SuperGroupingFinalText } from './super-grouping/SuperGroupingCard';\nimport { SuperGroupingTranscript } from './super-grouping/SuperGroupingTranscript';\nimport {\n StatewireApprovalWaitProvider,\n useApprovalWaitInScope,\n} from './use-statewire-approval-request';\nimport {\n NestedPtcComponentsProvider,\n NestedPtcMessages,\n useNestedPtcComponents,\n} from '../tools/NestedPtcMessages';\nimport { TooltipIconButton } from './tooltip-icon-button';\nimport { Button } from '../ui/button';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../ui/collapsible';\nimport { ChatComposerDock } from '../chat-ui/thread/chat-composer-dock';\nimport { ChatThreadShell } from '../chat-ui/thread/chat-thread-shell';\nimport { HandoffCursorReveal } from '../chat-ui/thread/handoff-cursor';\nimport { StatewireHistoryEdge } from '../chat-ui/thread/statewire-history-edge';\nimport { DeepAgentLaneFollowScope } from '../subagents/lane-follow';\nimport { ThreadLoadingOverlay } from '../chat-ui/thread/thread-loading-overlay';\nimport { ComposerSendOrStop } from '../chat-ui/thread/composer-send-or-stop';\nimport { type ComposerAction, resolveComposerAction } from '../chat-ui/composer/composer-action';\nimport { type ComposerSend, prepareComposerSend } from '../chat-ui/composer/composer-message';\nimport type { ComposerSlashCommand } from '../chat-ui/composer/slash-commands';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport { useDictation } from '../dictation/use-dictation';\nimport { DictationStrip } from '../dictation/DictationStrip';\nimport {\n DictationCancelButton,\n DictationMicButton,\n DictationStopButton,\n} from '../dictation/dictation-controls';\nimport { composeDictationDraft, DICTATION_STATUSES } from '../dictation/dictation-state';\nimport type { DictationEngine } from '../dictation/dictation-engine';\nimport { useAthenaDictationEngine } from '../dictation/use-athena-dictation-engine';\nimport {\n TiptapComposer,\n type ComposerFileIntake,\n type TiptapComposerHandle,\n} from '../chat-ui/composer/tiptap-composer';\nimport {\n MentionAuthCtx,\n type MentionAuthContext,\n} from '../chat-ui/mentions/suggestions/data/api-client';\nimport { useAccountIdentity } from '../chat-ui/mentions/use-account-workspace-id';\nimport type { MentionRootCategory } from '../chat-ui/mentions/suggestions/data/use-mention-suggestions';\nimport type { MentionTool } from '../chat-ui/mentions/suggestions/data/types';\nimport {\n keepDeepAgentNamedAgentsForIdentity,\n readDeepAgentNamedAgents,\n} from '@athenaintel/agent-runtime/named-agents';\nimport { stageComposerNamedAgents } from '../chat-ui/composer/composer-named-agents';\nimport { useAthenaViewerIsAdmin } from '../catalog/runtime-catalog';\nimport {\n clearAttachedReferences,\n keepAttachedReferencesForIdentity,\n stageThreadAttachedReferencesForSend,\n usePendingAttachedReferences,\n} from '../composer/attached-references';\nimport { takeStagedMessageMetadata } from '../composer/staged-message-metadata';\nimport {\n ComposerAttachedReferences,\n MessageAttachedReferences,\n} from '../composer/ComposerAttachedReferences';\nimport { useAttachedReferencesComposerProps } from '../composer/useAttachedReferencesComposerProps';\nimport { ComposerNamedAgents } from '../composer/ComposerNamedAgents';\nimport { useAthenaChatAgentsMention } from './chat-agent-mentions';\nimport { AnswerLabel } from '../chat-ui/messages/answer-label';\nimport {\n MESSAGE_ARRIVAL_ANIMATION_CLASS,\n useMessageArrivalAnimation,\n} from '../chat-ui/messages/arrival-animation';\nimport { MessageImageGallery, MessageImagePart } from '../chat-ui/messages/message-images';\nimport {\n InboundChannelLine,\n InboundChannelSubject,\n useUserMessageCopy,\n withInboundMessageBody,\n} from '../chat-ui/messages/inbound-channel-message';\nimport {\n ACTION_BAR_REVEAL_CLASS,\n BranchPicker,\n UserMessageText,\n} from '../chat-ui/messages/message-components';\nimport { useMessageActionsReadOnly } from '../chat-ui/messages/message-actions-config';\nimport { useAthenaRunLive } from './use-athena-run-live';\nimport {\n AthenaChatWelcome,\n AthenaChatWelcomeSuggestions,\n DEFAULT_WELCOME_SUGGESTIONS,\n welcomeComposerDelayMs,\n welcomeEntrance,\n type WelcomeSuggestion,\n} from './athena-chat-welcome';\nimport {\n ATHENA_COMPOSER_COMPONENTS,\n AthenaComposerMentionButton,\n AthenaComposerSendButton,\n} from './athena-composer-controls';\nimport { ComposerKeyboardHint, useComposerKeyboardHint } from './composer-keyboard-hint';\nimport { FollowUpSuggestions } from './follow-up-suggestions';\nimport { usePrefersReducedMotion } from '../lib/use-prefers-reduced-motion';\nimport { useStatewireSessionLane } from '../runtime/statewire-session-lane';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n ActionBarMorePrimitive,\n ActionBarPrimitive,\n AuiIf,\n ErrorPrimitive,\n MessagePrimitive,\n ThreadPrimitive,\n useAui,\n useAuiState,\n} from '@assistant-ui/react';\nimport type {\n EmptyMessagePartComponent,\n PartState,\n ReasoningMessagePartProps,\n ReasoningMessagePartComponent,\n TextMessagePartProps,\n TextMessagePartComponent,\n ToolCallMessagePartComponent,\n ToolCallMessagePartProps,\n} from '@assistant-ui/react';\nimport {\n AlertCircleIcon,\n ArrowUpIcon,\n BrainIcon,\n CheckIcon,\n ChevronDownIcon,\n ChevronRightIcon,\n CopyIcon,\n DownloadIcon,\n ExternalLinkIcon,\n LayersIcon,\n MoreHorizontalIcon,\n PencilIcon,\n RefreshCwIcon,\n} from 'lucide-react';\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type FC,\n type ReactNode,\n} from 'react';\nimport {\n AthenaStatewireThreadIdContext,\n useAthenaStatewireThreadId,\n useAthenaThreadId,\n} from '../threads/thread-id-context';\nimport {\n AthenaThreadListAppendedSendContext,\n useAthenaStatewireThreadList,\n} from '../threads/statewire-thread-list';\nimport { MarkViewedThreadRead } from '../threads/mark-viewed-thread-read';\nimport { FileUploadButton } from '../composer/FileUploadButton';\nimport { ComposerQuotePreview } from '../composer/ComposerQuotePreview';\nimport { ComposerAttachmentPreview } from '../composer/ComposerAttachmentPreview';\nimport { ComposerDropZone } from '../composer/ComposerDropZone';\nimport { useQuote, QuoteProvider, useQuoteFromPostMessage } from '../composer/QuoteContext';\nimport { AttachmentProvider, useAttachments } from '../composer/AttachmentContext';\nimport { buildComposedSend, holdComposedSend } from '../composer/build-composed-message';\nimport { useAttachFiles } from '../composer/useAttachFiles';\nimport { type AthenaChatComposerActions, AthenaChatComposerActionsContext } from './composer-actions';\nimport { useAthenaConfig } from '../provider/AthenaContext';\nimport { createAthenaSpacesUrl } from '../lib/athena-urls';\nimport { cn, isRecord } from '../lib/utils';\nimport { getToolkitDisplayInfo } from '../toolkits';\nimport {\n isRunActivityStalled,\n isToolCallInFlight,\n runActivityKey,\n runActivityLabel,\n runActivityVerb,\n runElapsedLabel,\n runProgressKey,\n} from './run-activity';\nimport {\n formatDayLabel,\n formatMessageDateTime,\n formatMessageTime,\n isSameCalendarDay,\n parseMessageTime,\n readMessageCreatedAt,\n} from './message-time';\nimport { ThreadScrollToBottom } from './thread-scroll-to-bottom';\nimport {\n type AthenaChatTurnChanges,\n AthenaTurnChangesContext,\n AthenaTurnChangesSlot,\n} from './turn-changes';\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport { useCatalogQueryClient } from '../catalog/runtime-catalog';\nimport { isStatewireChannelLive } from '../runtime/statewire-lifecycle';\nimport {\n type AthenaChatContinueByVoice,\n ChatVoiceButton,\n ChatVoiceContinueOffer,\n ChatVoiceStatus,\n useComposerChatVoice,\n type AthenaChatVoiceOptions,\n} from './chat-voice-controls';\n\nexport type { AthenaChatContinueByVoice, AthenaChatVoiceOptions } from './chat-voice-controls';\n\nconst DEFAULT_COMPOSER_PLACEHOLDER = 'Type @ to tag an asset';\n\nfunction QuotePostMessageBridge() {\n // Inside the chat's root: with several chats in a window, ⌘L quotes into the one it belongs to.\n const marker = useRef<HTMLSpanElement | null>(null);\n useQuoteFromPostMessage({ scope: marker });\n return <span ref={marker} hidden />;\n}\n\nexport type { WelcomeSuggestion } from './athena-chat-welcome';\n\nexport interface AthenaChatProps {\n /** CSS class name for the root element. */\n className?: string;\n /** Welcome heading text. Defaults to \"Hello there!\" */\n welcomeMessage?: string;\n /** Welcome subheading text. */\n welcomeSubtext?: string;\n /**\n * Maximum width of the reading column (messages, welcome, composer).\n * Defaults to \"46rem\" — about 760 px, a comfortable measure for 15 px text.\n */\n maxWidth?: string;\n /**\n * Scroll anchoring for new turns. \"bottom\" (default) keeps the viewport\n * pinned to the end while the assistant streams — classic chat follow.\n * \"top\" pins the just-sent user message to the top of the viewport and\n * intentionally does NOT follow the streaming response (assistant-ui\n * disables autoScroll in that mode), so readers scroll at their own pace.\n */\n turnAnchor?: \"top\" | \"bottom\";\n /**\n * Marks the transcript read-only: Edit and Regenerate hide while Copy stays\n * available. For threads whose server rejects dispatch (e.g. legacy\n * pre-cutover conversations) — the runtime's static capability flags cannot\n * express a per-thread fence, so the host that knows passes it here.\n */\n readOnly?: boolean;\n /**\n * What sits above the composer for the run's plan. Defaults to\n * `<AthenaPlanStrip />`: the plan's progress and current step, opening to\n * the whole `write_todos` list. Pass your own element to replace it, or\n * `null` for none (a host that shows the plan elsewhere).\n */\n plan?: ReactNode;\n /**\n * The Athena app this chat runs in. With it, the chat says when the person\n * is driving the conversation from another of their apps (\"Driving on your\n * phone\") above the composer. Omit it in an app that is not one of Athena's\n * own and nothing shows.\n */\n surface?: ThreadDriverSurface;\n /**\n * \"Confirm with your passkey\" before an approval that lets anything run\n * (identity 0b.9): handed to the chat's approval card, which sends the\n * token it resolves as `decisionCheck`. An app on another origin than the\n * Athena web app passes `useAthenaBrowserDecisionConfirmer()`, which runs\n * the check in a browser tab on the web app. Omit it and approvals are\n * sent without a check, as before (report-only).\n */\n confirmDecision?: StatewireDecisionConfirmer;\n /** Additional tool UIs to register by name. */\n toolUIs?: Record<string, ToolCallMessagePartComponent>;\n /** Tools / Toolkits offered by the composer's `@` menu beside the asset\n * library. Defaults to the toolkits enabled on the provider. */\n mentionTools?: MentionTool[];\n /**\n * What the composer's `@` menu offers beside Tools / Toolkits (which follow `mentionTools`).\n * Defaults to the asset library: Favorites, Assets, Projects and Folders. Add `team` for people\n * (the workspace's members and groups; an Athena admin's people, ranked, as in Olympus), `agents`\n * to name agents for a message, `browse_profiles` and `drives`. The menu shows them in Athena's\n * order whatever order they are given in.\n *\n * With `agents`, choosing one names it for the message: a chip on the composer's To line, never\n * text, and the send names it to Athena (`addressed_agents`, on the run and on the message), as\n * Olympus's composer does. The person's own assistant and the agents the chat's agent picker lists\n * are offered, to Athena admins only for now, as in Olympus; Athena checks every agent a message\n * names. A person mention is the link Olympus writes (`mention://person?id=…&email=…&name=…`).\n */\n mentionCategories?: readonly AthenaChatMentionCategory[];\n /** Suggestion cards shown on the welcome screen. Pass `[]` to hide.\n * For workflow launchers outside AthenaChat, use `useSendMessage()`.\n */\n welcomeSuggestions?: WelcomeSuggestion[];\n /** Optional component overrides for message containers and key message parts. */\n components?: AthenaChatComponents;\n /**\n * The collapsed view (previously called the conversational view): the\n * agent's sentences stay in the transcript in the order it wrote them, each\n * run of tool calls and reasoning between them folds into a collapsed step\n * row that names what it did (\"Ran `git log`\"), a header counts the turn\n * (\"Working for 1m 12s\", \"Worked for 2m 30s\"), and the answer renders below.\n * Defaults to `true`; pass `false` to list every tool card inline in the\n * order it was called.\n */\n groupToolCalls?: boolean;\n /**\n * Extra composer toolbar content and send hooks. `toolbarStart` renders\n * after the attach button, `toolbarEnd` renders before the mic and Send.\n * Slot components render inside the chat's thread scope, so `useAthenaRunLive`\n * and `useAppendToComposer` work in them.\n */\n composer?: AthenaChatComposerSlots;\n /**\n * Built-in microphone dictation in the composer: a mic left of Send that\n * swaps the editor for a live waveform while recording, then puts the words\n * into the draft (Stop) or sends them (Send). Recording is transcribed by\n * Athena (Deepgram) once the user stops; the words land after a short\n * \"Transcribing…\" pause. Defaults to `true`. Pass `false` to remove it, or\n * options to pick the language or a custom speech engine.\n */\n dictation?: boolean | AthenaChatDictationOptions;\n /**\n * Realtime chat voice through the shared controller and lazy LiveKit media.\n * Available by default where the workspace and deployment enable voice.\n * `false` removes it; options select a voice model or supply a media adapter.\n * The default browser adapter loads its LiveKit dependency only on start.\n */\n voice?: boolean | AthenaChatVoiceOptions;\n /**\n * A \"Continue by voice\" offer for the open conversation, after a handover\n * the person sent in voice mode landed in this app. The composer shows one\n * button above the editor while voice is enabled and idle; tapping it starts\n * a call whose model opens by saying where things stand. `onDone` runs when\n * the person answers it (the tap, Not now, or a typed or dictated send):\n * clear the offer then, and when the conversation changes. `null` or absent:\n * no offer. A `readOnly` chat never shows it.\n */\n continueByVoice?: AthenaChatContinueByVoice | null;\n /**\n * The turn changes card: a finished assistant turn that changed files ends with Codex's card,\n * \"Edited N files +A −D\", Undo and View changes, and the first three files with theirs (\"Show N\n * more files\" for the rest). The SDK draws it and places it; the host reads each turn's changes\n * (`read`, once per finished turn, by the runs that answered it) and does what Undo and View\n * changes mean (`onUndo`, `onView`; `reviewScope` says whether View changes opens the chat's\n * changes or the turn's). Off unless `enabled`: absent, `null` or off, nothing renders and\n * nothing is read.\n */\n turnChanges?: AthenaChatTurnChanges | null;\n /**\n * Suggested follow-up prompts: once a run the person watched finishes with a reply, up to three\n * prompts they might type next show as chips just above the composer. A chip puts its text in the\n * composer and sends nothing; the chips go away once the person types or sends, or a new run\n * starts. A run that was stopped, failed or waits on the person gets none, and neither does a\n * conversation opened at rest. Athena writes them from the turn's last message and reply\n * (`POST /api/chat/follow-up-suggestions`, with the chat's own credential, one request per\n * finished turn, charged to the conversation); a failed request shows nothing. Defaults to\n * `false`: off, nothing is requested.\n */\n followUpSuggestions?: boolean;\n}\n\n/** What a host's `composer.onBeforeSend` hears of the message about to go. */\nexport interface AthenaChatBeforeSend {\n /** `send` starts a turn; `queue` waits behind the run that is live. */\n action: Extract<ComposerAction, 'send' | 'queue'>;\n /** Its words as typed (empty for a message of attachments or a quote alone). */\n text: string;\n}\n\nexport interface AthenaChatComposerSlots {\n /** The empty composer's hint (default \"Type @ to tag an asset\"). */\n placeholder?: string;\n /**\n * The hint while a run is live, when a message steers or queues instead of\n * starting a turn (\"Guide the agent while it works…\"); defaults to\n * `placeholder`.\n */\n runningPlaceholder?: string;\n /**\n * A row at the top of the composer, above the editor and inside its border: where Spaces shows\n * its running status and Follow Agent Operations switch (Athena Desktop's Follow Athena). Rendered\n * as given, above any voice offer, quote or attachment preview; absent, nothing changes.\n */\n aboveEditor?: ReactNode;\n /**\n * Toolbar contents after the attach button. In a composer too narrow for every chip they wrap\n * onto another row, so the mic, voice and Send stay in reach.\n */\n toolbarStart?: ReactNode;\n /** Toolbar contents before the mic and the send/stop control. */\n toolbarEnd?: ReactNode;\n /**\n * The composer's own attach button (the paperclip). `false` leaves it out, for a host that offers\n * attaching from a control of its own in a slot (`useAthenaComposerActions().openFilePicker`);\n * pasting and dropping files still attach them. Default `true`.\n */\n attachButton?: boolean;\n /**\n * The composer's own `@` button. `false` leaves it out, for a host that opens the `@` menu from a\n * control of its own in a slot (`useAthenaComposerActions().openMentionMenu`); typing `@` still\n * opens it. Default `true`.\n */\n mentionButton?: boolean;\n /**\n * Host work awaited before a message goes, however it is sent: Enter, the send button, or a\n * dictated send, once each. It hears whether the message starts a turn or queues, and its words.\n * Not for a message the chat outbox holds while Athena can't be reached (it goes later). A\n * rejection keeps the message in the composer, unsent.\n */\n onBeforeSend?: (context: AthenaChatBeforeSend) => void | Promise<void>;\n /**\n * Why the composer's controls that need Athena are off, while the host knows Athena can't be\n * reached (from its own reachability: Olympus's model, the desktop app's main process). Attach\n * (the paperclip), the `@` button, dictation's mic and voice then show disabled with this as their\n * tooltip, instead of failing once used, and come back as soon as it is cleared. Typing `@` still\n * opens the mention menu, which fetches nothing from Athena: what it can list without Athena (the\n * host's tools, what it already loaded) shows, and what would load from Athena says it needs a\n * connection (`NEEDS_CONNECTION`) instead of spinning. Typing goes on, and Send follows the chat\n * outbox (a host that has one holds what is sent until Athena is back). A file pasted or dropped\n * meanwhile is refused as before, by the chat outbox's own reachability. `null` or absent: on.\n */\n needsConnectionReason?: string | null;\n /**\n * The composer's `/` commands: typing `/` opens a menu of them, and picking\n * one runs it (`TiptapComposer`'s `slashCommands`). Absent or empty: `/` is\n * plain text.\n */\n slashCommands?: readonly ComposerSlashCommand[];\n}\n\nexport interface AthenaChatDictationOptions {\n /**\n * Speech engine; defaults to record-then-transcribe through Athena\n * (`createRecordedDictationEngine`). Pass `createWebSpeechDictationEngine()`\n * for the browser's live Web Speech API instead.\n */\n engine?: DictationEngine;\n /** BCP-47 language tag; defaults to the document language. */\n lang?: string;\n}\n\nexport interface AthenaChatMessagePartComponents {\n Text?: TextMessagePartComponent;\n Reasoning?: ReasoningMessagePartComponent;\n Empty?: EmptyMessagePartComponent;\n}\n\nexport interface AthenaChatComponents {\n UserMessage?: FC;\n AssistantMessage?: FC;\n AssistantActionBar?: FC<AthenaAssistantActionBarProps>;\n /**\n * Rendered in a leading column on every assistant turn (a small avatar or\n * mark). Without it there is no leading column: the reply sits flush with\n * the thread column and is told apart from the right-aligned user bubbles by\n * alignment alone.\n */\n AssistantAvatar?: FC;\n messageParts?: AthenaChatMessagePartComponents;\n}\n\nexport interface AthenaUserMessageProps {\n /**\n * Renders the message's text. Defaults to `UserMessageText`, which shows a\n * composer send exactly as it was typed (its `metadata.composer_markdown`\n * draft) and any other text with raw HTML and underscore emphasis left as\n * typed. A component given here receives the text as sent.\n */\n TextComponent?: TextMessagePartComponent;\n}\n\nexport interface AthenaAssistantActionBarProps {\n className?: string;\n}\n\nexport interface AthenaAssistantMessageProps {\n toolUIs: Record<string, ToolCallMessagePartComponent>;\n /** Leading-column content for the turn; no leading column at all when unset. */\n AvatarComponent?: FC;\n TextComponent?: TextMessagePartComponent;\n ReasoningComponent?: ReasoningMessagePartComponent;\n EmptyComponent?: EmptyMessagePartComponent;\n ActionBarComponent?: FC<AthenaAssistantActionBarProps>;\n /** The collapsed view (see `AthenaChatProps.groupToolCalls`). Defaults to `true`. */\n groupToolCalls?: boolean;\n}\n\nexport interface AthenaReasoningPartProps extends ReasoningMessagePartProps {\n TextComponent?: TextMessagePartComponent;\n}\n\ninterface AthenaChatDefaultComponentsContextValue {\n toolUIs: Record<string, ToolCallMessagePartComponent>;\n TextComponent: TextMessagePartComponent;\n /** The user bubble's text: a host's `messageParts.Text`, else `UserMessageText`. */\n UserTextComponent: TextMessagePartComponent;\n ReasoningComponent?: ReasoningMessagePartComponent;\n EmptyComponent: EmptyMessagePartComponent;\n ActionBarComponent: FC<AthenaAssistantActionBarProps>;\n AvatarComponent?: FC;\n groupToolCalls: boolean;\n}\n\nconst AthenaChatDefaultComponentsContext =\n createContext<AthenaChatDefaultComponentsContextValue | null>(null);\n\nconst AthenaReasoningTextComponentContext = createContext<TextMessagePartComponent | null>(null);\n\nconst useAthenaChatDefaultComponents = (): AthenaChatDefaultComponentsContextValue => {\n const value = useContext(AthenaChatDefaultComponentsContext);\n\n if (!value) {\n throw new Error('Athena default chat components must be used within AthenaChat.');\n }\n\n return value;\n};\n\nconst AthenaDefaultAssistantMessage: FC = () => {\n const {\n toolUIs,\n TextComponent,\n ReasoningComponent,\n EmptyComponent,\n ActionBarComponent,\n AvatarComponent,\n groupToolCalls,\n } = useAthenaChatDefaultComponents();\n\n return (\n <AthenaAssistantMessage\n toolUIs={toolUIs}\n AvatarComponent={AvatarComponent}\n TextComponent={TextComponent}\n ReasoningComponent={ReasoningComponent}\n EmptyComponent={EmptyComponent}\n ActionBarComponent={ActionBarComponent}\n groupToolCalls={groupToolCalls}\n />\n );\n};\n\nconst AthenaDefaultUserMessage: FC = () => {\n const { UserTextComponent } = useAthenaChatDefaultComponents();\n\n return <AthenaUserMessage TextComponent={UserTextComponent} />;\n};\n\nconst getReasoningTokensFromMetadata = (metadata: unknown): number | undefined => {\n if (!isRecord(metadata)) {\n return undefined;\n }\n\n const customMetadata = metadata.custom;\n if (!isRecord(customMetadata)) {\n return undefined;\n }\n\n const athenaMetadata = customMetadata._athena;\n if (!isRecord(athenaMetadata)) {\n return undefined;\n }\n\n const reasoningTokens = athenaMetadata.reasoningTokens;\n return typeof reasoningTokens === 'number' && Number.isFinite(reasoningTokens)\n ? reasoningTokens\n : undefined;\n};\n\nconst formatReasoningTokens = (reasoningTokens: number) =>\n `${reasoningTokens.toLocaleString('en-US')} ${reasoningTokens === 1 ? 'token' : 'tokens'}`;\n\nconst withNestedPtcMessages = (\n ToolUI: ToolCallMessagePartComponent\n): ToolCallMessagePartComponent => {\n const ToolUIWithNestedPtcMessages: ToolCallMessagePartComponent = (props) => {\n const nestedComponents = useNestedPtcComponents(ToolFallback);\n\n return (\n <>\n <ToolUI {...props} />\n <NestedPtcMessages components={nestedComponents} />\n </>\n );\n };\n\n return ToolUIWithNestedPtcMessages;\n};\n\nexport const AthenaChat: FC<AthenaChatProps> = (props) => {\n const queryClient = useCatalogQueryClient();\n return <QueryClientProvider client={queryClient}><AthenaChatContent {...props} /></QueryClientProvider>;\n};\n\nconst AthenaChatContent: FC<AthenaChatProps> = ({\n className,\n welcomeMessage = \"Hello there!\",\n welcomeSubtext = \"What can I help you with?\",\n maxWidth = \"46rem\",\n turnAnchor = \"bottom\",\n readOnly = false,\n plan,\n surface,\n confirmDecision,\n toolUIs,\n mentionTools,\n mentionCategories = ATHENA_CHAT_MENTION_CATEGORIES,\n welcomeSuggestions = DEFAULT_WELCOME_SUGGESTIONS,\n components,\n groupToolCalls = true,\n composer: composerSlots,\n dictation = true,\n voice = true,\n continueByVoice = null,\n turnChanges = null,\n followUpSuggestions = false,\n}) => {\n const athenaConfig = useAthenaConfig();\n const authState = useContext(AthenaAuthContext);\n // The chat names agents when its host offers the Agents category.\n const namesAgents = mentionCategories.includes('agents');\n // The chat surface is per thread. `AthenaProvider` keeps the host's\n // children mounted across a thread switch and swaps only the client under\n // them, so what used to reset with the whole tree — the composer draft, the\n // viewport's scroll position, the approval card and banner state, a caught\n // render crash — is reset here instead, keyed on the attached thread (the\n // id the provider publishes together with that thread's client, so the\n // fresh surface never renders against the previous thread's runtime).\n const statewireThreadId = useContext(AthenaStatewireThreadIdContext);\n // A refusal whose way on is a new session (a send in the other mode of the\n // session's collab agent) offers one in thread-list mode.\n const startNewSession = useAthenaStatewireThreadList()?.newThread;\n // The mention menu's GraphQL credentials: the backend and credential the\n // provider resolved. `athenaConfig` keeps its identity across token\n // rotations (its `token` is a getter over a ref — see useAthenaConfigValue),\n // so this object is stable too. The mention store lists `accessToken` among\n // its memo dependencies, so it rebuilds (and refetches its lists) on the\n // composer's next render after a rotation; the getter is what hands the\n // rotated token to any fetch before that render. With neither token nor\n // API key the fetch rides the same-origin session cookie, as the SDK's\n // upload and thread REST calls do.\n const mentionCredentials = useMemo<MentionAuthContext>(\n () => ({\n backendUrl: athenaConfig.backendUrl,\n appUrl: athenaConfig.appUrl,\n apiKey: athenaConfig.apiKey,\n credentials: 'include',\n userId: authState?.user?.userId,\n get accessToken() {\n return athenaConfig.token ?? undefined;\n },\n getAccessToken: async () => (await athenaConfig.getToken?.()) ?? undefined,\n renewAccessToken: async () => (await athenaConfig.getToken?.({ force: true })) ?? undefined,\n }),\n [athenaConfig, authState?.user?.userId],\n );\n // One `/me` read: the workspace mentions search, and the viewer's agora id\n // the answer labels need (\"for you\"). It is keyed by the credential it is\n // read with (the provider's token getter among it), so an API-key switch or\n // a getter now signing in someone else reads it again.\n const account = useAccountIdentity(mentionCredentials, { tokenGetter: athenaConfig.getToken });\n const accountWorkspaceId = account.workspaceId;\n // Names this page made under another identity are not this person's to send: every chip,\n // staged send and send on its way goes once someone else is signed in.\n const accountUserId = account.userId;\n useEffect(() => {\n if (namesAgents && accountUserId) keepDeepAgentNamedAgentsForIdentity(accountUserId);\n }, [accountUserId, namesAgents]);\n // So are the references attached to the next message (`useAttachToChat`).\n useEffect(() => {\n if (accountUserId) keepAttachedReferencesForIdentity(accountUserId);\n }, [accountUserId]);\n const mentionAuth = useMemo<MentionAuthContext>(\n () => ({\n ...mentionCredentials,\n workspaceId: mentionCredentials.workspaceId ?? accountWorkspaceId,\n }),\n [mentionCredentials, accountWorkspaceId],\n );\n const providerMentionTools = useMemo<MentionTool[]>(() => {\n const uniqueToolkitIds = Array.from(new Set(athenaConfig.enabledToolkits));\n\n return uniqueToolkitIds.map((id) => {\n const toolkit = getToolkitDisplayInfo(id);\n\n return {\n id: toolkit.id,\n name: toolkit.name,\n description: toolkit.description,\n icon: toolkit.icon,\n type: 'toolkit',\n };\n });\n }, [athenaConfig.enabledToolkits]);\n const tools = mentionTools ?? providerMentionTools;\n const mergedToolUIs = useMemo(\n () => ({\n append_markdown_to_athena_document: AppendDocumentToolUI,\n read_full_asset: ReadAssetToolUI,\n read_asset: ReadAssetToolUI,\n ...TOOL_UI_REGISTRY,\n ...toolUIs,\n }),\n [toolUIs],\n );\n\n const textComponent = components?.messageParts?.Text ?? TiptapText;\n const userTextComponent = components?.messageParts?.Text ?? UserMessageText;\n const reasoningComponent = components?.messageParts?.Reasoning;\n const emptyComponent = components?.messageParts?.Empty ?? AthenaAssistantMessageEmpty;\n const actionBarComponent = components?.AssistantActionBar ?? AthenaAssistantActionBar;\n const avatarComponent = components?.AssistantAvatar;\n\n const defaultComponentsContextValue = useMemo<AthenaChatDefaultComponentsContextValue>(\n () => ({\n toolUIs: mergedToolUIs,\n TextComponent: textComponent,\n UserTextComponent: userTextComponent,\n ReasoningComponent: reasoningComponent,\n EmptyComponent: emptyComponent,\n ActionBarComponent: actionBarComponent,\n AvatarComponent: avatarComponent,\n groupToolCalls,\n }),\n [\n actionBarComponent,\n avatarComponent,\n emptyComponent,\n groupToolCalls,\n mergedToolUIs,\n reasoningComponent,\n textComponent,\n userTextComponent,\n ],\n );\n // One value while the host's settings and hooks stay the same, so no turn re-renders for a host\n // render that changed nothing of them.\n const turnChangesEnabled = turnChanges?.enabled === true;\n const turnChangesScope = turnChanges?.reviewScope;\n const turnChangesRead = turnChanges?.read;\n const turnChangesView = turnChanges?.onView;\n const turnChangesUndo = turnChanges?.onUndo;\n const turnChangesValue = useMemo<AthenaChatTurnChanges | null>(\n () =>\n turnChangesEnabled && turnChangesRead && turnChangesView && turnChangesUndo\n ? {\n enabled: true,\n ...(turnChangesScope !== undefined && { reviewScope: turnChangesScope }),\n read: turnChangesRead,\n onView: turnChangesView,\n onUndo: turnChangesUndo,\n }\n : null,\n [turnChangesEnabled, turnChangesScope, turnChangesRead, turnChangesView, turnChangesUndo],\n );\n const AssistantMessageComponent = components?.AssistantMessage ?? AthenaDefaultAssistantMessage;\n const UserMessageComponent = components?.UserMessage ?? AthenaDefaultUserMessage;\n const messageComponents = useMemo(\n () => ({\n UserMessage: UserMessageComponent,\n AssistantMessage: AssistantMessageComponent,\n }),\n [AssistantMessageComponent, UserMessageComponent],\n );\n\n return (\n <AthenaChatDefaultComponentsContext.Provider value={defaultComponentsContextValue}>\n <AthenaTurnChangesContext.Provider value={turnChangesValue}>\n {/* Contain render crashes to the chat pane (telemetry + retry) instead of\n unmounting the integrator's subtree. */}\n <AthenaChatErrorBoundary key={statewireThreadId ?? undefined}>\n {/* The calls the run waits on a person's approval for, read once for\n every turn's steps and subagent card (read-only: the approval\n card answers). */}\n <StatewireApprovalWaitProvider>\n {/* The running subagent lanes an open transcript drawer shows, which\n the history edge's window sync follows on the wire. */}\n <DeepAgentLaneFollowScope>\n {/* Every tool call in the thread — generic fallback, dedicated tool\n UI, nested PTC sub-call — renders as the one-line thread row. */}\n <ToolFallbackAppearanceProvider appearance=\"thread\">\n <MentionAuthCtx.Provider value={mentionAuth}>\n <ChatThreadShell\n overlay={\n <>\n <ThreadLoadingOverlay />\n {/* The session on screen is marked read for the viewer\n (thread-list mode), as Olympus's chat does; its sentinel\n covers the panel, so a hidden chat marks nothing. */}\n <MarkViewedThreadRead />\n </>\n }\n panelClassName={cn(\n 'aui-root aui-thread-root @container relative flex h-full flex-col bg-background',\n className,\n )}\n maxWidth={maxWidth}\n turnAnchor={turnAnchor}\n readOnly={readOnly}\n arrivalThreadId={statewireThreadId}\n viewerUserId={account.userId ?? null}\n // Persistent \"waiting on you\" strip above the viewport; the approval\n // card it points at stays in the sticky footer below. Above it, when\n // the thread opened from this device offline, as of when.\n banners={\n <>\n <OfflineSnapshotBanner className=\"px-4 pt-3\" />\n <WaitingOnYouBanner className=\"px-4 pt-3\" />\n </>\n }\n // The composer is the sticky footer inside this viewport, so\n // whatever moves the viewport's content moves the composer too;\n // both guards keep it put, as in Olympus's thread (#28797, #26018).\n // `overflow-x-hidden`: a scroll container cannot leave one axis\n // `visible`, so with `overflow-x-auto` anything wider than the\n // column scrolled the whole thread, composer included, sideways\n // under a trackpad. Wide tables and code scroll in their own boxes.\n // `overscroll-y-none`: a fling that reaches the top or bottom\n // neither chains into the page nor starts the macOS elastic\n // bounce, either of which carried the composer off its place.\n viewportClassName=\"aui-thread-viewport relative flex flex-1 flex-col overflow-x-hidden overflow-y-scroll overscroll-y-none scroll-smooth px-4 pt-4\"\n contentClassName=\"flex w-full flex-1 flex-col\"\n viewportOverlay={\n <>\n {/* A conversation handed over to this app opens where it was being read. */}\n <HandoffCursorReveal threadId={statewireThreadId} />\n <ThreadScrollToTop />\n </>\n }\n welcome={\n <AthenaChatWelcome welcomeMessage={welcomeMessage} welcomeSubtext={welcomeSubtext} />\n }\n beforeMessages={<StatewireHistoryEdge className=\"aui-thread-history-edge\" />}\n components={messageComponents}\n runningIndicator={null}\n // The scroll-to-bottom pill, centred just above the footer as\n // Spaces places it: over no footer content (queued messages,\n // banners) and not in the corner where the reader's own messages end.\n scrollToBottom={<ThreadScrollToBottom />}\n viewportFooterClassName=\"aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-3xl bg-background pt-4 pb-4 md:pb-6\"\n viewportFooter={\n <>\n {/* Empty state: the suggestion cards sit directly above the\n composer (the greeting stays centred in the viewport). */}\n {welcomeSuggestions.length > 0 && (\n <ThreadPrimitive.Empty>\n <AthenaChatWelcomeSuggestions suggestions={welcomeSuggestions} />\n </ThreadPrimitive.Empty>\n )}\n {surface && <DrivingOnChip here={surface} />}\n <StatewireConnectionBanner />\n <StatewireErrorBanner onStartNewSession={startNewSession} />\n <StatewireRunRefusalNotice onStartNewSession={startNewSession} />\n {/* The agent's typed questions and approvals answer in their\n own cards, as on the web. */}\n <StatewireApprovalCard\n confirmDecision={confirmDecision}\n typedInterrupts={statewireTypedInterrupts}\n />\n {plan === undefined ? <AthenaPlanStrip className=\"mx-3\" /> : plan}\n {/* Queued rows render mention chips, which need the app URL\n to link to their asset. */}\n <StatewireQueuedMessages />\n <AttachmentProvider>\n <QuoteProvider>\n <QuotePostMessageBridge />\n <AthenaChatComposer\n tools={tools}\n mentionCategories={mentionCategories}\n slots={composerSlots}\n dictation={dictation}\n voice={readOnly ? false : voice}\n continueByVoice={readOnly ? null : continueByVoice}\n welcomeSuggestionCount={welcomeSuggestions.length}\n followUpSuggestions={followUpSuggestions && !readOnly}\n />\n </QuoteProvider>\n </AttachmentProvider>\n </>\n }\n />\n </MentionAuthCtx.Provider>\n </ToolFallbackAppearanceProvider>\n </DeepAgentLaneFollowScope>\n </StatewireApprovalWaitProvider>\n </AthenaChatErrorBoundary>\n </AthenaTurnChangesContext.Provider>\n </AthenaChatDefaultComponentsContext.Provider>\n );\n};\n\nconst THREAD_VIEWPORT_ATTR = 'data-aui-thread-viewport';\n\nconst useScrollToTop = () => {\n const [isAtTop, setIsAtTop] = useState(true);\n const [buttonEl, setButtonEl] = useState<HTMLButtonElement | null>(null);\n\n const containerRef = useCallback((node: HTMLButtonElement | null) => {\n setButtonEl(node);\n }, []);\n\n const getViewport = useCallback((): HTMLElement | null => {\n if (!buttonEl) return null;\n return buttonEl.closest(`[${THREAD_VIEWPORT_ATTR}]`) as HTMLElement | null;\n }, [buttonEl]);\n\n useEffect(() => {\n const viewport: HTMLElement | null = getViewport();\n if (!viewport) return;\n\n const handleScroll = () => {\n setIsAtTop(viewport.scrollTop <= 50);\n };\n\n handleScroll();\n viewport.addEventListener('scroll', handleScroll, { passive: true });\n return () => viewport.removeEventListener('scroll', handleScroll);\n }, [getViewport]);\n\n const handleClick = useCallback(() => {\n const viewport: HTMLElement | null = getViewport();\n if (!viewport) return;\n viewport.scrollTo({ top: 0, behavior: 'smooth' });\n }, [getViewport]);\n\n return { isAtTop, containerRef, handleClick };\n};\n\nconst ThreadScrollToTop: FC = () => {\n const { isAtTop, containerRef, handleClick } = useScrollToTop();\n const isEmpty = useAuiState((s) => s.thread.isEmpty);\n\n if (isEmpty) return null;\n\n return (\n // At the viewport's right edge, beside the text column: over the column\n // it would cover the line being read.\n <div className=\"pointer-events-none sticky top-0 z-10 flex h-0 w-full justify-end\">\n <TooltipIconButton\n ref={containerRef}\n tooltip=\"Scroll to top\"\n variant=\"outline\"\n className={cn(\n 'aui-thread-scroll-to-top pointer-events-auto absolute top-2 right-0 size-8 rounded-full bg-background/90 shadow-sm dark:bg-background dark:hover:bg-accent',\n isAtTop && 'invisible',\n )}\n onClick={handleClick}\n >\n <ArrowUpIcon />\n </TooltipIconButton>\n </div>\n );\n};\n\n/**\n * A category a host can offer in AthenaChat's `@` menu (`AthenaChatProps.mentionCategories`).\n * Tools and Toolkits are not among them: they follow `mentionTools`.\n */\nexport type AthenaChatMentionCategory = Exclude<MentionRootCategory, 'tools' | 'toolkits'>;\n\n/**\n * The categories AthenaChat's `@` menu offers by default: the asset library. A host adds people\n * (`team`), agents (`agents`), browse profiles or drives through `mentionCategories`. The Tools /\n * Toolkits categories are added when the host (or the provider's enabled toolkits) offers any.\n */\nconst ATHENA_CHAT_MENTION_CATEGORIES: readonly AthenaChatMentionCategory[] = [\n 'favorites',\n 'assets',\n 'projects',\n 'folders',\n];\n\n/**\n * The order AthenaChat's `@` menu lists its categories in, Olympus's (Toolkits ahead of Tools, as\n * AthenaChat always listed them): the library, the host's tools, then Team, Agents and Drives.\n */\nconst ATHENA_CHAT_MENTION_ORDER: readonly MentionRootCategory[] = [\n 'favorites',\n 'assets',\n 'projects',\n 'browse_profiles',\n 'folders',\n 'toolkits',\n 'tools',\n 'team',\n 'agents',\n 'drives',\n];\n\n/**\n * AthenaChat's composer: the shared chat-ui Tiptap editor and `@` mention menu\n * with AthenaChat's quote and attachment pills composed into the send.\n *\n * A draft with a quote or attachment pills — text or not — is intercepted on\n * submit and dispatched as one composed message through the composer runtime,\n * the path the server-owned queue observes, so a mid-run submit queues like\n * any other send. Pasted images upload into the pills through the same intake\n * as the paperclip and the drop zone, and every submit path (Enter, the send\n * button) waits for an in-flight upload so a send never leaves without its\n * attachment. The send control resolves send / queue / stop through the\n * shared chat-ui logic.\n *\n * The chrome is the shared dock's paper appearance (`data-appearance=\"paper\"`\n * on `.aui-composer-root`): the drop zone reports drag-over into\n * `data-drag-active`, the first focus in a browser shows the Enter /\n * Shift+Enter hint until the first send, and a thread that mounts empty\n * brings the composer in last, after the greeting and the suggestion cards.\n */\nconst AthenaChatComposer: FC<{\n tools: MentionTool[];\n /** The categories the host offers beside Tools / Toolkits (`AthenaChatProps.mentionCategories`). */\n mentionCategories: readonly AthenaChatMentionCategory[];\n slots?: AthenaChatComposerSlots;\n dictation: boolean | AthenaChatDictationOptions;\n voice: boolean | AthenaChatVoiceOptions;\n continueByVoice: AthenaChatContinueByVoice | null;\n /** How many suggestion cards precede the composer's entrance in the empty state. */\n welcomeSuggestionCount: number;\n /** Chips of follow-up prompts above the composer after a finished turn (`AthenaChatProps`). */\n followUpSuggestions: boolean;\n}> = ({\n tools,\n mentionCategories,\n slots,\n dictation,\n voice: voiceOptions,\n continueByVoice,\n welcomeSuggestionCount,\n followUpSuggestions,\n}) => {\n const aui = useAui();\n const threadId = useAthenaStatewireThreadId();\n const noteAppendedSend = useContext(AthenaThreadListAppendedSendContext);\n const { appUrl } = useAthenaConfig();\n const { attachments, clearAttachments, isUploading, notice: attachNotice, setNotice: setAttachNotice } =\n useAttachments();\n const { quote, clearQuote } = useQuote();\n // What the next message carries as attached references (`useAttachToChat`): chips above the\n // editor, sent in the message's own metadata, never in its text.\n const attachedReferences = usePendingAttachedReferences(threadId);\n const attachedReferencesComposerProps = useAttachedReferencesComposerProps(threadId);\n const { attachFiles } = useAttachFiles();\n const sessionLane = useStatewireSessionLane();\n const composerRef = useRef<TiptapComposerHandle>(null);\n const [hasText, setHasText] = useState(false);\n // Why a send stayed in the composer (something in it can't wait in the chat outbox), or why a\n // file was not attached (picked while Athena can't be reached); gone once the draft changes.\n const [composerNotice, setComposerNotice] = useState<string | null>(null);\n const onDraftStateChange = useCallback(\n (next: boolean) => {\n setHasText(next);\n setComposerNotice(null);\n setAttachNotice(null);\n },\n [setAttachNotice],\n );\n const notice = composerNotice ?? attachNotice;\n // The host's reason the controls that need Athena are off right now, if any.\n const needsConnectionReason = slots?.needsConnectionReason || null;\n const isRunning = useAuiState((state) => state.optional.thread?.isRunning ?? false);\n // The hint follows the live-run verdict other live surfaces read\n // (`useAthenaRunLive`): `isRunning` follows the presented status and blinks\n // off for a first dial's attach round-trip, which would flash the idle hint.\n const connection = useDeepAgentConnection();\n const { voice, active: voiceActive, enabled: voiceEnabled, audioRef } = useComposerChatVoice({ options: voiceOptions });\n const runLive = useAuiState((state) => {\n const thread = state.optional.thread;\n return thread ? readRunLive(thread, connection) : false;\n });\n const [dragActive, setDragActive] = useState(false);\n const keyboardHint = useComposerKeyboardHint();\n const reducedMotion = usePrefersReducedMotion();\n // The staged entrance belongs to the empty state only: a composer that\n // mounts over an existing transcript is simply there.\n const isEmpty = useAuiState((state) => state.thread.isEmpty);\n const [mountedEmpty] = useState(() => isEmpty);\n const entrance = welcomeEntrance(\n welcomeComposerDelayMs(welcomeSuggestionCount),\n reducedMotion || !mountedEmpty,\n );\n\n // Dictation: the hook is inert until `start()`, so it mounts even when the\n // mic is turned off; `isSupported` hides the control where the engine is\n // missing (Firefox) instead of rendering a button that cannot work.\n const dictationEnabled = dictation !== false;\n const dictationOptions = typeof dictation === 'object' ? dictation : undefined;\n // Words join the draft that existed before recording (manual edits are\n // kept) as typed plain text in the editor, so they are never read as\n // Markdown and a send delivers them, and the typed draft, as typed.\n const appendSpokenText = useCallback(\n (spoken: string) => {\n if (!spoken) return;\n const composer = composerRef.current;\n if (composer?.appendText) {\n composer.appendText(spoken);\n return;\n }\n aui.composer.setText(composeDictationDraft(aui.composer.getState().text ?? '', spoken));\n },\n [aui],\n );\n const dictationEngine = useAthenaDictationEngine(dictationOptions?.engine);\n const dictationCtl = useDictation({\n engine: dictationEngine,\n lang: dictationOptions?.lang,\n // A recognizer that gives up on its own (silence window) still hands\n // over what it heard instead of dropping the words with the session.\n onAutoEnd: appendSpokenText,\n });\n const recording = dictationEnabled && dictationCtl.isActive;\n const showMic = dictationEnabled && dictationCtl.isSupported && !voiceActive;\n // A host that turns dictation off mid-session takes the controls away with\n // it; release the microphone and the recognizer rather than letting them\n // run on with no way to stop them.\n const { isActive: dictationActive, cancel: cancelDictation } = dictationCtl;\n useEffect(() => {\n if (!dictationEnabled && dictationActive) cancelDictation();\n }, [cancelDictation, dictationActive, dictationEnabled]);\n\n // The host's categories in Athena's order, with Tools / Toolkits where the host offers any. A host\n // that hands a new array each render rebuilds nothing: the menu keys its data on the list's words.\n const rootCategories = useMemo<readonly MentionRootCategory[]>(() => {\n const offered = new Set<string>(mentionCategories);\n if (tools.some((tool) => tool.type === 'toolkit')) offered.add('toolkits');\n if (tools.some((tool) => tool.type === 'tool')) offered.add('tools');\n return ATHENA_CHAT_MENTION_ORDER.filter((category) => offered.has(category));\n }, [mentionCategories, tools]);\n const namesAgents = rootCategories.includes('agents');\n // Whether the viewer is an Athena admin, read only for a menu that offers people or agents: Team\n // ranks an admin's people, and the Agents section is an admin's for now, as in Olympus.\n const viewerIsAdmin = useAthenaViewerIsAdmin({\n enabled: namesAgents || rootCategories.includes('team'),\n });\n // Choosing past the limit says which agents were left out, once the chosen item's `@query` has\n // left the draft (a draft change clears the composer's notice).\n const sayNamedAgentsLimit = useCallback((message: string) => {\n queueMicrotask(() => setComposerNotice(message));\n }, []);\n const chatAgents = useAthenaChatAgentsMention({\n threadId,\n enabled: namesAgents,\n isAdmin: viewerIsAdmin,\n onLimit: sayNamedAgentsLimit,\n });\n const focusComposer = useCallback(() => composerRef.current?.focus?.(), []);\n // What a host's own controls in the slots run, as the attach and `@` buttons do.\n const filePickerRef = useRef<HTMLInputElement>(null);\n const composerActions = useMemo<AthenaChatComposerActions>(\n () => ({\n openFilePicker: () => {\n if (needsConnectionReason) return;\n filePickerRef.current?.click();\n },\n openMentionMenu: () => composerRef.current?.openMentionMenu?.(),\n needsConnectionReason,\n }),\n [needsConnectionReason],\n );\n // A follow-up chip's words go into the (empty) draft as typed plain text, with the caret after\n // them; nothing is sent.\n const pickFollowUp = useCallback(\n (text: string) => {\n const composer = composerRef.current;\n if (composer?.appendText) composer.appendText(text);\n else aui.composer.setText(text);\n composer?.focus?.();\n },\n [aui],\n );\n\n // The submit paths are captured once by the editor's keybinding, so they\n // read the current draft extras through refs.\n const attachmentsRef = useRef(attachments);\n attachmentsRef.current = attachments;\n const quoteRef = useRef(quote);\n quoteRef.current = quote;\n const attachedReferencesRef = useRef(attachedReferences);\n attachedReferencesRef.current = attachedReferences;\n // Attached references alone send nothing (a message needs words), so they are not a draft here.\n const hasExtras = attachments.length > 0 || quote !== null;\n\n // The host's work before a message goes runs in the editor's own submit, which Enter, the send\n // button and the handle all go through, so each send runs it once whichever way it went; the\n // action is the send control's verdict at that moment (a draft for a live voice conversation\n // goes into it; any other queues behind a live run).\n const sendStateRef = useRef({ isRunning, liveVoice: false });\n sendStateRef.current = { isRunning, liveVoice: voice.phase === 'live' && !hasExtras };\n const onBeforeSend = slots?.onBeforeSend;\n const beforeSubmit = useCallback(\n async ({ text }: { text: string }) => {\n if (!onBeforeSend) return;\n const { isRunning: running, liveVoice } = sendStateRef.current;\n const action = liveVoice\n ? 'send'\n : resolveComposerAction({ hasDraft: true, isRunning: running });\n if (action === 'stop') return;\n await onBeforeSend({ action, text });\n },\n [onBeforeSend],\n );\n\n // A submit during an upload parks until the pills have the asset; the\n // waiters resolve on the render that turns `isUploading` off, by which\n // point `attachmentsRef` holds the uploaded asset.\n const isUploadingRef = useRef(isUploading);\n isUploadingRef.current = isUploading;\n const uploadWaitersRef = useRef<Array<() => void>>([]);\n useEffect(() => {\n if (isUploading) return;\n const waiters = uploadWaitersRef.current;\n uploadWaitersRef.current = [];\n for (const resolve of waiters) resolve();\n }, [isUploading]);\n const waitForHostUploads = useCallback(() => {\n if (!isUploadingRef.current) return;\n return new Promise<void>((resolve) => {\n uploadWaitersRef.current.push(resolve);\n });\n }, []);\n\n const sendComposed = useCallback(\n (editorSend: ComposerSend): boolean => {\n const send = buildComposedSend({\n attachments: attachmentsRef.current,\n quote: quoteRef.current,\n send: editorSend,\n appUrl,\n });\n if (!send) return false;\n // The editor's text goes out as typed; the same message built from the\n // editor's Markdown draft is what a send statewire hands back loads, and\n // what the message carries as its composer markdown.\n prepareComposerSend({ threadId, ...send });\n // The agents it names (its To line): staged right before it leaves.\n if (namesAgents) {\n stageComposerNamedAgents({\n threadId,\n text: send.text,\n agents: readDeepAgentNamedAgents(threadId),\n });\n }\n // The references attached to it ride its metadata, staged the same way and remembered with\n // its text, so a send statewire hands back brings its chips back.\n const references = stageThreadAttachedReferencesForSend({ threadId, text: send.text });\n if (references.length > 0) {\n // A message with attachments carries its metadata (the references, and the draft and\n // agents staged with them) on the message itself: the composer runtime's send leaves it to\n // `getMessageMetadata`, which only the monorepo's patch of `@assistant-ui/react-statewire`\n // reads, so on the stock package an app installs from npm the references never left. It\n // waits for its own run, as the composer's queued send would (statewire's queue lane):\n // Athena tells the agent about attachments when a run starts, and a message folded into a\n // running turn would join a run that has already started.\n aui.thread().append({\n role: 'user',\n content: [{ type: 'text', text: send.text }],\n metadata: { custom: takeStagedMessageMetadata(threadId) ?? {} },\n });\n aui.composer.setText('');\n // An append raises no `composer.send`, which the conversation list watches to move the\n // row to the top (and list a new chat) at once: tell it here.\n noteAppendedSend?.(send.text);\n } else {\n // An `auto` send: mid-run the host's prioritizer folds it into the run, stops the run for\n // it or queues it; idle sends dispatch immediately.\n aui.composer.setText(send.text);\n aui.composer.send(autoComposerSendOptions(aui.thread().getState().isRunning));\n }\n clearAttachments();\n clearQuote();\n return true;\n },\n [appUrl, aui, clearAttachments, clearQuote, namesAgents, noteAppendedSend, threadId],\n );\n\n // Consumes the editor's draft (possibly empty) only when there are extras\n // to compose with it.\n // A message the composer accepted (sent, held in the outbox, or taken into\n // the live call) answers the host's \"Continue by voice\" offer.\n const continueByVoiceRef = useRef(continueByVoice);\n continueByVoiceRef.current = continueByVoice;\n const settleContinueByVoice = useCallback(() => continueByVoiceRef.current?.onDone(), []);\n const { onSubmitted: onKeyboardHintSubmitted } = keyboardHint;\n const handleComposerSubmitted = useCallback(() => {\n onKeyboardHintSubmitted();\n settleContinueByVoice();\n }, [onKeyboardHintSubmitted, settleContinueByVoice]);\n const interceptSubmit = useCallback(\n async (text: string, draftMarkdown: string) => {\n // Rich extras keep their structured normal-run send. Plain text enters\n // the live conversation; a refusal falls back to the normal queue/outbox.\n if (\n attachmentsRef.current.length > 0 ||\n quoteRef.current !== null ||\n (attachedReferencesRef.current.length > 0 && text.length > 0)\n ) {\n return sendComposed({ text, draftMarkdown });\n }\n return voice.phase === 'live' && text.length > 0 ? voice.sendUserText(text) : false;\n },\n [sendComposed, voice.phase, voice.sendUserText],\n );\n\n // Pills, a quote and attached references ride the composed send, and wait with it in the chat\n // outbox while sends are on hold: the pills are files already uploaded to Athena, the quote is\n // text, and the references ride the held message's metadata. References count only with words\n // to send: alone they are not a message, so the composer neither sends nor runs the host's\n // per-send work for them.\n const hasPendingExtras = useCallback(\n () =>\n attachmentsRef.current.length > 0 ||\n quoteRef.current !== null ||\n (attachedReferencesRef.current.length > 0 &&\n Boolean(composerRef.current?.captureSend?.()?.text ?? aui.composer.getState().text)),\n [aui],\n );\n const holdPendingExtras = useCallback(\n ({\n outbox,\n send,\n attachments,\n addressedAgents,\n }: {\n outbox: ChatOutbox;\n send: ComposerSend;\n attachments: ChatOutboxAttachment[];\n addressedAgents?: readonly string[];\n }): boolean => {\n const held = holdComposedSend({\n outbox,\n attachments: attachmentsRef.current,\n carried: attachments,\n quote: quoteRef.current,\n send,\n appUrl,\n // The agents it names ride its message.\n ...(addressedAgents && { addressedAgents }),\n // So do the references attached to it.\n attachedReferences: attachedReferencesRef.current,\n });\n if (!held) return false;\n clearAttachments();\n clearQuote();\n clearAttachedReferences(threadId);\n return true;\n },\n [appUrl, clearAttachments, clearQuote, threadId],\n );\n\n // Pasted images go through the pills' intake; drops are left to the\n // enclosing ComposerDropZone.\n const fileIntake = useMemo<ComposerFileIntake>(\n () => ({\n onPaste: (files) => {\n void attachFiles(files, 'paste');\n },\n }),\n [attachFiles],\n );\n\n // Stop: the spoken words join the draft and the editor comes back for review.\n const stopDictation = useCallback(async () => {\n appendSpokenText((await dictationCtl.stop()).text);\n }, [appendSpokenText, dictationCtl]);\n\n // Send: same merge, then dispatched the way the send button would — through\n // the composed-message path when pills are pending, else straight through\n // the composer runtime (a mid-run send queues; see sendComposed).\n const sendDictation = useCallback(async () => {\n const { text: spoken, error } = await dictationCtl.stop();\n // The words join the editor's draft before anything else, so a failed\n // transcription or a host hook that rejects leaves them in the composer\n // for review instead of losing them.\n appendSpokenText(spoken);\n // A failed transcription has nothing to send; keep whatever landed in the\n // draft for review next to the error notice rather than dispatching a\n // message that is missing the dictated words.\n if (error) return;\n // While the sign-in provider is still resolving who is signed in, the\n // chat's session lane is pending and refuses a send unsent: the message\n // waits for the lane in the draft, as a typed send does.\n if (sessionLane?.isPending()) await sessionLane.whenKnown();\n // What the send button would deliver: the typed text exactly as typed\n // with the dictated words after it, and the draft it came from.\n const send: ComposerSend = composerRef.current?.captureSend?.() ?? {\n text: aui.composer.getState().text ?? '',\n draftMarkdown: aui.composer.getState().text ?? '',\n };\n const extras =\n attachmentsRef.current.length > 0 ||\n quoteRef.current !== null ||\n (attachedReferencesRef.current.length > 0 && send.text.length > 0);\n if (!send.text && !extras) return;\n const action = resolveComposerAction({ hasDraft: true, isRunning });\n if (action === 'stop') return;\n try {\n await slots?.onBeforeSend?.({ action, text: send.text });\n } catch (error) {\n athenaDiagnostics.emit('composer.dictation', {\n level: 'warn',\n data: {\n phase: 'before_send_rejected',\n error: error instanceof Error ? error.message : String(error),\n },\n });\n return;\n }\n // The agents the dictated message names: the To line's chips as it goes.\n const namedAgents = namesAgents ? readDeepAgentNamedAgents(threadId) : [];\n // The host let the dictated message go: it answers a \"Continue by voice\" offer.\n settleContinueByVoice();\n if (extras) {\n sendComposed(send);\n return;\n }\n prepareComposerSend({ threadId, ...send });\n if (namesAgents) stageComposerNamedAgents({ threadId, text: send.text, agents: namedAgents });\n aui.composer.setText(send.text);\n aui.composer.send(autoComposerSendOptions(aui.thread().getState().isRunning));\n }, [\n appendSpokenText,\n aui,\n dictationCtl,\n isRunning,\n namesAgents,\n sendComposed,\n sessionLane,\n settleContinueByVoice,\n slots,\n threadId,\n ]);\n\n const composer = (\n <ComposerDropZone onDragActiveChange={setDragActive}>\n {/* The replicated chat transcript captions this live synthesized audio. */}\n <audio ref={audioRef} autoPlay playsInline />\n {/* The file picker a host's own control opens (`useAthenaComposerActions`). */}\n <input\n ref={filePickerRef}\n type=\"file\"\n multiple\n className=\"hidden\"\n aria-hidden\n tabIndex={-1}\n onChange={(event) => {\n const input = event.currentTarget;\n const files = input.files ? Array.from(input.files) : [];\n // Reset so the same file can be picked again.\n input.value = '';\n if (files.length > 0) void attachFiles(files, 'paperclip');\n }}\n />\n {/* React delivers `onFocus` as focusin, so the editor's focus reaches\n this wrapper; the same element carries the staged entrance. */}\n <div\n className={cn('aui-composer-entrance', entrance.className)}\n style={entrance.style}\n onFocus={keyboardHint.onFocus}\n >\n <ChatComposerDock\n appearance=\"paper\"\n dragActive={dragActive}\n aboveSurface={\n <FollowUpSuggestions\n enabled={followUpSuggestions}\n threadId={threadId}\n hasDraft={hasText || hasExtras}\n onPick={pickFollowUp}\n />\n }\n beforeEditor={\n <>\n {slots?.aboveEditor}\n <ChatVoiceStatus\n voice={voice}\n offerMove={voiceEnabled}\n moveDisabled={isUploading || dictationCtl.isActive || !isStatewireChannelLive(connection)}\n moveDisabledReason={needsConnectionReason}\n />\n <ChatVoiceContinueOffer\n voice={voice}\n offer={voiceEnabled ? continueByVoice : null}\n disabled={isUploading || dictationCtl.isActive || !isStatewireChannelLive(connection)}\n disabledReason={needsConnectionReason}\n />\n {/* The agents the next message names (chosen from the `@` menu's Agents section),\n each answering it in its own turn. */}\n {namesAgents ? (\n <ComposerNamedAgents threadId={threadId} onEmptied={focusComposer} />\n ) : null}\n {/* The objects the app attached to the next message (`useAttachToChat`). */}\n <ComposerAttachedReferences threadId={threadId} onEmptied={focusComposer} />\n <ComposerQuotePreview />\n <ComposerAttachmentPreview />\n </>\n }\n editor={\n <>\n {/* The editor stays mounted while recording so its draft and\n mention state survive; the waveform takes its place visually. */}\n <div className={cn(recording && 'hidden')}>\n <TiptapComposer\n ref={composerRef}\n threadId={threadId}\n // Its own sends (runtime attachments skip the interception) carry what an app\n // attached too, and a send handed back brings their chips back.\n {...attachedReferencesComposerProps}\n appearance=\"paper\"\n placeholder={\n (runLive ? slots?.runningPlaceholder : undefined) ??\n slots?.placeholder ??\n DEFAULT_COMPOSER_PLACEHOLDER\n }\n tools={tools}\n rootCategories={rootCategories}\n chatAgents={chatAgents}\n viewerIsAdmin={viewerIsAdmin}\n onDraftStateChange={onDraftStateChange}\n mentionSearchUnavailable={needsConnectionReason ? NEEDS_CONNECTION : null}\n waitForHostUploads={waitForHostUploads}\n interceptSubmit={interceptSubmit}\n beforeSubmit={onBeforeSend ? beforeSubmit : undefined}\n hasPendingExtras={hasPendingExtras}\n holdPendingExtras={holdPendingExtras}\n onAttachmentError={setComposerNotice}\n fileIntake={fileIntake}\n onSubmitted={handleComposerSubmitted}\n slashCommands={slots?.slashCommands}\n />\n </div>\n {notice && (\n <p className=\"aui-composer-notice px-1.5 pb-1 text-destructive text-xs\" role=\"alert\">\n {notice}\n </p>\n )}\n {recording && (\n <DictationStrip\n status={dictationCtl.status}\n transcript={dictationCtl.transcript}\n stream={dictationCtl.stream}\n stoppingLabel={dictationCtl.engine.stoppingLabel}\n />\n )}\n {dictationEnabled && dictationCtl.status === DICTATION_STATUSES.error && dictationCtl.error && (\n <p className=\"aui-dictation-error px-1.5 pb-1 text-destructive text-xs\" role=\"alert\">\n {dictationCtl.error.message}\n </p>\n )}\n </>\n }\n toolbarStart={\n // `min-w-0 flex-wrap`: when the chips are wider than the composer (a narrow pane, or a\n // host's own chips), they wrap onto another row instead of pushing voice and Send past\n // its edge. A toolbar that fits lays out as before.\n <div className=\"flex min-w-0 flex-wrap items-center gap-1\">\n {recording ? (\n <DictationCancelButton onClick={dictationCtl.cancel} />\n ) : (\n <>\n {slots?.attachButton === false ? null : (\n <FileUploadButton\n className=\"aui-composer-attach size-8 rounded-full p-0 disabled:opacity-30\"\n disabledReason={needsConnectionReason}\n />\n )}\n {slots?.mentionButton === false ? null : (\n <AthenaComposerMentionButton\n onClick={() => composerRef.current?.openMentionMenu?.()}\n disabledReason={needsConnectionReason}\n />\n )}\n <AthenaChatModeMenu />\n {slots?.toolbarStart}\n </>\n )}\n </div>\n }\n toolbarEnd={\n // Never shrinks, and sits at the last row's end once the chips wrap.\n <div className=\"flex shrink-0 items-center gap-1 self-end\">\n {recording ? (\n <>\n <DictationStopButton\n onClick={() => void stopDictation()}\n disabled={dictationCtl.status === DICTATION_STATUSES.stopping}\n />\n <AthenaComposerSendButton\n action={isRunning ? 'queue' : 'send'}\n onSend={() => void sendDictation()}\n disabled={dictationCtl.status !== DICTATION_STATUSES.listening || isUploading}\n title={isUploading ? 'Upload in progress...' : undefined}\n />\n </>\n ) : (\n <>\n {slots?.toolbarEnd}\n {showMic && (\n <DictationMicButton\n onClick={dictationCtl.start}\n disabled={isUploading}\n disabledReason={needsConnectionReason}\n />\n )}\n {voiceEnabled && (\n <ChatVoiceButton\n voice={voice}\n disabled={isUploading || dictationCtl.isActive || !isStatewireChannelLive(connection)}\n disabledReason={needsConnectionReason}\n />\n )}\n <ComposerSendOrStop\n composerRef={composerRef}\n hasDraft={hasText || hasExtras}\n liveVoice={voice.phase === 'live' && !hasExtras}\n liveSession={voiceActive ? voice : null}\n sendBlockedReason={isUploading ? 'Upload in progress...' : null}\n components={ATHENA_COMPOSER_COMPONENTS}\n />\n </>\n )}\n </div>\n }\n belowSurface={<ComposerKeyboardHint visible={keyboardHint.visible} />}\n />\n </div>\n </ComposerDropZone>\n );\n return (\n <AthenaChatComposerActionsContext.Provider value={composerActions}>\n {composer}\n </AthenaChatComposerActionsContext.Provider>\n );\n};\n\nconst MessageError: FC = () => (\n <MessagePrimitive.Error>\n <ErrorPrimitive.Root className=\"aui-message-error-root mt-2 flex items-start gap-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm dark:bg-destructive/5 dark:text-red-200\">\n <AlertCircleIcon className=\"mt-0.5 size-4 shrink-0\" />\n <ErrorPrimitive.Message className=\"aui-message-error-message grow\" />\n <ActionBarPrimitive.Reload asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-6 shrink-0 text-destructive hover:text-destructive dark:text-red-200 dark:hover:text-red-100\"\n >\n <RefreshCwIcon className=\"size-3.5\" />\n </Button>\n </ActionBarPrimitive.Reload>\n </ErrorPrimitive.Root>\n </MessagePrimitive.Error>\n);\n\n/**\n * Seconds since `resetKey` last changed, counted while `ticking` (0 while\n * not, so a counter nobody shows re-renders nothing).\n */\nfunction useSecondsSince({ resetKey, ticking = true }: { resetKey: string; ticking?: boolean }): number {\n const [seconds, setSeconds] = useState(0);\n useEffect(() => {\n setSeconds(0);\n if (!ticking) return;\n const startedAt = Date.now();\n const timer = setInterval(() => {\n setSeconds(Math.floor((Date.now() - startedAt) / 1000));\n }, 1000);\n return () => clearInterval(timer);\n }, [resetKey, ticking]);\n return seconds;\n}\n\n/**\n * The quiet status line under a running turn: one pulsing dot, the verb\n * (\"Thinking…\", or the running tool's activity such as \"Searching the web…\"),\n * the elapsed counter once it is due, and a stall tone once the model has\n * been quiet for a while — so a busy run and a possibly-stuck one stop\n * looking identical. A tool call in flight never gets the stall tone: a\n * command or a build streams nothing for minutes while it works, so its line\n * keeps the verb and a neutral counter. The timer restarts whenever\n * `resetKey` changes.\n */\nconst RunStatusLine: FC<{\n verb: string;\n resetKey: string;\n toolCallInFlight?: boolean;\n className?: string;\n}> = ({ verb, resetKey, toolCallInFlight = false, className }) => {\n const seconds = useSecondsSince({ resetKey });\n const stalled = isRunActivityStalled({ seconds, toolCallInFlight });\n return (\n <div\n data-slot=\"run-status-line\"\n data-stalled={stalled ? 'true' : undefined}\n className={cn(\n 'aui-run-activity mt-2 flex items-center gap-2 px-1 text-[12px] text-muted-foreground',\n className,\n )}\n >\n <span\n aria-hidden=\"true\"\n className={cn(\n 'size-1.5 shrink-0 rounded-full bg-current opacity-60',\n !stalled && 'animate-pulse motion-reduce:animate-none',\n )}\n />\n <span\n aria-hidden=\"true\"\n className={cn('tabular-nums', stalled && 'text-amber-600 dark:text-amber-400')}\n >\n {runActivityLabel({ seconds, verb, stalled })}\n </span>\n {/* The visible counter ticks every second; announcing each tick would\n drown a screen reader, so the live region only speaks the two\n meaningful transitions: what the run is doing, and that it looks\n stalled. */}\n <span aria-live=\"polite\" className=\"sr-only\">\n {stalled ? 'Assistant is still working; nothing new for over thirty seconds.' : `${verb}…`}\n </span>\n </div>\n );\n};\n\nconst AthenaAssistantMessageEmpty: EmptyMessagePartComponent = ({ status }) => {\n if (status?.type !== 'running') return null;\n return <RunStatusLine verb=\"Thinking\" resetKey=\"empty\" className=\"mt-0\" />;\n};\n\n/**\n * Renders the empty/loading indicator while a message is running but has no\n * parts yet. `MessagePrimitive.GroupedParts` only renders existing parts, so\n * the indicator can't live inside its switch — it goes here as a sibling.\n */\nconst AthenaMessageEmptyIndicator: FC<{ EmptyComponent: EmptyMessagePartComponent }> = ({\n EmptyComponent,\n}) => {\n const hasParts = useAuiState((s) => s.message.parts.length > 0);\n const isRunning = useAuiState((s) => s.message.status?.type === 'running');\n if (hasParts || !isRunning) return null;\n return <EmptyComponent status={{ type: 'running' }} />;\n};\n\n/**\n * Run-liveness line under a running message whose tail is a tool call: the\n * tool's own verb from the shared registry and an elapsed counter that resets\n * whenever the stream moves the tail part. Once the call has its result and\n * the model stays quiet, the stall tone; never while the call is in flight.\n * Text and reasoning tails animate on their own and render no line.\n */\nconst AthenaMessageActivityIndicator: FC = () => {\n const isRunning = useAuiState((s) => s.message.status?.type === 'running');\n const activityKey = useAuiState((s) => runActivityKey(s.message.parts));\n const verb = useAuiState((s) => runActivityVerb(s.message.parts));\n const toolCallInFlight = useAuiState((s) => isToolCallInFlight(s.message.parts));\n if (!isRunning || activityKey === null) return null;\n return (\n <RunStatusLine\n verb={verb ?? 'Working'}\n resetKey={activityKey}\n toolCallInFlight={toolCallInFlight}\n />\n );\n};\n\n/**\n * The grouped view's running meta, inline on the transcript's header row. The\n * header already counts the whole turn (\"Working for 1m 12s\"), so this shows\n * nothing until nothing has streamed for the stall threshold, then says so in\n * the stall tone (\"Nothing new for 42s\"). The clock restarts whenever anything\n * streams, an answer or the agent's thinking growing included\n * (`runProgressKey`), so a long answer that is still arriving never reads as\n * quiet. Nothing while a tool call is in flight: its step row says it is\n * running, and the header goes on counting the turn.\n */\nconst AthenaGroupedRunMeta: FC = () => {\n const progressKey = useAuiState((s) => runProgressKey(s.message.parts));\n const toolCallInFlight = useAuiState((s) => isToolCallInFlight(s.message.parts));\n const seconds = useSecondsSince({ resetKey: progressKey, ticking: !toolCallInFlight });\n const stalled = isRunActivityStalled({ seconds, toolCallInFlight });\n if (!stalled) return null;\n return (\n <span\n data-slot=\"run-stalled\"\n data-stalled=\"true\"\n className=\"tabular-nums text-amber-600 dark:text-amber-400\"\n >\n <span aria-hidden=\"true\">Nothing new for {runElapsedLabel(seconds)}</span>\n {/* The counter ticks every second, so it stays out of the live region;\n only the stall transition is announced. */}\n <span aria-live=\"polite\" className=\"sr-only\">\n Assistant is still working; nothing new for over thirty seconds.\n </span>\n </span>\n );\n};\nconst renderGroupedRunningMeta = () => <AthenaGroupedRunMeta />;\n\n/**\n * The centered hairline with the date, rendered above the first message of a\n * calendar day that differs from the previous message's. Both messages need\n * the runtime's `_created_at` stamp; without it there is nothing truthful to\n * separate on.\n */\nconst MessageDaySeparator: FC = () => {\n const stamp = useAuiState((s) => readMessageCreatedAt(s.message.metadata?.custom));\n const previousStamp = useAuiState((s) => {\n const index = s.message.index;\n const previous = index > 0 ? s.thread.messages[index - 1] : undefined;\n return readMessageCreatedAt(previous?.metadata?.custom);\n });\n const label = useMemo(() => {\n const date = stamp ? parseMessageTime(stamp) : null;\n const previous = previousStamp ? parseMessageTime(previousStamp) : null;\n if (!date || !previous || isSameCalendarDay(date, previous)) return null;\n return formatDayLabel(date);\n }, [stamp, previousStamp]);\n if (!label) return null;\n return (\n <div\n role=\"separator\"\n aria-label={label}\n data-slot=\"day-separator\"\n className=\"aui-day-separator mb-3 flex w-full items-center gap-3 text-[11px] font-medium text-muted-foreground\"\n >\n <span aria-hidden=\"true\" className=\"h-px flex-1 bg-border\" />\n <span>{label}</span>\n <span aria-hidden=\"true\" className=\"h-px flex-1 bg-border\" />\n </div>\n );\n};\n\n/**\n * The message's clock time, revealed on hover beside the action bar (the\n * full date in its `title`). Reads the runtime's `_created_at` stamp; a\n * message without one shows no time rather than a wrong one.\n */\nconst MessageTimestamp: FC<{ className?: string }> = ({ className }) => {\n const stamp = useAuiState((s) => readMessageCreatedAt(s.message.metadata?.custom));\n const date = useMemo(() => (stamp ? parseMessageTime(stamp) : null), [stamp]);\n if (!date) return null;\n return (\n <time\n dateTime={date.toISOString()}\n title={formatMessageDateTime(date)}\n data-slot=\"message-timestamp\"\n className={cn(\n 'aui-message-timestamp shrink-0 text-[11px] tabular-nums text-muted-foreground',\n ACTION_BAR_REVEAL_CLASS,\n className,\n )}\n >\n {formatMessageTime(date)}\n </time>\n );\n};\n\nexport const AthenaReasoningPart: FC<AthenaReasoningPartProps> = ({\n text,\n status,\n TextComponent,\n}) => {\n const inheritedTextComponent = useContext(AthenaReasoningTextComponentContext);\n const EffectiveTextComponent = TextComponent ?? inheritedTextComponent ?? TiptapText;\n const isMessageRunning = useAuiState((state) => state.message.status?.type === 'running');\n const reasoningTokens = useAuiState((state) =>\n getReasoningTokensFromMetadata(state.message.metadata)\n );\n const isRunning = isMessageRunning || status?.type === 'running';\n const [isCollapsed, setIsCollapsed] = useState(!isRunning);\n const userOverrodeOpenStateRef = useRef(false);\n const hasText = text.trim().length > 0;\n\n const reasoningTextProps: TextMessagePartProps = {\n type: 'text',\n text,\n status: isRunning\n ? ({ type: 'running' } as TextMessagePartProps['status'])\n : (status as TextMessagePartProps['status']),\n };\n\n useEffect(() => {\n if (userOverrodeOpenStateRef.current) {\n return;\n }\n\n setIsCollapsed(!isRunning);\n }, [isRunning]);\n\n if (!hasText && !isRunning) {\n return null;\n }\n\n return (\n <Collapsible\n open={!isCollapsed}\n onOpenChange={(open) => {\n userOverrodeOpenStateRef.current = true;\n setIsCollapsed(!open);\n }}\n className=\"aui-assistant-reasoning-root mb-3 rounded-2xl border border-border/60 bg-muted/30 px-3 py-2\"\n >\n <CollapsibleTrigger asChild>\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-3 text-left\"\n aria-label={isRunning ? 'Toggle reasoning while streaming' : 'Toggle reasoning'}\n >\n <span className=\"flex min-w-0 items-center gap-2 text-[13px] font-medium text-muted-foreground\">\n <BrainIcon className=\"size-4 shrink-0\" />\n <span>{isRunning ? 'Reasoning...' : 'Reasoning'}</span>\n </span>\n <span className=\"flex shrink-0 items-center gap-2\">\n {reasoningTokens !== undefined && (\n <span className=\"rounded-full border border-border/60 bg-background px-2 py-0.5 text-[11px] font-medium text-muted-foreground\">\n {formatReasoningTokens(reasoningTokens)}\n </span>\n )}\n <span\n className={cn(\n 'flex size-5 items-center justify-center text-muted-foreground transition-transform',\n isCollapsed ? 'rotate-0' : 'rotate-90'\n )}\n aria-hidden=\"true\"\n >\n <ChevronRightIcon className=\"size-4\" />\n </span>\n </span>\n </button>\n </CollapsibleTrigger>\n\n <CollapsibleContent className=\"pt-3\">\n {isRunning && !hasText ? (\n <span className=\"shimmer text-[13px] text-muted-foreground\">Analyzing...</span>\n ) : (\n <div className=\"aui-assistant-reasoning-body text-[13px] leading-relaxed\">\n <EffectiveTextComponent {...reasoningTextProps} />\n </div>\n )}\n </CollapsibleContent>\n </Collapsible>\n );\n};\n\nconst groupAdjacentToolCalls = (part: PartState) =>\n part.type === 'tool-call' ? (['group-tool'] as const) : null;\nconst noToolGrouping = () => null;\n\n/** `isSdkInlineTool`, plus `task`: the subagent card is how a turn shows its delegated work. */\nconst isInlineToolOrSubagent = (toolName: string): boolean =>\n toolName === TASK_TOOL_NAME || isSdkInlineTool(toolName);\n\n/**\n * The run ending this message holds (`readRuntimeMessageFromSourceMessages`)\n * as the status card every chat surface draws, or nothing for a silent one.\n */\nconst AthenaRuntimeEndingCard: FC = () => {\n // Select the message (a stable store reference) and derive from it: the\n // reader builds a fresh object per call, which as a selector result would\n // re-render on every store update.\n const message = useAuiState((s) => s.message);\n const runtime = useMemo(() => readRuntimeMessageFromSourceMessages(message), [message]);\n if (!runtime || runtime.silent) return null;\n return <RuntimeMessageCard message={runtime} />;\n};\n\nexport const AthenaAssistantMessage: FC<AthenaAssistantMessageProps> = ({\n toolUIs,\n AvatarComponent,\n TextComponent = TiptapText,\n ReasoningComponent,\n EmptyComponent = AthenaAssistantMessageEmpty,\n ActionBarComponent = AthenaAssistantActionBar,\n groupToolCalls = true,\n}) => {\n const effectiveReasoningComponent = ReasoningComponent ?? AthenaReasoningPart;\n const toolUIsWithNestedMessages = useMemo(() => {\n const wrappedToolUIs: Record<string, ToolCallMessagePartComponent> = {};\n\n for (const [toolName, ToolUI] of Object.entries(toolUIs)) {\n wrappedToolUIs[toolName] = withNestedPtcMessages(ToolUI);\n }\n\n return wrappedToolUIs;\n }, [toolUIs]);\n // The subagent card stays in the conversation, outside the collapsed steps,\n // so a delegated lane shows its progress; a host's own `task` UI stays where\n // every other tool UI is.\n const isInlineTool =\n toolUIs[TASK_TOOL_NAME] === SubagentTaskToolUI ? isInlineToolOrSubagent : isSdkInlineTool;\n // The turn's steps the run's approval waits on (a gated call, or a `task`\n // call whose subagent holds one) read \"Waiting for your input\", never running\n // or done; none outside `AthenaChat`'s provider.\n const waitingToolCallIds = useTurnToolCallsAwaitingApproval(useApprovalWaitInScope().toolCallIds);\n\n // NestedPtcComponentsProvider still consumes the legacy parts-config shape\n // (Text / Reasoning / tools.by_name / Empty) to render PTC sub-tool messages\n // inside a tool card. The outer rendering uses GroupedParts, but the inner\n // PTC tree continues to mirror the parent registry.\n const nestedPtcComponents = useMemo(\n () => ({\n Text: TextComponent,\n Reasoning: effectiveReasoningComponent,\n tools: {\n Fallback: ToolFallback,\n by_name: toolUIsWithNestedMessages,\n },\n Empty: EmptyComponent,\n }),\n [EmptyComponent, TextComponent, effectiveReasoningComponent, toolUIsWithNestedMessages],\n );\n const arrivedLive = useMessageArrivalAnimation();\n // How a run ended is a system event, not the assistant's words: a stop, a\n // server-update pause or a failure draws the status card, never its marker's\n // transcript copy (\"⏹️ Run stopped by user.\"). Send now and a double text end\n // the live run as plumbing, so their marker paints nothing (`silent`): the\n // person stopped nothing. Primitive selectors, since the reader builds a\n // fresh object per call.\n const soleEndingKind = useAuiState((s) => readSoleRuntimeMessageKind(s.message));\n const endingSilent = useAuiState(\n (s) => readRuntimeMessageFromSourceMessages(s.message)?.silent === true,\n );\n // A marker appended after the turn's own work is chunked into this message\n // as its last part: that part draws the card (or nothing) in its place, and\n // the work above it keeps rendering. Text parts render without their index,\n // so the marker is found by its text, and only while no other text part\n // reads the same: the assistant's own words never turn into the card.\n const chunkedEndingText = useAuiState((s) => {\n const runtime = readRuntimeMessageFromSourceMessages(s.message);\n if (!runtime || runtime.isSoleSourceMessage || runtime.kind === 'handoff') return undefined;\n const markerText = runtime.text;\n const last = s.message.content.at(-1);\n if (markerText === undefined || last?.type !== 'text' || last.text !== markerText) return undefined;\n const sameText = s.message.content.filter((part) => part.type === 'text' && part.text === markerText);\n return sameText.length === 1 ? markerText : undefined;\n });\n const AnswerTextComponent = useMemo<TextMessagePartComponent>(() => {\n if (chunkedEndingText === undefined) return TextComponent;\n const Base = TextComponent;\n return function TextOrRunEnding(props) {\n return props.text === chunkedEndingText ? <AthenaRuntimeEndingCard /> : <Base {...props} />;\n };\n }, [TextComponent, chunkedEndingText]);\n\n if (soleEndingKind !== undefined && soleEndingKind !== 'handoff') {\n if (endingSilent) return null;\n return (\n <MessagePrimitive.Root\n className=\"aui-assistant-message-root aui-run-ending-root mx-auto w-full max-w-(--thread-max-width) px-2 py-1\"\n data-role=\"assistant\"\n >\n <MessageDaySeparator />\n <AthenaRuntimeEndingCard />\n </MessagePrimitive.Root>\n );\n }\n\n return (\n <MessagePrimitive.Root\n className={cn(\n 'aui-assistant-message-root group/aui-assistant-message relative mx-auto w-full max-w-(--thread-max-width) py-3',\n arrivedLive && MESSAGE_ARRIVAL_ANIMATION_CLASS,\n )}\n data-role=\"assistant\"\n >\n <MessageDaySeparator />\n <div className=\"flex gap-3\">\n {/* The leading column exists only when the host supplies an avatar;\n without one the turn is told apart from the right-aligned user\n bubbles by alignment alone, with no rule or gutter of its own. */}\n {AvatarComponent ? (\n <div\n data-slot=\"assistant-lead\"\n className=\"aui-assistant-message-lead flex shrink-0 justify-center\"\n >\n <AvatarComponent />\n </div>\n ) : null}\n <div className=\"min-w-0 flex-1\">\n <AnswerLabel className=\"px-2 pb-1\" />\n <AthenaReasoningTextComponentContext.Provider value={TextComponent}>\n <div className=\"aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed\">\n <NestedPtcComponentsProvider components={nestedPtcComponents}>\n {groupToolCalls ? (\n <div className=\"flex flex-col space-y-2\">\n <SuperGroupingTranscript\n toolUIs={toolUIsWithNestedMessages}\n TextComponent={TextComponent}\n ReasoningComponent={effectiveReasoningComponent}\n isInlineTool={isInlineTool}\n waitingToolCallIds={waitingToolCallIds}\n renderRunningMeta={renderGroupedRunningMeta}\n />\n <SuperGroupingFinalText TextComponent={AnswerTextComponent} />\n </div>\n ) : (\n <>\n <AthenaMessageEmptyIndicator EmptyComponent={EmptyComponent} />\n <MessagePrimitive.GroupedParts groupBy={noToolGrouping}>\n {({ part }) => {\n switch (part.type) {\n case 'tool-call': {\n const ToolUI = toolUIsWithNestedMessages[part.toolName];\n const toolProps = part as unknown as ToolCallMessagePartProps;\n return ToolUI ? <ToolUI {...toolProps} /> : <ToolFallback {...toolProps} />;\n }\n case 'reasoning': {\n const ReasoningRenderer = effectiveReasoningComponent;\n return <ReasoningRenderer {...(part as ReasoningMessagePartProps)} />;\n }\n case 'text': {\n const textPart = part as TextMessagePartProps;\n if (textPart.text === '' && textPart.status?.type === 'running') {\n return <EmptyComponent status={textPart.status} />;\n }\n return <AnswerTextComponent {...textPart} />;\n }\n default:\n return null;\n }\n }}\n </MessagePrimitive.GroupedParts>\n <AthenaMessageActivityIndicator />\n </>\n )}\n </NestedPtcComponentsProvider>\n <MessageError />\n </div>\n </AthenaReasoningTextComponentContext.Provider>\n {/* What the turn changed, at its end, while the host turned the card on. */}\n <AthenaTurnChangesSlot className=\"mx-2\" />\n <div className=\"aui-assistant-message-footer mt-1 ml-2 flex items-center gap-1\">\n <BranchPicker />\n <ActionBarComponent />\n <MessageTimestamp className=\"ml-auto group-hover/aui-assistant-message:opacity-100\" />\n </div>\n </div>\n </div>\n </MessagePrimitive.Root>\n );\n};\n\nconst AthenaToolGroup: FC<{ children: React.ReactNode; count: number }> = ({ children, count }) => {\n const [expanded, setExpanded] = useState(false);\n\n return (\n <div className=\"my-3 w-full overflow-hidden rounded-xl border border-border/60 bg-background shadow-sm\">\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-muted/20\"\n aria-expanded={expanded}\n >\n <div className=\"flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted/60 text-muted-foreground\">\n <LayersIcon className=\"size-4\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <span className=\"text-[13px] font-medium text-foreground\">\n {count} tool {count === 1 ? 'call' : 'calls'}\n </span>\n </div>\n <ChevronDownIcon\n className={cn(\n 'size-4 shrink-0 text-muted-foreground transition-transform duration-200',\n !expanded && '-rotate-90',\n )}\n />\n </button>\n {expanded && (\n <div className=\"border-t border-border/40 bg-muted/5 px-3 pt-1 pb-2 [&>*]:my-2\">\n {children}\n </div>\n )}\n </div>\n );\n};\n\nconst CopyMessageButton: FC = () => (\n <ActionBarPrimitive.Copy asChild>\n <TooltipIconButton tooltip=\"Copy\">\n <AuiIf condition={(s) => s.message.isCopied}>\n <CheckIcon />\n </AuiIf>\n <AuiIf condition={(s) => !s.message.isCopied}>\n <CopyIcon />\n </AuiIf>\n </TooltipIconButton>\n </ActionBarPrimitive.Copy>\n);\n\n/** Copy on a user bubble copies what the bubble shows (`useUserMessageCopy`). */\nconst UserCopyMessageButton: FC = () => {\n const { copy, disabled, isCopied } = useUserMessageCopy();\n return (\n <TooltipIconButton\n tooltip=\"Copy\"\n onClick={copy}\n disabled={disabled}\n data-copied={isCopied ? 'true' : undefined}\n >\n {isCopied ? <CheckIcon /> : <CopyIcon />}\n </TooltipIconButton>\n );\n};\n\n/** Regenerate dispatches `run/reload`, so it hides on read-only threads. */\nconst RegenerateMessageButton: FC = () => {\n const readOnly = useMessageActionsReadOnly();\n if (readOnly) return null;\n return (\n <ActionBarPrimitive.Reload asChild>\n <TooltipIconButton tooltip=\"Regenerate\">\n <RefreshCwIcon />\n </TooltipIconButton>\n </ActionBarPrimitive.Reload>\n );\n};\n\n/**\n * The edit primitive does not check the runtime's edit capability itself —\n * clicking it on a runtime without one throws inside onPress — so the button\n * gates on the capability and, to match the rewind semantics of `run/edit`,\n * stays hidden while a run is live or the transcript is read-only. While the\n * host's chat outbox says Athena can't be reached it is not offered: shown\n * disabled, its tooltip says why, and it comes back once Athena answers.\n */\nconst EditMessageButton: FC = () => {\n const allowEdit = useAuiState((s) => s.thread.capabilities.edit);\n const isRunning = useAthenaRunLive();\n const readOnly = useMessageActionsReadOnly();\n const reachable = useChatOutboxReachable(useDeepAgentChatOutboxContext());\n if (!allowEdit || isRunning || readOnly) return null;\n if (!reachable) {\n return (\n <TooltipIconButton\n tooltip={CHAT_EDIT_UNREACHABLE_LABEL}\n aria-disabled\n data-testid=\"chat-message-edit-unreachable\"\n className=\"cursor-not-allowed opacity-50\"\n >\n <PencilIcon />\n </TooltipIconButton>\n );\n }\n return (\n <ActionBarPrimitive.Edit asChild>\n <TooltipIconButton tooltip=\"Edit\">\n <PencilIcon />\n </TooltipIconButton>\n </ActionBarPrimitive.Edit>\n );\n};\n\n/** Hover-revealed copy / edit row under a user bubble; mirrors the assistant bar. */\nconst AthenaUserActionBar: FC = () => {\n const isThreadRunning = useAuiState((s) => s.thread.isRunning);\n return (\n <ActionBarPrimitive.Root\n autohide=\"never\"\n className={cn(\n 'aui-user-action-bar-root flex min-h-6 gap-1 text-muted-foreground',\n isThreadRunning\n ? 'invisible'\n : [\n ACTION_BAR_REVEAL_CLASS,\n 'group-hover/aui-user-message:pointer-events-auto group-hover/aui-user-message:opacity-100',\n ],\n )}\n >\n <UserCopyMessageButton />\n <EditMessageButton />\n </ActionBarPrimitive.Root>\n );\n};\n\nexport const AthenaAssistantActionBar: FC<AthenaAssistantActionBarProps> = ({ className }) => {\n const threadId = useAthenaThreadId();\n const { appUrl } = useAthenaConfig();\n // The bar stays mounted so the footer keeps its height: assistant-ui's\n // `autohide` / `hideWhenRunning` unmount it, which shifts the whole message\n // up and down on every hover. Visibility is CSS instead — the latest reply\n // keeps its actions, older replies reveal on hover or keyboard focus, and\n // while the thread runs every bar is `invisible` (layout kept, controls\n // unfocusable — opacity alone would still let Tab reveal them).\n const isLast = useAuiState((s) => s.message.isLast);\n const isThreadRunning = useAuiState((s) => s.thread.isRunning);\n\n return (\n <ActionBarPrimitive.Root\n autohide=\"never\"\n className={cn(\n 'aui-assistant-action-bar-root -ml-1 flex min-h-6 gap-1 text-muted-foreground',\n isThreadRunning && 'invisible',\n !isThreadRunning &&\n !isLast && [\n ACTION_BAR_REVEAL_CLASS,\n 'group-hover/aui-assistant-message:pointer-events-auto group-hover/aui-assistant-message:opacity-100',\n ],\n className,\n )}\n >\n <CopyMessageButton />\n <RegenerateMessageButton />\n <ActionBarMorePrimitive.Root>\n <ActionBarMorePrimitive.Trigger asChild>\n <TooltipIconButton tooltip=\"More\" className=\"data-[state=open]:bg-accent\">\n <MoreHorizontalIcon />\n </TooltipIconButton>\n </ActionBarMorePrimitive.Trigger>\n <ActionBarMorePrimitive.Content\n side=\"bottom\"\n align=\"start\"\n className=\"aui-action-bar-more-content z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md\"\n >\n <ActionBarPrimitive.ExportMarkdown asChild>\n <ActionBarMorePrimitive.Item className=\"aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground\">\n <DownloadIcon className=\"size-4\" />\n Export as Markdown\n </ActionBarMorePrimitive.Item>\n </ActionBarPrimitive.ExportMarkdown>\n {threadId && (\n <ActionBarMorePrimitive.Item\n className=\"aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground\"\n onClick={() => {\n window.open(createAthenaSpacesUrl({ appUrl, sessionId: threadId }), '_blank');\n }}\n >\n <ExternalLinkIcon className=\"size-4\" />\n Open in Athena\n </ActionBarMorePrimitive.Item>\n )}\n </ActionBarMorePrimitive.Content>\n </ActionBarMorePrimitive.Root>\n </ActionBarPrimitive.Root>\n );\n};\n\nexport const AthenaUserMessage: FC<AthenaUserMessageProps> = ({\n TextComponent = UserMessageText,\n}) => {\n // A GitHub wake or a subscription's delivery is an event, not words the\n // user typed: it renders as the compact wake marker instead of a bubble\n // quoting the injected text.\n const isWake = useAuiState(\n (s) =>\n isGithubWakeMessage(s.message.metadata?.custom) ||\n isSubscriptionWakeMessage(s.message.metadata?.custom)\n );\n const arrivedLive = useMessageArrivalAnimation();\n // A message that came in over a channel (Slack, email, a text, Teams)\n // shows the words sent, without the routing block the agent read.\n const partComponents = useMemo(\n () => ({ Text: withInboundMessageBody(TextComponent), Image: MessageImagePart }),\n [TextComponent],\n );\n if (isWake) {\n return (\n <MessagePrimitive.Root\n className=\"aui-user-message-root aui-wake-marker-root mx-auto w-full max-w-(--thread-max-width) px-2 py-1\"\n data-role=\"user\"\n >\n <MessageDaySeparator />\n <WakeMarkerMessage />\n </MessagePrimitive.Root>\n );\n }\n return (\n <MessagePrimitive.Root\n className={cn(\n 'aui-user-message-root group/aui-user-message mx-auto flex w-full max-w-(--thread-max-width) flex-col items-end px-2 py-3',\n arrivedLive && MESSAGE_ARRIVAL_ANIMATION_CLASS,\n )}\n data-role=\"user\"\n >\n <MessageDaySeparator />\n {/* A soft bubble on a 75% measure: the user's words stay a bubble, the\n assistant's reading column stays the page. */}\n <div className=\"flex min-w-0 max-w-[75%] flex-col items-end gap-1\">\n {/* A message that came in over a channel: the line naming the channel\n and the sender, above the words that were sent. */}\n <InboundChannelLine />\n {/* What the app attached to the message (`useAttachToChat`). */}\n <MessageAttachedReferences />\n <div className=\"aui-user-message-content wrap-break-word min-w-0 max-w-full rounded-2xl bg-muted/70 px-4 py-2.5 text-foreground\">\n <InboundChannelSubject />\n <MessageImageGallery>\n <MessagePrimitive.Parts components={partComponents} />\n </MessageImageGallery>\n </div>\n <div className=\"aui-user-message-footer -mr-1 flex items-center gap-1\">\n <MessageTimestamp className=\"mr-1 group-hover/aui-user-message:opacity-100\" />\n <BranchPicker />\n <AthenaUserActionBar />\n </div>\n </div>\n </MessagePrimitive.Root>\n );\n};\n"],"names":["_a","composer","attachments","error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AthenaChat.js","sources":["../../src/chat/AthenaChat.tsx"],"sourcesContent":["import {\n CHAT_EDIT_UNREACHABLE_LABEL,\n type ChatOutbox,\n type ChatOutboxAttachment,\n isGithubWakeMessage,\n isSubscriptionWakeMessage,\n readRunLive,\n readRuntimeMessageFromSourceMessages,\n readSoleRuntimeMessageKind,\n TASK_TOOL_NAME,\n useChatOutboxReachable,\n useDeepAgentChatOutboxContext,\n useDeepAgentConnection,\n useTurnToolCallsAwaitingApproval,\n autoComposerSendOptions,\n} from '@athenaintel/agent-runtime';\nimport { TiptapText } from './tiptap-text';\nimport { AthenaChatErrorBoundary } from './AthenaChatErrorBoundary';\nimport { StatewireApprovalCard, type StatewireDecisionConfirmer } from './StatewireApprovalCard';\nimport { StatewireClientToolConsentCard } from './StatewireClientToolConsentCard';\nimport { statewireTypedInterrupts } from './typed-interrupts/StatewireTypedInterruptCard';\nimport { AthenaPlanStrip } from './AthenaPlanStrip';\nimport { StatewireQueuedMessages } from './StatewireQueuedMessages';\nimport { StatewireConnectionBanner, StatewireErrorBanner } from './statewire-banners';\nimport { AthenaChatModeMenu } from '../catalog/chat-pickers';\nimport { NEEDS_CONNECTION } from '@athenaintel/agent-runtime/offline-status';\nimport { StatewireRunRefusalNotice } from './StatewireRunRefusalNotice';\nimport { WaitingOnYouBanner } from './WaitingOnYouBanner';\nimport type { ThreadDriverSurface } from '@athenaintel/agent-runtime/thread-driver';\nimport { DrivingOnChip } from './DrivingOnChip';\nimport { OfflineSnapshotBanner } from '../offline/offline-history';\nimport { WakeMarkerMessage } from '../chat-ui/messages/wake-marker';\nimport { RuntimeMessageCard } from '../chat-ui/messages/runtime-message';\nimport { ToolFallback, ToolFallbackAppearanceProvider } from '../tools/tool-fallback';\nimport { AppendDocumentToolUI } from '../tools/append-document-tool-ui';\nimport { ReadAssetToolUI } from '../tools/read-asset-tool-ui';\nimport { isSdkInlineTool } from '../tools/inline-tools';\nimport { SubagentTaskToolUI } from '../tools/subagent-task-tool-ui';\nimport { TOOL_UI_REGISTRY } from '../tools/tool-uis';\nimport { SuperGroupingFinalText } from './super-grouping/SuperGroupingCard';\nimport { SuperGroupingTranscript } from './super-grouping/SuperGroupingTranscript';\nimport {\n StatewireApprovalWaitProvider,\n useApprovalWaitInScope,\n} from './use-statewire-approval-request';\nimport {\n NestedPtcComponentsProvider,\n NestedPtcMessages,\n useNestedPtcComponents,\n} from '../tools/NestedPtcMessages';\nimport { TooltipIconButton } from './tooltip-icon-button';\nimport { Button } from '../ui/button';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../ui/collapsible';\nimport { ChatComposerDock } from '../chat-ui/thread/chat-composer-dock';\nimport { ChatThreadShell } from '../chat-ui/thread/chat-thread-shell';\nimport { HandoffCursorReveal } from '../chat-ui/thread/handoff-cursor';\nimport { StatewireHistoryEdge } from '../chat-ui/thread/statewire-history-edge';\nimport { DeepAgentLaneFollowScope } from '../subagents/lane-follow';\nimport { ThreadLoadingOverlay } from '../chat-ui/thread/thread-loading-overlay';\nimport { ComposerSendOrStop } from '../chat-ui/thread/composer-send-or-stop';\nimport { type ComposerAction, resolveComposerAction } from '../chat-ui/composer/composer-action';\nimport { type ComposerSend, prepareComposerSend } from '../chat-ui/composer/composer-message';\nimport type { ComposerSlashCommand } from '../chat-ui/composer/slash-commands';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport { useDictation } from '../dictation/use-dictation';\nimport { DictationStrip } from '../dictation/DictationStrip';\nimport {\n DictationCancelButton,\n DictationMicButton,\n DictationStopButton,\n} from '../dictation/dictation-controls';\nimport { composeDictationDraft, DICTATION_STATUSES } from '../dictation/dictation-state';\nimport type { DictationEngine } from '../dictation/dictation-engine';\nimport { useAthenaDictationEngine } from '../dictation/use-athena-dictation-engine';\nimport {\n TiptapComposer,\n type ComposerFileIntake,\n type TiptapComposerHandle,\n} from '../chat-ui/composer/tiptap-composer';\nimport {\n MentionAuthCtx,\n type MentionAuthContext,\n} from '../chat-ui/mentions/suggestions/data/api-client';\nimport { useAccountIdentity } from '../chat-ui/mentions/use-account-workspace-id';\nimport type { MentionRootCategory } from '../chat-ui/mentions/suggestions/data/use-mention-suggestions';\nimport type { MentionTool } from '../chat-ui/mentions/suggestions/data/types';\nimport {\n keepDeepAgentNamedAgentsForIdentity,\n readDeepAgentNamedAgents,\n} from '@athenaintel/agent-runtime/named-agents';\nimport { stageComposerNamedAgents } from '../chat-ui/composer/composer-named-agents';\nimport { useAthenaViewerIsAdmin } from '../catalog/runtime-catalog';\nimport {\n clearAttachedReferences,\n keepAttachedReferencesForIdentity,\n stageThreadAttachedReferencesForSend,\n usePendingAttachedReferences,\n} from '../composer/attached-references';\nimport { takeStagedMessageMetadata } from '../composer/staged-message-metadata';\nimport {\n ComposerAttachedReferences,\n MessageAttachedReferences,\n} from '../composer/ComposerAttachedReferences';\nimport { useAttachedReferencesComposerProps } from '../composer/useAttachedReferencesComposerProps';\nimport { ComposerNamedAgents } from '../composer/ComposerNamedAgents';\nimport { useAthenaChatAgentsMention } from './chat-agent-mentions';\nimport { AnswerLabel } from '../chat-ui/messages/answer-label';\nimport {\n MESSAGE_ARRIVAL_ANIMATION_CLASS,\n useMessageArrivalAnimation,\n} from '../chat-ui/messages/arrival-animation';\nimport { MessageImageGallery, MessageImagePart } from '../chat-ui/messages/message-images';\nimport {\n InboundChannelLine,\n InboundChannelSubject,\n useUserMessageCopy,\n withInboundMessageBody,\n} from '../chat-ui/messages/inbound-channel-message';\nimport {\n ACTION_BAR_REVEAL_CLASS,\n BranchPicker,\n UserMessageText,\n} from '../chat-ui/messages/message-components';\nimport { useMessageActionsReadOnly } from '../chat-ui/messages/message-actions-config';\nimport { useAthenaRunLive } from './use-athena-run-live';\nimport {\n AthenaChatWelcome,\n AthenaChatWelcomeSuggestions,\n DEFAULT_WELCOME_SUGGESTIONS,\n welcomeComposerDelayMs,\n welcomeEntrance,\n type WelcomeSuggestion,\n} from './athena-chat-welcome';\nimport {\n ATHENA_COMPOSER_COMPONENTS,\n AthenaComposerMentionButton,\n AthenaComposerSendButton,\n} from './athena-composer-controls';\nimport { ComposerKeyboardHint, useComposerKeyboardHint } from './composer-keyboard-hint';\nimport { FollowUpSuggestions } from './follow-up-suggestions';\nimport { usePrefersReducedMotion } from '../lib/use-prefers-reduced-motion';\nimport { useStatewireSessionLane } from '../runtime/statewire-session-lane';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n ActionBarMorePrimitive,\n ActionBarPrimitive,\n AuiIf,\n ErrorPrimitive,\n MessagePrimitive,\n ThreadPrimitive,\n useAui,\n useAuiState,\n} from '@assistant-ui/react';\nimport type {\n EmptyMessagePartComponent,\n PartState,\n ReasoningMessagePartProps,\n ReasoningMessagePartComponent,\n TextMessagePartProps,\n TextMessagePartComponent,\n ToolCallMessagePartComponent,\n ToolCallMessagePartProps,\n} from '@assistant-ui/react';\nimport {\n AlertCircleIcon,\n ArrowUpIcon,\n BrainIcon,\n CheckIcon,\n ChevronDownIcon,\n ChevronRightIcon,\n CopyIcon,\n DownloadIcon,\n ExternalLinkIcon,\n LayersIcon,\n MoreHorizontalIcon,\n PencilIcon,\n RefreshCwIcon,\n} from 'lucide-react';\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type FC,\n type ReactNode,\n} from 'react';\nimport {\n AthenaStatewireThreadIdContext,\n useAthenaStatewireThreadId,\n useAthenaThreadId,\n} from '../threads/thread-id-context';\nimport {\n AthenaThreadListAppendedSendContext,\n useAthenaStatewireThreadList,\n} from '../threads/statewire-thread-list';\nimport { MarkViewedThreadRead } from '../threads/mark-viewed-thread-read';\nimport { FileUploadButton } from '../composer/FileUploadButton';\nimport { ComposerQuotePreview } from '../composer/ComposerQuotePreview';\nimport { ComposerAttachmentPreview } from '../composer/ComposerAttachmentPreview';\nimport { ComposerDropZone } from '../composer/ComposerDropZone';\nimport { useQuote, QuoteProvider, useQuoteFromPostMessage } from '../composer/QuoteContext';\nimport { AttachmentProvider, useAttachments } from '../composer/AttachmentContext';\nimport { buildComposedSend, holdComposedSend } from '../composer/build-composed-message';\nimport { useAttachFiles } from '../composer/useAttachFiles';\nimport { type AthenaChatComposerActions, AthenaChatComposerActionsContext } from './composer-actions';\nimport { useAthenaConfig } from '../provider/AthenaContext';\nimport { createAthenaSpacesUrl } from '../lib/athena-urls';\nimport { cn, isRecord } from '../lib/utils';\nimport { getToolkitDisplayInfo } from '../toolkits';\nimport {\n isRunActivityStalled,\n isToolCallInFlight,\n runActivityKey,\n runActivityLabel,\n runActivityVerb,\n runElapsedLabel,\n runProgressKey,\n} from './run-activity';\nimport {\n formatDayLabel,\n formatMessageDateTime,\n formatMessageTime,\n isSameCalendarDay,\n parseMessageTime,\n readMessageCreatedAt,\n} from './message-time';\nimport { ThreadScrollToBottom } from './thread-scroll-to-bottom';\nimport {\n type AthenaChatTurnChanges,\n AthenaTurnChangesContext,\n AthenaTurnChangesSlot,\n} from './turn-changes';\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport { useCatalogQueryClient } from '../catalog/runtime-catalog';\nimport { isStatewireChannelLive } from '../runtime/statewire-lifecycle';\nimport {\n type AthenaChatContinueByVoice,\n ChatVoiceButton,\n ChatVoiceContinueOffer,\n ChatVoiceStatus,\n useComposerChatVoice,\n type AthenaChatVoiceOptions,\n} from './chat-voice-controls';\n\nexport type { AthenaChatContinueByVoice, AthenaChatVoiceOptions } from './chat-voice-controls';\n\nconst DEFAULT_COMPOSER_PLACEHOLDER = 'Type @ to tag an asset';\n\nfunction QuotePostMessageBridge() {\n // Inside the chat's root: with several chats in a window, ⌘L quotes into the one it belongs to.\n const marker = useRef<HTMLSpanElement | null>(null);\n useQuoteFromPostMessage({ scope: marker });\n return <span ref={marker} hidden />;\n}\n\nexport type { WelcomeSuggestion } from './athena-chat-welcome';\n\nexport interface AthenaChatProps {\n /** CSS class name for the root element. */\n className?: string;\n /** Welcome heading text. Defaults to \"Hello there!\" */\n welcomeMessage?: string;\n /** Welcome subheading text. */\n welcomeSubtext?: string;\n /**\n * Maximum width of the reading column (messages, welcome, composer).\n * Defaults to \"46rem\" — about 760 px, a comfortable measure for 15 px text.\n */\n maxWidth?: string;\n /**\n * Scroll anchoring for new turns. \"bottom\" (default) keeps the viewport\n * pinned to the end while the assistant streams — classic chat follow.\n * \"top\" pins the just-sent user message to the top of the viewport and\n * intentionally does NOT follow the streaming response (assistant-ui\n * disables autoScroll in that mode), so readers scroll at their own pace.\n */\n turnAnchor?: \"top\" | \"bottom\";\n /**\n * Marks the transcript read-only: Edit and Regenerate hide while Copy stays\n * available. For threads whose server rejects dispatch (e.g. legacy\n * pre-cutover conversations) — the runtime's static capability flags cannot\n * express a per-thread fence, so the host that knows passes it here.\n */\n readOnly?: boolean;\n /**\n * What sits above the composer for the run's plan. Defaults to\n * `<AthenaPlanStrip />`: the plan's progress and current step, opening to\n * the whole `write_todos` list. Pass your own element to replace it, or\n * `null` for none (a host that shows the plan elsewhere).\n */\n plan?: ReactNode;\n /**\n * The Athena app this chat runs in. With it, the chat says when the person\n * is driving the conversation from another of their apps (\"Driving on your\n * phone\") above the composer. Omit it in an app that is not one of Athena's\n * own and nothing shows.\n */\n surface?: ThreadDriverSurface;\n /**\n * \"Confirm with your passkey\" before an approval that lets anything run\n * (identity 0b.9): handed to the chat's approval card, which sends the\n * token it resolves as `decisionCheck`. An app on another origin than the\n * Athena web app passes `useAthenaBrowserDecisionConfirmer()`, which runs\n * the check in a browser tab on the web app. Omit it and approvals are\n * sent without a check, as before (report-only).\n */\n confirmDecision?: StatewireDecisionConfirmer;\n /** Additional tool UIs to register by name. */\n toolUIs?: Record<string, ToolCallMessagePartComponent>;\n /** Tools / Toolkits offered by the composer's `@` menu beside the asset\n * library. Defaults to the toolkits enabled on the provider. */\n mentionTools?: MentionTool[];\n /**\n * What the composer's `@` menu offers beside Tools / Toolkits (which follow `mentionTools`).\n * Defaults to the asset library: Favorites, Assets, Projects and Folders. Add `team` for people\n * (the workspace's members and groups; an Athena admin's people, ranked, as in Olympus), `agents`\n * to name agents for a message, `browse_profiles` and `drives`. The menu shows them in Athena's\n * order whatever order they are given in.\n *\n * With `agents`, choosing one names it for the message: a chip on the composer's To line, never\n * text, and the send names it to Athena (`addressed_agents`, on the run and on the message), as\n * Olympus's composer does. The person's own assistant and the agents the chat's agent picker lists\n * are offered, to Athena admins only for now, as in Olympus; Athena checks every agent a message\n * names. A person mention is the link Olympus writes (`mention://person?id=…&email=…&name=…`).\n */\n mentionCategories?: readonly AthenaChatMentionCategory[];\n /** Suggestion cards shown on the welcome screen. Pass `[]` to hide.\n * For workflow launchers outside AthenaChat, use `useSendMessage()`.\n */\n welcomeSuggestions?: WelcomeSuggestion[];\n /** Optional component overrides for message containers and key message parts. */\n components?: AthenaChatComponents;\n /**\n * The collapsed view (previously called the conversational view): the\n * agent's sentences stay in the transcript in the order it wrote them, each\n * run of tool calls and reasoning between them folds into a collapsed step\n * row that names what it did (\"Ran `git log`\"), a header counts the turn\n * (\"Working for 1m 12s\", \"Worked for 2m 30s\"), and the answer renders below.\n * Defaults to `true`; pass `false` to list every tool card inline in the\n * order it was called.\n */\n groupToolCalls?: boolean;\n /**\n * Extra composer toolbar content and send hooks. `toolbarStart` renders\n * after the attach button, `toolbarEnd` renders before the mic and Send.\n * Slot components render inside the chat's thread scope, so `useAthenaRunLive`\n * and `useAppendToComposer` work in them.\n */\n composer?: AthenaChatComposerSlots;\n /**\n * Built-in microphone dictation in the composer: a mic left of Send that\n * swaps the editor for a live waveform while recording, then puts the words\n * into the draft (Stop) or sends them (Send). Recording is transcribed by\n * Athena (Deepgram) once the user stops; the words land after a short\n * \"Transcribing…\" pause. Defaults to `true`. Pass `false` to remove it, or\n * options to pick the language or a custom speech engine.\n */\n dictation?: boolean | AthenaChatDictationOptions;\n /**\n * Realtime chat voice through the shared controller and lazy LiveKit media.\n * Available by default where the workspace and deployment enable voice.\n * `false` removes it; options select a voice model or supply a media adapter.\n * The default browser adapter loads its LiveKit dependency only on start.\n */\n voice?: boolean | AthenaChatVoiceOptions;\n /**\n * A \"Continue by voice\" offer for the open conversation, after a handover\n * the person sent in voice mode landed in this app. The composer shows one\n * button above the editor while voice is enabled and idle; tapping it starts\n * a call whose model opens by saying where things stand. `onDone` runs when\n * the person answers it (the tap, Not now, or a typed or dictated send):\n * clear the offer then, and when the conversation changes. `null` or absent:\n * no offer. A `readOnly` chat never shows it.\n */\n continueByVoice?: AthenaChatContinueByVoice | null;\n /**\n * The turn changes card: a finished assistant turn that changed files ends with Codex's card,\n * \"Edited N files +A −D\", Undo and View changes, and the first three files with theirs (\"Show N\n * more files\" for the rest). The SDK draws it and places it; the host reads each turn's changes\n * (`read`, once per finished turn, by the runs that answered it) and does what Undo and View\n * changes mean (`onUndo`, `onView`; `reviewScope` says whether View changes opens the chat's\n * changes or the turn's). Off unless `enabled`: absent, `null` or off, nothing renders and\n * nothing is read.\n */\n turnChanges?: AthenaChatTurnChanges | null;\n /**\n * Suggested follow-up prompts: once a run the person watched finishes with a reply, up to three\n * prompts they might type next show as chips just above the composer. A chip puts its text in the\n * composer and sends nothing; the chips go away once the person types or sends, or a new run\n * starts. A run that was stopped, failed or waits on the person gets none, and neither does a\n * conversation opened at rest. Athena writes them from the turn's last message and reply\n * (`POST /api/chat/follow-up-suggestions`, with the chat's own credential, one request per\n * finished turn, charged to the conversation); a failed request shows nothing. Defaults to\n * `false`: off, nothing is requested.\n */\n followUpSuggestions?: boolean;\n}\n\n/** What a host's `composer.onBeforeSend` hears of the message about to go. */\nexport interface AthenaChatBeforeSend {\n /** `send` starts a turn; `queue` waits behind the run that is live. */\n action: Extract<ComposerAction, 'send' | 'queue'>;\n /** Its words as typed (empty for a message of attachments or a quote alone). */\n text: string;\n}\n\nexport interface AthenaChatComposerSlots {\n /** The empty composer's hint (default \"Type @ to tag an asset\"). */\n placeholder?: string;\n /**\n * The hint while a run is live, when a message steers or queues instead of\n * starting a turn (\"Guide the agent while it works…\"); defaults to\n * `placeholder`.\n */\n runningPlaceholder?: string;\n /**\n * A row at the top of the composer, above the editor and inside its border: where Spaces shows\n * its running status and Follow Agent Operations switch (Athena Desktop's Follow Athena). Rendered\n * as given, above any voice offer, quote or attachment preview; absent, nothing changes.\n */\n aboveEditor?: ReactNode;\n /**\n * Toolbar contents after the attach button. In a composer too narrow for every chip they wrap\n * onto another row, so the mic, voice and Send stay in reach.\n */\n toolbarStart?: ReactNode;\n /** Toolbar contents before the mic and the send/stop control. */\n toolbarEnd?: ReactNode;\n /**\n * The composer's own attach button (the paperclip). `false` leaves it out, for a host that offers\n * attaching from a control of its own in a slot (`useAthenaComposerActions().openFilePicker`);\n * pasting and dropping files still attach them. Default `true`.\n */\n attachButton?: boolean;\n /**\n * The composer's own `@` button. `false` leaves it out, for a host that opens the `@` menu from a\n * control of its own in a slot (`useAthenaComposerActions().openMentionMenu`); typing `@` still\n * opens it. Default `true`.\n */\n mentionButton?: boolean;\n /**\n * Host work awaited before a message goes, however it is sent: Enter, the send button, or a\n * dictated send, once each. It hears whether the message starts a turn or queues, and its words.\n * Not for a message the chat outbox holds while Athena can't be reached (it goes later). A\n * rejection keeps the message in the composer, unsent.\n */\n onBeforeSend?: (context: AthenaChatBeforeSend) => void | Promise<void>;\n /**\n * Why the composer's controls that need Athena are off, while the host knows Athena can't be\n * reached (from its own reachability: Olympus's model, the desktop app's main process). Attach\n * (the paperclip), the `@` button, dictation's mic and voice then show disabled with this as their\n * tooltip, instead of failing once used, and come back as soon as it is cleared. Typing `@` still\n * opens the mention menu, which fetches nothing from Athena: what it can list without Athena (the\n * host's tools, what it already loaded) shows, and what would load from Athena says it needs a\n * connection (`NEEDS_CONNECTION`) instead of spinning. Typing goes on, and Send follows the chat\n * outbox (a host that has one holds what is sent until Athena is back). A file pasted or dropped\n * meanwhile is refused as before, by the chat outbox's own reachability. `null` or absent: on.\n */\n needsConnectionReason?: string | null;\n /**\n * The composer's `/` commands: typing `/` opens a menu of them, and picking\n * one runs it (`TiptapComposer`'s `slashCommands`). Absent or empty: `/` is\n * plain text.\n */\n slashCommands?: readonly ComposerSlashCommand[];\n}\n\nexport interface AthenaChatDictationOptions {\n /**\n * Speech engine; defaults to record-then-transcribe through Athena\n * (`createRecordedDictationEngine`). Pass `createWebSpeechDictationEngine()`\n * for the browser's live Web Speech API instead.\n */\n engine?: DictationEngine;\n /** BCP-47 language tag; defaults to the document language. */\n lang?: string;\n}\n\nexport interface AthenaChatMessagePartComponents {\n Text?: TextMessagePartComponent;\n Reasoning?: ReasoningMessagePartComponent;\n Empty?: EmptyMessagePartComponent;\n}\n\nexport interface AthenaChatComponents {\n UserMessage?: FC;\n AssistantMessage?: FC;\n AssistantActionBar?: FC<AthenaAssistantActionBarProps>;\n /**\n * Rendered in a leading column on every assistant turn (a small avatar or\n * mark). Without it there is no leading column: the reply sits flush with\n * the thread column and is told apart from the right-aligned user bubbles by\n * alignment alone.\n */\n AssistantAvatar?: FC;\n messageParts?: AthenaChatMessagePartComponents;\n}\n\nexport interface AthenaUserMessageProps {\n /**\n * Renders the message's text. Defaults to `UserMessageText`, which shows a\n * composer send exactly as it was typed (its `metadata.composer_markdown`\n * draft) and any other text with raw HTML and underscore emphasis left as\n * typed. A component given here receives the text as sent.\n */\n TextComponent?: TextMessagePartComponent;\n}\n\nexport interface AthenaAssistantActionBarProps {\n className?: string;\n}\n\nexport interface AthenaAssistantMessageProps {\n toolUIs: Record<string, ToolCallMessagePartComponent>;\n /** Leading-column content for the turn; no leading column at all when unset. */\n AvatarComponent?: FC;\n TextComponent?: TextMessagePartComponent;\n ReasoningComponent?: ReasoningMessagePartComponent;\n EmptyComponent?: EmptyMessagePartComponent;\n ActionBarComponent?: FC<AthenaAssistantActionBarProps>;\n /** The collapsed view (see `AthenaChatProps.groupToolCalls`). Defaults to `true`. */\n groupToolCalls?: boolean;\n}\n\nexport interface AthenaReasoningPartProps extends ReasoningMessagePartProps {\n TextComponent?: TextMessagePartComponent;\n}\n\ninterface AthenaChatDefaultComponentsContextValue {\n toolUIs: Record<string, ToolCallMessagePartComponent>;\n TextComponent: TextMessagePartComponent;\n /** The user bubble's text: a host's `messageParts.Text`, else `UserMessageText`. */\n UserTextComponent: TextMessagePartComponent;\n ReasoningComponent?: ReasoningMessagePartComponent;\n EmptyComponent: EmptyMessagePartComponent;\n ActionBarComponent: FC<AthenaAssistantActionBarProps>;\n AvatarComponent?: FC;\n groupToolCalls: boolean;\n}\n\nconst AthenaChatDefaultComponentsContext =\n createContext<AthenaChatDefaultComponentsContextValue | null>(null);\n\nconst AthenaReasoningTextComponentContext = createContext<TextMessagePartComponent | null>(null);\n\nconst useAthenaChatDefaultComponents = (): AthenaChatDefaultComponentsContextValue => {\n const value = useContext(AthenaChatDefaultComponentsContext);\n\n if (!value) {\n throw new Error('Athena default chat components must be used within AthenaChat.');\n }\n\n return value;\n};\n\nconst AthenaDefaultAssistantMessage: FC = () => {\n const {\n toolUIs,\n TextComponent,\n ReasoningComponent,\n EmptyComponent,\n ActionBarComponent,\n AvatarComponent,\n groupToolCalls,\n } = useAthenaChatDefaultComponents();\n\n return (\n <AthenaAssistantMessage\n toolUIs={toolUIs}\n AvatarComponent={AvatarComponent}\n TextComponent={TextComponent}\n ReasoningComponent={ReasoningComponent}\n EmptyComponent={EmptyComponent}\n ActionBarComponent={ActionBarComponent}\n groupToolCalls={groupToolCalls}\n />\n );\n};\n\nconst AthenaDefaultUserMessage: FC = () => {\n const { UserTextComponent } = useAthenaChatDefaultComponents();\n\n return <AthenaUserMessage TextComponent={UserTextComponent} />;\n};\n\nconst getReasoningTokensFromMetadata = (metadata: unknown): number | undefined => {\n if (!isRecord(metadata)) {\n return undefined;\n }\n\n const customMetadata = metadata.custom;\n if (!isRecord(customMetadata)) {\n return undefined;\n }\n\n const athenaMetadata = customMetadata._athena;\n if (!isRecord(athenaMetadata)) {\n return undefined;\n }\n\n const reasoningTokens = athenaMetadata.reasoningTokens;\n return typeof reasoningTokens === 'number' && Number.isFinite(reasoningTokens)\n ? reasoningTokens\n : undefined;\n};\n\nconst formatReasoningTokens = (reasoningTokens: number) =>\n `${reasoningTokens.toLocaleString('en-US')} ${reasoningTokens === 1 ? 'token' : 'tokens'}`;\n\nconst withNestedPtcMessages = (\n ToolUI: ToolCallMessagePartComponent\n): ToolCallMessagePartComponent => {\n const ToolUIWithNestedPtcMessages: ToolCallMessagePartComponent = (props) => {\n const nestedComponents = useNestedPtcComponents(ToolFallback);\n\n return (\n <>\n <ToolUI {...props} />\n <NestedPtcMessages components={nestedComponents} />\n </>\n );\n };\n\n return ToolUIWithNestedPtcMessages;\n};\n\nexport const AthenaChat: FC<AthenaChatProps> = (props) => {\n const queryClient = useCatalogQueryClient();\n return <QueryClientProvider client={queryClient}><AthenaChatContent {...props} /></QueryClientProvider>;\n};\n\nconst AthenaChatContent: FC<AthenaChatProps> = ({\n className,\n welcomeMessage = \"Hello there!\",\n welcomeSubtext = \"What can I help you with?\",\n maxWidth = \"46rem\",\n turnAnchor = \"bottom\",\n readOnly = false,\n plan,\n surface,\n confirmDecision,\n toolUIs,\n mentionTools,\n mentionCategories = ATHENA_CHAT_MENTION_CATEGORIES,\n welcomeSuggestions = DEFAULT_WELCOME_SUGGESTIONS,\n components,\n groupToolCalls = true,\n composer: composerSlots,\n dictation = true,\n voice = true,\n continueByVoice = null,\n turnChanges = null,\n followUpSuggestions = false,\n}) => {\n const athenaConfig = useAthenaConfig();\n const authState = useContext(AthenaAuthContext);\n // The chat names agents when its host offers the Agents category.\n const namesAgents = mentionCategories.includes('agents');\n // The chat surface is per thread. `AthenaProvider` keeps the host's\n // children mounted across a thread switch and swaps only the client under\n // them, so what used to reset with the whole tree — the composer draft, the\n // viewport's scroll position, the approval card and banner state, a caught\n // render crash — is reset here instead, keyed on the attached thread (the\n // id the provider publishes together with that thread's client, so the\n // fresh surface never renders against the previous thread's runtime).\n const statewireThreadId = useContext(AthenaStatewireThreadIdContext);\n // A refusal whose way on is a new session (a send in the other mode of the\n // session's collab agent) offers one in thread-list mode.\n const startNewSession = useAthenaStatewireThreadList()?.newThread;\n // The mention menu's GraphQL credentials: the backend and credential the\n // provider resolved. `athenaConfig` keeps its identity across token\n // rotations (its `token` is a getter over a ref — see useAthenaConfigValue),\n // so this object is stable too. The mention store lists `accessToken` among\n // its memo dependencies, so it rebuilds (and refetches its lists) on the\n // composer's next render after a rotation; the getter is what hands the\n // rotated token to any fetch before that render. With neither token nor\n // API key the fetch rides the same-origin session cookie, as the SDK's\n // upload and thread REST calls do.\n const mentionCredentials = useMemo<MentionAuthContext>(\n () => ({\n backendUrl: athenaConfig.backendUrl,\n appUrl: athenaConfig.appUrl,\n apiKey: athenaConfig.apiKey,\n credentials: 'include',\n userId: authState?.user?.userId,\n get accessToken() {\n return athenaConfig.token ?? undefined;\n },\n getAccessToken: async () => (await athenaConfig.getToken?.()) ?? undefined,\n renewAccessToken: async () => (await athenaConfig.getToken?.({ force: true })) ?? undefined,\n }),\n [athenaConfig, authState?.user?.userId],\n );\n // One `/me` read: the workspace mentions search, and the viewer's agora id\n // the answer labels need (\"for you\"). It is keyed by the credential it is\n // read with (the provider's token getter among it), so an API-key switch or\n // a getter now signing in someone else reads it again.\n const account = useAccountIdentity(mentionCredentials, { tokenGetter: athenaConfig.getToken });\n const accountWorkspaceId = account.workspaceId;\n // Names this page made under another identity are not this person's to send: every chip,\n // staged send and send on its way goes once someone else is signed in.\n const accountUserId = account.userId;\n useEffect(() => {\n if (namesAgents && accountUserId) keepDeepAgentNamedAgentsForIdentity(accountUserId);\n }, [accountUserId, namesAgents]);\n // So are the references attached to the next message (`useAttachToChat`).\n useEffect(() => {\n if (accountUserId) keepAttachedReferencesForIdentity(accountUserId);\n }, [accountUserId]);\n const mentionAuth = useMemo<MentionAuthContext>(\n () => ({\n ...mentionCredentials,\n workspaceId: mentionCredentials.workspaceId ?? accountWorkspaceId,\n }),\n [mentionCredentials, accountWorkspaceId],\n );\n const providerMentionTools = useMemo<MentionTool[]>(() => {\n const uniqueToolkitIds = Array.from(new Set(athenaConfig.enabledToolkits));\n\n return uniqueToolkitIds.map((id) => {\n const toolkit = getToolkitDisplayInfo(id);\n\n return {\n id: toolkit.id,\n name: toolkit.name,\n description: toolkit.description,\n icon: toolkit.icon,\n type: 'toolkit',\n };\n });\n }, [athenaConfig.enabledToolkits]);\n const tools = mentionTools ?? providerMentionTools;\n const mergedToolUIs = useMemo(\n () => ({\n append_markdown_to_athena_document: AppendDocumentToolUI,\n read_full_asset: ReadAssetToolUI,\n read_asset: ReadAssetToolUI,\n ...TOOL_UI_REGISTRY,\n ...toolUIs,\n }),\n [toolUIs],\n );\n\n const textComponent = components?.messageParts?.Text ?? TiptapText;\n const userTextComponent = components?.messageParts?.Text ?? UserMessageText;\n const reasoningComponent = components?.messageParts?.Reasoning;\n const emptyComponent = components?.messageParts?.Empty ?? AthenaAssistantMessageEmpty;\n const actionBarComponent = components?.AssistantActionBar ?? AthenaAssistantActionBar;\n const avatarComponent = components?.AssistantAvatar;\n\n const defaultComponentsContextValue = useMemo<AthenaChatDefaultComponentsContextValue>(\n () => ({\n toolUIs: mergedToolUIs,\n TextComponent: textComponent,\n UserTextComponent: userTextComponent,\n ReasoningComponent: reasoningComponent,\n EmptyComponent: emptyComponent,\n ActionBarComponent: actionBarComponent,\n AvatarComponent: avatarComponent,\n groupToolCalls,\n }),\n [\n actionBarComponent,\n avatarComponent,\n emptyComponent,\n groupToolCalls,\n mergedToolUIs,\n reasoningComponent,\n textComponent,\n userTextComponent,\n ],\n );\n // One value while the host's settings and hooks stay the same, so no turn re-renders for a host\n // render that changed nothing of them.\n const turnChangesEnabled = turnChanges?.enabled === true;\n const turnChangesScope = turnChanges?.reviewScope;\n const turnChangesRead = turnChanges?.read;\n const turnChangesView = turnChanges?.onView;\n const turnChangesUndo = turnChanges?.onUndo;\n const turnChangesValue = useMemo<AthenaChatTurnChanges | null>(\n () =>\n turnChangesEnabled && turnChangesRead && turnChangesView && turnChangesUndo\n ? {\n enabled: true,\n ...(turnChangesScope !== undefined && { reviewScope: turnChangesScope }),\n read: turnChangesRead,\n onView: turnChangesView,\n onUndo: turnChangesUndo,\n }\n : null,\n [turnChangesEnabled, turnChangesScope, turnChangesRead, turnChangesView, turnChangesUndo],\n );\n const AssistantMessageComponent = components?.AssistantMessage ?? AthenaDefaultAssistantMessage;\n const UserMessageComponent = components?.UserMessage ?? AthenaDefaultUserMessage;\n const messageComponents = useMemo(\n () => ({\n UserMessage: UserMessageComponent,\n AssistantMessage: AssistantMessageComponent,\n }),\n [AssistantMessageComponent, UserMessageComponent],\n );\n\n return (\n <AthenaChatDefaultComponentsContext.Provider value={defaultComponentsContextValue}>\n <AthenaTurnChangesContext.Provider value={turnChangesValue}>\n {/* Contain render crashes to the chat pane (telemetry + retry) instead of\n unmounting the integrator's subtree. */}\n <AthenaChatErrorBoundary key={statewireThreadId ?? undefined}>\n {/* The calls the run waits on a person's approval for, read once for\n every turn's steps and subagent card (read-only: the approval\n card answers). */}\n <StatewireApprovalWaitProvider>\n {/* The running subagent lanes an open transcript drawer shows, which\n the history edge's window sync follows on the wire. */}\n <DeepAgentLaneFollowScope>\n {/* Every tool call in the thread — generic fallback, dedicated tool\n UI, nested PTC sub-call — renders as the one-line thread row. */}\n <ToolFallbackAppearanceProvider appearance=\"thread\">\n <MentionAuthCtx.Provider value={mentionAuth}>\n <ChatThreadShell\n overlay={\n <>\n <ThreadLoadingOverlay />\n {/* The session on screen is marked read for the viewer\n (thread-list mode), as Olympus's chat does; its sentinel\n covers the panel, so a hidden chat marks nothing. */}\n <MarkViewedThreadRead />\n </>\n }\n panelClassName={cn(\n 'aui-root aui-thread-root @container relative flex h-full flex-col bg-background',\n className,\n )}\n maxWidth={maxWidth}\n turnAnchor={turnAnchor}\n readOnly={readOnly}\n arrivalThreadId={statewireThreadId}\n viewerUserId={account.userId ?? null}\n // Persistent \"waiting on you\" strip above the viewport; the approval\n // card it points at stays in the sticky footer below. Above it, when\n // the thread opened from this device offline, as of when.\n banners={\n <>\n <OfflineSnapshotBanner className=\"px-4 pt-3\" />\n <WaitingOnYouBanner className=\"px-4 pt-3\" />\n </>\n }\n // The composer is the sticky footer inside this viewport, so\n // whatever moves the viewport's content moves the composer too;\n // both guards keep it put, as in Olympus's thread (#28797, #26018).\n // `overflow-x-hidden`: a scroll container cannot leave one axis\n // `visible`, so with `overflow-x-auto` anything wider than the\n // column scrolled the whole thread, composer included, sideways\n // under a trackpad. Wide tables and code scroll in their own boxes.\n // `overscroll-y-none`: a fling that reaches the top or bottom\n // neither chains into the page nor starts the macOS elastic\n // bounce, either of which carried the composer off its place.\n viewportClassName=\"aui-thread-viewport relative flex flex-1 flex-col overflow-x-hidden overflow-y-scroll overscroll-y-none scroll-smooth px-4 pt-4\"\n contentClassName=\"flex w-full flex-1 flex-col\"\n viewportOverlay={\n <>\n {/* A conversation handed over to this app opens where it was being read. */}\n <HandoffCursorReveal threadId={statewireThreadId} />\n <ThreadScrollToTop />\n </>\n }\n welcome={\n <AthenaChatWelcome welcomeMessage={welcomeMessage} welcomeSubtext={welcomeSubtext} />\n }\n beforeMessages={<StatewireHistoryEdge className=\"aui-thread-history-edge\" />}\n components={messageComponents}\n runningIndicator={null}\n // The scroll-to-bottom pill, centred just above the footer as\n // Spaces places it: over no footer content (queued messages,\n // banners) and not in the corner where the reader's own messages end.\n scrollToBottom={<ThreadScrollToBottom />}\n viewportFooterClassName=\"aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-3xl bg-background pt-4 pb-4 md:pb-6\"\n viewportFooter={\n <>\n {/* Empty state: the suggestion cards sit directly above the\n composer (the greeting stays centred in the viewport). */}\n {welcomeSuggestions.length > 0 && (\n <ThreadPrimitive.Empty>\n <AthenaChatWelcomeSuggestions suggestions={welcomeSuggestions} />\n </ThreadPrimitive.Empty>\n )}\n {surface && <DrivingOnChip here={surface} />}\n <StatewireConnectionBanner />\n <StatewireErrorBanner onStartNewSession={startNewSession} />\n <StatewireRunRefusalNotice onStartNewSession={startNewSession} />\n {/* The agent's typed questions and approvals answer in their\n own cards, as on the web. */}\n <StatewireApprovalCard\n confirmDecision={confirmDecision}\n typedInterrupts={statewireTypedInterrupts}\n />\n {/* A frontend tool marked as a write asks before its first\n call in the conversation runs. */}\n <StatewireClientToolConsentCard />\n {plan === undefined ? <AthenaPlanStrip className=\"mx-3\" /> : plan}\n {/* Queued rows render mention chips, which need the app URL\n to link to their asset. */}\n <StatewireQueuedMessages />\n <AttachmentProvider>\n <QuoteProvider>\n <QuotePostMessageBridge />\n <AthenaChatComposer\n tools={tools}\n mentionCategories={mentionCategories}\n slots={composerSlots}\n dictation={dictation}\n voice={readOnly ? false : voice}\n continueByVoice={readOnly ? null : continueByVoice}\n welcomeSuggestionCount={welcomeSuggestions.length}\n followUpSuggestions={followUpSuggestions && !readOnly}\n />\n </QuoteProvider>\n </AttachmentProvider>\n </>\n }\n />\n </MentionAuthCtx.Provider>\n </ToolFallbackAppearanceProvider>\n </DeepAgentLaneFollowScope>\n </StatewireApprovalWaitProvider>\n </AthenaChatErrorBoundary>\n </AthenaTurnChangesContext.Provider>\n </AthenaChatDefaultComponentsContext.Provider>\n );\n};\n\nconst THREAD_VIEWPORT_ATTR = 'data-aui-thread-viewport';\n\nconst useScrollToTop = () => {\n const [isAtTop, setIsAtTop] = useState(true);\n const [buttonEl, setButtonEl] = useState<HTMLButtonElement | null>(null);\n\n const containerRef = useCallback((node: HTMLButtonElement | null) => {\n setButtonEl(node);\n }, []);\n\n const getViewport = useCallback((): HTMLElement | null => {\n if (!buttonEl) return null;\n return buttonEl.closest(`[${THREAD_VIEWPORT_ATTR}]`) as HTMLElement | null;\n }, [buttonEl]);\n\n useEffect(() => {\n const viewport: HTMLElement | null = getViewport();\n if (!viewport) return;\n\n const handleScroll = () => {\n setIsAtTop(viewport.scrollTop <= 50);\n };\n\n handleScroll();\n viewport.addEventListener('scroll', handleScroll, { passive: true });\n return () => viewport.removeEventListener('scroll', handleScroll);\n }, [getViewport]);\n\n const handleClick = useCallback(() => {\n const viewport: HTMLElement | null = getViewport();\n if (!viewport) return;\n viewport.scrollTo({ top: 0, behavior: 'smooth' });\n }, [getViewport]);\n\n return { isAtTop, containerRef, handleClick };\n};\n\nconst ThreadScrollToTop: FC = () => {\n const { isAtTop, containerRef, handleClick } = useScrollToTop();\n const isEmpty = useAuiState((s) => s.thread.isEmpty);\n\n if (isEmpty) return null;\n\n return (\n // At the viewport's right edge, beside the text column: over the column\n // it would cover the line being read.\n <div className=\"pointer-events-none sticky top-0 z-10 flex h-0 w-full justify-end\">\n <TooltipIconButton\n ref={containerRef}\n tooltip=\"Scroll to top\"\n variant=\"outline\"\n className={cn(\n 'aui-thread-scroll-to-top pointer-events-auto absolute top-2 right-0 size-8 rounded-full bg-background/90 shadow-sm dark:bg-background dark:hover:bg-accent',\n isAtTop && 'invisible',\n )}\n onClick={handleClick}\n >\n <ArrowUpIcon />\n </TooltipIconButton>\n </div>\n );\n};\n\n/**\n * A category a host can offer in AthenaChat's `@` menu (`AthenaChatProps.mentionCategories`).\n * Tools and Toolkits are not among them: they follow `mentionTools`.\n */\nexport type AthenaChatMentionCategory = Exclude<MentionRootCategory, 'tools' | 'toolkits'>;\n\n/**\n * The categories AthenaChat's `@` menu offers by default: the asset library. A host adds people\n * (`team`), agents (`agents`), browse profiles or drives through `mentionCategories`. The Tools /\n * Toolkits categories are added when the host (or the provider's enabled toolkits) offers any.\n */\nconst ATHENA_CHAT_MENTION_CATEGORIES: readonly AthenaChatMentionCategory[] = [\n 'favorites',\n 'assets',\n 'projects',\n 'folders',\n];\n\n/**\n * The order AthenaChat's `@` menu lists its categories in, Olympus's (Toolkits ahead of Tools, as\n * AthenaChat always listed them): the library, the host's tools, then Team, Agents and Drives.\n */\nconst ATHENA_CHAT_MENTION_ORDER: readonly MentionRootCategory[] = [\n 'favorites',\n 'assets',\n 'projects',\n 'browse_profiles',\n 'folders',\n 'toolkits',\n 'tools',\n 'team',\n 'agents',\n 'drives',\n];\n\n/**\n * AthenaChat's composer: the shared chat-ui Tiptap editor and `@` mention menu\n * with AthenaChat's quote and attachment pills composed into the send.\n *\n * A draft with a quote or attachment pills — text or not — is intercepted on\n * submit and dispatched as one composed message through the composer runtime,\n * the path the server-owned queue observes, so a mid-run submit queues like\n * any other send. Pasted images upload into the pills through the same intake\n * as the paperclip and the drop zone, and every submit path (Enter, the send\n * button) waits for an in-flight upload so a send never leaves without its\n * attachment. The send control resolves send / queue / stop through the\n * shared chat-ui logic.\n *\n * The chrome is the shared dock's paper appearance (`data-appearance=\"paper\"`\n * on `.aui-composer-root`): the drop zone reports drag-over into\n * `data-drag-active`, the first focus in a browser shows the Enter /\n * Shift+Enter hint until the first send, and a thread that mounts empty\n * brings the composer in last, after the greeting and the suggestion cards.\n */\nconst AthenaChatComposer: FC<{\n tools: MentionTool[];\n /** The categories the host offers beside Tools / Toolkits (`AthenaChatProps.mentionCategories`). */\n mentionCategories: readonly AthenaChatMentionCategory[];\n slots?: AthenaChatComposerSlots;\n dictation: boolean | AthenaChatDictationOptions;\n voice: boolean | AthenaChatVoiceOptions;\n continueByVoice: AthenaChatContinueByVoice | null;\n /** How many suggestion cards precede the composer's entrance in the empty state. */\n welcomeSuggestionCount: number;\n /** Chips of follow-up prompts above the composer after a finished turn (`AthenaChatProps`). */\n followUpSuggestions: boolean;\n}> = ({\n tools,\n mentionCategories,\n slots,\n dictation,\n voice: voiceOptions,\n continueByVoice,\n welcomeSuggestionCount,\n followUpSuggestions,\n}) => {\n const aui = useAui();\n const threadId = useAthenaStatewireThreadId();\n const noteAppendedSend = useContext(AthenaThreadListAppendedSendContext);\n const { appUrl } = useAthenaConfig();\n const { attachments, clearAttachments, isUploading, notice: attachNotice, setNotice: setAttachNotice } =\n useAttachments();\n const { quote, clearQuote } = useQuote();\n // What the next message carries as attached references (`useAttachToChat`): chips above the\n // editor, sent in the message's own metadata, never in its text.\n const attachedReferences = usePendingAttachedReferences(threadId);\n const attachedReferencesComposerProps = useAttachedReferencesComposerProps(threadId);\n const { attachFiles } = useAttachFiles();\n const sessionLane = useStatewireSessionLane();\n const composerRef = useRef<TiptapComposerHandle>(null);\n const [hasText, setHasText] = useState(false);\n // Why a send stayed in the composer (something in it can't wait in the chat outbox), or why a\n // file was not attached (picked while Athena can't be reached); gone once the draft changes.\n const [composerNotice, setComposerNotice] = useState<string | null>(null);\n const onDraftStateChange = useCallback(\n (next: boolean) => {\n setHasText(next);\n setComposerNotice(null);\n setAttachNotice(null);\n },\n [setAttachNotice],\n );\n const notice = composerNotice ?? attachNotice;\n // The host's reason the controls that need Athena are off right now, if any.\n const needsConnectionReason = slots?.needsConnectionReason || null;\n const isRunning = useAuiState((state) => state.optional.thread?.isRunning ?? false);\n // The hint follows the live-run verdict other live surfaces read\n // (`useAthenaRunLive`): `isRunning` follows the presented status and blinks\n // off for a first dial's attach round-trip, which would flash the idle hint.\n const connection = useDeepAgentConnection();\n const { voice, active: voiceActive, enabled: voiceEnabled, audioRef } = useComposerChatVoice({ options: voiceOptions });\n const runLive = useAuiState((state) => {\n const thread = state.optional.thread;\n return thread ? readRunLive(thread, connection) : false;\n });\n const [dragActive, setDragActive] = useState(false);\n const keyboardHint = useComposerKeyboardHint();\n const reducedMotion = usePrefersReducedMotion();\n // The staged entrance belongs to the empty state only: a composer that\n // mounts over an existing transcript is simply there.\n const isEmpty = useAuiState((state) => state.thread.isEmpty);\n const [mountedEmpty] = useState(() => isEmpty);\n const entrance = welcomeEntrance(\n welcomeComposerDelayMs(welcomeSuggestionCount),\n reducedMotion || !mountedEmpty,\n );\n\n // Dictation: the hook is inert until `start()`, so it mounts even when the\n // mic is turned off; `isSupported` hides the control where the engine is\n // missing (Firefox) instead of rendering a button that cannot work.\n const dictationEnabled = dictation !== false;\n const dictationOptions = typeof dictation === 'object' ? dictation : undefined;\n // Words join the draft that existed before recording (manual edits are\n // kept) as typed plain text in the editor, so they are never read as\n // Markdown and a send delivers them, and the typed draft, as typed.\n const appendSpokenText = useCallback(\n (spoken: string) => {\n if (!spoken) return;\n const composer = composerRef.current;\n if (composer?.appendText) {\n composer.appendText(spoken);\n return;\n }\n aui.composer.setText(composeDictationDraft(aui.composer.getState().text ?? '', spoken));\n },\n [aui],\n );\n const dictationEngine = useAthenaDictationEngine(dictationOptions?.engine);\n const dictationCtl = useDictation({\n engine: dictationEngine,\n lang: dictationOptions?.lang,\n // A recognizer that gives up on its own (silence window) still hands\n // over what it heard instead of dropping the words with the session.\n onAutoEnd: appendSpokenText,\n });\n const recording = dictationEnabled && dictationCtl.isActive;\n const showMic = dictationEnabled && dictationCtl.isSupported && !voiceActive;\n // A host that turns dictation off mid-session takes the controls away with\n // it; release the microphone and the recognizer rather than letting them\n // run on with no way to stop them.\n const { isActive: dictationActive, cancel: cancelDictation } = dictationCtl;\n useEffect(() => {\n if (!dictationEnabled && dictationActive) cancelDictation();\n }, [cancelDictation, dictationActive, dictationEnabled]);\n\n // The host's categories in Athena's order, with Tools / Toolkits where the host offers any. A host\n // that hands a new array each render rebuilds nothing: the menu keys its data on the list's words.\n const rootCategories = useMemo<readonly MentionRootCategory[]>(() => {\n const offered = new Set<string>(mentionCategories);\n if (tools.some((tool) => tool.type === 'toolkit')) offered.add('toolkits');\n if (tools.some((tool) => tool.type === 'tool')) offered.add('tools');\n return ATHENA_CHAT_MENTION_ORDER.filter((category) => offered.has(category));\n }, [mentionCategories, tools]);\n const namesAgents = rootCategories.includes('agents');\n // Whether the viewer is an Athena admin, read only for a menu that offers people or agents: Team\n // ranks an admin's people, and the Agents section is an admin's for now, as in Olympus.\n const viewerIsAdmin = useAthenaViewerIsAdmin({\n enabled: namesAgents || rootCategories.includes('team'),\n });\n // Choosing past the limit says which agents were left out, once the chosen item's `@query` has\n // left the draft (a draft change clears the composer's notice).\n const sayNamedAgentsLimit = useCallback((message: string) => {\n queueMicrotask(() => setComposerNotice(message));\n }, []);\n const chatAgents = useAthenaChatAgentsMention({\n threadId,\n enabled: namesAgents,\n isAdmin: viewerIsAdmin,\n onLimit: sayNamedAgentsLimit,\n });\n const focusComposer = useCallback(() => composerRef.current?.focus?.(), []);\n // What a host's own controls in the slots run, as the attach and `@` buttons do.\n const filePickerRef = useRef<HTMLInputElement>(null);\n const composerActions = useMemo<AthenaChatComposerActions>(\n () => ({\n openFilePicker: () => {\n if (needsConnectionReason) return;\n filePickerRef.current?.click();\n },\n openMentionMenu: () => composerRef.current?.openMentionMenu?.(),\n needsConnectionReason,\n }),\n [needsConnectionReason],\n );\n // A follow-up chip's words go into the (empty) draft as typed plain text, with the caret after\n // them; nothing is sent.\n const pickFollowUp = useCallback(\n (text: string) => {\n const composer = composerRef.current;\n if (composer?.appendText) composer.appendText(text);\n else aui.composer.setText(text);\n composer?.focus?.();\n },\n [aui],\n );\n\n // The submit paths are captured once by the editor's keybinding, so they\n // read the current draft extras through refs.\n const attachmentsRef = useRef(attachments);\n attachmentsRef.current = attachments;\n const quoteRef = useRef(quote);\n quoteRef.current = quote;\n const attachedReferencesRef = useRef(attachedReferences);\n attachedReferencesRef.current = attachedReferences;\n // Attached references alone send nothing (a message needs words), so they are not a draft here.\n const hasExtras = attachments.length > 0 || quote !== null;\n\n // The host's work before a message goes runs in the editor's own submit, which Enter, the send\n // button and the handle all go through, so each send runs it once whichever way it went; the\n // action is the send control's verdict at that moment (a draft for a live voice conversation\n // goes into it; any other queues behind a live run).\n const sendStateRef = useRef({ isRunning, liveVoice: false });\n sendStateRef.current = { isRunning, liveVoice: voice.phase === 'live' && !hasExtras };\n const onBeforeSend = slots?.onBeforeSend;\n const beforeSubmit = useCallback(\n async ({ text }: { text: string }) => {\n if (!onBeforeSend) return;\n const { isRunning: running, liveVoice } = sendStateRef.current;\n const action = liveVoice\n ? 'send'\n : resolveComposerAction({ hasDraft: true, isRunning: running });\n if (action === 'stop') return;\n await onBeforeSend({ action, text });\n },\n [onBeforeSend],\n );\n\n // A submit during an upload parks until the pills have the asset; the\n // waiters resolve on the render that turns `isUploading` off, by which\n // point `attachmentsRef` holds the uploaded asset.\n const isUploadingRef = useRef(isUploading);\n isUploadingRef.current = isUploading;\n const uploadWaitersRef = useRef<Array<() => void>>([]);\n useEffect(() => {\n if (isUploading) return;\n const waiters = uploadWaitersRef.current;\n uploadWaitersRef.current = [];\n for (const resolve of waiters) resolve();\n }, [isUploading]);\n const waitForHostUploads = useCallback(() => {\n if (!isUploadingRef.current) return;\n return new Promise<void>((resolve) => {\n uploadWaitersRef.current.push(resolve);\n });\n }, []);\n\n const sendComposed = useCallback(\n (editorSend: ComposerSend): boolean => {\n const send = buildComposedSend({\n attachments: attachmentsRef.current,\n quote: quoteRef.current,\n send: editorSend,\n appUrl,\n });\n if (!send) return false;\n // The editor's text goes out as typed; the same message built from the\n // editor's Markdown draft is what a send statewire hands back loads, and\n // what the message carries as its composer markdown.\n prepareComposerSend({ threadId, ...send });\n // The agents it names (its To line): staged right before it leaves.\n if (namesAgents) {\n stageComposerNamedAgents({\n threadId,\n text: send.text,\n agents: readDeepAgentNamedAgents(threadId),\n });\n }\n // The references attached to it ride its metadata, staged the same way and remembered with\n // its text, so a send statewire hands back brings its chips back.\n const references = stageThreadAttachedReferencesForSend({ threadId, text: send.text });\n if (references.length > 0) {\n // A message with attachments carries its metadata (the references, and the draft and\n // agents staged with them) on the message itself: the composer runtime's send leaves it to\n // `getMessageMetadata`, which only the monorepo's patch of `@assistant-ui/react-statewire`\n // reads, so on the stock package an app installs from npm the references never left. It\n // waits for its own run, as the composer's queued send would (statewire's queue lane):\n // Athena tells the agent about attachments when a run starts, and a message folded into a\n // running turn would join a run that has already started.\n aui.thread().append({\n role: 'user',\n content: [{ type: 'text', text: send.text }],\n metadata: { custom: takeStagedMessageMetadata(threadId) ?? {} },\n });\n aui.composer.setText('');\n // An append raises no `composer.send`, which the conversation list watches to move the\n // row to the top (and list a new chat) at once: tell it here.\n noteAppendedSend?.(send.text);\n } else {\n // An `auto` send: mid-run the host's prioritizer folds it into the run, stops the run for\n // it or queues it; idle sends dispatch immediately.\n aui.composer.setText(send.text);\n aui.composer.send(autoComposerSendOptions(aui.thread().getState().isRunning));\n }\n clearAttachments();\n clearQuote();\n return true;\n },\n [appUrl, aui, clearAttachments, clearQuote, namesAgents, noteAppendedSend, threadId],\n );\n\n // Consumes the editor's draft (possibly empty) only when there are extras\n // to compose with it.\n // A message the composer accepted (sent, held in the outbox, or taken into\n // the live call) answers the host's \"Continue by voice\" offer.\n const continueByVoiceRef = useRef(continueByVoice);\n continueByVoiceRef.current = continueByVoice;\n const settleContinueByVoice = useCallback(() => continueByVoiceRef.current?.onDone(), []);\n const { onSubmitted: onKeyboardHintSubmitted } = keyboardHint;\n const handleComposerSubmitted = useCallback(() => {\n onKeyboardHintSubmitted();\n settleContinueByVoice();\n }, [onKeyboardHintSubmitted, settleContinueByVoice]);\n const interceptSubmit = useCallback(\n async (text: string, draftMarkdown: string) => {\n // Rich extras keep their structured normal-run send. Plain text enters\n // the live conversation; a refusal falls back to the normal queue/outbox.\n if (\n attachmentsRef.current.length > 0 ||\n quoteRef.current !== null ||\n (attachedReferencesRef.current.length > 0 && text.length > 0)\n ) {\n return sendComposed({ text, draftMarkdown });\n }\n return voice.phase === 'live' && text.length > 0 ? voice.sendUserText(text) : false;\n },\n [sendComposed, voice.phase, voice.sendUserText],\n );\n\n // Pills, a quote and attached references ride the composed send, and wait with it in the chat\n // outbox while sends are on hold: the pills are files already uploaded to Athena, the quote is\n // text, and the references ride the held message's metadata. References count only with words\n // to send: alone they are not a message, so the composer neither sends nor runs the host's\n // per-send work for them.\n const hasPendingExtras = useCallback(\n () =>\n attachmentsRef.current.length > 0 ||\n quoteRef.current !== null ||\n (attachedReferencesRef.current.length > 0 &&\n Boolean(composerRef.current?.captureSend?.()?.text ?? aui.composer.getState().text)),\n [aui],\n );\n const holdPendingExtras = useCallback(\n ({\n outbox,\n send,\n attachments,\n addressedAgents,\n }: {\n outbox: ChatOutbox;\n send: ComposerSend;\n attachments: ChatOutboxAttachment[];\n addressedAgents?: readonly string[];\n }): boolean => {\n const held = holdComposedSend({\n outbox,\n attachments: attachmentsRef.current,\n carried: attachments,\n quote: quoteRef.current,\n send,\n appUrl,\n // The agents it names ride its message.\n ...(addressedAgents && { addressedAgents }),\n // So do the references attached to it.\n attachedReferences: attachedReferencesRef.current,\n });\n if (!held) return false;\n clearAttachments();\n clearQuote();\n clearAttachedReferences(threadId);\n return true;\n },\n [appUrl, clearAttachments, clearQuote, threadId],\n );\n\n // Pasted images go through the pills' intake; drops are left to the\n // enclosing ComposerDropZone.\n const fileIntake = useMemo<ComposerFileIntake>(\n () => ({\n onPaste: (files) => {\n void attachFiles(files, 'paste');\n },\n }),\n [attachFiles],\n );\n\n // Stop: the spoken words join the draft and the editor comes back for review.\n const stopDictation = useCallback(async () => {\n appendSpokenText((await dictationCtl.stop()).text);\n }, [appendSpokenText, dictationCtl]);\n\n // Send: same merge, then dispatched the way the send button would — through\n // the composed-message path when pills are pending, else straight through\n // the composer runtime (a mid-run send queues; see sendComposed).\n const sendDictation = useCallback(async () => {\n const { text: spoken, error } = await dictationCtl.stop();\n // The words join the editor's draft before anything else, so a failed\n // transcription or a host hook that rejects leaves them in the composer\n // for review instead of losing them.\n appendSpokenText(spoken);\n // A failed transcription has nothing to send; keep whatever landed in the\n // draft for review next to the error notice rather than dispatching a\n // message that is missing the dictated words.\n if (error) return;\n // While the sign-in provider is still resolving who is signed in, the\n // chat's session lane is pending and refuses a send unsent: the message\n // waits for the lane in the draft, as a typed send does.\n if (sessionLane?.isPending()) await sessionLane.whenKnown();\n // What the send button would deliver: the typed text exactly as typed\n // with the dictated words after it, and the draft it came from.\n const send: ComposerSend = composerRef.current?.captureSend?.() ?? {\n text: aui.composer.getState().text ?? '',\n draftMarkdown: aui.composer.getState().text ?? '',\n };\n const extras =\n attachmentsRef.current.length > 0 ||\n quoteRef.current !== null ||\n (attachedReferencesRef.current.length > 0 && send.text.length > 0);\n if (!send.text && !extras) return;\n const action = resolveComposerAction({ hasDraft: true, isRunning });\n if (action === 'stop') return;\n try {\n await slots?.onBeforeSend?.({ action, text: send.text });\n } catch (error) {\n athenaDiagnostics.emit('composer.dictation', {\n level: 'warn',\n data: {\n phase: 'before_send_rejected',\n error: error instanceof Error ? error.message : String(error),\n },\n });\n return;\n }\n // The agents the dictated message names: the To line's chips as it goes.\n const namedAgents = namesAgents ? readDeepAgentNamedAgents(threadId) : [];\n // The host let the dictated message go: it answers a \"Continue by voice\" offer.\n settleContinueByVoice();\n if (extras) {\n sendComposed(send);\n return;\n }\n prepareComposerSend({ threadId, ...send });\n if (namesAgents) stageComposerNamedAgents({ threadId, text: send.text, agents: namedAgents });\n aui.composer.setText(send.text);\n aui.composer.send(autoComposerSendOptions(aui.thread().getState().isRunning));\n }, [\n appendSpokenText,\n aui,\n dictationCtl,\n isRunning,\n namesAgents,\n sendComposed,\n sessionLane,\n settleContinueByVoice,\n slots,\n threadId,\n ]);\n\n const composer = (\n <ComposerDropZone onDragActiveChange={setDragActive}>\n {/* The replicated chat transcript captions this live synthesized audio. */}\n <audio ref={audioRef} autoPlay playsInline />\n {/* The file picker a host's own control opens (`useAthenaComposerActions`). */}\n <input\n ref={filePickerRef}\n type=\"file\"\n multiple\n className=\"hidden\"\n aria-hidden\n tabIndex={-1}\n onChange={(event) => {\n const input = event.currentTarget;\n const files = input.files ? Array.from(input.files) : [];\n // Reset so the same file can be picked again.\n input.value = '';\n if (files.length > 0) void attachFiles(files, 'paperclip');\n }}\n />\n {/* React delivers `onFocus` as focusin, so the editor's focus reaches\n this wrapper; the same element carries the staged entrance. */}\n <div\n className={cn('aui-composer-entrance', entrance.className)}\n style={entrance.style}\n onFocus={keyboardHint.onFocus}\n >\n <ChatComposerDock\n appearance=\"paper\"\n dragActive={dragActive}\n aboveSurface={\n <FollowUpSuggestions\n enabled={followUpSuggestions}\n threadId={threadId}\n hasDraft={hasText || hasExtras}\n onPick={pickFollowUp}\n />\n }\n beforeEditor={\n <>\n {slots?.aboveEditor}\n <ChatVoiceStatus\n voice={voice}\n offerMove={voiceEnabled}\n moveDisabled={isUploading || dictationCtl.isActive || !isStatewireChannelLive(connection)}\n moveDisabledReason={needsConnectionReason}\n />\n <ChatVoiceContinueOffer\n voice={voice}\n offer={voiceEnabled ? continueByVoice : null}\n disabled={isUploading || dictationCtl.isActive || !isStatewireChannelLive(connection)}\n disabledReason={needsConnectionReason}\n />\n {/* The agents the next message names (chosen from the `@` menu's Agents section),\n each answering it in its own turn. */}\n {namesAgents ? (\n <ComposerNamedAgents threadId={threadId} onEmptied={focusComposer} />\n ) : null}\n {/* The objects the app attached to the next message (`useAttachToChat`). */}\n <ComposerAttachedReferences threadId={threadId} onEmptied={focusComposer} />\n <ComposerQuotePreview />\n <ComposerAttachmentPreview />\n </>\n }\n editor={\n <>\n {/* The editor stays mounted while recording so its draft and\n mention state survive; the waveform takes its place visually. */}\n <div className={cn(recording && 'hidden')}>\n <TiptapComposer\n ref={composerRef}\n threadId={threadId}\n // Its own sends (runtime attachments skip the interception) carry what an app\n // attached too, and a send handed back brings their chips back.\n {...attachedReferencesComposerProps}\n appearance=\"paper\"\n placeholder={\n (runLive ? slots?.runningPlaceholder : undefined) ??\n slots?.placeholder ??\n DEFAULT_COMPOSER_PLACEHOLDER\n }\n tools={tools}\n rootCategories={rootCategories}\n chatAgents={chatAgents}\n viewerIsAdmin={viewerIsAdmin}\n onDraftStateChange={onDraftStateChange}\n mentionSearchUnavailable={needsConnectionReason ? NEEDS_CONNECTION : null}\n waitForHostUploads={waitForHostUploads}\n interceptSubmit={interceptSubmit}\n beforeSubmit={onBeforeSend ? beforeSubmit : undefined}\n hasPendingExtras={hasPendingExtras}\n holdPendingExtras={holdPendingExtras}\n onAttachmentError={setComposerNotice}\n fileIntake={fileIntake}\n onSubmitted={handleComposerSubmitted}\n slashCommands={slots?.slashCommands}\n />\n </div>\n {notice && (\n <p className=\"aui-composer-notice px-1.5 pb-1 text-destructive text-xs\" role=\"alert\">\n {notice}\n </p>\n )}\n {recording && (\n <DictationStrip\n status={dictationCtl.status}\n transcript={dictationCtl.transcript}\n stream={dictationCtl.stream}\n stoppingLabel={dictationCtl.engine.stoppingLabel}\n />\n )}\n {dictationEnabled && dictationCtl.status === DICTATION_STATUSES.error && dictationCtl.error && (\n <p className=\"aui-dictation-error px-1.5 pb-1 text-destructive text-xs\" role=\"alert\">\n {dictationCtl.error.message}\n </p>\n )}\n </>\n }\n toolbarStart={\n // `min-w-0 flex-wrap`: when the chips are wider than the composer (a narrow pane, or a\n // host's own chips), they wrap onto another row instead of pushing voice and Send past\n // its edge. A toolbar that fits lays out as before.\n <div className=\"flex min-w-0 flex-wrap items-center gap-1\">\n {recording ? (\n <DictationCancelButton onClick={dictationCtl.cancel} />\n ) : (\n <>\n {slots?.attachButton === false ? null : (\n <FileUploadButton\n className=\"aui-composer-attach size-8 rounded-full p-0 disabled:opacity-30\"\n disabledReason={needsConnectionReason}\n />\n )}\n {slots?.mentionButton === false ? null : (\n <AthenaComposerMentionButton\n onClick={() => composerRef.current?.openMentionMenu?.()}\n disabledReason={needsConnectionReason}\n />\n )}\n <AthenaChatModeMenu />\n {slots?.toolbarStart}\n </>\n )}\n </div>\n }\n toolbarEnd={\n // Never shrinks, and sits at the last row's end once the chips wrap.\n <div className=\"flex shrink-0 items-center gap-1 self-end\">\n {recording ? (\n <>\n <DictationStopButton\n onClick={() => void stopDictation()}\n disabled={dictationCtl.status === DICTATION_STATUSES.stopping}\n />\n <AthenaComposerSendButton\n action={isRunning ? 'queue' : 'send'}\n onSend={() => void sendDictation()}\n disabled={dictationCtl.status !== DICTATION_STATUSES.listening || isUploading}\n title={isUploading ? 'Upload in progress...' : undefined}\n />\n </>\n ) : (\n <>\n {slots?.toolbarEnd}\n {showMic && (\n <DictationMicButton\n onClick={dictationCtl.start}\n disabled={isUploading}\n disabledReason={needsConnectionReason}\n />\n )}\n {voiceEnabled && (\n <ChatVoiceButton\n voice={voice}\n disabled={isUploading || dictationCtl.isActive || !isStatewireChannelLive(connection)}\n disabledReason={needsConnectionReason}\n />\n )}\n <ComposerSendOrStop\n composerRef={composerRef}\n hasDraft={hasText || hasExtras}\n liveVoice={voice.phase === 'live' && !hasExtras}\n liveSession={voiceActive ? voice : null}\n sendBlockedReason={isUploading ? 'Upload in progress...' : null}\n components={ATHENA_COMPOSER_COMPONENTS}\n />\n </>\n )}\n </div>\n }\n belowSurface={<ComposerKeyboardHint visible={keyboardHint.visible} />}\n />\n </div>\n </ComposerDropZone>\n );\n return (\n <AthenaChatComposerActionsContext.Provider value={composerActions}>\n {composer}\n </AthenaChatComposerActionsContext.Provider>\n );\n};\n\nconst MessageError: FC = () => (\n <MessagePrimitive.Error>\n <ErrorPrimitive.Root className=\"aui-message-error-root mt-2 flex items-start gap-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm dark:bg-destructive/5 dark:text-red-200\">\n <AlertCircleIcon className=\"mt-0.5 size-4 shrink-0\" />\n <ErrorPrimitive.Message className=\"aui-message-error-message grow\" />\n <ActionBarPrimitive.Reload asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-6 shrink-0 text-destructive hover:text-destructive dark:text-red-200 dark:hover:text-red-100\"\n >\n <RefreshCwIcon className=\"size-3.5\" />\n </Button>\n </ActionBarPrimitive.Reload>\n </ErrorPrimitive.Root>\n </MessagePrimitive.Error>\n);\n\n/**\n * Seconds since `resetKey` last changed, counted while `ticking` (0 while\n * not, so a counter nobody shows re-renders nothing).\n */\nfunction useSecondsSince({ resetKey, ticking = true }: { resetKey: string; ticking?: boolean }): number {\n const [seconds, setSeconds] = useState(0);\n useEffect(() => {\n setSeconds(0);\n if (!ticking) return;\n const startedAt = Date.now();\n const timer = setInterval(() => {\n setSeconds(Math.floor((Date.now() - startedAt) / 1000));\n }, 1000);\n return () => clearInterval(timer);\n }, [resetKey, ticking]);\n return seconds;\n}\n\n/**\n * The quiet status line under a running turn: one pulsing dot, the verb\n * (\"Thinking…\", or the running tool's activity such as \"Searching the web…\"),\n * the elapsed counter once it is due, and a stall tone once the model has\n * been quiet for a while — so a busy run and a possibly-stuck one stop\n * looking identical. A tool call in flight never gets the stall tone: a\n * command or a build streams nothing for minutes while it works, so its line\n * keeps the verb and a neutral counter. The timer restarts whenever\n * `resetKey` changes.\n */\nconst RunStatusLine: FC<{\n verb: string;\n resetKey: string;\n toolCallInFlight?: boolean;\n className?: string;\n}> = ({ verb, resetKey, toolCallInFlight = false, className }) => {\n const seconds = useSecondsSince({ resetKey });\n const stalled = isRunActivityStalled({ seconds, toolCallInFlight });\n return (\n <div\n data-slot=\"run-status-line\"\n data-stalled={stalled ? 'true' : undefined}\n className={cn(\n 'aui-run-activity mt-2 flex items-center gap-2 px-1 text-[12px] text-muted-foreground',\n className,\n )}\n >\n <span\n aria-hidden=\"true\"\n className={cn(\n 'size-1.5 shrink-0 rounded-full bg-current opacity-60',\n !stalled && 'animate-pulse motion-reduce:animate-none',\n )}\n />\n <span\n aria-hidden=\"true\"\n className={cn('tabular-nums', stalled && 'text-amber-600 dark:text-amber-400')}\n >\n {runActivityLabel({ seconds, verb, stalled })}\n </span>\n {/* The visible counter ticks every second; announcing each tick would\n drown a screen reader, so the live region only speaks the two\n meaningful transitions: what the run is doing, and that it looks\n stalled. */}\n <span aria-live=\"polite\" className=\"sr-only\">\n {stalled ? 'Assistant is still working; nothing new for over thirty seconds.' : `${verb}…`}\n </span>\n </div>\n );\n};\n\nconst AthenaAssistantMessageEmpty: EmptyMessagePartComponent = ({ status }) => {\n if (status?.type !== 'running') return null;\n return <RunStatusLine verb=\"Thinking\" resetKey=\"empty\" className=\"mt-0\" />;\n};\n\n/**\n * Renders the empty/loading indicator while a message is running but has no\n * parts yet. `MessagePrimitive.GroupedParts` only renders existing parts, so\n * the indicator can't live inside its switch — it goes here as a sibling.\n */\nconst AthenaMessageEmptyIndicator: FC<{ EmptyComponent: EmptyMessagePartComponent }> = ({\n EmptyComponent,\n}) => {\n const hasParts = useAuiState((s) => s.message.parts.length > 0);\n const isRunning = useAuiState((s) => s.message.status?.type === 'running');\n if (hasParts || !isRunning) return null;\n return <EmptyComponent status={{ type: 'running' }} />;\n};\n\n/**\n * Run-liveness line under a running message whose tail is a tool call: the\n * tool's own verb from the shared registry and an elapsed counter that resets\n * whenever the stream moves the tail part. Once the call has its result and\n * the model stays quiet, the stall tone; never while the call is in flight.\n * Text and reasoning tails animate on their own and render no line.\n */\nconst AthenaMessageActivityIndicator: FC = () => {\n const isRunning = useAuiState((s) => s.message.status?.type === 'running');\n const activityKey = useAuiState((s) => runActivityKey(s.message.parts));\n const verb = useAuiState((s) => runActivityVerb(s.message.parts));\n const toolCallInFlight = useAuiState((s) => isToolCallInFlight(s.message.parts));\n if (!isRunning || activityKey === null) return null;\n return (\n <RunStatusLine\n verb={verb ?? 'Working'}\n resetKey={activityKey}\n toolCallInFlight={toolCallInFlight}\n />\n );\n};\n\n/**\n * The grouped view's running meta, inline on the transcript's header row. The\n * header already counts the whole turn (\"Working for 1m 12s\"), so this shows\n * nothing until nothing has streamed for the stall threshold, then says so in\n * the stall tone (\"Nothing new for 42s\"). The clock restarts whenever anything\n * streams, an answer or the agent's thinking growing included\n * (`runProgressKey`), so a long answer that is still arriving never reads as\n * quiet. Nothing while a tool call is in flight: its step row says it is\n * running, and the header goes on counting the turn.\n */\nconst AthenaGroupedRunMeta: FC = () => {\n const progressKey = useAuiState((s) => runProgressKey(s.message.parts));\n const toolCallInFlight = useAuiState((s) => isToolCallInFlight(s.message.parts));\n const seconds = useSecondsSince({ resetKey: progressKey, ticking: !toolCallInFlight });\n const stalled = isRunActivityStalled({ seconds, toolCallInFlight });\n if (!stalled) return null;\n return (\n <span\n data-slot=\"run-stalled\"\n data-stalled=\"true\"\n className=\"tabular-nums text-amber-600 dark:text-amber-400\"\n >\n <span aria-hidden=\"true\">Nothing new for {runElapsedLabel(seconds)}</span>\n {/* The counter ticks every second, so it stays out of the live region;\n only the stall transition is announced. */}\n <span aria-live=\"polite\" className=\"sr-only\">\n Assistant is still working; nothing new for over thirty seconds.\n </span>\n </span>\n );\n};\nconst renderGroupedRunningMeta = () => <AthenaGroupedRunMeta />;\n\n/**\n * The centered hairline with the date, rendered above the first message of a\n * calendar day that differs from the previous message's. Both messages need\n * the runtime's `_created_at` stamp; without it there is nothing truthful to\n * separate on.\n */\nconst MessageDaySeparator: FC = () => {\n const stamp = useAuiState((s) => readMessageCreatedAt(s.message.metadata?.custom));\n const previousStamp = useAuiState((s) => {\n const index = s.message.index;\n const previous = index > 0 ? s.thread.messages[index - 1] : undefined;\n return readMessageCreatedAt(previous?.metadata?.custom);\n });\n const label = useMemo(() => {\n const date = stamp ? parseMessageTime(stamp) : null;\n const previous = previousStamp ? parseMessageTime(previousStamp) : null;\n if (!date || !previous || isSameCalendarDay(date, previous)) return null;\n return formatDayLabel(date);\n }, [stamp, previousStamp]);\n if (!label) return null;\n return (\n <div\n role=\"separator\"\n aria-label={label}\n data-slot=\"day-separator\"\n className=\"aui-day-separator mb-3 flex w-full items-center gap-3 text-[11px] font-medium text-muted-foreground\"\n >\n <span aria-hidden=\"true\" className=\"h-px flex-1 bg-border\" />\n <span>{label}</span>\n <span aria-hidden=\"true\" className=\"h-px flex-1 bg-border\" />\n </div>\n );\n};\n\n/**\n * The message's clock time, revealed on hover beside the action bar (the\n * full date in its `title`). Reads the runtime's `_created_at` stamp; a\n * message without one shows no time rather than a wrong one.\n */\nconst MessageTimestamp: FC<{ className?: string }> = ({ className }) => {\n const stamp = useAuiState((s) => readMessageCreatedAt(s.message.metadata?.custom));\n const date = useMemo(() => (stamp ? parseMessageTime(stamp) : null), [stamp]);\n if (!date) return null;\n return (\n <time\n dateTime={date.toISOString()}\n title={formatMessageDateTime(date)}\n data-slot=\"message-timestamp\"\n className={cn(\n 'aui-message-timestamp shrink-0 text-[11px] tabular-nums text-muted-foreground',\n ACTION_BAR_REVEAL_CLASS,\n className,\n )}\n >\n {formatMessageTime(date)}\n </time>\n );\n};\n\nexport const AthenaReasoningPart: FC<AthenaReasoningPartProps> = ({\n text,\n status,\n TextComponent,\n}) => {\n const inheritedTextComponent = useContext(AthenaReasoningTextComponentContext);\n const EffectiveTextComponent = TextComponent ?? inheritedTextComponent ?? TiptapText;\n const isMessageRunning = useAuiState((state) => state.message.status?.type === 'running');\n const reasoningTokens = useAuiState((state) =>\n getReasoningTokensFromMetadata(state.message.metadata)\n );\n const isRunning = isMessageRunning || status?.type === 'running';\n const [isCollapsed, setIsCollapsed] = useState(!isRunning);\n const userOverrodeOpenStateRef = useRef(false);\n const hasText = text.trim().length > 0;\n\n const reasoningTextProps: TextMessagePartProps = {\n type: 'text',\n text,\n status: isRunning\n ? ({ type: 'running' } as TextMessagePartProps['status'])\n : (status as TextMessagePartProps['status']),\n };\n\n useEffect(() => {\n if (userOverrodeOpenStateRef.current) {\n return;\n }\n\n setIsCollapsed(!isRunning);\n }, [isRunning]);\n\n if (!hasText && !isRunning) {\n return null;\n }\n\n return (\n <Collapsible\n open={!isCollapsed}\n onOpenChange={(open) => {\n userOverrodeOpenStateRef.current = true;\n setIsCollapsed(!open);\n }}\n className=\"aui-assistant-reasoning-root mb-3 rounded-2xl border border-border/60 bg-muted/30 px-3 py-2\"\n >\n <CollapsibleTrigger asChild>\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-3 text-left\"\n aria-label={isRunning ? 'Toggle reasoning while streaming' : 'Toggle reasoning'}\n >\n <span className=\"flex min-w-0 items-center gap-2 text-[13px] font-medium text-muted-foreground\">\n <BrainIcon className=\"size-4 shrink-0\" />\n <span>{isRunning ? 'Reasoning...' : 'Reasoning'}</span>\n </span>\n <span className=\"flex shrink-0 items-center gap-2\">\n {reasoningTokens !== undefined && (\n <span className=\"rounded-full border border-border/60 bg-background px-2 py-0.5 text-[11px] font-medium text-muted-foreground\">\n {formatReasoningTokens(reasoningTokens)}\n </span>\n )}\n <span\n className={cn(\n 'flex size-5 items-center justify-center text-muted-foreground transition-transform',\n isCollapsed ? 'rotate-0' : 'rotate-90'\n )}\n aria-hidden=\"true\"\n >\n <ChevronRightIcon className=\"size-4\" />\n </span>\n </span>\n </button>\n </CollapsibleTrigger>\n\n <CollapsibleContent className=\"pt-3\">\n {isRunning && !hasText ? (\n <span className=\"shimmer text-[13px] text-muted-foreground\">Analyzing...</span>\n ) : (\n <div className=\"aui-assistant-reasoning-body text-[13px] leading-relaxed\">\n <EffectiveTextComponent {...reasoningTextProps} />\n </div>\n )}\n </CollapsibleContent>\n </Collapsible>\n );\n};\n\nconst groupAdjacentToolCalls = (part: PartState) =>\n part.type === 'tool-call' ? (['group-tool'] as const) : null;\nconst noToolGrouping = () => null;\n\n/** `isSdkInlineTool`, plus `task`: the subagent card is how a turn shows its delegated work. */\nconst isInlineToolOrSubagent = (toolName: string): boolean =>\n toolName === TASK_TOOL_NAME || isSdkInlineTool(toolName);\n\n/**\n * The run ending this message holds (`readRuntimeMessageFromSourceMessages`)\n * as the status card every chat surface draws, or nothing for a silent one.\n */\nconst AthenaRuntimeEndingCard: FC = () => {\n // Select the message (a stable store reference) and derive from it: the\n // reader builds a fresh object per call, which as a selector result would\n // re-render on every store update.\n const message = useAuiState((s) => s.message);\n const runtime = useMemo(() => readRuntimeMessageFromSourceMessages(message), [message]);\n if (!runtime || runtime.silent) return null;\n return <RuntimeMessageCard message={runtime} />;\n};\n\nexport const AthenaAssistantMessage: FC<AthenaAssistantMessageProps> = ({\n toolUIs,\n AvatarComponent,\n TextComponent = TiptapText,\n ReasoningComponent,\n EmptyComponent = AthenaAssistantMessageEmpty,\n ActionBarComponent = AthenaAssistantActionBar,\n groupToolCalls = true,\n}) => {\n const effectiveReasoningComponent = ReasoningComponent ?? AthenaReasoningPart;\n const toolUIsWithNestedMessages = useMemo(() => {\n const wrappedToolUIs: Record<string, ToolCallMessagePartComponent> = {};\n\n for (const [toolName, ToolUI] of Object.entries(toolUIs)) {\n wrappedToolUIs[toolName] = withNestedPtcMessages(ToolUI);\n }\n\n return wrappedToolUIs;\n }, [toolUIs]);\n // The subagent card stays in the conversation, outside the collapsed steps,\n // so a delegated lane shows its progress; a host's own `task` UI stays where\n // every other tool UI is.\n const isInlineTool =\n toolUIs[TASK_TOOL_NAME] === SubagentTaskToolUI ? isInlineToolOrSubagent : isSdkInlineTool;\n // The turn's steps the run's approval waits on (a gated call, or a `task`\n // call whose subagent holds one) read \"Waiting for your input\", never running\n // or done; none outside `AthenaChat`'s provider.\n const waitingToolCallIds = useTurnToolCallsAwaitingApproval(useApprovalWaitInScope().toolCallIds);\n\n // NestedPtcComponentsProvider still consumes the legacy parts-config shape\n // (Text / Reasoning / tools.by_name / Empty) to render PTC sub-tool messages\n // inside a tool card. The outer rendering uses GroupedParts, but the inner\n // PTC tree continues to mirror the parent registry.\n const nestedPtcComponents = useMemo(\n () => ({\n Text: TextComponent,\n Reasoning: effectiveReasoningComponent,\n tools: {\n Fallback: ToolFallback,\n by_name: toolUIsWithNestedMessages,\n },\n Empty: EmptyComponent,\n }),\n [EmptyComponent, TextComponent, effectiveReasoningComponent, toolUIsWithNestedMessages],\n );\n const arrivedLive = useMessageArrivalAnimation();\n // How a run ended is a system event, not the assistant's words: a stop, a\n // server-update pause or a failure draws the status card, never its marker's\n // transcript copy (\"⏹️ Run stopped by user.\"). Send now and a double text end\n // the live run as plumbing, so their marker paints nothing (`silent`): the\n // person stopped nothing. Primitive selectors, since the reader builds a\n // fresh object per call.\n const soleEndingKind = useAuiState((s) => readSoleRuntimeMessageKind(s.message));\n const endingSilent = useAuiState(\n (s) => readRuntimeMessageFromSourceMessages(s.message)?.silent === true,\n );\n // A marker appended after the turn's own work is chunked into this message\n // as its last part: that part draws the card (or nothing) in its place, and\n // the work above it keeps rendering. Text parts render without their index,\n // so the marker is found by its text, and only while no other text part\n // reads the same: the assistant's own words never turn into the card.\n const chunkedEndingText = useAuiState((s) => {\n const runtime = readRuntimeMessageFromSourceMessages(s.message);\n if (!runtime || runtime.isSoleSourceMessage || runtime.kind === 'handoff') return undefined;\n const markerText = runtime.text;\n const last = s.message.content.at(-1);\n if (markerText === undefined || last?.type !== 'text' || last.text !== markerText) return undefined;\n const sameText = s.message.content.filter((part) => part.type === 'text' && part.text === markerText);\n return sameText.length === 1 ? markerText : undefined;\n });\n const AnswerTextComponent = useMemo<TextMessagePartComponent>(() => {\n if (chunkedEndingText === undefined) return TextComponent;\n const Base = TextComponent;\n return function TextOrRunEnding(props) {\n return props.text === chunkedEndingText ? <AthenaRuntimeEndingCard /> : <Base {...props} />;\n };\n }, [TextComponent, chunkedEndingText]);\n\n if (soleEndingKind !== undefined && soleEndingKind !== 'handoff') {\n if (endingSilent) return null;\n return (\n <MessagePrimitive.Root\n className=\"aui-assistant-message-root aui-run-ending-root mx-auto w-full max-w-(--thread-max-width) px-2 py-1\"\n data-role=\"assistant\"\n >\n <MessageDaySeparator />\n <AthenaRuntimeEndingCard />\n </MessagePrimitive.Root>\n );\n }\n\n return (\n <MessagePrimitive.Root\n className={cn(\n 'aui-assistant-message-root group/aui-assistant-message relative mx-auto w-full max-w-(--thread-max-width) py-3',\n arrivedLive && MESSAGE_ARRIVAL_ANIMATION_CLASS,\n )}\n data-role=\"assistant\"\n >\n <MessageDaySeparator />\n <div className=\"flex gap-3\">\n {/* The leading column exists only when the host supplies an avatar;\n without one the turn is told apart from the right-aligned user\n bubbles by alignment alone, with no rule or gutter of its own. */}\n {AvatarComponent ? (\n <div\n data-slot=\"assistant-lead\"\n className=\"aui-assistant-message-lead flex shrink-0 justify-center\"\n >\n <AvatarComponent />\n </div>\n ) : null}\n <div className=\"min-w-0 flex-1\">\n <AnswerLabel className=\"px-2 pb-1\" />\n <AthenaReasoningTextComponentContext.Provider value={TextComponent}>\n <div className=\"aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed\">\n <NestedPtcComponentsProvider components={nestedPtcComponents}>\n {groupToolCalls ? (\n <div className=\"flex flex-col space-y-2\">\n <SuperGroupingTranscript\n toolUIs={toolUIsWithNestedMessages}\n TextComponent={TextComponent}\n ReasoningComponent={effectiveReasoningComponent}\n isInlineTool={isInlineTool}\n waitingToolCallIds={waitingToolCallIds}\n renderRunningMeta={renderGroupedRunningMeta}\n />\n <SuperGroupingFinalText TextComponent={AnswerTextComponent} />\n </div>\n ) : (\n <>\n <AthenaMessageEmptyIndicator EmptyComponent={EmptyComponent} />\n <MessagePrimitive.GroupedParts groupBy={noToolGrouping}>\n {({ part }) => {\n switch (part.type) {\n case 'tool-call': {\n const ToolUI = toolUIsWithNestedMessages[part.toolName];\n const toolProps = part as unknown as ToolCallMessagePartProps;\n return ToolUI ? <ToolUI {...toolProps} /> : <ToolFallback {...toolProps} />;\n }\n case 'reasoning': {\n const ReasoningRenderer = effectiveReasoningComponent;\n return <ReasoningRenderer {...(part as ReasoningMessagePartProps)} />;\n }\n case 'text': {\n const textPart = part as TextMessagePartProps;\n if (textPart.text === '' && textPart.status?.type === 'running') {\n return <EmptyComponent status={textPart.status} />;\n }\n return <AnswerTextComponent {...textPart} />;\n }\n default:\n return null;\n }\n }}\n </MessagePrimitive.GroupedParts>\n <AthenaMessageActivityIndicator />\n </>\n )}\n </NestedPtcComponentsProvider>\n <MessageError />\n </div>\n </AthenaReasoningTextComponentContext.Provider>\n {/* What the turn changed, at its end, while the host turned the card on. */}\n <AthenaTurnChangesSlot className=\"mx-2\" />\n <div className=\"aui-assistant-message-footer mt-1 ml-2 flex items-center gap-1\">\n <BranchPicker />\n <ActionBarComponent />\n <MessageTimestamp className=\"ml-auto group-hover/aui-assistant-message:opacity-100\" />\n </div>\n </div>\n </div>\n </MessagePrimitive.Root>\n );\n};\n\nconst AthenaToolGroup: FC<{ children: React.ReactNode; count: number }> = ({ children, count }) => {\n const [expanded, setExpanded] = useState(false);\n\n return (\n <div className=\"my-3 w-full overflow-hidden rounded-xl border border-border/60 bg-background shadow-sm\">\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-muted/20\"\n aria-expanded={expanded}\n >\n <div className=\"flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted/60 text-muted-foreground\">\n <LayersIcon className=\"size-4\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <span className=\"text-[13px] font-medium text-foreground\">\n {count} tool {count === 1 ? 'call' : 'calls'}\n </span>\n </div>\n <ChevronDownIcon\n className={cn(\n 'size-4 shrink-0 text-muted-foreground transition-transform duration-200',\n !expanded && '-rotate-90',\n )}\n />\n </button>\n {expanded && (\n <div className=\"border-t border-border/40 bg-muted/5 px-3 pt-1 pb-2 [&>*]:my-2\">\n {children}\n </div>\n )}\n </div>\n );\n};\n\nconst CopyMessageButton: FC = () => (\n <ActionBarPrimitive.Copy asChild>\n <TooltipIconButton tooltip=\"Copy\">\n <AuiIf condition={(s) => s.message.isCopied}>\n <CheckIcon />\n </AuiIf>\n <AuiIf condition={(s) => !s.message.isCopied}>\n <CopyIcon />\n </AuiIf>\n </TooltipIconButton>\n </ActionBarPrimitive.Copy>\n);\n\n/** Copy on a user bubble copies what the bubble shows (`useUserMessageCopy`). */\nconst UserCopyMessageButton: FC = () => {\n const { copy, disabled, isCopied } = useUserMessageCopy();\n return (\n <TooltipIconButton\n tooltip=\"Copy\"\n onClick={copy}\n disabled={disabled}\n data-copied={isCopied ? 'true' : undefined}\n >\n {isCopied ? <CheckIcon /> : <CopyIcon />}\n </TooltipIconButton>\n );\n};\n\n/** Regenerate dispatches `run/reload`, so it hides on read-only threads. */\nconst RegenerateMessageButton: FC = () => {\n const readOnly = useMessageActionsReadOnly();\n if (readOnly) return null;\n return (\n <ActionBarPrimitive.Reload asChild>\n <TooltipIconButton tooltip=\"Regenerate\">\n <RefreshCwIcon />\n </TooltipIconButton>\n </ActionBarPrimitive.Reload>\n );\n};\n\n/**\n * The edit primitive does not check the runtime's edit capability itself —\n * clicking it on a runtime without one throws inside onPress — so the button\n * gates on the capability and, to match the rewind semantics of `run/edit`,\n * stays hidden while a run is live or the transcript is read-only. While the\n * host's chat outbox says Athena can't be reached it is not offered: shown\n * disabled, its tooltip says why, and it comes back once Athena answers.\n */\nconst EditMessageButton: FC = () => {\n const allowEdit = useAuiState((s) => s.thread.capabilities.edit);\n const isRunning = useAthenaRunLive();\n const readOnly = useMessageActionsReadOnly();\n const reachable = useChatOutboxReachable(useDeepAgentChatOutboxContext());\n if (!allowEdit || isRunning || readOnly) return null;\n if (!reachable) {\n return (\n <TooltipIconButton\n tooltip={CHAT_EDIT_UNREACHABLE_LABEL}\n aria-disabled\n data-testid=\"chat-message-edit-unreachable\"\n className=\"cursor-not-allowed opacity-50\"\n >\n <PencilIcon />\n </TooltipIconButton>\n );\n }\n return (\n <ActionBarPrimitive.Edit asChild>\n <TooltipIconButton tooltip=\"Edit\">\n <PencilIcon />\n </TooltipIconButton>\n </ActionBarPrimitive.Edit>\n );\n};\n\n/** Hover-revealed copy / edit row under a user bubble; mirrors the assistant bar. */\nconst AthenaUserActionBar: FC = () => {\n const isThreadRunning = useAuiState((s) => s.thread.isRunning);\n return (\n <ActionBarPrimitive.Root\n autohide=\"never\"\n className={cn(\n 'aui-user-action-bar-root flex min-h-6 gap-1 text-muted-foreground',\n isThreadRunning\n ? 'invisible'\n : [\n ACTION_BAR_REVEAL_CLASS,\n 'group-hover/aui-user-message:pointer-events-auto group-hover/aui-user-message:opacity-100',\n ],\n )}\n >\n <UserCopyMessageButton />\n <EditMessageButton />\n </ActionBarPrimitive.Root>\n );\n};\n\nexport const AthenaAssistantActionBar: FC<AthenaAssistantActionBarProps> = ({ className }) => {\n const threadId = useAthenaThreadId();\n const { appUrl } = useAthenaConfig();\n // The bar stays mounted so the footer keeps its height: assistant-ui's\n // `autohide` / `hideWhenRunning` unmount it, which shifts the whole message\n // up and down on every hover. Visibility is CSS instead — the latest reply\n // keeps its actions, older replies reveal on hover or keyboard focus, and\n // while the thread runs every bar is `invisible` (layout kept, controls\n // unfocusable — opacity alone would still let Tab reveal them).\n const isLast = useAuiState((s) => s.message.isLast);\n const isThreadRunning = useAuiState((s) => s.thread.isRunning);\n\n return (\n <ActionBarPrimitive.Root\n autohide=\"never\"\n className={cn(\n 'aui-assistant-action-bar-root -ml-1 flex min-h-6 gap-1 text-muted-foreground',\n isThreadRunning && 'invisible',\n !isThreadRunning &&\n !isLast && [\n ACTION_BAR_REVEAL_CLASS,\n 'group-hover/aui-assistant-message:pointer-events-auto group-hover/aui-assistant-message:opacity-100',\n ],\n className,\n )}\n >\n <CopyMessageButton />\n <RegenerateMessageButton />\n <ActionBarMorePrimitive.Root>\n <ActionBarMorePrimitive.Trigger asChild>\n <TooltipIconButton tooltip=\"More\" className=\"data-[state=open]:bg-accent\">\n <MoreHorizontalIcon />\n </TooltipIconButton>\n </ActionBarMorePrimitive.Trigger>\n <ActionBarMorePrimitive.Content\n side=\"bottom\"\n align=\"start\"\n className=\"aui-action-bar-more-content z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md\"\n >\n <ActionBarPrimitive.ExportMarkdown asChild>\n <ActionBarMorePrimitive.Item className=\"aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground\">\n <DownloadIcon className=\"size-4\" />\n Export as Markdown\n </ActionBarMorePrimitive.Item>\n </ActionBarPrimitive.ExportMarkdown>\n {threadId && (\n <ActionBarMorePrimitive.Item\n className=\"aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground\"\n onClick={() => {\n window.open(createAthenaSpacesUrl({ appUrl, sessionId: threadId }), '_blank');\n }}\n >\n <ExternalLinkIcon className=\"size-4\" />\n Open in Athena\n </ActionBarMorePrimitive.Item>\n )}\n </ActionBarMorePrimitive.Content>\n </ActionBarMorePrimitive.Root>\n </ActionBarPrimitive.Root>\n );\n};\n\nexport const AthenaUserMessage: FC<AthenaUserMessageProps> = ({\n TextComponent = UserMessageText,\n}) => {\n // A GitHub wake or a subscription's delivery is an event, not words the\n // user typed: it renders as the compact wake marker instead of a bubble\n // quoting the injected text.\n const isWake = useAuiState(\n (s) =>\n isGithubWakeMessage(s.message.metadata?.custom) ||\n isSubscriptionWakeMessage(s.message.metadata?.custom)\n );\n const arrivedLive = useMessageArrivalAnimation();\n // A message that came in over a channel (Slack, email, a text, Teams)\n // shows the words sent, without the routing block the agent read.\n const partComponents = useMemo(\n () => ({ Text: withInboundMessageBody(TextComponent), Image: MessageImagePart }),\n [TextComponent],\n );\n if (isWake) {\n return (\n <MessagePrimitive.Root\n className=\"aui-user-message-root aui-wake-marker-root mx-auto w-full max-w-(--thread-max-width) px-2 py-1\"\n data-role=\"user\"\n >\n <MessageDaySeparator />\n <WakeMarkerMessage />\n </MessagePrimitive.Root>\n );\n }\n return (\n <MessagePrimitive.Root\n className={cn(\n 'aui-user-message-root group/aui-user-message mx-auto flex w-full max-w-(--thread-max-width) flex-col items-end px-2 py-3',\n arrivedLive && MESSAGE_ARRIVAL_ANIMATION_CLASS,\n )}\n data-role=\"user\"\n >\n <MessageDaySeparator />\n {/* A soft bubble on a 75% measure: the user's words stay a bubble, the\n assistant's reading column stays the page. */}\n <div className=\"flex min-w-0 max-w-[75%] flex-col items-end gap-1\">\n {/* A message that came in over a channel: the line naming the channel\n and the sender, above the words that were sent. */}\n <InboundChannelLine />\n {/* What the app attached to the message (`useAttachToChat`). */}\n <MessageAttachedReferences />\n <div className=\"aui-user-message-content wrap-break-word min-w-0 max-w-full rounded-2xl bg-muted/70 px-4 py-2.5 text-foreground\">\n <InboundChannelSubject />\n <MessageImageGallery>\n <MessagePrimitive.Parts components={partComponents} />\n </MessageImageGallery>\n </div>\n <div className=\"aui-user-message-footer -mr-1 flex items-center gap-1\">\n <MessageTimestamp className=\"mr-1 group-hover/aui-user-message:opacity-100\" />\n <BranchPicker />\n <AthenaUserActionBar />\n </div>\n </div>\n </MessagePrimitive.Root>\n );\n};\n"],"names":["_a","composer","attachments","error"],"mappings":"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"}
|