@athenaintel/react 0.55.0 → 0.57.0
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 +84 -1
- package/dist/agent-runtime/src/answer-label.cjs +8 -2
- package/dist/agent-runtime/src/answer-label.cjs.map +1 -1
- package/dist/agent-runtime/src/answer-label.d.ts +10 -4
- package/dist/agent-runtime/src/answer-label.js +8 -2
- package/dist/agent-runtime/src/answer-label.js.map +1 -1
- package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs +6 -3
- package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
- package/dist/agent-runtime/src/deep-agent-transport-recipe.js +6 -3
- package/dist/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
- package/dist/agent-runtime/src/edit-command.cjs +40 -19
- package/dist/agent-runtime/src/edit-command.cjs.map +1 -1
- package/dist/agent-runtime/src/edit-command.d.ts +2 -0
- package/dist/agent-runtime/src/edit-command.js +41 -20
- package/dist/agent-runtime/src/edit-command.js.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs +8 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +9 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.js +8 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/agent-runtime/src/history-store.cjs +426 -0
- package/dist/agent-runtime/src/history-store.cjs.map +1 -0
- package/dist/agent-runtime/src/history-store.d.ts +282 -0
- package/dist/agent-runtime/src/history-store.js +426 -0
- package/dist/agent-runtime/src/history-store.js.map +1 -0
- package/dist/agent-runtime/src/inbound-channel.cjs +96 -0
- package/dist/agent-runtime/src/inbound-channel.cjs.map +1 -0
- package/dist/agent-runtime/src/inbound-channel.d.ts +75 -0
- package/dist/agent-runtime/src/inbound-channel.js +96 -0
- package/dist/agent-runtime/src/inbound-channel.js.map +1 -0
- package/dist/agent-runtime/src/index.d.ts +6 -5
- package/dist/agent-runtime/src/interrupts.cjs +45 -3
- package/dist/agent-runtime/src/interrupts.cjs.map +1 -1
- package/dist/agent-runtime/src/interrupts.d.ts +51 -4
- package/dist/agent-runtime/src/interrupts.js +46 -4
- package/dist/agent-runtime/src/interrupts.js.map +1 -1
- package/dist/agent-runtime/src/message-window.cjs +43 -5
- package/dist/agent-runtime/src/message-window.cjs.map +1 -1
- package/dist/agent-runtime/src/message-window.d.ts +26 -2
- package/dist/agent-runtime/src/message-window.js +44 -6
- package/dist/agent-runtime/src/message-window.js.map +1 -1
- package/dist/agent-runtime/src/offline-status.cjs.map +1 -1
- package/dist/agent-runtime/src/offline-status.d.ts +110 -4
- package/dist/agent-runtime/src/offline-status.js.map +1 -1
- package/dist/agent-runtime/src/runtime.d.ts +1 -0
- package/dist/agent-runtime/src/thread-handoff-flow-machine.d.ts +8 -8
- package/dist/agent-runtime/src/tool-metadata.cjs +16 -0
- package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.js +16 -0
- package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs +8 -16
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.d.ts +1 -9
- package/dist/agent-runtime/src/use-deep-agent-thread.js +9 -17
- package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs +86 -79
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-window-sync.d.ts +2 -27
- package/dist/agent-runtime/src/use-deep-agent-window-sync.js +89 -82
- package/dist/agent-runtime/src/use-deep-agent-window-sync.js.map +1 -1
- package/dist/auth/AthenaSSOProvider.cjs +54 -12
- package/dist/auth/AthenaSSOProvider.cjs.map +1 -1
- package/dist/auth/AthenaSSOProvider.d.ts +23 -2
- package/dist/auth/AthenaSSOProvider.js +54 -12
- package/dist/auth/AthenaSSOProvider.js.map +1 -1
- package/dist/auth/index.cjs +2 -0
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.js +2 -0
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/sign-back-in.cjs +141 -0
- package/dist/auth/sign-back-in.cjs.map +1 -0
- package/dist/auth/sign-back-in.d.ts +117 -0
- package/dist/auth/sign-back-in.js +141 -0
- package/dist/auth/sign-back-in.js.map +1 -0
- package/dist/chat/AthenaChat.cjs +7 -2
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.js +7 -2
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/StatewireApprovalCard.cjs +6 -2
- package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
- package/dist/chat/StatewireApprovalCard.d.ts +8 -1
- package/dist/chat/StatewireApprovalCard.js +7 -3
- package/dist/chat/StatewireApprovalCard.js.map +1 -1
- package/dist/chat/super-grouping/CollapsibleGroup.cjs +1 -1
- package/dist/chat/super-grouping/CollapsibleGroup.cjs.map +1 -1
- package/dist/chat/super-grouping/CollapsibleGroup.d.ts +6 -5
- package/dist/chat/super-grouping/CollapsibleGroup.js +1 -1
- package/dist/chat/super-grouping/CollapsibleGroup.js.map +1 -1
- package/dist/chat/super-grouping/earlier-steps-button.cjs +5 -6
- package/dist/chat/super-grouping/earlier-steps-button.cjs.map +1 -1
- package/dist/chat/super-grouping/earlier-steps-button.d.ts +6 -6
- package/dist/chat/super-grouping/earlier-steps-button.js +5 -6
- package/dist/chat/super-grouping/earlier-steps-button.js.map +1 -1
- package/dist/chat/super-grouping/toolkit-map.cjs +1 -0
- package/dist/chat/super-grouping/toolkit-map.cjs.map +1 -1
- package/dist/chat/super-grouping/toolkit-map.js +1 -0
- package/dist/chat/super-grouping/toolkit-map.js.map +1 -1
- package/dist/chat/super-grouping/use-turn-steps.cjs +3 -3
- package/dist/chat/super-grouping/use-turn-steps.js +1 -1
- package/dist/chat-ui/index.cjs +4 -0
- package/dist/chat-ui/index.cjs.map +1 -1
- package/dist/chat-ui/index.d.ts +1 -0
- package/dist/chat-ui/index.js +5 -1
- package/dist/chat-ui/index.js.map +1 -1
- package/dist/chat-ui/messages/inbound-channel-message.cjs +219 -0
- package/dist/chat-ui/messages/inbound-channel-message.cjs.map +1 -0
- package/dist/chat-ui/messages/inbound-channel-message.d.ts +60 -0
- package/dist/chat-ui/messages/inbound-channel-message.js +219 -0
- package/dist/chat-ui/messages/inbound-channel-message.js.map +1 -0
- package/dist/chat-ui/messages/inbound-channel-reader.cjs +184 -0
- package/dist/chat-ui/messages/inbound-channel-reader.cjs.map +1 -0
- package/dist/chat-ui/messages/inbound-channel-reader.d.ts +65 -0
- package/dist/chat-ui/messages/inbound-channel-reader.js +184 -0
- package/dist/chat-ui/messages/inbound-channel-reader.js.map +1 -0
- package/dist/chat-ui/messages/message-components.cjs +18 -14
- package/dist/chat-ui/messages/message-components.cjs.map +1 -1
- package/dist/chat-ui/messages/message-components.d.ts +7 -0
- package/dist/chat-ui/messages/message-components.js +19 -15
- package/dist/chat-ui/messages/message-components.js.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.cjs +0 -4
- package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.d.ts +5 -7
- package/dist/chat-ui/thread/statewire-history-edge.js +1 -5
- package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
- package/dist/composer/sign-back-in-draft.cjs +62 -0
- package/dist/composer/sign-back-in-draft.cjs.map +1 -0
- package/dist/composer/sign-back-in-draft.d.ts +34 -0
- package/dist/composer/sign-back-in-draft.js +62 -0
- package/dist/composer/sign-back-in-draft.js.map +1 -0
- package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
- package/dist/diagnostics/athena-diagnostics.d.ts +6 -1
- package/dist/diagnostics/athena-diagnostics.js.map +1 -1
- package/dist/index.cjs +8 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/provider/AthenaProvider.cjs +60 -14
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.js +60 -14
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/provider/statewire-window-context.cjs.map +1 -1
- package/dist/provider/statewire-window-context.d.ts +8 -8
- package/dist/provider/statewire-window-context.js.map +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/runtime/auth.cjs +11 -0
- package/dist/runtime/auth.cjs.map +1 -1
- package/dist/runtime/auth.d.ts +18 -1
- package/dist/runtime/auth.js +11 -0
- package/dist/runtime/auth.js.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs +0 -2
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.d.ts +5 -5
- package/dist/runtime/useAthenaStatewireRuntime.js +0 -2
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/dist/agent-runtime/src/history-pages.cjs +0 -279
- package/dist/agent-runtime/src/history-pages.cjs.map +0 -1
- package/dist/agent-runtime/src/history-pages.d.ts +0 -252
- package/dist/agent-runtime/src/history-pages.js +0 -279
- package/dist/agent-runtime/src/history-pages.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-components.cjs","sources":["../../../src/chat-ui/messages/message-components.tsx"],"sourcesContent":["import {\n ActionBarPrimitive,\n AuiIf,\n BranchPickerPrimitive,\n MessagePrimitive,\n useAuiState,\n useMessagePartText,\n useSmooth,\n type ToolCallMessagePartComponent,\n} from \"@assistant-ui/react\";\nimport {\n CHAT_EDIT_UNREACHABLE_LABEL,\n DEEP_AGENT_COMPOSER_MARKDOWN_KEY,\n hideUnterminatedMarkdownLink,\n isGithubWakeMessage,\n isSubscriptionWakeMessage,\n isVoiceDelegationMessage,\n readDeepAgentComposerMarkdown,\n readRuntimeMessageFromSourceMessages,\n readSoleRuntimeMessageKind,\n useChatOutboxReachable,\n useDeepAgentChatOutboxContext,\n} from \"@athenaintel/agent-runtime\";\nimport {\n ArrowUpIcon,\n CheckIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n CopyIcon,\n ListPlusIcon,\n PencilIcon,\n RefreshCwIcon,\n} from \"lucide-react\";\nimport {\n type FC,\n type ReactNode,\n useMemo,\n} from \"react\";\nimport { useAthenaRunLive } from \"../../chat/use-athena-run-live\";\nimport type { ComposerAction } from \"../composer/composer-action\";\nimport { cn } from \"../../lib/utils\";\nimport { ChatMessageBody } from \"../rich-text/chat-message-body\";\nimport { AnswerLabel } from \"./answer-label\";\nimport { useMessageActionsReadOnly } from \"./message-actions-config\";\nimport { MessageImageGallery, MessageImagePart } from \"./message-images\";\nimport { RuntimeMessageCard } from \"./runtime-message\";\nimport { hasVisibleContent } from \"./running-indicator\";\nimport { VoiceDelegationMessage } from \"./voice-delegation-card\";\nimport { WakeMarkerMessage } from \"./wake-marker\";\nimport { SmallIconButton } from \"./thread-chrome\";\n\nexport {\n IconButton,\n SmallIconButton,\n THREAD_HEADER_ACTIONS_CLASS,\n THREAD_HEADER_CLASS,\n THREAD_HEADER_ICON_CLASS,\n THREAD_HEADER_PILL_CLASS,\n THREAD_PANEL_CLASS,\n} from \"./thread-chrome\";\n\nexport const BranchPicker: FC = () => (\n <BranchPickerPrimitive.Root\n hideWhenSingleBranch\n className=\"inline-flex items-center gap-0.5 text-xs text-muted-foreground\"\n data-testid=\"chat-branch-picker\"\n >\n <BranchPickerPrimitive.Previous asChild>\n <SmallIconButton\n tooltip=\"Previous branch\"\n data-testid=\"chat-branch-previous\"\n >\n <ChevronLeftIcon className=\"size-3\" />\n </SmallIconButton>\n </BranchPickerPrimitive.Previous>\n <span className=\"font-medium\" data-testid=\"chat-branch-count\">\n <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />\n </span>\n <BranchPickerPrimitive.Next asChild>\n <SmallIconButton tooltip=\"Next branch\" data-testid=\"chat-branch-next\">\n <ChevronRightIcon className=\"size-3\" />\n </SmallIconButton>\n </BranchPickerPrimitive.Next>\n </BranchPickerPrimitive.Root>\n);\n\nconst CopyActionButton: FC = () => (\n <ActionBarPrimitive.Copy asChild>\n <SmallIconButton tooltip=\"Copy\">\n <AuiIf condition={(state) => state.message.isCopied}>\n <CheckIcon className=\"size-3\" />\n </AuiIf>\n <AuiIf condition={(state) => !state.message.isCopied}>\n <CopyIcon className=\"size-3\" />\n </AuiIf>\n </SmallIconButton>\n </ActionBarPrimitive.Copy>\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, where no error\n * boundary can catch it — so the button must gate on the capability and, to\n * match the rewind semantics of `run/edit`, stay hidden while a run is live.\n * The read-only context covers threads the capability flags cannot: a host's\n * static `edit: true` still applies to fenced legacy conversations. 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 EditActionButton: 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 <SmallIconButton\n tooltip={CHAT_EDIT_UNREACHABLE_LABEL}\n aria-disabled\n data-testid=\"chat-message-edit-unreachable\"\n className=\"cursor-not-allowed opacity-50 hover:bg-transparent hover:text-muted-foreground\"\n >\n <PencilIcon className=\"size-3\" />\n </SmallIconButton>\n );\n }\n return (\n <ActionBarPrimitive.Edit asChild>\n <SmallIconButton tooltip=\"Edit\" data-testid=\"chat-message-edit\">\n <PencilIcon className=\"size-3\" />\n </SmallIconButton>\n </ActionBarPrimitive.Edit>\n );\n};\n\n/** Regenerate dispatches `run/reload`, so it hides on read-only threads too. */\nconst RegenerateActionButton: FC = () => {\n const readOnly = useMessageActionsReadOnly();\n if (readOnly) return null;\n return (\n <ActionBarPrimitive.Reload asChild>\n <SmallIconButton tooltip=\"Regenerate\">\n <RefreshCwIcon className=\"size-3\" />\n </SmallIconButton>\n </ActionBarPrimitive.Reload>\n );\n};\n\n/**\n * Reveal-on-demand treatment for action bars: invisible and click-through\n * until the surrounding named group is hovered or a control inside receives\n * keyboard focus. The `focus-within` escape hatch is what keeps the hidden\n * controls reachable for keyboard users.\n */\nexport const ACTION_BAR_REVEAL_CLASS =\n \"pointer-events-none opacity-0 transition-opacity focus-within:pointer-events-auto focus-within:opacity-100\";\n\n/** Shared chat body; the reveal holds incomplete links until their URL is complete. */\nexport const MarkdownText: FC = () => {\n const revealed = useSmooth(useMessagePartText(), true);\n const isRunning = revealed.status.type === \"running\";\n const text = isRunning ? hideUnterminatedMarkdownLink(revealed.text) : revealed.text;\n return <ChatMessageBody text={text} isRunning={isRunning} />;\n};\n\n/**\n * A user message's text, shown as it was typed.\n *\n * A composer sends plain text exactly as typed, because the model reads it\n * literally, so the text alone no longer says which characters are\n * formatting: read as Markdown, `List<T>` loses `<T>`, `obj.__init__` shows a\n * bold \"init\" and `a\\\\b` one backslash. A composer send therefore carries the\n * draft it was serialized from (`metadata.composer_markdown`, only when the\n * two differ), and this renders that draft when it is a draft of the\n * message's own text (`readDeepAgentComposerMarkdown`), formatting and\n * mention chips included. Any other text — no draft, or one of other words —\n * renders with the typed reading (`ChatMessageBody typed`), which leaves raw\n * HTML and underscore emphasis as the characters they were typed with, so\n * `List<T>`, `obj.__init__` and `a\\b` show as typed there too.\n *\n * Copy copies the message text, which is the text as sent, and Edit opens it\n * in a plain-text box, so neither reads the draft.\n */\nexport const UserMessageText: FC<{ text: string }> = ({ text }) => {\n const composerMarkdown: unknown = useAuiState(\n (s) => s.message.metadata?.custom?.[DEEP_AGENT_COMPOSER_MARKDOWN_KEY],\n );\n const shown = useMemo(\n () =>\n readDeepAgentComposerMarkdown({\n metadata: { [DEEP_AGENT_COMPOSER_MARKDOWN_KEY]: composerMarkdown },\n text,\n }) ?? text,\n [composerMarkdown, text],\n );\n return <ChatMessageBody text={shown} typed />;\n};\n\n/** A user message's parts: its text as typed, and its pictures, each opening the viewer. */\nconst USER_MESSAGE_PART_COMPONENTS = { Text: UserMessageText, Image: MessageImagePart };\n\nconst UserActionBar: FC = () => (\n <ActionBarPrimitive.Root\n autohide=\"never\"\n className={cn(\n \"flex min-h-6 items-center gap-0.5\",\n ACTION_BAR_REVEAL_CLASS,\n \"group-hover/user-message:pointer-events-auto group-hover/user-message:opacity-100\",\n )}\n >\n <CopyActionButton />\n <EditActionButton />\n </ActionBarPrimitive.Root>\n);\n\nexport const UserMessage: FC = () => {\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 // A voice delegation's anchor is the ask the live voice model handed to the\n // thread, not words the user typed: it renders as the shared voice-task\n // card on every host instead of a second user bubble under the spoken turn.\n const isVoiceDelegation = useAuiState((s) =>\n isVoiceDelegationMessage({ messageId: s.message.id, custom: s.message.metadata?.custom }),\n );\n if (isWake) {\n return (\n <MessagePrimitive.Root data-message-role=\"user\" className=\"mb-3\">\n <WakeMarkerMessage />\n </MessagePrimitive.Root>\n );\n }\n if (isVoiceDelegation) {\n return (\n <MessagePrimitive.Root data-message-role=\"user\" className=\"mb-3\">\n <VoiceDelegationMessage />\n </MessagePrimitive.Root>\n );\n }\n return (\n <MessagePrimitive.Root\n data-message-role=\"user\"\n className=\"group/user-message mb-3 flex justify-end\"\n >\n <div className=\"flex min-w-0 max-w-[85%] flex-col items-end gap-1\">\n <div className=\"min-w-0 max-w-full rounded-2xl rounded-br-md bg-muted px-3.5 py-2 text-sm text-foreground\">\n <MessageImageGallery>\n <MessagePrimitive.Content components={USER_MESSAGE_PART_COMPONENTS} />\n </MessageImageGallery>\n </div>\n <div className=\"flex min-h-6 items-center gap-1\">\n <BranchPicker />\n <UserActionBar />\n </div>\n </div>\n </MessagePrimitive.Root>\n );\n};\n\nexport interface CreateAssistantMessageOptions {\n /** Host-registered card for tools without a dedicated UI. */\n toolFallback: ToolCallMessagePartComponent;\n /** Extra action-bar controls appended after copy/regenerate. */\n extraActions?: ReactNode;\n /**\n * Renders the message body. Hosts that group content into activity\n * timelines supply their own; the default renders markdown and tool cards.\n */\n content?: FC;\n /**\n * Inline affordance rendered inside a runtime-ending card (e.g. a Continue\n * button). Hosts without one leave it unset.\n */\n runtimeMessageAction?: ReactNode;\n}\n\n/**\n * Builds the assistant bubble. Call this once per host (memoized on its\n * inputs) so the returned component identity stays stable across renders.\n */\nexport function createAssistantMessage({\n toolFallback,\n extraActions,\n content: Content,\n runtimeMessageAction,\n}: CreateAssistantMessageOptions): FC {\n const AssistantActionBar: FC = () => {\n // The latest reply keeps its actions visible; older replies reveal them\n // on hover so a long transcript is not a wall of icon rows.\n const isLast = useAuiState((s) => s.message.isLast);\n return (\n <ActionBarPrimitive.Root\n autohide=\"never\"\n className={cn(\n \"mt-1 flex min-h-6 items-center gap-0.5\",\n !isLast && [\n ACTION_BAR_REVEAL_CLASS,\n \"group-hover/assistant-message:pointer-events-auto group-hover/assistant-message:opacity-100\",\n ],\n )}\n >\n <CopyActionButton />\n <RegenerateActionButton />\n {extraActions}\n </ActionBarPrimitive.Root>\n );\n };\n\n // A run-lifecycle marker or handoff summary is a system event, not\n // assistant speech. When it owns the whole row, render the status card in\n // place of the bubble; when it is chunked in with the assistant's own work\n // (or is a handoff whose text IS the closing summary), keep the body and\n // frame it with the card above.\n const RuntimeEnding: FC<{ placement: \"row\" | \"banner\" }> = ({ placement }) => {\n // Select the message (a stable store reference) and derive from it: the\n // reader allocates a fresh object per call, and `useAuiState` compares\n // snapshots with `Object.is`, so selecting the reader's result directly\n // would re-render on every store update and trip React's update-depth\n // guard.\n const message = useAuiState((s) => s.message);\n const runtime = useMemo(() => readRuntimeMessageFromSourceMessages(message), [message]);\n if (!runtime || runtime.silent) return null;\n if (placement === \"row\" && !runtime.isSoleSourceMessage) return null;\n if (placement === \"banner\" && runtime.isSoleSourceMessage && runtime.kind !== \"handoff\") {\n return null;\n }\n return <RuntimeMessageCard message={runtime} action={runtimeMessageAction} />;\n };\n\n const AssistantMessage: FC = () => {\n // An assistant row exists before its first token streams; showing\n // copy/regenerate against nothing looks broken, so wait for content.\n const showActions = useAuiState((state) =>\n hasVisibleContent(state.message.content),\n );\n // Primitive selector: the reader builds a fresh object per call.\n const soleRuntimeKind = useAuiState((s) => readSoleRuntimeMessageKind(s.message));\n const soleRuntimeSilent = useAuiState(\n (s) => readRuntimeMessageFromSourceMessages(s.message)?.silent === true,\n );\n\n if (soleRuntimeKind && soleRuntimeKind !== \"handoff\") {\n if (soleRuntimeSilent) return null;\n return (\n <MessagePrimitive.Root\n data-message-role=\"assistant\"\n className=\"group group/assistant-message mb-3\"\n >\n <div className=\"max-w-[95%]\">\n <RuntimeEnding placement=\"row\" />\n </div>\n </MessagePrimitive.Root>\n );\n }\n\n return (\n <MessagePrimitive.Root\n data-message-role=\"assistant\"\n className=\"group group/assistant-message mb-3\"\n >\n <div className=\"max-w-[95%]\">\n <AnswerLabel className=\"mb-1\" />\n <RuntimeEnding placement=\"banner\" />\n {Content ? (\n <Content />\n ) : (\n <MessagePrimitive.Content\n components={{\n Text: MarkdownText,\n tools: { Fallback: toolFallback },\n }}\n />\n )}\n {showActions ? (\n <div className=\"flex min-h-6 items-center gap-1\">\n <BranchPicker />\n <AssistantActionBar />\n </div>\n ) : null}\n </div>\n </MessagePrimitive.Root>\n );\n };\n\n return AssistantMessage;\n}\n\n/** Composer chrome: the dock around the composer, its surface and its rows. */\nexport const COMPOSER_DOCK_CLASS = \"bg-background px-2.5 pb-2 pt-1.5\";\nexport const COMPOSER_SURFACE_CLASS =\n \"relative flex flex-col gap-1 rounded-xl border border-neutral-200 bg-white shadow-[0_2px_10px_rgba(54,45,33,0.08)]\";\nexport const COMPOSER_EDITOR_ROW_CLASS = \"px-2.5 pt-1\";\nexport const COMPOSER_TOOLBAR_CLASS =\n \"flex items-center gap-1 border-t border-neutral-100 px-2 py-1.5\";\n/**\n * Paper composer chrome (`ChatComposerDock appearance=\"paper\"`): a card-toned\n * surface with a larger radius, a focus-within ring, a drag-over tint keyed\n * off `data-drag-active`, and a bottom rail — the chrome the SDK's\n * `AthenaChat` thread renders. Hosts on the default chrome above are\n * untouched. The dock carries no padding of its own; the paper host's footer\n * spaces it. The radius and border colour also bind to the `--composer-radius`\n * / `--composer-border` theme variables in `styles.css`.\n */\nexport const COMPOSER_PAPER_DOCK_CLASS = \"aui-composer-dock\";\nexport const COMPOSER_PAPER_SURFACE_CLASS =\n \"aui-composer-root relative flex w-full flex-col rounded-[1.375rem] border border-border bg-card p-2.5 text-card-foreground shadow-[0_1px_2px_rgba(0,0,0,0.04)] outline-none transition-shadow duration-150 focus-within:shadow-[0_8px_24px_-14px_rgba(0,0,0,0.25)] focus-within:ring-2 focus-within:ring-ring/40 data-[drag-active=true]:bg-primary/5 data-[drag-active=true]:ring-2 data-[drag-active=true]:ring-primary/40\";\nexport const COMPOSER_PAPER_EDITOR_ROW_CLASS = \"px-0.5\";\nexport const COMPOSER_PAPER_TOOLBAR_CLASS =\n \"aui-composer-action-wrapper relative flex items-center justify-between gap-1 pt-1\";\nexport const THREAD_SCROLL_TO_BOTTOM_CLASS =\n \"inline-flex items-center justify-center rounded-full border bg-background/80 p-1 shadow-sm backdrop-blur transition-opacity hover:bg-accent disabled:invisible\";\n\nconst ComposerStopIcon: FC = () => (\n <svg\n aria-hidden=\"true\"\n className=\"size-4\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n >\n <rect width=\"10\" height=\"10\" x=\"3\" y=\"3\" rx=\"2\" />\n </svg>\n);\n\nexport interface ComposerStopButtonProps {\n onStop: () => void;\n disabled?: boolean;\n title?: string;\n}\n\nexport interface ComposerSendButtonProps {\n action: Extract<ComposerAction, \"send\" | \"queue\">;\n onSend: () => void;\n disabled?: boolean;\n title?: string;\n}\n\n/** Stop control shown while a run is in flight and there is nothing queued. */\nexport const ComposerStopButton: FC<ComposerStopButtonProps> = ({\n onStop,\n disabled = false,\n title = \"Stop generation\",\n}) => (\n <button\n type=\"button\"\n onClick={onStop}\n disabled={disabled}\n title={title}\n className={cn(\n \"inline-flex size-8 shrink-0 items-center justify-center rounded-lg bg-foreground text-background shadow-sm transition-colors hover:bg-foreground/80\",\n disabled && \"cursor-not-allowed opacity-60\",\n )}\n >\n <ComposerStopIcon />\n </button>\n);\n/** Send control, which becomes a queue control while a run is in flight. */\nexport const ComposerSendButton: FC<ComposerSendButtonProps> = ({\n action,\n onSend,\n disabled = false,\n title,\n}) => (\n <button\n type=\"button\"\n onClick={onSend}\n disabled={disabled}\n title={title ?? (action === \"queue\" ? \"Queue message\" : \"Send\")}\n className={cn(\n \"inline-flex size-8 shrink-0 items-center justify-center rounded-full shadow-sm transition-colors\",\n disabled\n ? \"cursor-not-allowed bg-muted text-muted-foreground opacity-60\"\n : \"bg-foreground text-background hover:bg-foreground/80\",\n )}\n >\n {action === \"queue\" ? (\n <ListPlusIcon className=\"size-4\" />\n ) : (\n <ArrowUpIcon className=\"size-4\" />\n )}\n </button>\n);\n"],"names":["jsxs","BranchPickerPrimitive","jsx","SmallIconButton","ChevronLeftIcon","ChevronRightIcon","ActionBarPrimitive","AuiIf","CheckIcon","CopyIcon","useAuiState","useAthenaRunLive","useMessageActionsReadOnly","useChatOutboxReachable","useDeepAgentChatOutboxContext","CHAT_EDIT_UNREACHABLE_LABEL","PencilIcon","RefreshCwIcon","useSmooth","useMessagePartText","hideUnterminatedMarkdownLink","ChatMessageBody","composerMarkdown","DEEP_AGENT_COMPOSER_MARKDOWN_KEY","useMemo","readDeepAgentComposerMarkdown","MessageImagePart","cn","isGithubWakeMessage","isSubscriptionWakeMessage","isVoiceDelegationMessage","MessagePrimitive","WakeMarkerMessage","VoiceDelegationMessage","MessageImageGallery","readRuntimeMessageFromSourceMessages","RuntimeMessageCard","hasVisibleContent","readSoleRuntimeMessageKind","AnswerLabel","ListPlusIcon","ArrowUpIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"message-components.cjs","sources":["../../../src/chat-ui/messages/message-components.tsx"],"sourcesContent":["import {\n ActionBarPrimitive,\n AuiIf,\n BranchPickerPrimitive,\n MessagePrimitive,\n useAuiState,\n useMessagePartText,\n useSmooth,\n type ToolCallMessagePartComponent,\n} from \"@assistant-ui/react\";\nimport {\n CHAT_EDIT_UNREACHABLE_LABEL,\n DEEP_AGENT_COMPOSER_MARKDOWN_KEY,\n hideUnterminatedMarkdownLink,\n inboundMessageBody,\n isGithubWakeMessage,\n isSubscriptionWakeMessage,\n isVoiceDelegationMessage,\n readDeepAgentComposerMarkdown,\n readRuntimeMessageFromSourceMessages,\n readSoleRuntimeMessageKind,\n useChatOutboxReachable,\n useDeepAgentChatOutboxContext,\n} from \"@athenaintel/agent-runtime\";\nimport {\n ArrowUpIcon,\n CheckIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n CopyIcon,\n ListPlusIcon,\n PencilIcon,\n RefreshCwIcon,\n} from \"lucide-react\";\nimport {\n type FC,\n type ReactNode,\n useMemo,\n} from \"react\";\nimport { useAthenaRunLive } from \"../../chat/use-athena-run-live\";\nimport type { ComposerAction } from \"../composer/composer-action\";\nimport { cn } from \"../../lib/utils\";\nimport { ChatMessageBody } from \"../rich-text/chat-message-body\";\nimport { AnswerLabel } from \"./answer-label\";\nimport { InboundChannelLine, InboundChannelSubject } from \"./inbound-channel-message\";\nimport { useMessageActionsReadOnly } from \"./message-actions-config\";\nimport { MessageImageGallery, MessageImagePart } from \"./message-images\";\nimport { RuntimeMessageCard } from \"./runtime-message\";\nimport { hasVisibleContent } from \"./running-indicator\";\nimport { VoiceDelegationMessage } from \"./voice-delegation-card\";\nimport { WakeMarkerMessage } from \"./wake-marker\";\nimport { SmallIconButton } from \"./thread-chrome\";\n\nexport {\n IconButton,\n SmallIconButton,\n THREAD_HEADER_ACTIONS_CLASS,\n THREAD_HEADER_CLASS,\n THREAD_HEADER_ICON_CLASS,\n THREAD_HEADER_PILL_CLASS,\n THREAD_PANEL_CLASS,\n} from \"./thread-chrome\";\n\nexport const BranchPicker: FC = () => (\n <BranchPickerPrimitive.Root\n hideWhenSingleBranch\n className=\"inline-flex items-center gap-0.5 text-xs text-muted-foreground\"\n data-testid=\"chat-branch-picker\"\n >\n <BranchPickerPrimitive.Previous asChild>\n <SmallIconButton\n tooltip=\"Previous branch\"\n data-testid=\"chat-branch-previous\"\n >\n <ChevronLeftIcon className=\"size-3\" />\n </SmallIconButton>\n </BranchPickerPrimitive.Previous>\n <span className=\"font-medium\" data-testid=\"chat-branch-count\">\n <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />\n </span>\n <BranchPickerPrimitive.Next asChild>\n <SmallIconButton tooltip=\"Next branch\" data-testid=\"chat-branch-next\">\n <ChevronRightIcon className=\"size-3\" />\n </SmallIconButton>\n </BranchPickerPrimitive.Next>\n </BranchPickerPrimitive.Root>\n);\n\nconst CopyActionButton: FC = () => (\n <ActionBarPrimitive.Copy asChild>\n <SmallIconButton tooltip=\"Copy\">\n <AuiIf condition={(state) => state.message.isCopied}>\n <CheckIcon className=\"size-3\" />\n </AuiIf>\n <AuiIf condition={(state) => !state.message.isCopied}>\n <CopyIcon className=\"size-3\" />\n </AuiIf>\n </SmallIconButton>\n </ActionBarPrimitive.Copy>\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, where no error\n * boundary can catch it — so the button must gate on the capability and, to\n * match the rewind semantics of `run/edit`, stay hidden while a run is live.\n * The read-only context covers threads the capability flags cannot: a host's\n * static `edit: true` still applies to fenced legacy conversations. 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 EditActionButton: 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 <SmallIconButton\n tooltip={CHAT_EDIT_UNREACHABLE_LABEL}\n aria-disabled\n data-testid=\"chat-message-edit-unreachable\"\n className=\"cursor-not-allowed opacity-50 hover:bg-transparent hover:text-muted-foreground\"\n >\n <PencilIcon className=\"size-3\" />\n </SmallIconButton>\n );\n }\n return (\n <ActionBarPrimitive.Edit asChild>\n <SmallIconButton tooltip=\"Edit\" data-testid=\"chat-message-edit\">\n <PencilIcon className=\"size-3\" />\n </SmallIconButton>\n </ActionBarPrimitive.Edit>\n );\n};\n\n/** Regenerate dispatches `run/reload`, so it hides on read-only threads too. */\nconst RegenerateActionButton: FC = () => {\n const readOnly = useMessageActionsReadOnly();\n if (readOnly) return null;\n return (\n <ActionBarPrimitive.Reload asChild>\n <SmallIconButton tooltip=\"Regenerate\">\n <RefreshCwIcon className=\"size-3\" />\n </SmallIconButton>\n </ActionBarPrimitive.Reload>\n );\n};\n\n/**\n * Reveal-on-demand treatment for action bars: invisible and click-through\n * until the surrounding named group is hovered or a control inside receives\n * keyboard focus. The `focus-within` escape hatch is what keeps the hidden\n * controls reachable for keyboard users.\n */\nexport const ACTION_BAR_REVEAL_CLASS =\n \"pointer-events-none opacity-0 transition-opacity focus-within:pointer-events-auto focus-within:opacity-100\";\n\n/** Shared chat body; the reveal holds incomplete links until their URL is complete. */\nexport const MarkdownText: FC = () => {\n const revealed = useSmooth(useMessagePartText(), true);\n const isRunning = revealed.status.type === \"running\";\n const text = isRunning ? hideUnterminatedMarkdownLink(revealed.text) : revealed.text;\n return <ChatMessageBody text={text} isRunning={isRunning} />;\n};\n\n/**\n * A user message's text, shown as it was typed.\n *\n * A composer sends plain text exactly as typed, because the model reads it\n * literally, so the text alone no longer says which characters are\n * formatting: read as Markdown, `List<T>` loses `<T>`, `obj.__init__` shows a\n * bold \"init\" and `a\\\\b` one backslash. A composer send therefore carries the\n * draft it was serialized from (`metadata.composer_markdown`, only when the\n * two differ), and this renders that draft when it is a draft of the\n * message's own text (`readDeepAgentComposerMarkdown`), formatting and\n * mention chips included. Any other text — no draft, or one of other words —\n * renders with the typed reading (`ChatMessageBody typed`), which leaves raw\n * HTML and underscore emphasis as the characters they were typed with, so\n * `List<T>`, `obj.__init__` and `a\\b` show as typed there too.\n *\n * A message that came in over a channel (Slack, email, a text, Teams) starts\n * with the routing block the agent read (`<inbound-message-context>`); it\n * shows without it, as the words that were sent (`inboundMessageBody`), and\n * the line above the bubble opens the block (`InboundChannelSource`). Only a\n * message with the channel's `inbound_channel` envelope is one: tags a person\n * typed at the start of a chat message show as typed.\n *\n * Copy copies the message text, which is the text as sent, and Edit opens it\n * in a plain-text box, so neither reads the draft.\n */\nexport const UserMessageText: FC<{ text: string }> = ({ text }) => {\n const custom = useAuiState((s) => s.message.metadata?.custom);\n const shown = useMemo(() => {\n const body = inboundMessageBody({ custom, text });\n return (\n readDeepAgentComposerMarkdown({\n metadata: { [DEEP_AGENT_COMPOSER_MARKDOWN_KEY]: custom?.[DEEP_AGENT_COMPOSER_MARKDOWN_KEY] },\n text: body,\n }) ?? body\n );\n }, [custom, text]);\n return <ChatMessageBody text={shown} typed />;\n};\n\n/** A user message's parts: its text as typed, and its pictures, each opening the viewer. */\nconst USER_MESSAGE_PART_COMPONENTS = { Text: UserMessageText, Image: MessageImagePart };\n\nconst UserActionBar: FC = () => (\n <ActionBarPrimitive.Root\n autohide=\"never\"\n className={cn(\n \"flex min-h-6 items-center gap-0.5\",\n ACTION_BAR_REVEAL_CLASS,\n \"group-hover/user-message:pointer-events-auto group-hover/user-message:opacity-100\",\n )}\n >\n <CopyActionButton />\n <EditActionButton />\n </ActionBarPrimitive.Root>\n);\n\nexport const UserMessage: FC = () => {\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 // A voice delegation's anchor is the ask the live voice model handed to the\n // thread, not words the user typed: it renders as the shared voice-task\n // card on every host instead of a second user bubble under the spoken turn.\n const isVoiceDelegation = useAuiState((s) =>\n isVoiceDelegationMessage({ messageId: s.message.id, custom: s.message.metadata?.custom }),\n );\n if (isWake) {\n return (\n <MessagePrimitive.Root data-message-role=\"user\" className=\"mb-3\">\n <WakeMarkerMessage />\n </MessagePrimitive.Root>\n );\n }\n if (isVoiceDelegation) {\n return (\n <MessagePrimitive.Root data-message-role=\"user\" className=\"mb-3\">\n <VoiceDelegationMessage />\n </MessagePrimitive.Root>\n );\n }\n return (\n <MessagePrimitive.Root\n data-message-role=\"user\"\n className=\"group/user-message mb-3 flex justify-end\"\n >\n <div className=\"flex min-w-0 max-w-[85%] 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 <div className=\"min-w-0 max-w-full rounded-2xl rounded-br-md bg-muted px-3.5 py-2 text-sm text-foreground\">\n <InboundChannelSubject />\n <MessageImageGallery>\n <MessagePrimitive.Content components={USER_MESSAGE_PART_COMPONENTS} />\n </MessageImageGallery>\n </div>\n <div className=\"flex min-h-6 items-center gap-1\">\n <BranchPicker />\n <UserActionBar />\n </div>\n </div>\n </MessagePrimitive.Root>\n );\n};\n\nexport interface CreateAssistantMessageOptions {\n /** Host-registered card for tools without a dedicated UI. */\n toolFallback: ToolCallMessagePartComponent;\n /** Extra action-bar controls appended after copy/regenerate. */\n extraActions?: ReactNode;\n /**\n * Renders the message body. Hosts that group content into activity\n * timelines supply their own; the default renders markdown and tool cards.\n */\n content?: FC;\n /**\n * Inline affordance rendered inside a runtime-ending card (e.g. a Continue\n * button). Hosts without one leave it unset.\n */\n runtimeMessageAction?: ReactNode;\n}\n\n/**\n * Builds the assistant bubble. Call this once per host (memoized on its\n * inputs) so the returned component identity stays stable across renders.\n */\nexport function createAssistantMessage({\n toolFallback,\n extraActions,\n content: Content,\n runtimeMessageAction,\n}: CreateAssistantMessageOptions): FC {\n const AssistantActionBar: FC = () => {\n // The latest reply keeps its actions visible; older replies reveal them\n // on hover so a long transcript is not a wall of icon rows.\n const isLast = useAuiState((s) => s.message.isLast);\n return (\n <ActionBarPrimitive.Root\n autohide=\"never\"\n className={cn(\n \"mt-1 flex min-h-6 items-center gap-0.5\",\n !isLast && [\n ACTION_BAR_REVEAL_CLASS,\n \"group-hover/assistant-message:pointer-events-auto group-hover/assistant-message:opacity-100\",\n ],\n )}\n >\n <CopyActionButton />\n <RegenerateActionButton />\n {extraActions}\n </ActionBarPrimitive.Root>\n );\n };\n\n // A run-lifecycle marker or handoff summary is a system event, not\n // assistant speech. When it owns the whole row, render the status card in\n // place of the bubble; when it is chunked in with the assistant's own work\n // (or is a handoff whose text IS the closing summary), keep the body and\n // frame it with the card above.\n const RuntimeEnding: FC<{ placement: \"row\" | \"banner\" }> = ({ placement }) => {\n // Select the message (a stable store reference) and derive from it: the\n // reader allocates a fresh object per call, and `useAuiState` compares\n // snapshots with `Object.is`, so selecting the reader's result directly\n // would re-render on every store update and trip React's update-depth\n // guard.\n const message = useAuiState((s) => s.message);\n const runtime = useMemo(() => readRuntimeMessageFromSourceMessages(message), [message]);\n if (!runtime || runtime.silent) return null;\n if (placement === \"row\" && !runtime.isSoleSourceMessage) return null;\n if (placement === \"banner\" && runtime.isSoleSourceMessage && runtime.kind !== \"handoff\") {\n return null;\n }\n return <RuntimeMessageCard message={runtime} action={runtimeMessageAction} />;\n };\n\n const AssistantMessage: FC = () => {\n // An assistant row exists before its first token streams; showing\n // copy/regenerate against nothing looks broken, so wait for content.\n const showActions = useAuiState((state) =>\n hasVisibleContent(state.message.content),\n );\n // Primitive selector: the reader builds a fresh object per call.\n const soleRuntimeKind = useAuiState((s) => readSoleRuntimeMessageKind(s.message));\n const soleRuntimeSilent = useAuiState(\n (s) => readRuntimeMessageFromSourceMessages(s.message)?.silent === true,\n );\n\n if (soleRuntimeKind && soleRuntimeKind !== \"handoff\") {\n if (soleRuntimeSilent) return null;\n return (\n <MessagePrimitive.Root\n data-message-role=\"assistant\"\n className=\"group group/assistant-message mb-3\"\n >\n <div className=\"max-w-[95%]\">\n <RuntimeEnding placement=\"row\" />\n </div>\n </MessagePrimitive.Root>\n );\n }\n\n return (\n <MessagePrimitive.Root\n data-message-role=\"assistant\"\n className=\"group group/assistant-message mb-3\"\n >\n <div className=\"max-w-[95%]\">\n <AnswerLabel className=\"mb-1\" />\n <RuntimeEnding placement=\"banner\" />\n {Content ? (\n <Content />\n ) : (\n <MessagePrimitive.Content\n components={{\n Text: MarkdownText,\n tools: { Fallback: toolFallback },\n }}\n />\n )}\n {showActions ? (\n <div className=\"flex min-h-6 items-center gap-1\">\n <BranchPicker />\n <AssistantActionBar />\n </div>\n ) : null}\n </div>\n </MessagePrimitive.Root>\n );\n };\n\n return AssistantMessage;\n}\n\n/** Composer chrome: the dock around the composer, its surface and its rows. */\nexport const COMPOSER_DOCK_CLASS = \"bg-background px-2.5 pb-2 pt-1.5\";\nexport const COMPOSER_SURFACE_CLASS =\n \"relative flex flex-col gap-1 rounded-xl border border-neutral-200 bg-white shadow-[0_2px_10px_rgba(54,45,33,0.08)]\";\nexport const COMPOSER_EDITOR_ROW_CLASS = \"px-2.5 pt-1\";\nexport const COMPOSER_TOOLBAR_CLASS =\n \"flex items-center gap-1 border-t border-neutral-100 px-2 py-1.5\";\n/**\n * Paper composer chrome (`ChatComposerDock appearance=\"paper\"`): a card-toned\n * surface with a larger radius, a focus-within ring, a drag-over tint keyed\n * off `data-drag-active`, and a bottom rail — the chrome the SDK's\n * `AthenaChat` thread renders. Hosts on the default chrome above are\n * untouched. The dock carries no padding of its own; the paper host's footer\n * spaces it. The radius and border colour also bind to the `--composer-radius`\n * / `--composer-border` theme variables in `styles.css`.\n */\nexport const COMPOSER_PAPER_DOCK_CLASS = \"aui-composer-dock\";\nexport const COMPOSER_PAPER_SURFACE_CLASS =\n \"aui-composer-root relative flex w-full flex-col rounded-[1.375rem] border border-border bg-card p-2.5 text-card-foreground shadow-[0_1px_2px_rgba(0,0,0,0.04)] outline-none transition-shadow duration-150 focus-within:shadow-[0_8px_24px_-14px_rgba(0,0,0,0.25)] focus-within:ring-2 focus-within:ring-ring/40 data-[drag-active=true]:bg-primary/5 data-[drag-active=true]:ring-2 data-[drag-active=true]:ring-primary/40\";\nexport const COMPOSER_PAPER_EDITOR_ROW_CLASS = \"px-0.5\";\nexport const COMPOSER_PAPER_TOOLBAR_CLASS =\n \"aui-composer-action-wrapper relative flex items-center justify-between gap-1 pt-1\";\nexport const THREAD_SCROLL_TO_BOTTOM_CLASS =\n \"inline-flex items-center justify-center rounded-full border bg-background/80 p-1 shadow-sm backdrop-blur transition-opacity hover:bg-accent disabled:invisible\";\n\nconst ComposerStopIcon: FC = () => (\n <svg\n aria-hidden=\"true\"\n className=\"size-4\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n >\n <rect width=\"10\" height=\"10\" x=\"3\" y=\"3\" rx=\"2\" />\n </svg>\n);\n\nexport interface ComposerStopButtonProps {\n onStop: () => void;\n disabled?: boolean;\n title?: string;\n}\n\nexport interface ComposerSendButtonProps {\n action: Extract<ComposerAction, \"send\" | \"queue\">;\n onSend: () => void;\n disabled?: boolean;\n title?: string;\n}\n\n/** Stop control shown while a run is in flight and there is nothing queued. */\nexport const ComposerStopButton: FC<ComposerStopButtonProps> = ({\n onStop,\n disabled = false,\n title = \"Stop generation\",\n}) => (\n <button\n type=\"button\"\n onClick={onStop}\n disabled={disabled}\n title={title}\n className={cn(\n \"inline-flex size-8 shrink-0 items-center justify-center rounded-lg bg-foreground text-background shadow-sm transition-colors hover:bg-foreground/80\",\n disabled && \"cursor-not-allowed opacity-60\",\n )}\n >\n <ComposerStopIcon />\n </button>\n);\n/** Send control, which becomes a queue control while a run is in flight. */\nexport const ComposerSendButton: FC<ComposerSendButtonProps> = ({\n action,\n onSend,\n disabled = false,\n title,\n}) => (\n <button\n type=\"button\"\n onClick={onSend}\n disabled={disabled}\n title={title ?? (action === \"queue\" ? \"Queue message\" : \"Send\")}\n className={cn(\n \"inline-flex size-8 shrink-0 items-center justify-center rounded-full shadow-sm transition-colors\",\n disabled\n ? \"cursor-not-allowed bg-muted text-muted-foreground opacity-60\"\n : \"bg-foreground text-background hover:bg-foreground/80\",\n )}\n >\n {action === \"queue\" ? (\n <ListPlusIcon className=\"size-4\" />\n ) : (\n <ArrowUpIcon className=\"size-4\" />\n )}\n </button>\n);\n"],"names":["jsxs","BranchPickerPrimitive","jsx","SmallIconButton","ChevronLeftIcon","ChevronRightIcon","ActionBarPrimitive","AuiIf","CheckIcon","CopyIcon","useAuiState","useAthenaRunLive","useMessageActionsReadOnly","useChatOutboxReachable","useDeepAgentChatOutboxContext","CHAT_EDIT_UNREACHABLE_LABEL","PencilIcon","RefreshCwIcon","useSmooth","useMessagePartText","hideUnterminatedMarkdownLink","ChatMessageBody","useMemo","inboundMessageBody","readDeepAgentComposerMarkdown","DEEP_AGENT_COMPOSER_MARKDOWN_KEY","MessageImagePart","cn","isGithubWakeMessage","isSubscriptionWakeMessage","isVoiceDelegationMessage","MessagePrimitive","WakeMarkerMessage","VoiceDelegationMessage","InboundChannelLine","InboundChannelSubject","MessageImageGallery","readRuntimeMessageFromSourceMessages","RuntimeMessageCard","hasVisibleContent","readSoleRuntimeMessageKind","AnswerLabel","ListPlusIcon","ArrowUpIcon"],"mappings":"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"}
|
|
@@ -27,6 +27,13 @@ export declare const MarkdownText: FC;
|
|
|
27
27
|
* HTML and underscore emphasis as the characters they were typed with, so
|
|
28
28
|
* `List<T>`, `obj.__init__` and `a\b` show as typed there too.
|
|
29
29
|
*
|
|
30
|
+
* A message that came in over a channel (Slack, email, a text, Teams) starts
|
|
31
|
+
* with the routing block the agent read (`<inbound-message-context>`); it
|
|
32
|
+
* shows without it, as the words that were sent (`inboundMessageBody`), and
|
|
33
|
+
* the line above the bubble opens the block (`InboundChannelSource`). Only a
|
|
34
|
+
* message with the channel's `inbound_channel` envelope is one: tags a person
|
|
35
|
+
* typed at the start of a chat message show as typed.
|
|
36
|
+
*
|
|
30
37
|
* Copy copies the message text, which is the text as sent, and Edit opens it
|
|
31
38
|
* in a plain-text box, so neither reads the draft.
|
|
32
39
|
*/
|
|
@@ -5,6 +5,7 @@ import { useMemo } from "react";
|
|
|
5
5
|
import { useAthenaRunLive } from "../../chat/use-athena-run-live.js";
|
|
6
6
|
import { ChatMessageBody } from "../rich-text/chat-message-body.js";
|
|
7
7
|
import { AnswerLabel } from "./answer-label.js";
|
|
8
|
+
import { InboundChannelLine, InboundChannelSubject } from "./inbound-channel-message.js";
|
|
8
9
|
import { useMessageActionsReadOnly } from "./message-actions-config.js";
|
|
9
10
|
import { MessageImageGallery, MessageImagePart } from "./message-images.js";
|
|
10
11
|
import { RuntimeMessageCard } from "./runtime-message.js";
|
|
@@ -17,7 +18,8 @@ import { hideUnterminatedMarkdownLink } from "../../agent-runtime/src/streaming-
|
|
|
17
18
|
import { isGithubWakeMessage } from "../../agent-runtime/src/github-wake-event.js";
|
|
18
19
|
import { isSubscriptionWakeMessage } from "../../agent-runtime/src/subscription-wake-event.js";
|
|
19
20
|
import { isVoiceDelegationMessage } from "../../agent-runtime/src/voice-presentation.js";
|
|
20
|
-
import {
|
|
21
|
+
import { inboundMessageBody } from "../../agent-runtime/src/inbound-channel.js";
|
|
22
|
+
import { readDeepAgentComposerMarkdown, DEEP_AGENT_COMPOSER_MARKDOWN_KEY } from "../../agent-runtime/src/composer-markdown.js";
|
|
21
23
|
import { readSoleRuntimeMessageKind, readRuntimeMessageFromSourceMessages } from "../../agent-runtime/src/runtime-messages.js";
|
|
22
24
|
import { useChatOutboxReachable, useDeepAgentChatOutboxContext } from "../../agent-runtime/src/use-deep-agent-chat-outbox.js";
|
|
23
25
|
import { CHAT_EDIT_UNREACHABLE_LABEL } from "../../agent-runtime/src/chat-outbox.js";
|
|
@@ -83,19 +85,17 @@ const MarkdownText = () => {
|
|
|
83
85
|
return /* @__PURE__ */ jsx(ChatMessageBody, { text, isRunning });
|
|
84
86
|
};
|
|
85
87
|
const UserMessageText = ({ text }) => {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
[composerMarkdown, text]
|
|
98
|
-
);
|
|
88
|
+
const custom = useAuiState((s) => {
|
|
89
|
+
var _a;
|
|
90
|
+
return (_a = s.message.metadata) == null ? void 0 : _a.custom;
|
|
91
|
+
});
|
|
92
|
+
const shown = useMemo(() => {
|
|
93
|
+
const body = inboundMessageBody({ custom, text });
|
|
94
|
+
return readDeepAgentComposerMarkdown({
|
|
95
|
+
metadata: { [DEEP_AGENT_COMPOSER_MARKDOWN_KEY]: custom == null ? void 0 : custom[DEEP_AGENT_COMPOSER_MARKDOWN_KEY] },
|
|
96
|
+
text: body
|
|
97
|
+
}) ?? body;
|
|
98
|
+
}, [custom, text]);
|
|
99
99
|
return /* @__PURE__ */ jsx(ChatMessageBody, { text: shown, typed: true });
|
|
100
100
|
};
|
|
101
101
|
const USER_MESSAGE_PART_COMPONENTS = { Text: UserMessageText, Image: MessageImagePart };
|
|
@@ -139,7 +139,11 @@ const UserMessage = () => {
|
|
|
139
139
|
"data-message-role": "user",
|
|
140
140
|
className: "group/user-message mb-3 flex justify-end",
|
|
141
141
|
children: /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 max-w-[85%] flex-col items-end gap-1", children: [
|
|
142
|
-
/* @__PURE__ */ jsx(
|
|
142
|
+
/* @__PURE__ */ jsx(InboundChannelLine, {}),
|
|
143
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 max-w-full rounded-2xl rounded-br-md bg-muted px-3.5 py-2 text-sm text-foreground", children: [
|
|
144
|
+
/* @__PURE__ */ jsx(InboundChannelSubject, {}),
|
|
145
|
+
/* @__PURE__ */ jsx(MessageImageGallery, { children: /* @__PURE__ */ jsx(MessagePrimitive.Content, { components: USER_MESSAGE_PART_COMPONENTS }) })
|
|
146
|
+
] }),
|
|
143
147
|
/* @__PURE__ */ jsxs("div", { className: "flex min-h-6 items-center gap-1", children: [
|
|
144
148
|
/* @__PURE__ */ jsx(BranchPicker, {}),
|
|
145
149
|
/* @__PURE__ */ jsx(UserActionBar, {})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-components.js","sources":["../../../src/chat-ui/messages/message-components.tsx"],"sourcesContent":["import {\n ActionBarPrimitive,\n AuiIf,\n BranchPickerPrimitive,\n MessagePrimitive,\n useAuiState,\n useMessagePartText,\n useSmooth,\n type ToolCallMessagePartComponent,\n} from \"@assistant-ui/react\";\nimport {\n CHAT_EDIT_UNREACHABLE_LABEL,\n DEEP_AGENT_COMPOSER_MARKDOWN_KEY,\n hideUnterminatedMarkdownLink,\n isGithubWakeMessage,\n isSubscriptionWakeMessage,\n isVoiceDelegationMessage,\n readDeepAgentComposerMarkdown,\n readRuntimeMessageFromSourceMessages,\n readSoleRuntimeMessageKind,\n useChatOutboxReachable,\n useDeepAgentChatOutboxContext,\n} from \"@athenaintel/agent-runtime\";\nimport {\n ArrowUpIcon,\n CheckIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n CopyIcon,\n ListPlusIcon,\n PencilIcon,\n RefreshCwIcon,\n} from \"lucide-react\";\nimport {\n type FC,\n type ReactNode,\n useMemo,\n} from \"react\";\nimport { useAthenaRunLive } from \"../../chat/use-athena-run-live\";\nimport type { ComposerAction } from \"../composer/composer-action\";\nimport { cn } from \"../../lib/utils\";\nimport { ChatMessageBody } from \"../rich-text/chat-message-body\";\nimport { AnswerLabel } from \"./answer-label\";\nimport { useMessageActionsReadOnly } from \"./message-actions-config\";\nimport { MessageImageGallery, MessageImagePart } from \"./message-images\";\nimport { RuntimeMessageCard } from \"./runtime-message\";\nimport { hasVisibleContent } from \"./running-indicator\";\nimport { VoiceDelegationMessage } from \"./voice-delegation-card\";\nimport { WakeMarkerMessage } from \"./wake-marker\";\nimport { SmallIconButton } from \"./thread-chrome\";\n\nexport {\n IconButton,\n SmallIconButton,\n THREAD_HEADER_ACTIONS_CLASS,\n THREAD_HEADER_CLASS,\n THREAD_HEADER_ICON_CLASS,\n THREAD_HEADER_PILL_CLASS,\n THREAD_PANEL_CLASS,\n} from \"./thread-chrome\";\n\nexport const BranchPicker: FC = () => (\n <BranchPickerPrimitive.Root\n hideWhenSingleBranch\n className=\"inline-flex items-center gap-0.5 text-xs text-muted-foreground\"\n data-testid=\"chat-branch-picker\"\n >\n <BranchPickerPrimitive.Previous asChild>\n <SmallIconButton\n tooltip=\"Previous branch\"\n data-testid=\"chat-branch-previous\"\n >\n <ChevronLeftIcon className=\"size-3\" />\n </SmallIconButton>\n </BranchPickerPrimitive.Previous>\n <span className=\"font-medium\" data-testid=\"chat-branch-count\">\n <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />\n </span>\n <BranchPickerPrimitive.Next asChild>\n <SmallIconButton tooltip=\"Next branch\" data-testid=\"chat-branch-next\">\n <ChevronRightIcon className=\"size-3\" />\n </SmallIconButton>\n </BranchPickerPrimitive.Next>\n </BranchPickerPrimitive.Root>\n);\n\nconst CopyActionButton: FC = () => (\n <ActionBarPrimitive.Copy asChild>\n <SmallIconButton tooltip=\"Copy\">\n <AuiIf condition={(state) => state.message.isCopied}>\n <CheckIcon className=\"size-3\" />\n </AuiIf>\n <AuiIf condition={(state) => !state.message.isCopied}>\n <CopyIcon className=\"size-3\" />\n </AuiIf>\n </SmallIconButton>\n </ActionBarPrimitive.Copy>\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, where no error\n * boundary can catch it — so the button must gate on the capability and, to\n * match the rewind semantics of `run/edit`, stay hidden while a run is live.\n * The read-only context covers threads the capability flags cannot: a host's\n * static `edit: true` still applies to fenced legacy conversations. 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 EditActionButton: 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 <SmallIconButton\n tooltip={CHAT_EDIT_UNREACHABLE_LABEL}\n aria-disabled\n data-testid=\"chat-message-edit-unreachable\"\n className=\"cursor-not-allowed opacity-50 hover:bg-transparent hover:text-muted-foreground\"\n >\n <PencilIcon className=\"size-3\" />\n </SmallIconButton>\n );\n }\n return (\n <ActionBarPrimitive.Edit asChild>\n <SmallIconButton tooltip=\"Edit\" data-testid=\"chat-message-edit\">\n <PencilIcon className=\"size-3\" />\n </SmallIconButton>\n </ActionBarPrimitive.Edit>\n );\n};\n\n/** Regenerate dispatches `run/reload`, so it hides on read-only threads too. */\nconst RegenerateActionButton: FC = () => {\n const readOnly = useMessageActionsReadOnly();\n if (readOnly) return null;\n return (\n <ActionBarPrimitive.Reload asChild>\n <SmallIconButton tooltip=\"Regenerate\">\n <RefreshCwIcon className=\"size-3\" />\n </SmallIconButton>\n </ActionBarPrimitive.Reload>\n );\n};\n\n/**\n * Reveal-on-demand treatment for action bars: invisible and click-through\n * until the surrounding named group is hovered or a control inside receives\n * keyboard focus. The `focus-within` escape hatch is what keeps the hidden\n * controls reachable for keyboard users.\n */\nexport const ACTION_BAR_REVEAL_CLASS =\n \"pointer-events-none opacity-0 transition-opacity focus-within:pointer-events-auto focus-within:opacity-100\";\n\n/** Shared chat body; the reveal holds incomplete links until their URL is complete. */\nexport const MarkdownText: FC = () => {\n const revealed = useSmooth(useMessagePartText(), true);\n const isRunning = revealed.status.type === \"running\";\n const text = isRunning ? hideUnterminatedMarkdownLink(revealed.text) : revealed.text;\n return <ChatMessageBody text={text} isRunning={isRunning} />;\n};\n\n/**\n * A user message's text, shown as it was typed.\n *\n * A composer sends plain text exactly as typed, because the model reads it\n * literally, so the text alone no longer says which characters are\n * formatting: read as Markdown, `List<T>` loses `<T>`, `obj.__init__` shows a\n * bold \"init\" and `a\\\\b` one backslash. A composer send therefore carries the\n * draft it was serialized from (`metadata.composer_markdown`, only when the\n * two differ), and this renders that draft when it is a draft of the\n * message's own text (`readDeepAgentComposerMarkdown`), formatting and\n * mention chips included. Any other text — no draft, or one of other words —\n * renders with the typed reading (`ChatMessageBody typed`), which leaves raw\n * HTML and underscore emphasis as the characters they were typed with, so\n * `List<T>`, `obj.__init__` and `a\\b` show as typed there too.\n *\n * Copy copies the message text, which is the text as sent, and Edit opens it\n * in a plain-text box, so neither reads the draft.\n */\nexport const UserMessageText: FC<{ text: string }> = ({ text }) => {\n const composerMarkdown: unknown = useAuiState(\n (s) => s.message.metadata?.custom?.[DEEP_AGENT_COMPOSER_MARKDOWN_KEY],\n );\n const shown = useMemo(\n () =>\n readDeepAgentComposerMarkdown({\n metadata: { [DEEP_AGENT_COMPOSER_MARKDOWN_KEY]: composerMarkdown },\n text,\n }) ?? text,\n [composerMarkdown, text],\n );\n return <ChatMessageBody text={shown} typed />;\n};\n\n/** A user message's parts: its text as typed, and its pictures, each opening the viewer. */\nconst USER_MESSAGE_PART_COMPONENTS = { Text: UserMessageText, Image: MessageImagePart };\n\nconst UserActionBar: FC = () => (\n <ActionBarPrimitive.Root\n autohide=\"never\"\n className={cn(\n \"flex min-h-6 items-center gap-0.5\",\n ACTION_BAR_REVEAL_CLASS,\n \"group-hover/user-message:pointer-events-auto group-hover/user-message:opacity-100\",\n )}\n >\n <CopyActionButton />\n <EditActionButton />\n </ActionBarPrimitive.Root>\n);\n\nexport const UserMessage: FC = () => {\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 // A voice delegation's anchor is the ask the live voice model handed to the\n // thread, not words the user typed: it renders as the shared voice-task\n // card on every host instead of a second user bubble under the spoken turn.\n const isVoiceDelegation = useAuiState((s) =>\n isVoiceDelegationMessage({ messageId: s.message.id, custom: s.message.metadata?.custom }),\n );\n if (isWake) {\n return (\n <MessagePrimitive.Root data-message-role=\"user\" className=\"mb-3\">\n <WakeMarkerMessage />\n </MessagePrimitive.Root>\n );\n }\n if (isVoiceDelegation) {\n return (\n <MessagePrimitive.Root data-message-role=\"user\" className=\"mb-3\">\n <VoiceDelegationMessage />\n </MessagePrimitive.Root>\n );\n }\n return (\n <MessagePrimitive.Root\n data-message-role=\"user\"\n className=\"group/user-message mb-3 flex justify-end\"\n >\n <div className=\"flex min-w-0 max-w-[85%] flex-col items-end gap-1\">\n <div className=\"min-w-0 max-w-full rounded-2xl rounded-br-md bg-muted px-3.5 py-2 text-sm text-foreground\">\n <MessageImageGallery>\n <MessagePrimitive.Content components={USER_MESSAGE_PART_COMPONENTS} />\n </MessageImageGallery>\n </div>\n <div className=\"flex min-h-6 items-center gap-1\">\n <BranchPicker />\n <UserActionBar />\n </div>\n </div>\n </MessagePrimitive.Root>\n );\n};\n\nexport interface CreateAssistantMessageOptions {\n /** Host-registered card for tools without a dedicated UI. */\n toolFallback: ToolCallMessagePartComponent;\n /** Extra action-bar controls appended after copy/regenerate. */\n extraActions?: ReactNode;\n /**\n * Renders the message body. Hosts that group content into activity\n * timelines supply their own; the default renders markdown and tool cards.\n */\n content?: FC;\n /**\n * Inline affordance rendered inside a runtime-ending card (e.g. a Continue\n * button). Hosts without one leave it unset.\n */\n runtimeMessageAction?: ReactNode;\n}\n\n/**\n * Builds the assistant bubble. Call this once per host (memoized on its\n * inputs) so the returned component identity stays stable across renders.\n */\nexport function createAssistantMessage({\n toolFallback,\n extraActions,\n content: Content,\n runtimeMessageAction,\n}: CreateAssistantMessageOptions): FC {\n const AssistantActionBar: FC = () => {\n // The latest reply keeps its actions visible; older replies reveal them\n // on hover so a long transcript is not a wall of icon rows.\n const isLast = useAuiState((s) => s.message.isLast);\n return (\n <ActionBarPrimitive.Root\n autohide=\"never\"\n className={cn(\n \"mt-1 flex min-h-6 items-center gap-0.5\",\n !isLast && [\n ACTION_BAR_REVEAL_CLASS,\n \"group-hover/assistant-message:pointer-events-auto group-hover/assistant-message:opacity-100\",\n ],\n )}\n >\n <CopyActionButton />\n <RegenerateActionButton />\n {extraActions}\n </ActionBarPrimitive.Root>\n );\n };\n\n // A run-lifecycle marker or handoff summary is a system event, not\n // assistant speech. When it owns the whole row, render the status card in\n // place of the bubble; when it is chunked in with the assistant's own work\n // (or is a handoff whose text IS the closing summary), keep the body and\n // frame it with the card above.\n const RuntimeEnding: FC<{ placement: \"row\" | \"banner\" }> = ({ placement }) => {\n // Select the message (a stable store reference) and derive from it: the\n // reader allocates a fresh object per call, and `useAuiState` compares\n // snapshots with `Object.is`, so selecting the reader's result directly\n // would re-render on every store update and trip React's update-depth\n // guard.\n const message = useAuiState((s) => s.message);\n const runtime = useMemo(() => readRuntimeMessageFromSourceMessages(message), [message]);\n if (!runtime || runtime.silent) return null;\n if (placement === \"row\" && !runtime.isSoleSourceMessage) return null;\n if (placement === \"banner\" && runtime.isSoleSourceMessage && runtime.kind !== \"handoff\") {\n return null;\n }\n return <RuntimeMessageCard message={runtime} action={runtimeMessageAction} />;\n };\n\n const AssistantMessage: FC = () => {\n // An assistant row exists before its first token streams; showing\n // copy/regenerate against nothing looks broken, so wait for content.\n const showActions = useAuiState((state) =>\n hasVisibleContent(state.message.content),\n );\n // Primitive selector: the reader builds a fresh object per call.\n const soleRuntimeKind = useAuiState((s) => readSoleRuntimeMessageKind(s.message));\n const soleRuntimeSilent = useAuiState(\n (s) => readRuntimeMessageFromSourceMessages(s.message)?.silent === true,\n );\n\n if (soleRuntimeKind && soleRuntimeKind !== \"handoff\") {\n if (soleRuntimeSilent) return null;\n return (\n <MessagePrimitive.Root\n data-message-role=\"assistant\"\n className=\"group group/assistant-message mb-3\"\n >\n <div className=\"max-w-[95%]\">\n <RuntimeEnding placement=\"row\" />\n </div>\n </MessagePrimitive.Root>\n );\n }\n\n return (\n <MessagePrimitive.Root\n data-message-role=\"assistant\"\n className=\"group group/assistant-message mb-3\"\n >\n <div className=\"max-w-[95%]\">\n <AnswerLabel className=\"mb-1\" />\n <RuntimeEnding placement=\"banner\" />\n {Content ? (\n <Content />\n ) : (\n <MessagePrimitive.Content\n components={{\n Text: MarkdownText,\n tools: { Fallback: toolFallback },\n }}\n />\n )}\n {showActions ? (\n <div className=\"flex min-h-6 items-center gap-1\">\n <BranchPicker />\n <AssistantActionBar />\n </div>\n ) : null}\n </div>\n </MessagePrimitive.Root>\n );\n };\n\n return AssistantMessage;\n}\n\n/** Composer chrome: the dock around the composer, its surface and its rows. */\nexport const COMPOSER_DOCK_CLASS = \"bg-background px-2.5 pb-2 pt-1.5\";\nexport const COMPOSER_SURFACE_CLASS =\n \"relative flex flex-col gap-1 rounded-xl border border-neutral-200 bg-white shadow-[0_2px_10px_rgba(54,45,33,0.08)]\";\nexport const COMPOSER_EDITOR_ROW_CLASS = \"px-2.5 pt-1\";\nexport const COMPOSER_TOOLBAR_CLASS =\n \"flex items-center gap-1 border-t border-neutral-100 px-2 py-1.5\";\n/**\n * Paper composer chrome (`ChatComposerDock appearance=\"paper\"`): a card-toned\n * surface with a larger radius, a focus-within ring, a drag-over tint keyed\n * off `data-drag-active`, and a bottom rail — the chrome the SDK's\n * `AthenaChat` thread renders. Hosts on the default chrome above are\n * untouched. The dock carries no padding of its own; the paper host's footer\n * spaces it. The radius and border colour also bind to the `--composer-radius`\n * / `--composer-border` theme variables in `styles.css`.\n */\nexport const COMPOSER_PAPER_DOCK_CLASS = \"aui-composer-dock\";\nexport const COMPOSER_PAPER_SURFACE_CLASS =\n \"aui-composer-root relative flex w-full flex-col rounded-[1.375rem] border border-border bg-card p-2.5 text-card-foreground shadow-[0_1px_2px_rgba(0,0,0,0.04)] outline-none transition-shadow duration-150 focus-within:shadow-[0_8px_24px_-14px_rgba(0,0,0,0.25)] focus-within:ring-2 focus-within:ring-ring/40 data-[drag-active=true]:bg-primary/5 data-[drag-active=true]:ring-2 data-[drag-active=true]:ring-primary/40\";\nexport const COMPOSER_PAPER_EDITOR_ROW_CLASS = \"px-0.5\";\nexport const COMPOSER_PAPER_TOOLBAR_CLASS =\n \"aui-composer-action-wrapper relative flex items-center justify-between gap-1 pt-1\";\nexport const THREAD_SCROLL_TO_BOTTOM_CLASS =\n \"inline-flex items-center justify-center rounded-full border bg-background/80 p-1 shadow-sm backdrop-blur transition-opacity hover:bg-accent disabled:invisible\";\n\nconst ComposerStopIcon: FC = () => (\n <svg\n aria-hidden=\"true\"\n className=\"size-4\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n >\n <rect width=\"10\" height=\"10\" x=\"3\" y=\"3\" rx=\"2\" />\n </svg>\n);\n\nexport interface ComposerStopButtonProps {\n onStop: () => void;\n disabled?: boolean;\n title?: string;\n}\n\nexport interface ComposerSendButtonProps {\n action: Extract<ComposerAction, \"send\" | \"queue\">;\n onSend: () => void;\n disabled?: boolean;\n title?: string;\n}\n\n/** Stop control shown while a run is in flight and there is nothing queued. */\nexport const ComposerStopButton: FC<ComposerStopButtonProps> = ({\n onStop,\n disabled = false,\n title = \"Stop generation\",\n}) => (\n <button\n type=\"button\"\n onClick={onStop}\n disabled={disabled}\n title={title}\n className={cn(\n \"inline-flex size-8 shrink-0 items-center justify-center rounded-lg bg-foreground text-background shadow-sm transition-colors hover:bg-foreground/80\",\n disabled && \"cursor-not-allowed opacity-60\",\n )}\n >\n <ComposerStopIcon />\n </button>\n);\n/** Send control, which becomes a queue control while a run is in flight. */\nexport const ComposerSendButton: FC<ComposerSendButtonProps> = ({\n action,\n onSend,\n disabled = false,\n title,\n}) => (\n <button\n type=\"button\"\n onClick={onSend}\n disabled={disabled}\n title={title ?? (action === \"queue\" ? \"Queue message\" : \"Send\")}\n className={cn(\n \"inline-flex size-8 shrink-0 items-center justify-center rounded-full shadow-sm transition-colors\",\n disabled\n ? \"cursor-not-allowed bg-muted text-muted-foreground opacity-60\"\n : \"bg-foreground text-background hover:bg-foreground/80\",\n )}\n >\n {action === \"queue\" ? (\n <ListPlusIcon className=\"size-4\" />\n ) : (\n <ArrowUpIcon className=\"size-4\" />\n )}\n </button>\n);\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"message-components.js","sources":["../../../src/chat-ui/messages/message-components.tsx"],"sourcesContent":["import {\n ActionBarPrimitive,\n AuiIf,\n BranchPickerPrimitive,\n MessagePrimitive,\n useAuiState,\n useMessagePartText,\n useSmooth,\n type ToolCallMessagePartComponent,\n} from \"@assistant-ui/react\";\nimport {\n CHAT_EDIT_UNREACHABLE_LABEL,\n DEEP_AGENT_COMPOSER_MARKDOWN_KEY,\n hideUnterminatedMarkdownLink,\n inboundMessageBody,\n isGithubWakeMessage,\n isSubscriptionWakeMessage,\n isVoiceDelegationMessage,\n readDeepAgentComposerMarkdown,\n readRuntimeMessageFromSourceMessages,\n readSoleRuntimeMessageKind,\n useChatOutboxReachable,\n useDeepAgentChatOutboxContext,\n} from \"@athenaintel/agent-runtime\";\nimport {\n ArrowUpIcon,\n CheckIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n CopyIcon,\n ListPlusIcon,\n PencilIcon,\n RefreshCwIcon,\n} from \"lucide-react\";\nimport {\n type FC,\n type ReactNode,\n useMemo,\n} from \"react\";\nimport { useAthenaRunLive } from \"../../chat/use-athena-run-live\";\nimport type { ComposerAction } from \"../composer/composer-action\";\nimport { cn } from \"../../lib/utils\";\nimport { ChatMessageBody } from \"../rich-text/chat-message-body\";\nimport { AnswerLabel } from \"./answer-label\";\nimport { InboundChannelLine, InboundChannelSubject } from \"./inbound-channel-message\";\nimport { useMessageActionsReadOnly } from \"./message-actions-config\";\nimport { MessageImageGallery, MessageImagePart } from \"./message-images\";\nimport { RuntimeMessageCard } from \"./runtime-message\";\nimport { hasVisibleContent } from \"./running-indicator\";\nimport { VoiceDelegationMessage } from \"./voice-delegation-card\";\nimport { WakeMarkerMessage } from \"./wake-marker\";\nimport { SmallIconButton } from \"./thread-chrome\";\n\nexport {\n IconButton,\n SmallIconButton,\n THREAD_HEADER_ACTIONS_CLASS,\n THREAD_HEADER_CLASS,\n THREAD_HEADER_ICON_CLASS,\n THREAD_HEADER_PILL_CLASS,\n THREAD_PANEL_CLASS,\n} from \"./thread-chrome\";\n\nexport const BranchPicker: FC = () => (\n <BranchPickerPrimitive.Root\n hideWhenSingleBranch\n className=\"inline-flex items-center gap-0.5 text-xs text-muted-foreground\"\n data-testid=\"chat-branch-picker\"\n >\n <BranchPickerPrimitive.Previous asChild>\n <SmallIconButton\n tooltip=\"Previous branch\"\n data-testid=\"chat-branch-previous\"\n >\n <ChevronLeftIcon className=\"size-3\" />\n </SmallIconButton>\n </BranchPickerPrimitive.Previous>\n <span className=\"font-medium\" data-testid=\"chat-branch-count\">\n <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />\n </span>\n <BranchPickerPrimitive.Next asChild>\n <SmallIconButton tooltip=\"Next branch\" data-testid=\"chat-branch-next\">\n <ChevronRightIcon className=\"size-3\" />\n </SmallIconButton>\n </BranchPickerPrimitive.Next>\n </BranchPickerPrimitive.Root>\n);\n\nconst CopyActionButton: FC = () => (\n <ActionBarPrimitive.Copy asChild>\n <SmallIconButton tooltip=\"Copy\">\n <AuiIf condition={(state) => state.message.isCopied}>\n <CheckIcon className=\"size-3\" />\n </AuiIf>\n <AuiIf condition={(state) => !state.message.isCopied}>\n <CopyIcon className=\"size-3\" />\n </AuiIf>\n </SmallIconButton>\n </ActionBarPrimitive.Copy>\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, where no error\n * boundary can catch it — so the button must gate on the capability and, to\n * match the rewind semantics of `run/edit`, stay hidden while a run is live.\n * The read-only context covers threads the capability flags cannot: a host's\n * static `edit: true` still applies to fenced legacy conversations. 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 EditActionButton: 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 <SmallIconButton\n tooltip={CHAT_EDIT_UNREACHABLE_LABEL}\n aria-disabled\n data-testid=\"chat-message-edit-unreachable\"\n className=\"cursor-not-allowed opacity-50 hover:bg-transparent hover:text-muted-foreground\"\n >\n <PencilIcon className=\"size-3\" />\n </SmallIconButton>\n );\n }\n return (\n <ActionBarPrimitive.Edit asChild>\n <SmallIconButton tooltip=\"Edit\" data-testid=\"chat-message-edit\">\n <PencilIcon className=\"size-3\" />\n </SmallIconButton>\n </ActionBarPrimitive.Edit>\n );\n};\n\n/** Regenerate dispatches `run/reload`, so it hides on read-only threads too. */\nconst RegenerateActionButton: FC = () => {\n const readOnly = useMessageActionsReadOnly();\n if (readOnly) return null;\n return (\n <ActionBarPrimitive.Reload asChild>\n <SmallIconButton tooltip=\"Regenerate\">\n <RefreshCwIcon className=\"size-3\" />\n </SmallIconButton>\n </ActionBarPrimitive.Reload>\n );\n};\n\n/**\n * Reveal-on-demand treatment for action bars: invisible and click-through\n * until the surrounding named group is hovered or a control inside receives\n * keyboard focus. The `focus-within` escape hatch is what keeps the hidden\n * controls reachable for keyboard users.\n */\nexport const ACTION_BAR_REVEAL_CLASS =\n \"pointer-events-none opacity-0 transition-opacity focus-within:pointer-events-auto focus-within:opacity-100\";\n\n/** Shared chat body; the reveal holds incomplete links until their URL is complete. */\nexport const MarkdownText: FC = () => {\n const revealed = useSmooth(useMessagePartText(), true);\n const isRunning = revealed.status.type === \"running\";\n const text = isRunning ? hideUnterminatedMarkdownLink(revealed.text) : revealed.text;\n return <ChatMessageBody text={text} isRunning={isRunning} />;\n};\n\n/**\n * A user message's text, shown as it was typed.\n *\n * A composer sends plain text exactly as typed, because the model reads it\n * literally, so the text alone no longer says which characters are\n * formatting: read as Markdown, `List<T>` loses `<T>`, `obj.__init__` shows a\n * bold \"init\" and `a\\\\b` one backslash. A composer send therefore carries the\n * draft it was serialized from (`metadata.composer_markdown`, only when the\n * two differ), and this renders that draft when it is a draft of the\n * message's own text (`readDeepAgentComposerMarkdown`), formatting and\n * mention chips included. Any other text — no draft, or one of other words —\n * renders with the typed reading (`ChatMessageBody typed`), which leaves raw\n * HTML and underscore emphasis as the characters they were typed with, so\n * `List<T>`, `obj.__init__` and `a\\b` show as typed there too.\n *\n * A message that came in over a channel (Slack, email, a text, Teams) starts\n * with the routing block the agent read (`<inbound-message-context>`); it\n * shows without it, as the words that were sent (`inboundMessageBody`), and\n * the line above the bubble opens the block (`InboundChannelSource`). Only a\n * message with the channel's `inbound_channel` envelope is one: tags a person\n * typed at the start of a chat message show as typed.\n *\n * Copy copies the message text, which is the text as sent, and Edit opens it\n * in a plain-text box, so neither reads the draft.\n */\nexport const UserMessageText: FC<{ text: string }> = ({ text }) => {\n const custom = useAuiState((s) => s.message.metadata?.custom);\n const shown = useMemo(() => {\n const body = inboundMessageBody({ custom, text });\n return (\n readDeepAgentComposerMarkdown({\n metadata: { [DEEP_AGENT_COMPOSER_MARKDOWN_KEY]: custom?.[DEEP_AGENT_COMPOSER_MARKDOWN_KEY] },\n text: body,\n }) ?? body\n );\n }, [custom, text]);\n return <ChatMessageBody text={shown} typed />;\n};\n\n/** A user message's parts: its text as typed, and its pictures, each opening the viewer. */\nconst USER_MESSAGE_PART_COMPONENTS = { Text: UserMessageText, Image: MessageImagePart };\n\nconst UserActionBar: FC = () => (\n <ActionBarPrimitive.Root\n autohide=\"never\"\n className={cn(\n \"flex min-h-6 items-center gap-0.5\",\n ACTION_BAR_REVEAL_CLASS,\n \"group-hover/user-message:pointer-events-auto group-hover/user-message:opacity-100\",\n )}\n >\n <CopyActionButton />\n <EditActionButton />\n </ActionBarPrimitive.Root>\n);\n\nexport const UserMessage: FC = () => {\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 // A voice delegation's anchor is the ask the live voice model handed to the\n // thread, not words the user typed: it renders as the shared voice-task\n // card on every host instead of a second user bubble under the spoken turn.\n const isVoiceDelegation = useAuiState((s) =>\n isVoiceDelegationMessage({ messageId: s.message.id, custom: s.message.metadata?.custom }),\n );\n if (isWake) {\n return (\n <MessagePrimitive.Root data-message-role=\"user\" className=\"mb-3\">\n <WakeMarkerMessage />\n </MessagePrimitive.Root>\n );\n }\n if (isVoiceDelegation) {\n return (\n <MessagePrimitive.Root data-message-role=\"user\" className=\"mb-3\">\n <VoiceDelegationMessage />\n </MessagePrimitive.Root>\n );\n }\n return (\n <MessagePrimitive.Root\n data-message-role=\"user\"\n className=\"group/user-message mb-3 flex justify-end\"\n >\n <div className=\"flex min-w-0 max-w-[85%] 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 <div className=\"min-w-0 max-w-full rounded-2xl rounded-br-md bg-muted px-3.5 py-2 text-sm text-foreground\">\n <InboundChannelSubject />\n <MessageImageGallery>\n <MessagePrimitive.Content components={USER_MESSAGE_PART_COMPONENTS} />\n </MessageImageGallery>\n </div>\n <div className=\"flex min-h-6 items-center gap-1\">\n <BranchPicker />\n <UserActionBar />\n </div>\n </div>\n </MessagePrimitive.Root>\n );\n};\n\nexport interface CreateAssistantMessageOptions {\n /** Host-registered card for tools without a dedicated UI. */\n toolFallback: ToolCallMessagePartComponent;\n /** Extra action-bar controls appended after copy/regenerate. */\n extraActions?: ReactNode;\n /**\n * Renders the message body. Hosts that group content into activity\n * timelines supply their own; the default renders markdown and tool cards.\n */\n content?: FC;\n /**\n * Inline affordance rendered inside a runtime-ending card (e.g. a Continue\n * button). Hosts without one leave it unset.\n */\n runtimeMessageAction?: ReactNode;\n}\n\n/**\n * Builds the assistant bubble. Call this once per host (memoized on its\n * inputs) so the returned component identity stays stable across renders.\n */\nexport function createAssistantMessage({\n toolFallback,\n extraActions,\n content: Content,\n runtimeMessageAction,\n}: CreateAssistantMessageOptions): FC {\n const AssistantActionBar: FC = () => {\n // The latest reply keeps its actions visible; older replies reveal them\n // on hover so a long transcript is not a wall of icon rows.\n const isLast = useAuiState((s) => s.message.isLast);\n return (\n <ActionBarPrimitive.Root\n autohide=\"never\"\n className={cn(\n \"mt-1 flex min-h-6 items-center gap-0.5\",\n !isLast && [\n ACTION_BAR_REVEAL_CLASS,\n \"group-hover/assistant-message:pointer-events-auto group-hover/assistant-message:opacity-100\",\n ],\n )}\n >\n <CopyActionButton />\n <RegenerateActionButton />\n {extraActions}\n </ActionBarPrimitive.Root>\n );\n };\n\n // A run-lifecycle marker or handoff summary is a system event, not\n // assistant speech. When it owns the whole row, render the status card in\n // place of the bubble; when it is chunked in with the assistant's own work\n // (or is a handoff whose text IS the closing summary), keep the body and\n // frame it with the card above.\n const RuntimeEnding: FC<{ placement: \"row\" | \"banner\" }> = ({ placement }) => {\n // Select the message (a stable store reference) and derive from it: the\n // reader allocates a fresh object per call, and `useAuiState` compares\n // snapshots with `Object.is`, so selecting the reader's result directly\n // would re-render on every store update and trip React's update-depth\n // guard.\n const message = useAuiState((s) => s.message);\n const runtime = useMemo(() => readRuntimeMessageFromSourceMessages(message), [message]);\n if (!runtime || runtime.silent) return null;\n if (placement === \"row\" && !runtime.isSoleSourceMessage) return null;\n if (placement === \"banner\" && runtime.isSoleSourceMessage && runtime.kind !== \"handoff\") {\n return null;\n }\n return <RuntimeMessageCard message={runtime} action={runtimeMessageAction} />;\n };\n\n const AssistantMessage: FC = () => {\n // An assistant row exists before its first token streams; showing\n // copy/regenerate against nothing looks broken, so wait for content.\n const showActions = useAuiState((state) =>\n hasVisibleContent(state.message.content),\n );\n // Primitive selector: the reader builds a fresh object per call.\n const soleRuntimeKind = useAuiState((s) => readSoleRuntimeMessageKind(s.message));\n const soleRuntimeSilent = useAuiState(\n (s) => readRuntimeMessageFromSourceMessages(s.message)?.silent === true,\n );\n\n if (soleRuntimeKind && soleRuntimeKind !== \"handoff\") {\n if (soleRuntimeSilent) return null;\n return (\n <MessagePrimitive.Root\n data-message-role=\"assistant\"\n className=\"group group/assistant-message mb-3\"\n >\n <div className=\"max-w-[95%]\">\n <RuntimeEnding placement=\"row\" />\n </div>\n </MessagePrimitive.Root>\n );\n }\n\n return (\n <MessagePrimitive.Root\n data-message-role=\"assistant\"\n className=\"group group/assistant-message mb-3\"\n >\n <div className=\"max-w-[95%]\">\n <AnswerLabel className=\"mb-1\" />\n <RuntimeEnding placement=\"banner\" />\n {Content ? (\n <Content />\n ) : (\n <MessagePrimitive.Content\n components={{\n Text: MarkdownText,\n tools: { Fallback: toolFallback },\n }}\n />\n )}\n {showActions ? (\n <div className=\"flex min-h-6 items-center gap-1\">\n <BranchPicker />\n <AssistantActionBar />\n </div>\n ) : null}\n </div>\n </MessagePrimitive.Root>\n );\n };\n\n return AssistantMessage;\n}\n\n/** Composer chrome: the dock around the composer, its surface and its rows. */\nexport const COMPOSER_DOCK_CLASS = \"bg-background px-2.5 pb-2 pt-1.5\";\nexport const COMPOSER_SURFACE_CLASS =\n \"relative flex flex-col gap-1 rounded-xl border border-neutral-200 bg-white shadow-[0_2px_10px_rgba(54,45,33,0.08)]\";\nexport const COMPOSER_EDITOR_ROW_CLASS = \"px-2.5 pt-1\";\nexport const COMPOSER_TOOLBAR_CLASS =\n \"flex items-center gap-1 border-t border-neutral-100 px-2 py-1.5\";\n/**\n * Paper composer chrome (`ChatComposerDock appearance=\"paper\"`): a card-toned\n * surface with a larger radius, a focus-within ring, a drag-over tint keyed\n * off `data-drag-active`, and a bottom rail — the chrome the SDK's\n * `AthenaChat` thread renders. Hosts on the default chrome above are\n * untouched. The dock carries no padding of its own; the paper host's footer\n * spaces it. The radius and border colour also bind to the `--composer-radius`\n * / `--composer-border` theme variables in `styles.css`.\n */\nexport const COMPOSER_PAPER_DOCK_CLASS = \"aui-composer-dock\";\nexport const COMPOSER_PAPER_SURFACE_CLASS =\n \"aui-composer-root relative flex w-full flex-col rounded-[1.375rem] border border-border bg-card p-2.5 text-card-foreground shadow-[0_1px_2px_rgba(0,0,0,0.04)] outline-none transition-shadow duration-150 focus-within:shadow-[0_8px_24px_-14px_rgba(0,0,0,0.25)] focus-within:ring-2 focus-within:ring-ring/40 data-[drag-active=true]:bg-primary/5 data-[drag-active=true]:ring-2 data-[drag-active=true]:ring-primary/40\";\nexport const COMPOSER_PAPER_EDITOR_ROW_CLASS = \"px-0.5\";\nexport const COMPOSER_PAPER_TOOLBAR_CLASS =\n \"aui-composer-action-wrapper relative flex items-center justify-between gap-1 pt-1\";\nexport const THREAD_SCROLL_TO_BOTTOM_CLASS =\n \"inline-flex items-center justify-center rounded-full border bg-background/80 p-1 shadow-sm backdrop-blur transition-opacity hover:bg-accent disabled:invisible\";\n\nconst ComposerStopIcon: FC = () => (\n <svg\n aria-hidden=\"true\"\n className=\"size-4\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n >\n <rect width=\"10\" height=\"10\" x=\"3\" y=\"3\" rx=\"2\" />\n </svg>\n);\n\nexport interface ComposerStopButtonProps {\n onStop: () => void;\n disabled?: boolean;\n title?: string;\n}\n\nexport interface ComposerSendButtonProps {\n action: Extract<ComposerAction, \"send\" | \"queue\">;\n onSend: () => void;\n disabled?: boolean;\n title?: string;\n}\n\n/** Stop control shown while a run is in flight and there is nothing queued. */\nexport const ComposerStopButton: FC<ComposerStopButtonProps> = ({\n onStop,\n disabled = false,\n title = \"Stop generation\",\n}) => (\n <button\n type=\"button\"\n onClick={onStop}\n disabled={disabled}\n title={title}\n className={cn(\n \"inline-flex size-8 shrink-0 items-center justify-center rounded-lg bg-foreground text-background shadow-sm transition-colors hover:bg-foreground/80\",\n disabled && \"cursor-not-allowed opacity-60\",\n )}\n >\n <ComposerStopIcon />\n </button>\n);\n/** Send control, which becomes a queue control while a run is in flight. */\nexport const ComposerSendButton: FC<ComposerSendButtonProps> = ({\n action,\n onSend,\n disabled = false,\n title,\n}) => (\n <button\n type=\"button\"\n onClick={onSend}\n disabled={disabled}\n title={title ?? (action === \"queue\" ? \"Queue message\" : \"Send\")}\n className={cn(\n \"inline-flex size-8 shrink-0 items-center justify-center rounded-full shadow-sm transition-colors\",\n disabled\n ? \"cursor-not-allowed bg-muted text-muted-foreground opacity-60\"\n : \"bg-foreground text-background hover:bg-foreground/80\",\n )}\n >\n {action === \"queue\" ? (\n <ListPlusIcon className=\"size-4\" />\n ) : (\n <ArrowUpIcon className=\"size-4\" />\n )}\n </button>\n);\n"],"names":[],"mappings":"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"}
|
|
@@ -161,14 +161,11 @@ const HistoryEdgeRow = ({
|
|
|
161
161
|
};
|
|
162
162
|
const StatewireHistoryEdge = ({
|
|
163
163
|
toolOutputs: toolOutputsProp,
|
|
164
|
-
historyPages: historyPagesProp,
|
|
165
164
|
className,
|
|
166
165
|
onHistoryLoad
|
|
167
166
|
}) => {
|
|
168
167
|
const providerToolOutputs = statewireWindowContext.useStatewireToolOutputs();
|
|
169
168
|
const toolOutputs = toolOutputsProp ?? providerToolOutputs ?? void 0;
|
|
170
|
-
const providerHistoryPages = statewireWindowContext.useStatewireHistoryPages();
|
|
171
|
-
const historyPages = historyPagesProp === null ? void 0 : historyPagesProp ?? providerHistoryPages ?? void 0;
|
|
172
169
|
const messages = react.useAuiState((s) => s.thread.messages);
|
|
173
170
|
const threadId = require$$0.useContext(threadIdContext.AthenaStatewireThreadIdContext);
|
|
174
171
|
const [nearTop, setNearTop] = require$$0.useState(false);
|
|
@@ -195,7 +192,6 @@ const StatewireHistoryEdge = ({
|
|
|
195
192
|
isMessageMounted,
|
|
196
193
|
maxConcurrentToolOutputs: HISTORY_EDGE_TOOL_OUTPUT_CONCURRENCY,
|
|
197
194
|
onHistoryLoad,
|
|
198
|
-
historyPages,
|
|
199
195
|
onError: (error, command) => {
|
|
200
196
|
if (error instanceof Error && errors.isStatewireChannelTeardown(error)) return;
|
|
201
197
|
console.warn(`[StatewireHistoryEdge] ${command} failed:`, error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statewire-history-edge.cjs","sources":["../../../src/chat-ui/thread/statewire-history-edge.tsx"],"sourcesContent":["import {\n getExternalStoreMessages,\n type ThreadMessage,\n type ThreadViewportState,\n useAuiState,\n useThreadViewport,\n useThreadViewportStore,\n} from \"@assistant-ui/react\";\nimport {\n type DeepAgentHistoryLoadEvent,\n type DeepAgentHistoryStore,\n type DeepAgentToolOutputStore,\n isStatewireChannelTeardown,\n useDeepAgentWindowSync,\n} from \"@athenaintel/agent-runtime\";\nimport type { FC } from \"react\";\nimport { Component, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport {\n NO_STATEWIRE_HISTORY,\n StatewireHistoryContext,\n} from \"../../provider/statewire-history-context\";\nimport {\n useStatewireHistoryPages,\n useStatewireToolOutputs,\n} from \"../../provider/statewire-window-context\";\nimport { AthenaStatewireThreadIdContext } from \"../../threads/thread-id-context\";\n\n/** The attribute `ChatThreadShell` stamps on the scroll viewport. */\nexport const THREAD_VIEWPORT_ATTR = \"data-aui-thread-viewport\";\n/** The attribute `ChatThreadShell` stamps on its sticky viewport footer (the composer dock). */\nexport const THREAD_VIEWPORT_FOOTER_ATTR = \"data-aui-thread-viewport-footer\";\n\n/**\n * How far above the viewport the edge row counts as near: the row sits above\n * the first loaded message, so reaching it means the user has scrolled past\n * everything loaded and the next page should already be on its way. Messages\n * this close to the viewport also count as on screen for cut tool outputs.\n */\nexport const HISTORY_EDGE_NEAR_MARGIN_PX = 1500;\n\n/**\n * Cut tool outputs a transcript reads at once. The reads share the session's\n * command lane with everything the person sends, so a long transcript must\n * not queue dozens of them ahead of a message or a Stop.\n */\nexport const HISTORY_EDGE_TOOL_OUTPUT_CONCURRENCY = 2;\n\n/** What assistant-ui's `MessagePrimitive.Root` stamps on every message. */\nconst MESSAGE_SELECTOR = \"[data-message-id]\";\n\nconst NO_MESSAGE_IDS: ReadonlySet<string> = new Set();\n\nfunction sameIds({ a, b }: { a: ReadonlySet<string>; b: ReadonlySet<string> }): boolean {\n if (a.size !== b.size) return false;\n for (const id of a) if (!b.has(id)) return false;\n return true;\n}\n\n/**\n * Which messages sit within {@link HISTORY_EDGE_NEAR_MARGIN_PX} of the\n * viewport, so cut tool outputs are read for what the person can reach. A\n * thread opens at its newest turn; reading every loaded step's output up\n * front sent dozens of reads, each re-rendering the transcript, for steps\n * nobody had scrolled to.\n *\n * `undefined` (every message counts) where nothing can be observed: no\n * viewport around the row, or no `IntersectionObserver`. A message rendered\n * without a `data-message-id` root (a host's own renderer) cannot be observed\n * either, so it counts as before.\n */\nfunction useMessagesNearViewport({\n viewport,\n hasViewport,\n messages,\n}: {\n viewport: HTMLElement | null;\n /** A viewport is (or will be) registered around the row. */\n hasViewport: boolean;\n /** The converted thread: every change may have mounted or remounted a message. */\n messages: readonly ThreadMessage[];\n}): ((messageId: string) => boolean) | undefined {\n const [nearIds, setNearIds] = useState<ReadonlySet<string>>(NO_MESSAGE_IDS);\n const observable = hasViewport && typeof IntersectionObserver !== \"undefined\";\n const trackRef = useRef<(() => void) | null>(null);\n // Every id a rendered element carries, as of the last scan.\n const renderedIdsRef = useRef<ReadonlySet<string>>(NO_MESSAGE_IDS);\n\n useEffect(() => {\n if (!viewport || !observable) return undefined;\n const near = new Set<Element>();\n const observed = new Set<Element>();\n const publish = () => {\n const ids = new Set<string>();\n for (const element of near) {\n const id = element.getAttribute(\"data-message-id\");\n if (id) ids.add(id);\n }\n setNearIds((previous) => (sameIds({ a: previous, b: ids }) ? previous : ids));\n };\n const intersections = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting && entry.target.isConnected) near.add(entry.target);\n else near.delete(entry.target);\n }\n publish();\n },\n { root: viewport, rootMargin: `${HISTORY_EDGE_NEAR_MARGIN_PX}px 0px` },\n );\n // A page that folds into a turn gives it a new id: a host keyed by id\n // remounts the turn's element, a host keyed by row (`ChatThreadShell`)\n // keeps it and the element's id changes. So what is observed follows the\n // rendered elements, not the message list, and the near ids are read off\n // those elements again on every scan.\n const track = () => {\n for (const element of observed) {\n if (element.isConnected) continue;\n intersections.unobserve(element);\n observed.delete(element);\n near.delete(element);\n }\n const rendered = new Set<string>();\n for (const element of viewport.querySelectorAll(MESSAGE_SELECTOR)) {\n const id = element.getAttribute(\"data-message-id\");\n if (id) rendered.add(id);\n if (observed.has(element)) continue;\n observed.add(element);\n intersections.observe(element);\n }\n renderedIdsRef.current = rendered;\n publish();\n };\n trackRef.current = track;\n track();\n return () => {\n trackRef.current = null;\n renderedIdsRef.current = NO_MESSAGE_IDS;\n intersections.disconnect();\n setNearIds(NO_MESSAGE_IDS);\n };\n }, [viewport, observable]);\n\n // A changed message list is the trigger to re-scan: its messages render in\n // the same commit, so their elements are in the DOM by this effect (a\n // query, no layout read).\n useEffect(() => {\n trackRef.current?.();\n }, [messages]);\n\n return useMemo(() => {\n if (!observable) return undefined;\n return (messageId: string) => {\n // Not registered yet: nothing is on screen to read for.\n if (viewport === null) return false;\n return nearIds.has(messageId) || !renderedIdsRef.current.has(messageId);\n };\n }, [nearIds, observable, viewport]);\n}\n\n/** The wire message a converted message was built from first (its oldest source). */\nfunction oldestSourceId(message: ThreadMessage): string | undefined {\n const source = getExternalStoreMessages<{ id?: unknown }>(message)[0];\n return typeof source?.id === \"string\" ? source.id : undefined;\n}\n\n/**\n * Whether older history landed ahead of what was loaded: the old first\n * message now sits further down (a page ahead of it), or the first message's\n * old oldest wire message now follows earlier ones (a page that folded into\n * the first loaded turn). A first message replaced in place — a branch picked\n * on it, an edit — is neither, and a run streaming at the tail never touches\n * the first message.\n */\nfunction prependedOlderHistory({\n previous,\n next,\n}: {\n previous: readonly ThreadMessage[];\n next: readonly ThreadMessage[];\n}): boolean {\n const previousFirst = previous[0];\n const nextFirst = next[0];\n if (previousFirst === undefined || nextFirst === undefined || previousFirst === nextFirst) return false;\n if (previousFirst.id !== nextFirst.id && next.some((message, index) => index > 0 && message.id === previousFirst.id)) {\n return true;\n }\n const previousOldest = oldestSourceId(previousFirst);\n if (previousOldest === undefined || previousOldest === oldestSourceId(nextFirst)) return false;\n return getExternalStoreMessages<{ id?: unknown }>(nextFirst).some(\n (source, index) => index > 0 && source?.id === previousOldest,\n );\n}\n\ninterface KeepReadingPlaceProps {\n viewport: HTMLElement | null;\n threadId: string | null;\n /** The converted thread. */\n messages: readonly ThreadMessage[];\n}\n\n/**\n * Keeps the reader's place when older history lands. Everything a page adds\n * sits above what the person is reading, so their distance from the bottom of\n * the transcript is what must survive. A class for `getSnapshotBeforeUpdate`:\n * the distance is read right before React applies the commit that renders the\n * page — the one moment it is exact, even for a scroll the browser has not\n * reported yet — and restored after it, instantly (never through the\n * viewport's smooth scrolling). Other commits read no layout.\n *\n * The browser's scroll anchoring and assistant-ui's prepend anchor aim at the\n * same position, so whichever ran first leaves this nothing to do; on its own\n * it covers what they miss: a reader at the very top (browsers never anchor\n * at scroll offset 0) and a page that folds into the first loaded turn of a\n * host that keys rows by message id (that message remounts under a new id,\n * taking the browser's anchor node with it; `ChatThreadShell` keeps the row).\n */\nclass KeepReadingPlace extends Component<KeepReadingPlaceProps> {\n getSnapshotBeforeUpdate(previous: Readonly<KeepReadingPlaceProps>): number | null {\n const { viewport, threadId, messages } = this.props;\n if (\n viewport === null ||\n viewport !== previous.viewport ||\n threadId !== previous.threadId ||\n messages === previous.messages ||\n !prependedOlderHistory({ previous: previous.messages, next: messages })\n ) {\n return null;\n }\n return viewport.scrollHeight - viewport.scrollTop;\n }\n\n componentDidUpdate(\n _previous: Readonly<KeepReadingPlaceProps>,\n _state: unknown,\n fromBottom: number | null,\n ): void {\n const { viewport } = this.props;\n if (viewport === null || fromBottom === null) return;\n const top = viewport.scrollHeight - fromBottom;\n if (Math.abs(viewport.scrollTop - top) >= 1) viewport.scrollTo({ top, behavior: \"instant\" });\n }\n\n render(): null {\n return null;\n }\n}\n\nexport interface HistoryEdgeRowProps {\n /** Whether the server holds messages older than the loaded window. */\n hasOlder: boolean;\n /** Whether the next page can be asked for; `false` with `hasOlder` is the connection's loading depth spent. Defaults to `hasOlder`. */\n canLoadOlder?: boolean;\n /** A page of older history is in flight. */\n loading: boolean;\n onLoadOlder: () => void;\n className?: string;\n /** The row element, for the viewport observer. */\n rowRef?: (element: HTMLElement | null) => void;\n}\n\n/**\n * The top edge of the LOADED history: a manual way to load the next page of\n * older messages, and the in-flight state. Renders nothing when the whole\n * transcript is loaded (or the head interest has not resolved).\n */\nexport const HistoryEdgeRow: FC<HistoryEdgeRowProps> = ({\n hasOlder,\n canLoadOlder = hasOlder,\n loading,\n onLoadOlder,\n className,\n rowRef,\n}) => {\n if (!hasOlder) return null;\n return (\n <div\n ref={rowRef}\n data-testid=\"thread-history-edge\"\n className={cn(\n \"mx-auto flex w-full max-w-(--thread-max-width) items-center justify-center py-1 text-xs text-muted-foreground\",\n className,\n )}\n >\n {loading ? (\n <span data-testid=\"thread-history-edge-loading\">Loading earlier messages…</span>\n ) : canLoadOlder ? (\n <button\n type=\"button\"\n data-testid=\"thread-history-edge-load\"\n onClick={onLoadOlder}\n className=\"rounded-lg px-2.5 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n >\n Load earlier messages\n </button>\n ) : (\n <span data-testid=\"thread-history-edge-limit\">Earlier messages can't be loaded here</span>\n )}\n </div>\n );\n};\n\nexport interface StatewireHistoryEdgeProps {\n /**\n * The thread's tool-output store (the one its converter substitutes from).\n * Defaults to `AthenaProvider`'s; hosts mounting the runtime themselves pass\n * the store they gave `useDeepAgentRuntime({ toolOutputs })`.\n */\n toolOutputs?: DeepAgentToolOutputStore;\n /**\n * Where older turns are paged by command (`history/page`) from a host that\n * answers it: the store the thread joins (`useDeepAgentThread({\n * historyStore })`). Defaults to `AthenaProvider`'s; `null` keeps interest\n * pages even under the provider. A host that mounts the runtime itself\n * also provides the store through `StatewireHistoryPagesContext` and the\n * control through `TurnStepsControlContext` (`EarlierStepsButton`), so a\n * summarized turn's rows can open its steps.\n */\n historyPages?: DeepAgentHistoryStore | null;\n className?: string;\n /** A page interest resolved (telemetry). */\n onHistoryLoad?: (event: DeepAgentHistoryLoadEvent) => void;\n}\n\n/**\n * The client half of the interest window for a DOM thread — mounted once per\n * thread, inside the scroll viewport above the messages (`ChatThreadShell`'s\n * `beforeMessages` slot):\n *\n * - renders the \"Load earlier messages\" edge row and loads the next page when\n * the row comes near the viewport (scrolling up) or on its button, keeping\n * the reading position when the page lands above the view;\n * - fetches cut tool outputs whole for the cards near the viewport, a few at\n * a time, so they re-render complete through the converter (`toolOutputs`).\n *\n * Inert until the head interest resolves: no row, no reads.\n */\nexport const StatewireHistoryEdge: FC<StatewireHistoryEdgeProps> = ({\n toolOutputs: toolOutputsProp,\n historyPages: historyPagesProp,\n className,\n onHistoryLoad,\n}) => {\n const providerToolOutputs = useStatewireToolOutputs();\n const toolOutputs = toolOutputsProp ?? providerToolOutputs ?? undefined;\n const providerHistoryPages = useStatewireHistoryPages();\n const historyPages =\n historyPagesProp === null ? undefined : (historyPagesProp ?? providerHistoryPages ?? undefined);\n const messages = useAuiState((s) => s.thread.messages);\n const threadId = useContext(AthenaStatewireThreadIdContext);\n const [nearTop, setNearTop] = useState(false);\n const [nearTopEpoch, setNearTopEpoch] = useState(0);\n const nearTopRef = useRef(false);\n const [rowEl, setRowEl] = useState<HTMLElement | null>(null);\n // The scroll viewport the thread registered (assistant-ui's viewport store),\n // known even while the row renders nothing; the row's ancestor otherwise.\n const hasViewportStore = useThreadViewportStore({ optional: true }) !== null;\n const registeredViewport = useThreadViewport({\n optional: true,\n selector: (state: ThreadViewportState) => state.element.viewport,\n });\n const viewport =\n registeredViewport ?? rowEl?.closest<HTMLElement>(`[${THREAD_VIEWPORT_ATTR}]`) ?? null;\n const isMessageMounted = useMessagesNearViewport({\n viewport,\n hasViewport: hasViewportStore || viewport !== null,\n messages,\n });\n const historyStore = useContext(StatewireHistoryContext);\n const { hasOlder, canLoadOlder, loading, loadOlder } = useDeepAgentWindowSync({\n messages,\n toolOutputs,\n nearTop,\n nearTopEpoch,\n isMessageMounted,\n maxConcurrentToolOutputs: HISTORY_EDGE_TOOL_OUTPUT_CONCURRENCY,\n onHistoryLoad,\n historyPages,\n onError: (error, command) => {\n // Leaving the thread settles an in-flight read as lost: lifecycle, not a failure.\n if (error instanceof Error && isStatewireChannelTeardown(error)) return;\n console.warn(`[StatewireHistoryEdge] ${command} failed:`, error);\n },\n });\n\n // Other surfaces of the provider (the workbench's Shell pane) read where the\n // history stands; leaving the thread or unmounting withdraws the report.\n useEffect(() => {\n if (!historyStore || !threadId) return undefined;\n historyStore.set({ threadId, hasOlder, canLoadOlder, loading, loadOlder });\n return undefined;\n }, [historyStore, threadId, hasOlder, canLoadOlder, loading, loadOlder]);\n useEffect(() => {\n if (!historyStore || !threadId) return undefined;\n return () => {\n if (historyStore.get().threadId === threadId) historyStore.set(NO_STATEWIRE_HISTORY);\n };\n }, [historyStore, threadId]);\n\n // The row's own visibility is the near-top level: a level, not an edge, so\n // pages chain while the user stays at the top and stop once the prepended\n // content has pushed the row away again.\n useEffect(() => {\n if (!rowEl || !hasOlder || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n const near = entry.isIntersecting;\n if (nearTopRef.current === near) continue;\n nearTopRef.current = near;\n setNearTop(near);\n if (near) setNearTopEpoch((epoch) => epoch + 1);\n }\n },\n {\n root: viewport,\n rootMargin: `${HISTORY_EDGE_NEAR_MARGIN_PX}px 0px`,\n },\n );\n observer.observe(rowEl);\n return () => {\n observer.disconnect();\n nearTopRef.current = false;\n setNearTop(false);\n };\n }, [rowEl, hasOlder, viewport]);\n\n return (\n <>\n <KeepReadingPlace viewport={viewport} threadId={threadId} messages={messages} />\n <HistoryEdgeRow\n rowRef={setRowEl}\n hasOlder={hasOlder}\n canLoadOlder={canLoadOlder}\n loading={loading}\n onLoadOlder={loadOlder}\n className={className}\n />\n </>\n );\n};\n"],"names":["useState","useRef","useEffect","useMemo","getExternalStoreMessages","Component","jsx","cn","useStatewireToolOutputs","useStatewireHistoryPages","useAuiState","useContext","AthenaStatewireThreadIdContext","useThreadViewportStore","useThreadViewport","StatewireHistoryContext","useDeepAgentWindowSync","isStatewireChannelTeardown","NO_STATEWIRE_HISTORY","jsxs","Fragment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"statewire-history-edge.cjs","sources":["../../../src/chat-ui/thread/statewire-history-edge.tsx"],"sourcesContent":["import {\n getExternalStoreMessages,\n type ThreadMessage,\n type ThreadViewportState,\n useAuiState,\n useThreadViewport,\n useThreadViewportStore,\n} from \"@assistant-ui/react\";\nimport {\n type DeepAgentHistoryLoadEvent,\n type DeepAgentToolOutputStore,\n isStatewireChannelTeardown,\n useDeepAgentWindowSync,\n} from \"@athenaintel/agent-runtime\";\nimport type { FC } from \"react\";\nimport { Component, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport {\n NO_STATEWIRE_HISTORY,\n StatewireHistoryContext,\n} from \"../../provider/statewire-history-context\";\nimport { useStatewireToolOutputs } from \"../../provider/statewire-window-context\";\nimport { AthenaStatewireThreadIdContext } from \"../../threads/thread-id-context\";\n\n/** The attribute `ChatThreadShell` stamps on the scroll viewport. */\nexport const THREAD_VIEWPORT_ATTR = \"data-aui-thread-viewport\";\n/** The attribute `ChatThreadShell` stamps on its sticky viewport footer (the composer dock). */\nexport const THREAD_VIEWPORT_FOOTER_ATTR = \"data-aui-thread-viewport-footer\";\n\n/**\n * How far above the viewport the edge row counts as near: the row sits above\n * the first loaded message, so reaching it means the user has scrolled past\n * everything loaded and the next page should already be on its way. Messages\n * this close to the viewport also count as on screen for cut tool outputs.\n */\nexport const HISTORY_EDGE_NEAR_MARGIN_PX = 1500;\n\n/**\n * Cut tool outputs a transcript reads at once. The reads share the session's\n * command lane with everything the person sends, so a long transcript must\n * not queue dozens of them ahead of a message or a Stop.\n */\nexport const HISTORY_EDGE_TOOL_OUTPUT_CONCURRENCY = 2;\n\n/** What assistant-ui's `MessagePrimitive.Root` stamps on every message. */\nconst MESSAGE_SELECTOR = \"[data-message-id]\";\n\nconst NO_MESSAGE_IDS: ReadonlySet<string> = new Set();\n\nfunction sameIds({ a, b }: { a: ReadonlySet<string>; b: ReadonlySet<string> }): boolean {\n if (a.size !== b.size) return false;\n for (const id of a) if (!b.has(id)) return false;\n return true;\n}\n\n/**\n * Which messages sit within {@link HISTORY_EDGE_NEAR_MARGIN_PX} of the\n * viewport, so cut tool outputs are read for what the person can reach. A\n * thread opens at its newest turn; reading every loaded step's output up\n * front sent dozens of reads, each re-rendering the transcript, for steps\n * nobody had scrolled to.\n *\n * `undefined` (every message counts) where nothing can be observed: no\n * viewport around the row, or no `IntersectionObserver`. A message rendered\n * without a `data-message-id` root (a host's own renderer) cannot be observed\n * either, so it counts as before.\n */\nfunction useMessagesNearViewport({\n viewport,\n hasViewport,\n messages,\n}: {\n viewport: HTMLElement | null;\n /** A viewport is (or will be) registered around the row. */\n hasViewport: boolean;\n /** The converted thread: every change may have mounted or remounted a message. */\n messages: readonly ThreadMessage[];\n}): ((messageId: string) => boolean) | undefined {\n const [nearIds, setNearIds] = useState<ReadonlySet<string>>(NO_MESSAGE_IDS);\n const observable = hasViewport && typeof IntersectionObserver !== \"undefined\";\n const trackRef = useRef<(() => void) | null>(null);\n // Every id a rendered element carries, as of the last scan.\n const renderedIdsRef = useRef<ReadonlySet<string>>(NO_MESSAGE_IDS);\n\n useEffect(() => {\n if (!viewport || !observable) return undefined;\n const near = new Set<Element>();\n const observed = new Set<Element>();\n const publish = () => {\n const ids = new Set<string>();\n for (const element of near) {\n const id = element.getAttribute(\"data-message-id\");\n if (id) ids.add(id);\n }\n setNearIds((previous) => (sameIds({ a: previous, b: ids }) ? previous : ids));\n };\n const intersections = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting && entry.target.isConnected) near.add(entry.target);\n else near.delete(entry.target);\n }\n publish();\n },\n { root: viewport, rootMargin: `${HISTORY_EDGE_NEAR_MARGIN_PX}px 0px` },\n );\n // A page that folds into a turn gives it a new id: a host keyed by id\n // remounts the turn's element, a host keyed by row (`ChatThreadShell`)\n // keeps it and the element's id changes. So what is observed follows the\n // rendered elements, not the message list, and the near ids are read off\n // those elements again on every scan.\n const track = () => {\n for (const element of observed) {\n if (element.isConnected) continue;\n intersections.unobserve(element);\n observed.delete(element);\n near.delete(element);\n }\n const rendered = new Set<string>();\n for (const element of viewport.querySelectorAll(MESSAGE_SELECTOR)) {\n const id = element.getAttribute(\"data-message-id\");\n if (id) rendered.add(id);\n if (observed.has(element)) continue;\n observed.add(element);\n intersections.observe(element);\n }\n renderedIdsRef.current = rendered;\n publish();\n };\n trackRef.current = track;\n track();\n return () => {\n trackRef.current = null;\n renderedIdsRef.current = NO_MESSAGE_IDS;\n intersections.disconnect();\n setNearIds(NO_MESSAGE_IDS);\n };\n }, [viewport, observable]);\n\n // A changed message list is the trigger to re-scan: its messages render in\n // the same commit, so their elements are in the DOM by this effect (a\n // query, no layout read).\n useEffect(() => {\n trackRef.current?.();\n }, [messages]);\n\n return useMemo(() => {\n if (!observable) return undefined;\n return (messageId: string) => {\n // Not registered yet: nothing is on screen to read for.\n if (viewport === null) return false;\n return nearIds.has(messageId) || !renderedIdsRef.current.has(messageId);\n };\n }, [nearIds, observable, viewport]);\n}\n\n/** The wire message a converted message was built from first (its oldest source). */\nfunction oldestSourceId(message: ThreadMessage): string | undefined {\n const source = getExternalStoreMessages<{ id?: unknown }>(message)[0];\n return typeof source?.id === \"string\" ? source.id : undefined;\n}\n\n/**\n * Whether older history landed ahead of what was loaded: the old first\n * message now sits further down (a page ahead of it), or the first message's\n * old oldest wire message now follows earlier ones (a page that folded into\n * the first loaded turn). A first message replaced in place — a branch picked\n * on it, an edit — is neither, and a run streaming at the tail never touches\n * the first message.\n */\nfunction prependedOlderHistory({\n previous,\n next,\n}: {\n previous: readonly ThreadMessage[];\n next: readonly ThreadMessage[];\n}): boolean {\n const previousFirst = previous[0];\n const nextFirst = next[0];\n if (previousFirst === undefined || nextFirst === undefined || previousFirst === nextFirst) return false;\n if (previousFirst.id !== nextFirst.id && next.some((message, index) => index > 0 && message.id === previousFirst.id)) {\n return true;\n }\n const previousOldest = oldestSourceId(previousFirst);\n if (previousOldest === undefined || previousOldest === oldestSourceId(nextFirst)) return false;\n return getExternalStoreMessages<{ id?: unknown }>(nextFirst).some(\n (source, index) => index > 0 && source?.id === previousOldest,\n );\n}\n\ninterface KeepReadingPlaceProps {\n viewport: HTMLElement | null;\n threadId: string | null;\n /** The converted thread. */\n messages: readonly ThreadMessage[];\n}\n\n/**\n * Keeps the reader's place when older history lands. Everything a page adds\n * sits above what the person is reading, so their distance from the bottom of\n * the transcript is what must survive. A class for `getSnapshotBeforeUpdate`:\n * the distance is read right before React applies the commit that renders the\n * page — the one moment it is exact, even for a scroll the browser has not\n * reported yet — and restored after it, instantly (never through the\n * viewport's smooth scrolling). Other commits read no layout.\n *\n * The browser's scroll anchoring and assistant-ui's prepend anchor aim at the\n * same position, so whichever ran first leaves this nothing to do; on its own\n * it covers what they miss: a reader at the very top (browsers never anchor\n * at scroll offset 0) and a page that folds into the first loaded turn of a\n * host that keys rows by message id (that message remounts under a new id,\n * taking the browser's anchor node with it; `ChatThreadShell` keeps the row).\n */\nclass KeepReadingPlace extends Component<KeepReadingPlaceProps> {\n getSnapshotBeforeUpdate(previous: Readonly<KeepReadingPlaceProps>): number | null {\n const { viewport, threadId, messages } = this.props;\n if (\n viewport === null ||\n viewport !== previous.viewport ||\n threadId !== previous.threadId ||\n messages === previous.messages ||\n !prependedOlderHistory({ previous: previous.messages, next: messages })\n ) {\n return null;\n }\n return viewport.scrollHeight - viewport.scrollTop;\n }\n\n componentDidUpdate(\n _previous: Readonly<KeepReadingPlaceProps>,\n _state: unknown,\n fromBottom: number | null,\n ): void {\n const { viewport } = this.props;\n if (viewport === null || fromBottom === null) return;\n const top = viewport.scrollHeight - fromBottom;\n if (Math.abs(viewport.scrollTop - top) >= 1) viewport.scrollTo({ top, behavior: \"instant\" });\n }\n\n render(): null {\n return null;\n }\n}\n\nexport interface HistoryEdgeRowProps {\n /** Whether the server holds messages older than the loaded window. */\n hasOlder: boolean;\n /** Whether the next page can be asked for; `false` with `hasOlder` is the connection's loading depth spent. Defaults to `hasOlder`. */\n canLoadOlder?: boolean;\n /** A page of older history is in flight. */\n loading: boolean;\n onLoadOlder: () => void;\n className?: string;\n /** The row element, for the viewport observer. */\n rowRef?: (element: HTMLElement | null) => void;\n}\n\n/**\n * The top edge of the LOADED history: a manual way to load the next page of\n * older messages, and the in-flight state. Renders nothing when the whole\n * transcript is loaded (or the head interest has not resolved).\n */\nexport const HistoryEdgeRow: FC<HistoryEdgeRowProps> = ({\n hasOlder,\n canLoadOlder = hasOlder,\n loading,\n onLoadOlder,\n className,\n rowRef,\n}) => {\n if (!hasOlder) return null;\n return (\n <div\n ref={rowRef}\n data-testid=\"thread-history-edge\"\n className={cn(\n \"mx-auto flex w-full max-w-(--thread-max-width) items-center justify-center py-1 text-xs text-muted-foreground\",\n className,\n )}\n >\n {loading ? (\n <span data-testid=\"thread-history-edge-loading\">Loading earlier messages…</span>\n ) : canLoadOlder ? (\n <button\n type=\"button\"\n data-testid=\"thread-history-edge-load\"\n onClick={onLoadOlder}\n className=\"rounded-lg px-2.5 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n >\n Load earlier messages\n </button>\n ) : (\n <span data-testid=\"thread-history-edge-limit\">Earlier messages can't be loaded here</span>\n )}\n </div>\n );\n};\n\nexport interface StatewireHistoryEdgeProps {\n /**\n * The thread's tool-output store (the one its converter substitutes from).\n * Defaults to `AthenaProvider`'s; hosts mounting the runtime themselves pass\n * the store they gave `useDeepAgentRuntime({ toolOutputs })`.\n */\n toolOutputs?: DeepAgentToolOutputStore;\n /**\n * @deprecated Ignored. Older history pages by command (`history/page`) on\n * every host that serves it, into the conversation's own store, which the\n * thread joins. A host that mounts the runtime itself provides the steps\n * control through `TurnStepsControlContext` (`EarlierStepsButton`), so a\n * summarized turn's rows can open its steps.\n */\n historyPages?: unknown;\n className?: string;\n /** A page interest resolved (telemetry). */\n onHistoryLoad?: (event: DeepAgentHistoryLoadEvent) => void;\n}\n\n/**\n * The client half of the interest window for a DOM thread — mounted once per\n * thread, inside the scroll viewport above the messages (`ChatThreadShell`'s\n * `beforeMessages` slot):\n *\n * - renders the \"Load earlier messages\" edge row and loads the next page when\n * the row comes near the viewport (scrolling up) or on its button, keeping\n * the reading position when the page lands above the view;\n * - fetches cut tool outputs whole for the cards near the viewport, a few at\n * a time, so they re-render complete through the converter (`toolOutputs`).\n *\n * Inert until the head interest resolves: no row, no reads.\n */\nexport const StatewireHistoryEdge: FC<StatewireHistoryEdgeProps> = ({\n toolOutputs: toolOutputsProp,\n className,\n onHistoryLoad,\n}) => {\n const providerToolOutputs = useStatewireToolOutputs();\n const toolOutputs = toolOutputsProp ?? providerToolOutputs ?? undefined;\n const messages = useAuiState((s) => s.thread.messages);\n const threadId = useContext(AthenaStatewireThreadIdContext);\n const [nearTop, setNearTop] = useState(false);\n const [nearTopEpoch, setNearTopEpoch] = useState(0);\n const nearTopRef = useRef(false);\n const [rowEl, setRowEl] = useState<HTMLElement | null>(null);\n // The scroll viewport the thread registered (assistant-ui's viewport store),\n // known even while the row renders nothing; the row's ancestor otherwise.\n const hasViewportStore = useThreadViewportStore({ optional: true }) !== null;\n const registeredViewport = useThreadViewport({\n optional: true,\n selector: (state: ThreadViewportState) => state.element.viewport,\n });\n const viewport =\n registeredViewport ?? rowEl?.closest<HTMLElement>(`[${THREAD_VIEWPORT_ATTR}]`) ?? null;\n const isMessageMounted = useMessagesNearViewport({\n viewport,\n hasViewport: hasViewportStore || viewport !== null,\n messages,\n });\n const historyStore = useContext(StatewireHistoryContext);\n const { hasOlder, canLoadOlder, loading, loadOlder } = useDeepAgentWindowSync({\n messages,\n toolOutputs,\n nearTop,\n nearTopEpoch,\n isMessageMounted,\n maxConcurrentToolOutputs: HISTORY_EDGE_TOOL_OUTPUT_CONCURRENCY,\n onHistoryLoad,\n onError: (error, command) => {\n // Leaving the thread settles an in-flight read as lost: lifecycle, not a failure.\n if (error instanceof Error && isStatewireChannelTeardown(error)) return;\n console.warn(`[StatewireHistoryEdge] ${command} failed:`, error);\n },\n });\n\n // Other surfaces of the provider (the workbench's Shell pane) read where the\n // history stands; leaving the thread or unmounting withdraws the report.\n useEffect(() => {\n if (!historyStore || !threadId) return undefined;\n historyStore.set({ threadId, hasOlder, canLoadOlder, loading, loadOlder });\n return undefined;\n }, [historyStore, threadId, hasOlder, canLoadOlder, loading, loadOlder]);\n useEffect(() => {\n if (!historyStore || !threadId) return undefined;\n return () => {\n if (historyStore.get().threadId === threadId) historyStore.set(NO_STATEWIRE_HISTORY);\n };\n }, [historyStore, threadId]);\n\n // The row's own visibility is the near-top level: a level, not an edge, so\n // pages chain while the user stays at the top and stop once the prepended\n // content has pushed the row away again.\n useEffect(() => {\n if (!rowEl || !hasOlder || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n const near = entry.isIntersecting;\n if (nearTopRef.current === near) continue;\n nearTopRef.current = near;\n setNearTop(near);\n if (near) setNearTopEpoch((epoch) => epoch + 1);\n }\n },\n {\n root: viewport,\n rootMargin: `${HISTORY_EDGE_NEAR_MARGIN_PX}px 0px`,\n },\n );\n observer.observe(rowEl);\n return () => {\n observer.disconnect();\n nearTopRef.current = false;\n setNearTop(false);\n };\n }, [rowEl, hasOlder, viewport]);\n\n return (\n <>\n <KeepReadingPlace viewport={viewport} threadId={threadId} messages={messages} />\n <HistoryEdgeRow\n rowRef={setRowEl}\n hasOlder={hasOlder}\n canLoadOlder={canLoadOlder}\n loading={loading}\n onLoadOlder={loadOlder}\n className={className}\n />\n </>\n );\n};\n"],"names":["useState","useRef","useEffect","useMemo","getExternalStoreMessages","Component","jsx","cn","useStatewireToolOutputs","useAuiState","useContext","AthenaStatewireThreadIdContext","useThreadViewportStore","useThreadViewport","StatewireHistoryContext","useDeepAgentWindowSync","isStatewireChannelTeardown","NO_STATEWIRE_HISTORY","jsxs","Fragment"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type DeepAgentHistoryLoadEvent, type
|
|
1
|
+
import { type DeepAgentHistoryLoadEvent, type DeepAgentToolOutputStore } from "../../agent-runtime/src/index";
|
|
2
2
|
import type { FC } from "react";
|
|
3
3
|
/** The attribute `ChatThreadShell` stamps on the scroll viewport. */
|
|
4
4
|
export declare const THREAD_VIEWPORT_ATTR = "data-aui-thread-viewport";
|
|
@@ -43,15 +43,13 @@ export interface StatewireHistoryEdgeProps {
|
|
|
43
43
|
*/
|
|
44
44
|
toolOutputs?: DeepAgentToolOutputStore;
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* pages even under the provider. A host that mounts the runtime itself
|
|
50
|
-
* also provides the store through `StatewireHistoryPagesContext` and the
|
|
46
|
+
* @deprecated Ignored. Older history pages by command (`history/page`) on
|
|
47
|
+
* every host that serves it, into the conversation's own store, which the
|
|
48
|
+
* thread joins. A host that mounts the runtime itself provides the steps
|
|
51
49
|
* control through `TurnStepsControlContext` (`EarlierStepsButton`), so a
|
|
52
50
|
* summarized turn's rows can open its steps.
|
|
53
51
|
*/
|
|
54
|
-
historyPages?:
|
|
52
|
+
historyPages?: unknown;
|
|
55
53
|
className?: string;
|
|
56
54
|
/** A page interest resolved (telemetry). */
|
|
57
55
|
onHistoryLoad?: (event: DeepAgentHistoryLoadEvent) => void;
|
|
@@ -2,7 +2,7 @@ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useAuiState, useThreadViewportStore, useThreadViewport, getExternalStoreMessages } from "@assistant-ui/react";
|
|
3
3
|
import { useContext, useState, useRef, useEffect, useMemo, Component } from "react";
|
|
4
4
|
import { StatewireHistoryContext, NO_STATEWIRE_HISTORY } from "../../provider/statewire-history-context.js";
|
|
5
|
-
import { useStatewireToolOutputs
|
|
5
|
+
import { useStatewireToolOutputs } from "../../provider/statewire-window-context.js";
|
|
6
6
|
import { AthenaStatewireThreadIdContext } from "../../threads/thread-id-context.js";
|
|
7
7
|
import { useDeepAgentWindowSync } from "../../agent-runtime/src/use-deep-agent-window-sync.js";
|
|
8
8
|
import { isStatewireChannelTeardown } from "../../agent-runtime/src/errors.js";
|
|
@@ -159,14 +159,11 @@ const HistoryEdgeRow = ({
|
|
|
159
159
|
};
|
|
160
160
|
const StatewireHistoryEdge = ({
|
|
161
161
|
toolOutputs: toolOutputsProp,
|
|
162
|
-
historyPages: historyPagesProp,
|
|
163
162
|
className,
|
|
164
163
|
onHistoryLoad
|
|
165
164
|
}) => {
|
|
166
165
|
const providerToolOutputs = useStatewireToolOutputs();
|
|
167
166
|
const toolOutputs = toolOutputsProp ?? providerToolOutputs ?? void 0;
|
|
168
|
-
const providerHistoryPages = useStatewireHistoryPages();
|
|
169
|
-
const historyPages = historyPagesProp === null ? void 0 : historyPagesProp ?? providerHistoryPages ?? void 0;
|
|
170
167
|
const messages = useAuiState((s) => s.thread.messages);
|
|
171
168
|
const threadId = useContext(AthenaStatewireThreadIdContext);
|
|
172
169
|
const [nearTop, setNearTop] = useState(false);
|
|
@@ -193,7 +190,6 @@ const StatewireHistoryEdge = ({
|
|
|
193
190
|
isMessageMounted,
|
|
194
191
|
maxConcurrentToolOutputs: HISTORY_EDGE_TOOL_OUTPUT_CONCURRENCY,
|
|
195
192
|
onHistoryLoad,
|
|
196
|
-
historyPages,
|
|
197
193
|
onError: (error, command) => {
|
|
198
194
|
if (error instanceof Error && isStatewireChannelTeardown(error)) return;
|
|
199
195
|
console.warn(`[StatewireHistoryEdge] ${command} failed:`, error);
|