@athenaintel/react 0.48.0 → 0.52.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -10
- package/dist/agent-runtime/src/call-recap.cjs +319 -0
- package/dist/agent-runtime/src/call-recap.cjs.map +1 -0
- package/dist/agent-runtime/src/call-recap.d.ts +142 -0
- package/dist/agent-runtime/src/call-recap.js +319 -0
- package/dist/agent-runtime/src/call-recap.js.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-store.cjs +1 -0
- package/dist/agent-runtime/src/chat-outbox-store.cjs.map +1 -1
- package/dist/agent-runtime/src/chat-outbox-store.d.ts +7 -0
- package/dist/agent-runtime/src/chat-outbox-store.js +1 -0
- package/dist/agent-runtime/src/chat-outbox-store.js.map +1 -1
- package/dist/agent-runtime/src/chat-outbox.cjs +46 -5
- package/dist/agent-runtime/src/chat-outbox.cjs.map +1 -1
- package/dist/agent-runtime/src/chat-outbox.d.ts +29 -0
- package/dist/agent-runtime/src/chat-outbox.js +46 -5
- package/dist/agent-runtime/src/chat-outbox.js.map +1 -1
- package/dist/agent-runtime/src/conversation-index.cjs.map +1 -1
- package/dist/agent-runtime/src/conversation-index.d.ts +7 -0
- package/dist/agent-runtime/src/conversation-index.js.map +1 -1
- package/dist/agent-runtime/src/conversation-list.cjs +2 -1
- package/dist/agent-runtime/src/conversation-list.cjs.map +1 -1
- package/dist/agent-runtime/src/conversation-list.d.ts +19 -3
- package/dist/agent-runtime/src/conversation-list.js +2 -1
- package/dist/agent-runtime/src/conversation-list.js.map +1 -1
- package/dist/agent-runtime/src/desktop-handoff.d.ts +10 -0
- package/dist/agent-runtime/src/edit-command.cjs +21 -0
- package/dist/agent-runtime/src/edit-command.cjs.map +1 -1
- package/dist/agent-runtime/src/edit-command.d.ts +8 -0
- package/dist/agent-runtime/src/edit-command.js +21 -0
- package/dist/agent-runtime/src/edit-command.js.map +1 -1
- package/dist/agent-runtime/src/handoff-arrival.cjs +19 -0
- package/dist/agent-runtime/src/handoff-arrival.cjs.map +1 -1
- package/dist/agent-runtime/src/handoff-arrival.d.ts +18 -3
- package/dist/agent-runtime/src/handoff-arrival.js +20 -1
- package/dist/agent-runtime/src/handoff-arrival.js.map +1 -1
- package/dist/agent-runtime/src/handoff-cursor-id.cjs +6 -0
- package/dist/agent-runtime/src/handoff-cursor-id.cjs.map +1 -0
- package/dist/agent-runtime/src/handoff-cursor-id.d.ts +12 -0
- package/dist/agent-runtime/src/handoff-cursor-id.js +6 -0
- package/dist/agent-runtime/src/handoff-cursor-id.js.map +1 -0
- package/dist/agent-runtime/src/handoff-cursor.cjs +88 -0
- package/dist/agent-runtime/src/handoff-cursor.cjs.map +1 -0
- package/dist/agent-runtime/src/handoff-cursor.d.ts +120 -0
- package/dist/agent-runtime/src/handoff-cursor.js +88 -0
- package/dist/agent-runtime/src/handoff-cursor.js.map +1 -0
- package/dist/agent-runtime/src/index.d.ts +9 -7
- package/dist/agent-runtime/src/interrupts.cjs +28 -1
- package/dist/agent-runtime/src/interrupts.cjs.map +1 -1
- package/dist/agent-runtime/src/interrupts.d.ts +21 -1
- package/dist/agent-runtime/src/interrupts.js +28 -1
- package/dist/agent-runtime/src/interrupts.js.map +1 -1
- package/dist/agent-runtime/src/model-context.cjs +3 -2
- package/dist/agent-runtime/src/model-context.cjs.map +1 -1
- package/dist/agent-runtime/src/model-context.d.ts +6 -1
- package/dist/agent-runtime/src/model-context.js +3 -2
- package/dist/agent-runtime/src/model-context.js.map +1 -1
- package/dist/agent-runtime/src/runtime.d.ts +3 -2
- package/dist/agent-runtime/src/send-recovery.cjs +37 -3
- package/dist/agent-runtime/src/send-recovery.cjs.map +1 -1
- package/dist/agent-runtime/src/send-recovery.d.ts +19 -0
- package/dist/agent-runtime/src/send-recovery.js +37 -3
- package/dist/agent-runtime/src/send-recovery.js.map +1 -1
- package/dist/agent-runtime/src/thread-handoff-flow-machine.d.ts +14 -8
- package/dist/agent-runtime/src/thread-handoff-protocol.d.ts +227 -5
- package/dist/agent-runtime/src/thread-handoff.d.ts +1 -1
- package/dist/agent-runtime/src/use-conversation-list.cjs +3 -2
- package/dist/agent-runtime/src/use-conversation-list.cjs.map +1 -1
- package/dist/agent-runtime/src/use-conversation-list.d.ts +6 -0
- package/dist/agent-runtime/src/use-conversation-list.js +3 -2
- package/dist/agent-runtime/src/use-conversation-list.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs +21 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.d.ts +8 -2
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js +21 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +24 -6
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +17 -0
- package/dist/agent-runtime/src/use-deep-agent-runtime.js +24 -6
- package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs +44 -9
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +34 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.js +44 -9
- package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs +8 -3
- 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 +7 -0
- package/dist/agent-runtime/src/use-deep-agent-window-sync.js +9 -4
- package/dist/agent-runtime/src/use-deep-agent-window-sync.js.map +1 -1
- package/dist/agent-runtime/src/use-thread-handoff-flow.d.ts +13 -2
- package/dist/agent-runtime/src/voice-earcon.cjs +139 -0
- package/dist/agent-runtime/src/voice-earcon.cjs.map +1 -0
- package/dist/agent-runtime/src/voice-earcon.d.ts +38 -0
- package/dist/agent-runtime/src/voice-earcon.js +139 -0
- package/dist/agent-runtime/src/voice-earcon.js.map +1 -0
- package/dist/agent-runtime/src/voice-media.cjs.map +1 -1
- package/dist/agent-runtime/src/voice-media.d.ts +14 -0
- package/dist/agent-runtime/src/voice-media.js.map +1 -1
- package/dist/agent-runtime/src/voice-presentation.cjs +2 -0
- package/dist/agent-runtime/src/voice-presentation.cjs.map +1 -1
- package/dist/agent-runtime/src/voice-presentation.js +2 -0
- package/dist/agent-runtime/src/voice-presentation.js.map +1 -1
- package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
- package/dist/assets/AthenaAssetEmbed.d.ts +11 -5
- package/dist/assets/AthenaAssetEmbed.js.map +1 -1
- package/dist/assets/use-asset-embed.cjs.map +1 -1
- package/dist/assets/use-asset-embed.d.ts +12 -5
- package/dist/assets/use-asset-embed.js.map +1 -1
- package/dist/chat/AthenaChat.cjs +27 -12
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.d.ts +13 -0
- package/dist/chat/AthenaChat.js +27 -12
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/AthenaPlanStrip.cjs +97 -0
- package/dist/chat/AthenaPlanStrip.cjs.map +1 -0
- package/dist/chat/AthenaPlanStrip.d.ts +15 -0
- package/dist/chat/AthenaPlanStrip.js +97 -0
- package/dist/chat/AthenaPlanStrip.js.map +1 -0
- package/dist/chat/StatewireApprovalCard.cjs +41 -6
- package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
- package/dist/chat/StatewireApprovalCard.d.ts +18 -1
- package/dist/chat/StatewireApprovalCard.js +42 -7
- package/dist/chat/StatewireApprovalCard.js.map +1 -1
- package/dist/chat/StatewireQueuedMessages.cjs +56 -6
- package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
- package/dist/chat/StatewireQueuedMessages.d.ts +14 -0
- package/dist/chat/StatewireQueuedMessages.js +58 -8
- package/dist/chat/StatewireQueuedMessages.js.map +1 -1
- package/dist/chat/WaitingOnYouBanner.cjs +6 -2
- package/dist/chat/WaitingOnYouBanner.cjs.map +1 -1
- package/dist/chat/WaitingOnYouBanner.js +7 -3
- package/dist/chat/WaitingOnYouBanner.js.map +1 -1
- package/dist/chat/chat-voice-controls.cjs +3 -1
- package/dist/chat/chat-voice-controls.cjs.map +1 -1
- package/dist/chat/chat-voice-controls.d.ts +6 -1
- package/dist/chat/chat-voice-controls.js +3 -1
- package/dist/chat/chat-voice-controls.js.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.cjs +4 -2
- package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.js +4 -2
- package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs +4 -2
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.js +4 -2
- package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.cjs +6 -4
- package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.d.ts +9 -1
- package/dist/chat/super-grouping/activity-timeline.js +6 -4
- package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
- package/dist/chat/super-grouping/index.d.ts +1 -1
- package/dist/chat/super-grouping/use-earlier-steps-unloaded.cjs +17 -0
- package/dist/chat/super-grouping/use-earlier-steps-unloaded.cjs.map +1 -0
- package/dist/chat/super-grouping/use-earlier-steps-unloaded.d.ts +8 -0
- package/dist/chat/super-grouping/use-earlier-steps-unloaded.js +17 -0
- package/dist/chat/super-grouping/use-earlier-steps-unloaded.js.map +1 -0
- package/dist/chat-ui/index.cjs +11 -0
- package/dist/chat-ui/index.cjs.map +1 -1
- package/dist/chat-ui/index.d.ts +3 -1
- package/dist/chat-ui/index.js +12 -1
- package/dist/chat-ui/index.js.map +1 -1
- package/dist/chat-ui/messages/from-the-call-card.cjs +124 -0
- package/dist/chat-ui/messages/from-the-call-card.cjs.map +1 -0
- package/dist/chat-ui/messages/from-the-call-card.d.ts +17 -0
- package/dist/chat-ui/messages/from-the-call-card.js +124 -0
- package/dist/chat-ui/messages/from-the-call-card.js.map +1 -0
- package/dist/chat-ui/rich-text/chat-link.cjs +1 -0
- package/dist/chat-ui/rich-text/chat-link.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-link.d.ts +4 -0
- package/dist/chat-ui/rich-text/chat-link.js +4 -3
- package/dist/chat-ui/rich-text/chat-link.js.map +1 -1
- package/dist/chat-ui/rich-text/chat-message-body.cjs +1 -0
- package/dist/chat-ui/rich-text/chat-message-body.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-message-body.d.ts +12 -0
- package/dist/chat-ui/rich-text/chat-message-body.js +2 -1
- package/dist/chat-ui/rich-text/chat-message-body.js.map +1 -1
- package/dist/chat-ui/thread/chat-thread-shell.cjs +4 -0
- package/dist/chat-ui/thread/chat-thread-shell.cjs.map +1 -1
- package/dist/chat-ui/thread/chat-thread-shell.d.ts +4 -0
- package/dist/chat-ui/thread/chat-thread-shell.js +4 -0
- package/dist/chat-ui/thread/chat-thread-shell.js.map +1 -1
- package/dist/chat-ui/thread/handoff-cursor.cjs +216 -0
- package/dist/chat-ui/thread/handoff-cursor.cjs.map +1 -0
- package/dist/chat-ui/thread/handoff-cursor.d.ts +57 -0
- package/dist/chat-ui/thread/handoff-cursor.js +216 -0
- package/dist/chat-ui/thread/handoff-cursor.js.map +1 -0
- package/dist/chat-ui/thread/statewire-history-edge.cjs +2 -0
- package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.d.ts +2 -0
- package/dist/chat-ui/thread/statewire-history-edge.js +3 -1
- package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
- package/dist/collab/client.cjs +15 -3
- package/dist/collab/client.cjs.map +1 -1
- package/dist/collab/client.d.ts +4 -2
- package/dist/collab/client.js +16 -4
- package/dist/collab/client.js.map +1 -1
- package/dist/composer/index.d.ts +1 -1
- package/dist/composer/useReadComposerDraft.cjs +26 -7
- package/dist/composer/useReadComposerDraft.cjs.map +1 -1
- package/dist/composer/useReadComposerDraft.d.ts +23 -1
- package/dist/composer/useReadComposerDraft.js +27 -8
- package/dist/composer/useReadComposerDraft.js.map +1 -1
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/keryx-http/src/unconfirmed-update-attributions.cjs +207 -0
- package/dist/keryx-http/src/unconfirmed-update-attributions.cjs.map +1 -0
- package/dist/keryx-http/src/unconfirmed-update-attributions.d.ts +141 -0
- package/dist/keryx-http/src/unconfirmed-update-attributions.js +207 -0
- package/dist/keryx-http/src/unconfirmed-update-attributions.js.map +1 -0
- package/dist/keryx-http/src/update-attributions.cjs +34 -4
- package/dist/keryx-http/src/update-attributions.cjs.map +1 -1
- package/dist/keryx-http/src/update-attributions.d.ts +36 -4
- package/dist/keryx-http/src/update-attributions.js +35 -5
- package/dist/keryx-http/src/update-attributions.js.map +1 -1
- package/dist/provider/AthenaProvider.cjs +4 -0
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.d.ts +11 -1
- package/dist/provider/AthenaProvider.js +4 -0
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/threads/api.cjs.map +1 -1
- package/dist/threads/api.d.ts +15 -0
- package/dist/threads/api.js.map +1 -1
- package/dist/threads/conversation-list-fetcher.cjs +13 -5
- package/dist/threads/conversation-list-fetcher.cjs.map +1 -1
- package/dist/threads/conversation-list-fetcher.d.ts +4 -1
- package/dist/threads/conversation-list-fetcher.js +13 -5
- package/dist/threads/conversation-list-fetcher.js.map +1 -1
- package/dist/threads/statewire-thread-list.cjs +28 -6
- package/dist/threads/statewire-thread-list.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.d.ts +20 -8
- package/dist/threads/statewire-thread-list.js +28 -6
- package/dist/threads/statewire-thread-list.js.map +1 -1
- package/dist/threads/use-athena-sessions.cjs +27 -5
- package/dist/threads/use-athena-sessions.cjs.map +1 -1
- package/dist/threads/use-athena-sessions.d.ts +10 -5
- package/dist/threads/use-athena-sessions.js +28 -6
- package/dist/threads/use-athena-sessions.js.map +1 -1
- package/dist/threads/use-rest-conversation-history.d.ts +1 -0
- package/dist/tools/write-todos-tool-ui.cjs +8 -0
- package/dist/tools/write-todos-tool-ui.cjs.map +1 -1
- package/dist/tools/write-todos-tool-ui.d.ts +2 -0
- package/dist/tools/write-todos-tool-ui.js +8 -0
- package/dist/tools/write-todos-tool-ui.js.map +1 -1
- package/dist/workbench/session-workbench-panes.cjs +1 -8
- package/dist/workbench/session-workbench-panes.cjs.map +1 -1
- package/dist/workbench/session-workbench-panes.js +2 -9
- package/dist/workbench/session-workbench-panes.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatewireQueuedMessages.cjs","sources":["../../src/chat/StatewireQueuedMessages.tsx"],"sourcesContent":["import { useAui, useAuiState } from '@assistant-ui/react';\nimport type { StatewireThread } from '@assistant-ui/react-statewire';\nimport {\n useStatewireRuns,\n useStatewireSendCommand,\n useStatewireState,\n} from '@assistant-ui/react-statewire';\nimport {\n buildQueueEditCommand,\n buildStatewireQueueRows,\n type DeepAgentThreadStatus,\n describeQueueSendFailure,\n hasStatewireThreadExtras,\n isFailedSendEntryRace,\n isQueueEntryUnsettled,\n isServerUpdateStopSource,\n QUEUE_AUTO_CONTINUE_DELAY_MS,\n queueEntryText,\n queueLaneFlags,\n readDeepAgentStreamValues,\n readRetryableRunRefusal,\n readRunMarkerFromSourceMessages,\n requireStatewireFailedActions,\n type StatewireFailedActions,\n showQueueRowSteer,\n useChatOutboxSnapshot,\n useDeepAgentChatOutboxContext,\n useDeepAgentThreadStatus,\n userStopBlocksQueueAutoContinue,\n} from '@athenaintel/agent-runtime';\nimport {\n AlertCircleIcon,\n CheckIcon,\n ChevronDownIcon,\n ChevronRightIcon,\n CircleIcon,\n Loader2Icon,\n PencilIcon,\n RotateCcwIcon,\n ShipWheelIcon,\n Trash2Icon,\n XIcon,\n} from 'lucide-react';\nimport {\n type FC,\n type KeyboardEvent,\n type MutableRefObject,\n type ReactNode,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { mentionsToPlainText, parseMentionsInText } from '../chat-ui/mentions/mention-chip';\nimport { ContinuePill } from '../chat-ui/messages/continue-pill';\nimport { cn } from '../lib/utils';\nimport { ChatOutboxRows } from './chat-outbox-rows';\n\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /**\n * The ⚡ on a queued row (`DeepAgentThread.run_prioritize`). With\n * `priority: true` the host moves the entry to the head of the queue\n * lane (behind entries prioritized before it), records it durably, and\n * the live run ends at its next model-call boundary — after the\n * in-flight tool chain, never mid-tool — so the settle delivers the\n * entry on top of the finished tool results instead of after the whole\n * turn. `priority: false` withdraws the request and leaves the entry\n * where it is.\n */\n runPrioritize: {\n type: 'run/prioritize';\n runId: string;\n messageId: string;\n priority: boolean;\n };\n /**\n * \"Steer\" on a queued row (`DeepAgentThread.run_steer_live`) — what\n * ChatGPT and Codex call Steer, versus Queue. The host moves the entry\n * to the steer lane and records it as a live steer, so the running\n * turn is NOT cancelled: at its next model call — after the in-flight\n * tool chain, never mid-tool — the run drains the entry into its own\n * context as a user turn and continues. Everything the run produces\n * from then on lands after the steered message. Mirrors `run/steer`'s\n * params (exactly one of `message` or `messageId`).\n */\n runSteerLive: {\n type: 'run/steer-live';\n runId: string;\n messageId: string;\n };\n }\n }\n}\n\n/**\n * The one queued-messages tray for the server-owned statewire queue and steer\n * lanes, mounted by the SDK's `AthenaChat`, the Chrome side panel, the Office\n * task pane, and Olympus.\n *\n * A message sent before the live run has produced any output is a double\n * text: the host folds it into the run's turn (`run/enqueue` steers it and\n * the run redispatches with both messages), so it never lists here. A\n * message sent once the run is answering queues behind it. Rows offer\n * \"Steer\" (`run/steer-live` — the host parks the entry on the steer lane as a\n * live steer and the running turn drains it into its own context at its next\n * model call, so the run continues with it; ChatGPT's Steer versus Queue),\n * inline edit (re-sent under the entry's own id on its own lane, which the\n * host folds as an in-place content update), and remove (`run/dequeue`).\n * While the thread rests stopped/errored, stranded steer-lane entries list\n * ahead of the queue (they dispatch first, as one batch) and a Continue pill\n * steer-promotes the queue head — a steer entry moved onto its own lane is a\n * no-op, so a steer-only rest state gets no dead button.\n *\n * A row whose send has not settled yet (`isQueueEntryUnsettled` — this\n * client's optimistic fold, not a host-admitted lane entry) renders as\n * \"Sending…\" with no acting affordances: admission is server-side and can\n * still refuse the message. Failed run sends (`runs.failed`) list after the\n * lanes with Retry (`retryFailed`) and Discard (`discardFailed`).\n *\n * With `autoContinue`, an ordinary stranded settle promotes the queue head\n * once after `QUEUE_AUTO_CONTINUE_DELAY_MS`. User stops remain manual;\n * infrastructure pauses and retryable dispatch refusals recover on the server.\n *\n * Renders nothing on the legacy transport or when every lane is empty.\n */\n\nexport type StatewireQueueEvent =\n | {\n type: 'auto-continued';\n threadId: string | null;\n status: DeepAgentThreadStatus;\n headEntryId: string;\n }\n | {\n type: 'failed-send-action-raced';\n threadId: string | null;\n messageId: string;\n action: 'retry' | 'discard';\n error: string;\n };\n\nexport interface StatewireQueueRowContentContext {\n text: string;\n index: number;\n item: StatewireThread.RunsQueueEntry;\n}\n\nexport interface StatewireQueueRowMarkerContext {\n item: StatewireThread.RunsQueueEntry;\n lane: 'queue' | 'steer';\n index: number;\n /** This client's optimistic fold, not yet admitted by the host (renders \"Sending…\"). */\n isUnsettled: boolean;\n}\n\nexport interface StatewireQueueEditorContext {\n value: string;\n /** The entry being edited, for an editor that reads its metadata (e.g. the composer markdown it was sent from). */\n item: StatewireThread.RunsQueueEntry;\n onChange: (value: string) => void;\n /**\n * Save the edit; a blank or unchanged message sends nothing but closes the\n * editor. `metadata`, when given, replaces the entry's message metadata.\n */\n onSave: (text: string, options?: { metadata?: Record<string, unknown> }) => void;\n onCancel: () => void;\n}\n\nexport interface StatewireQueuedMessagesProps {\n /** Surface-styling overrides merged onto the default classes. */\n classNames?: {\n /** The tray container. */\n root?: string;\n /** The row list. */\n list?: string;\n };\n /**\n * Steer-promote a stranded queue head automatically after a settle (see the\n * component docs). Off by default: a host opts in to dispatching runs on the\n * user's behalf. Pass `{ delayMs }` to tune the grace before the promotion\n * (defaults to `QUEUE_AUTO_CONTINUE_DELAY_MS`).\n */\n autoContinue?: boolean | { delayMs?: number };\n /** Identifies the thread for once-per-entry auto-continue attempts and events. */\n threadId?: string | null;\n /** Telemetry sink for the tray's notable moments. */\n onEvent?: (event: StatewireQueueEvent) => void;\n /** Replace the plain-text row body (e.g. a mention-aware renderer). */\n renderContent?: (context: StatewireQueueRowContentContext) => ReactNode;\n /** Replace the plain textarea inline editor (e.g. the host's composer editor). */\n renderEditor?: (context: StatewireQueueEditorContext) => ReactNode;\n /**\n * Replace a lane row's leading marker (the bullet, or the spinner while the\n * send is unsettled) — e.g. the submitter's avatar on a shared thread.\n * Returning `null`/`undefined` keeps the default marker for that row.\n */\n renderRowMarker?: (context: StatewireQueueRowMarkerContext) => ReactNode;\n}\n\nexport const StatewireQueuedMessages: FC<StatewireQueuedMessagesProps> = (props) => {\n const extras = useAuiState((s) => s.thread.extras);\n if (!hasStatewireThreadExtras(extras)) return null;\n return <StatewireQueuedMessagesInner {...props} />;\n};\n\nconst StatewireQueuedMessagesInner: FC<StatewireQueuedMessagesProps> = ({\n classNames,\n autoContinue = false,\n threadId = null,\n onEvent,\n renderContent,\n renderEditor,\n renderRowMarker,\n}) => {\n // The QUEUE lane only: composer.queue prepends the steer lane, whose entries\n // already render in the message list. A non-empty queue implies a live run\n // entry (the host retires runId only once both lanes drain), so the row\n // controls can always send.\n const runs = useStatewireRuns();\n const { queue, steerQueue, runId, epoch } = runs;\n // `failed` joined the runs projection in react-statewire 0.24; a projection\n // without it (an older lib, a stubbed runs read) must not crash the tray.\n const failed = runs.failed ?? [];\n const status = useDeepAgentThreadStatus();\n const { isRunning, isContinuable } = queueLaneFlags(status);\n const aui = useAui();\n const sendCommand = useStatewireSendCommand();\n const listId = useId();\n const [expanded, setExpanded] = useState(true);\n const [editingId, setEditingId] = useState<string | null>(null);\n const [editingText, setEditingText] = useState('');\n // Head entries already auto-promoted once on this mount: an attempt whose\n // continue run dies and re-strands the SAME entry must not loop — the manual\n // Continue pill is the fallback for a repeatedly failing dispatch. Kept on\n // the tray (not the auto-continue child) so it survives the empty-lane\n // renders between a promotion and its outcome.\n const autoContinuedRef = useRef<Set<string>>(new Set());\n const onEventRef = useRef(onEvent);\n onEventRef.current = onEvent;\n // Messages typed while Athena couldn't be reached (the host's chat outbox), shown above the\n // lanes until they are sent, cancelled or discarded.\n const outbox = useDeepAgentChatOutboxContext();\n const outboxSnapshot = useChatOutboxSnapshot(outbox);\n\n const rows = buildStatewireQueueRows({ queue, steerQueue, isContinuable });\n // Continue promotes the QUEUE head only: a queue→steer move dispatches the\n // stranded steer lane plus this entry, while a steer entry moved onto its\n // own lane is a no-op.\n const queueHeadId = queue[0]?.id ?? null;\n const continuationRef = useRef({ aui, threadId, runId, epoch, queueHeadId, isContinuable });\n useLayoutEffect(() => {\n continuationRef.current = { aui, threadId, runId, epoch, queueHeadId, isContinuable };\n }, [aui, threadId, runId, epoch, queueHeadId, isContinuable]);\n\n const continueQueue = (): void => {\n const current = continuationRef.current;\n // Draft recovery may remove the old head during the pill's exit animation.\n // Continue the surviving queue only within the clicked runtime/dispatch.\n if (\n current.aui !== aui || current.threadId !== threadId ||\n current.runId !== runId || current.epoch !== epoch ||\n !current.isContinuable || current.queueHeadId === null\n ) return;\n aui.composer.queueItem({ id: current.queueHeadId }).move({ lane: 'steer' });\n };\n const retryableRefusal = readRetryableRunRefusal(runs.error) !== null;\n const autoContinueOptions = autoContinue === true ? {} : autoContinue || null;\n\n /**\n * Re-send the entry under its own id on its own lane: the host replaces the\n * queued message's content in place, leaving its queue position and lane\n * untouched (a same-id send never dispatches).\n */\n const saveEdit = (\n item: StatewireThread.RunsQueueEntry,\n lane: 'queue' | 'steer',\n text: string,\n metadata?: Record<string, unknown>,\n ): void => {\n setEditingId(null);\n setEditingText('');\n const command = buildQueueEditCommand({ item, lane, runId, text, metadata });\n if (command !== null) sendCommand(command);\n };\n\n /**\n * Retry/Discard act on a rendered lane snapshot that can trail the session\n * record; acting on an entry statewire already dropped throws. Nothing is\n * lost in that race, so it is recorded instead of crashing the click.\n */\n const runFailedSendAction = ({\n action,\n messageId,\n run,\n }: {\n action: 'retry' | 'discard';\n messageId: string;\n run: (actions: StatewireFailedActions) => void;\n }): void => {\n try {\n run(requireStatewireFailedActions(aui.thread().getState().extras));\n } catch (error) {\n if (!(error instanceof Error) || !isFailedSendEntryRace(error)) throw error;\n onEvent?.({\n type: 'failed-send-action-raced',\n threadId,\n messageId,\n action,\n error: error.message,\n });\n }\n };\n\n const hasOutboxRows =\n outbox !== null && (outboxSnapshot.rows.length > 0 || outboxSnapshot.elsewhere.length > 0);\n const hasLaneRows = rows.length > 0 || failed.length > 0;\n if (!hasLaneRows && !hasOutboxRows) return null;\n\n const renderRowContent = (context: StatewireQueueRowContentContext): ReactNode =>\n renderContent ? renderContent(context) : <QueueRowText text={context.text} />;\n\n return (\n <section\n aria-label=\"Queued messages\"\n className={cn(\n 'aui-statewire-queue w-full rounded-xl border border-border/70 bg-muted/30 px-2 py-1.5',\n classNames?.root,\n )}\n >\n {hasOutboxRows ? (\n <ChatOutboxRows outbox={outbox} snapshot={outboxSnapshot} renderContent={renderRowContent} />\n ) : null}\n {autoContinueOptions ? (\n <QueueAutoContinue\n delayMs={autoContinueOptions.delayMs ?? QUEUE_AUTO_CONTINUE_DELAY_MS}\n queueHeadId={queueHeadId}\n retryableRefusal={retryableRefusal}\n isContinuable={isContinuable}\n status={status}\n threadId={threadId}\n editing={editingId !== null}\n continuedRef={autoContinuedRef}\n onEventRef={onEventRef}\n />\n ) : null}\n {hasLaneRows ? (\n <div className=\"flex items-center gap-1.5\">\n <button\n type=\"button\"\n onClick={() => setExpanded((value) => !value)}\n aria-expanded={expanded}\n aria-controls={listId}\n className=\"flex items-center gap-1 rounded px-1 py-1 font-medium text-muted-foreground text-xs hover:text-foreground\"\n >\n {expanded ? (\n <ChevronDownIcon className=\"size-3.5\" />\n ) : (\n <ChevronRightIcon className=\"size-3.5\" />\n )}\n {rows.length + failed.length} queued\n </button>\n {isContinuable && queueHeadId !== null ? (\n <ContinuePill\n ariaLabel=\"Continue with queued messages\"\n onClick={continueQueue}\n />\n ) : null}\n </div>\n ) : null}\n {expanded && hasLaneRows ? (\n <ul\n id={listId}\n className={cn('max-h-40 overflow-y-auto', classNames?.list)}\n data-testid=\"athena-statewire-queue\"\n >\n {rows.map(({ item, lane }, index) => {\n const text = queueEntryText(item.parts);\n const isUnsettled = isQueueEntryUnsettled(item);\n const isEditing = editingId === item.id;\n const showSteer =\n !isUnsettled && runId !== null && showQueueRowSteer({ lane, isRunning });\n const marker = renderRowMarker?.({ item, lane, index, isUnsettled });\n const editorContext: StatewireQueueEditorContext = {\n value: editingText,\n item,\n onChange: setEditingText,\n onSave: (next, options) => saveEdit(item, lane, next, options?.metadata),\n onCancel: () => {\n setEditingId(null);\n setEditingText('');\n },\n };\n return (\n <li\n key={item.id}\n className=\"group flex items-start gap-2 rounded-md px-1 py-1.5 hover:bg-background\"\n >\n {marker != null ? (\n marker\n ) : isUnsettled ? (\n <Loader2Icon className=\"mt-0.5 size-3.5 shrink-0 animate-spin text-muted-foreground/60\" />\n ) : (\n <CircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-muted-foreground/40\" />\n )}\n {isEditing ? (\n renderEditor ? (\n renderEditor(editorContext)\n ) : (\n <DefaultQueueEditor {...editorContext} />\n )\n ) : (\n renderRowContent({ text, index, item })\n )}\n <div\n className={cn('flex shrink-0 items-center gap-1', isEditing && 'hidden')}\n data-testid=\"statewire-queue-row-actions\"\n >\n {isUnsettled ? (\n <span\n className=\"px-1 text-[10px] text-muted-foreground\"\n data-testid=\"statewire-queued-message-sending\"\n >\n Sending…\n </span>\n ) : null}\n {showSteer ? (\n <button\n type=\"button\"\n aria-label=\"Steer\"\n title=\"Steer the current response: folded into the running turn at its next step, without stopping it.\"\n onClick={() => {\n if (runId === null) return;\n sendCommand({ type: 'run/steer-live', runId, messageId: item.id });\n }}\n className=\"inline-flex items-center gap-1 rounded-full border border-border px-2 py-1 font-medium text-[10px] text-foreground/80 hover:bg-background hover:text-foreground\"\n >\n <ShipWheelIcon className=\"size-2.5\" />\n Steer\n </button>\n ) : null}\n {!isUnsettled ? (\n <button\n type=\"button\"\n aria-label=\"Edit queued message\"\n onClick={() => {\n setEditingId(item.id);\n setEditingText(text);\n }}\n className=\"rounded p-1 text-muted-foreground transition-colors hover:text-primary\"\n >\n <PencilIcon className=\"size-3\" />\n </button>\n ) : null}\n <button\n type=\"button\"\n aria-label=\"Remove queued message\"\n onClick={() => aui.composer.queueItem({ id: item.id }).remove()}\n className={cn(\n 'rounded p-1 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive',\n !showSteer &&\n 'opacity-0 focus-visible:opacity-100 group-hover:opacity-100',\n )}\n >\n <Trash2Icon className=\"size-3\" />\n </button>\n </div>\n </li>\n );\n })}\n {failed.map((item, index) => (\n <li\n key={item.id}\n className=\"group flex items-start gap-2 rounded-md px-1 py-1.5 hover:bg-background\"\n >\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n {renderRowContent({\n text: queueEntryText(item.parts),\n index: rows.length + index,\n item,\n })}\n <div\n className=\"flex shrink-0 items-center gap-1\"\n data-testid=\"statewire-queue-row-actions\"\n >\n <span\n className=\"px-1 text-[10px] text-destructive\"\n title={describeQueueSendFailure(item.sendFailure)}\n >\n Failed to send\n </span>\n <button\n type=\"button\"\n aria-label=\"Retry failed message\"\n onClick={() =>\n runFailedSendAction({\n action: 'retry',\n messageId: item.id,\n run: (actions) => actions.retryFailed(item.id),\n })\n }\n className=\"inline-flex items-center gap-1 rounded-full border border-primary/30 px-2 py-1 font-medium text-[10px] text-primary hover:bg-primary/5\"\n >\n <RotateCcwIcon className=\"size-2.5\" />\n Retry\n </button>\n <button\n type=\"button\"\n aria-label=\"Discard failed message\"\n onClick={() =>\n runFailedSendAction({\n action: 'discard',\n messageId: item.id,\n run: (actions) => actions.discardFailed(item.id),\n })\n }\n className=\"rounded p-1 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive\"\n >\n <Trash2Icon className=\"size-3\" />\n </button>\n </div>\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n );\n};\n\n/** Promotes ordinary stranded queue heads once; infrastructure recovery stays server-owned. */\nconst QueueAutoContinue: FC<{\n delayMs: number;\n queueHeadId: string | null;\n retryableRefusal: boolean;\n isContinuable: boolean;\n status: DeepAgentThreadStatus;\n threadId: string | null;\n editing: boolean;\n continuedRef: MutableRefObject<Set<string>>;\n onEventRef: MutableRefObject<((event: StatewireQueueEvent) => void) | undefined>;\n}> = ({\n delayMs,\n queueHeadId,\n retryableRefusal,\n isContinuable,\n status,\n threadId,\n editing,\n continuedRef,\n onEventRef,\n}) => {\n const aui = useAui();\n // The settle that stranded the queue is described by the LAST message's run\n // marker (a marker deeper in history was superseded by a later send). The\n // selectors return primitives so the subscriptions stay shallow-stable.\n const lastMessageMarker = useAuiState((s) => {\n const last = s.thread.messages.at(-1);\n return last ? readRunMarkerFromSourceMessages(last)?.marker : undefined;\n });\n const lastMessageMarkerSource = useAuiState((s) => {\n const last = s.thread.messages.at(-1);\n return last ? readRunMarkerFromSourceMessages(last)?.source : undefined;\n });\n const userStopBlocks = userStopBlocksQueueAutoContinue({\n marker: lastMessageMarker,\n source: lastMessageMarkerSource,\n });\n\n useEffect(() => {\n if (\n !isContinuable ||\n userStopBlocks ||\n retryableRefusal ||\n isServerUpdateStopSource(lastMessageMarkerSource)\n ) return;\n // An open inline edit means the user is mid-revision on some row —\n // dispatching underneath them could send text they are about to change.\n if (editing) return;\n if (queueHeadId === null) return;\n const attemptKey = `${threadId ?? 'unknown'}:${queueHeadId}`;\n if (continuedRef.current.has(attemptKey)) return;\n const timeoutId = setTimeout(() => {\n continuedRef.current.add(attemptKey);\n onEventRef.current?.({ type: 'auto-continued', threadId, status, headEntryId: queueHeadId });\n aui.composer.queueItem({ id: queueHeadId }).move({ lane: 'steer' });\n }, delayMs);\n return () => clearTimeout(timeoutId);\n }, [\n continuedRef,\n aui,\n delayMs,\n editing,\n isContinuable,\n onEventRef,\n queueHeadId,\n retryableRefusal,\n lastMessageMarkerSource,\n status,\n threadId,\n userStopBlocks,\n ]);\n\n return null;\n};\n\n/**\n * The default row body: `[@name](…)` mentions render as chips, not raw\n * markdown links, and the body clamps to two lines. Show more / Show less\n * appears only when the rendered text overflows those two lines, so a short\n * message that wraps in a narrow tray is still caught and a short one gets no\n * dead control.\n */\nconst QueueRowText: FC<{ text: string }> = ({ text }) => {\n const bodyRef = useRef<HTMLParagraphElement>(null);\n const [expanded, setExpanded] = useState(false);\n const [overflows, setOverflows] = useState(false);\n\n useLayoutEffect(() => {\n const body = bodyRef.current;\n // Expanded text has no clamp to overflow; the toggle stays up to collapse it.\n if (!body || expanded) return;\n const measure = (): void => setOverflows(body.scrollHeight > body.clientHeight + 1);\n measure();\n if (typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(measure);\n observer.observe(body);\n return () => observer.disconnect();\n }, [text, expanded]);\n\n if (!text) {\n return <p className=\"min-w-0 flex-1 text-foreground text-xs\">Queued attachment</p>;\n }\n return (\n <div className=\"min-w-0 flex-1\">\n <p\n ref={bodyRef}\n className={cn(\n 'whitespace-pre-wrap break-words text-foreground text-xs leading-relaxed',\n !expanded && 'line-clamp-2',\n )}\n title={overflows && !expanded ? mentionsToPlainText(text) : undefined}\n >\n {parseMentionsInText(text)}\n </p>\n {overflows || expanded ? (\n <button\n type=\"button\"\n aria-expanded={expanded}\n onClick={() => setExpanded((value) => !value)}\n className=\"mt-0.5 font-medium text-[10px] text-muted-foreground hover:text-foreground\"\n >\n {expanded ? 'Show less' : 'Show more'}\n </button>\n ) : null}\n </div>\n );\n};\n\n/** Plain textarea editor: Enter saves, Shift+Enter breaks a line, Escape cancels. */\nconst DefaultQueueEditor: FC<StatewireQueueEditorContext> = ({\n value,\n onChange,\n onSave,\n onCancel,\n}) => {\n const canSave = value.trim().length > 0;\n const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>): void => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n if (canSave) onSave(value);\n } else if (event.key === 'Escape') {\n event.preventDefault();\n onCancel();\n }\n };\n return (\n <div className=\"flex min-w-0 flex-1 items-start gap-1\">\n <textarea\n autoFocus\n aria-label=\"Edit message\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n onKeyDown={handleKeyDown}\n rows={Math.min(6, Math.max(1, value.split('\\n').length))}\n className=\"min-w-0 flex-1 resize-none rounded-md border border-border bg-background px-2 py-1 text-foreground text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring/50\"\n />\n <button\n type=\"button\"\n aria-label=\"Save edit\"\n disabled={!canSave}\n onClick={() => onSave(value)}\n className={cn(\n 'rounded p-1 text-primary transition-colors hover:bg-primary/10',\n !canSave && 'cursor-not-allowed opacity-40',\n )}\n >\n <CheckIcon className=\"size-3.5\" />\n </button>\n <button\n type=\"button\"\n aria-label=\"Cancel edit\"\n onClick={onCancel}\n className=\"rounded p-1 text-muted-foreground transition-colors hover:bg-muted\"\n >\n <XIcon className=\"size-3.5\" />\n </button>\n </div>\n );\n};\n"],"names":["useAuiState","hasStatewireThreadExtras","jsx","useStatewireRuns","queue","useDeepAgentThreadStatus","queueLaneFlags","useAui","useStatewireSendCommand","useId","useState","useRef","useDeepAgentChatOutboxContext","useChatOutboxSnapshot","buildStatewireQueueRows","useLayoutEffect","readRetryableRunRefusal","buildQueueEditCommand","requireStatewireFailedActions","isFailedSendEntryRace","jsxs","cn","ChatOutboxRows","QUEUE_AUTO_CONTINUE_DELAY_MS","ChevronDownIcon","ChevronRightIcon","ContinuePill","queueEntryText","isQueueEntryUnsettled","showQueueRowSteer","Loader2Icon","CircleIcon","ShipWheelIcon","PencilIcon","Trash2Icon","AlertCircleIcon","describeQueueSendFailure","RotateCcwIcon","readRunMarkerFromSourceMessages","userStopBlocksQueueAutoContinue","useEffect","isServerUpdateStopSource","mentionsToPlainText","CheckIcon","XIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"StatewireQueuedMessages.cjs","sources":["../../src/chat/StatewireQueuedMessages.tsx"],"sourcesContent":["import { useAui, useAuiState } from '@assistant-ui/react';\nimport type { StatewireThread } from '@assistant-ui/react-statewire';\nimport {\n useStatewireRuns,\n useStatewireSendCommand,\n useStatewireState,\n} from '@assistant-ui/react-statewire';\nimport {\n buildQueueEditCommand,\n buildStatewireQueueRows,\n type DeepAgentThreadStatus,\n describeQueueSendFailure,\n hasStatewireThreadExtras,\n isFailedSendEntryRace,\n isQueueEntryUnsettled,\n isServerUpdateStopSource,\n QUEUE_AUTO_CONTINUE_DELAY_MS,\n queueEntryText,\n queueLaneFlags,\n readDeepAgentStreamValues,\n readRetryableRunRefusal,\n readRunMarkerFromSourceMessages,\n readStatewireFailedSendLane,\n requireStatewireFailedActions,\n type StatewireFailedActions,\n showQueueRowSteer,\n useChatOutboxSnapshot,\n useDeepAgentChatOutboxContext,\n useDeepAgentThreadStatus,\n userStopBlocksQueueAutoContinue,\n} from '@athenaintel/agent-runtime';\nimport {\n AlertCircleIcon,\n CheckIcon,\n ChevronDownIcon,\n ChevronRightIcon,\n CircleIcon,\n Loader2Icon,\n PencilIcon,\n RotateCcwIcon,\n ShipWheelIcon,\n Trash2Icon,\n XIcon,\n} from 'lucide-react';\nimport {\n type FC,\n type KeyboardEvent,\n type MutableRefObject,\n type ReactNode,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { mentionsToPlainText, parseMentionsInText } from '../chat-ui/mentions/mention-chip';\nimport { ContinuePill } from '../chat-ui/messages/continue-pill';\nimport { cn } from '../lib/utils';\nimport { ChatOutboxRows } from './chat-outbox-rows';\n\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /**\n * The ⚡ on a queued row (`DeepAgentThread.run_prioritize`). With\n * `priority: true` the host moves the entry to the head of the queue\n * lane (behind entries prioritized before it), records it durably, and\n * the live run ends at its next model-call boundary — after the\n * in-flight tool chain, never mid-tool — so the settle delivers the\n * entry on top of the finished tool results instead of after the whole\n * turn. `priority: false` withdraws the request and leaves the entry\n * where it is.\n */\n runPrioritize: {\n type: 'run/prioritize';\n runId: string;\n messageId: string;\n priority: boolean;\n };\n /**\n * \"Steer\" on a queued row (`DeepAgentThread.run_steer_live`) — what\n * ChatGPT and Codex call Steer, versus Queue. The host moves the entry\n * to the steer lane and records it as a live steer, so the running\n * turn is NOT cancelled: at its next model call — after the in-flight\n * tool chain, never mid-tool — the run drains the entry into its own\n * context as a user turn and continues. Everything the run produces\n * from then on lands after the steered message. Mirrors `run/steer`'s\n * params (exactly one of `message` or `messageId`).\n */\n runSteerLive: {\n type: 'run/steer-live';\n runId: string;\n messageId: string;\n };\n }\n }\n}\n\n/**\n * The one queued-messages tray for the server-owned statewire queue and steer\n * lanes, mounted by the SDK's `AthenaChat`, the Chrome side panel, the Office\n * task pane, and Olympus.\n *\n * A message sent before the live run has produced any output is a double\n * text: the host folds it into the run's turn (`run/enqueue` steers it and\n * the run redispatches with both messages), so it never lists here. A\n * message sent once the run is answering queues behind it. Rows offer\n * \"Steer\" (`run/steer-live` — the host parks the entry on the steer lane as a\n * live steer and the running turn drains it into its own context at its next\n * model call, so the run continues with it; ChatGPT's Steer versus Queue),\n * inline edit (re-sent under the entry's own id on its own lane, which the\n * host folds as an in-place content update), and remove (`run/dequeue`).\n * While the thread rests stopped/errored, stranded steer-lane entries list\n * ahead of the queue (they dispatch first, as one batch) and a Continue pill\n * steer-promotes the queue head — a steer entry moved onto its own lane is a\n * no-op, so a steer-only rest state gets no dead button.\n *\n * A row whose send has not settled yet (`isQueueEntryUnsettled` — this\n * client's optimistic fold, not a host-admitted lane entry) renders as\n * \"Sending…\" with no acting affordances: admission is server-side and can\n * still refuse the message. Failed run sends (`runs.failed`) list after the\n * lanes with Retry (`retryFailed`) and Discard (`discardFailed`).\n *\n * With `autoContinue`, an ordinary stranded settle promotes the queue head\n * once after `QUEUE_AUTO_CONTINUE_DELAY_MS`. User stops remain manual;\n * infrastructure pauses and retryable dispatch refusals recover on the server.\n *\n * Renders nothing on the legacy transport or when every lane is empty.\n */\n\nexport type StatewireQueueEvent =\n | {\n type: 'auto-continued';\n threadId: string | null;\n status: DeepAgentThreadStatus;\n headEntryId: string;\n }\n | {\n type: 'failed-send-action-raced';\n threadId: string | null;\n messageId: string;\n action: 'retry' | 'discard';\n error: string;\n };\n\nexport interface StatewireQueueRowContentContext {\n text: string;\n index: number;\n item: StatewireThread.RunsQueueEntry;\n}\n\nexport interface StatewireQueueRowMarkerContext {\n item: StatewireThread.RunsQueueEntry;\n lane: 'queue' | 'steer';\n index: number;\n /** This client's optimistic fold, not yet admitted by the host (renders \"Sending…\"). */\n isUnsettled: boolean;\n}\n\nexport interface StatewireQueueEditorContext {\n value: string;\n /** The entry being edited, for an editor that reads its metadata (e.g. the composer markdown it was sent from). */\n item: StatewireThread.RunsQueueEntry;\n onChange: (value: string) => void;\n /**\n * Save the edit; a blank or unchanged message sends nothing but closes the\n * editor. `metadata`, when given, replaces the entry's message metadata.\n */\n onSave: (text: string, options?: { metadata?: Record<string, unknown> }) => void;\n onCancel: () => void;\n}\n\nexport interface StatewireQueuedMessagesProps {\n /** Surface-styling overrides merged onto the default classes. */\n classNames?: {\n /** The tray container. */\n root?: string;\n /** The row list. */\n list?: string;\n };\n /**\n * Steer-promote a stranded queue head automatically after a settle (see the\n * component docs). Off by default: a host opts in to dispatching runs on the\n * user's behalf. Pass `{ delayMs }` to tune the grace before the promotion\n * (defaults to `QUEUE_AUTO_CONTINUE_DELAY_MS`).\n */\n autoContinue?: boolean | { delayMs?: number };\n /** Identifies the thread for once-per-entry auto-continue attempts and events. */\n threadId?: string | null;\n /** Telemetry sink for the tray's notable moments. */\n onEvent?: (event: StatewireQueueEvent) => void;\n /** Replace the plain-text row body (e.g. a mention-aware renderer). */\n renderContent?: (context: StatewireQueueRowContentContext) => ReactNode;\n /** Replace the plain textarea inline editor (e.g. the host's composer editor). */\n renderEditor?: (context: StatewireQueueEditorContext) => ReactNode;\n /**\n * Replace a lane row's leading marker (the bullet, or the spinner while the\n * send is unsettled) — e.g. the submitter's avatar on a shared thread.\n * Returning `null`/`undefined` keeps the default marker for that row.\n */\n renderRowMarker?: (context: StatewireQueueRowMarkerContext) => ReactNode;\n /**\n * Called right before a failed message is sent again (its Retry), with its\n * id, so the host can put back the per-send context that message was sent\n * with (e.g. the agents it named) before its command leaves. A promise holds\n * the Retry until it settles, then the host is asked again, unless the\n * message was sent or discarded meanwhile: it can't put that context back\n * while a send with another one is still on its way (every send of a\n * conversation rides one ambient context). A held Retry is held once (a\n * second click does nothing); after {@link MAX_RETRY_HOLDS} holds the message\n * goes regardless, and a hook that throws never holds it back. A function\n * returned is called when the message does not go after all (it left the\n * failed lane first), so the host lets go of what it put back.\n */\n onBeforeRetry?: (messageId: string) => void | PromiseLike<void> | (() => void);\n}\n\n/** How many times a host may hold one Retry (`onBeforeRetry`'s promise) before it goes regardless. */\nconst MAX_RETRY_HOLDS = 10;\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { then?: unknown }).then === 'function'\n );\n}\n\nexport const StatewireQueuedMessages: FC<StatewireQueuedMessagesProps> = (props) => {\n const extras = useAuiState((s) => s.thread.extras);\n if (!hasStatewireThreadExtras(extras)) return null;\n return <StatewireQueuedMessagesInner {...props} />;\n};\n\nconst StatewireQueuedMessagesInner: FC<StatewireQueuedMessagesProps> = ({\n classNames,\n autoContinue = false,\n threadId = null,\n onEvent,\n renderContent,\n renderEditor,\n renderRowMarker,\n onBeforeRetry,\n}) => {\n // The QUEUE lane only: composer.queue prepends the steer lane, whose entries\n // already render in the message list. A non-empty queue implies a live run\n // entry (the host retires runId only once both lanes drain), so the row\n // controls can always send.\n const runs = useStatewireRuns();\n const { queue, steerQueue, runId, epoch } = runs;\n // `failed` joined the runs projection in react-statewire 0.24; a projection\n // without it (an older lib, a stubbed runs read) must not crash the tray.\n const failed = runs.failed ?? [];\n const status = useDeepAgentThreadStatus();\n const { isRunning, isContinuable } = queueLaneFlags(status);\n const aui = useAui();\n const sendCommand = useStatewireSendCommand();\n const listId = useId();\n const [expanded, setExpanded] = useState(true);\n const [editingId, setEditingId] = useState<string | null>(null);\n const [editingText, setEditingText] = useState('');\n // Head entries already auto-promoted once on this mount: an attempt whose\n // continue run dies and re-strands the SAME entry must not loop — the manual\n // Continue pill is the fallback for a repeatedly failing dispatch. Kept on\n // the tray (not the auto-continue child) so it survives the empty-lane\n // renders between a promotion and its outcome.\n const autoContinuedRef = useRef<Set<string>>(new Set());\n const onEventRef = useRef(onEvent);\n onEventRef.current = onEvent;\n const onBeforeRetryRef = useRef(onBeforeRetry);\n onBeforeRetryRef.current = onBeforeRetry;\n // The messages whose Retry the host is holding (`onBeforeRetry`'s promise).\n const heldRetriesRef = useRef<Set<string>>(new Set());\n // A Retry the host held goes on only while the tray is still there.\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n // Messages typed while Athena couldn't be reached (the host's chat outbox), shown above the\n // lanes until they are sent, cancelled or discarded.\n const outbox = useDeepAgentChatOutboxContext();\n const outboxSnapshot = useChatOutboxSnapshot(outbox);\n\n const rows = buildStatewireQueueRows({ queue, steerQueue, isContinuable });\n // Continue promotes the QUEUE head only: a queue→steer move dispatches the\n // stranded steer lane plus this entry, while a steer entry moved onto its\n // own lane is a no-op.\n const queueHeadId = queue[0]?.id ?? null;\n const continuationRef = useRef({ aui, threadId, runId, epoch, queueHeadId, isContinuable });\n useLayoutEffect(() => {\n continuationRef.current = { aui, threadId, runId, epoch, queueHeadId, isContinuable };\n }, [aui, threadId, runId, epoch, queueHeadId, isContinuable]);\n\n const continueQueue = (): void => {\n const current = continuationRef.current;\n // Draft recovery may remove the old head during the pill's exit animation.\n // Continue the surviving queue only within the clicked runtime/dispatch.\n if (\n current.aui !== aui || current.threadId !== threadId ||\n current.runId !== runId || current.epoch !== epoch ||\n !current.isContinuable || current.queueHeadId === null\n ) return;\n aui.composer.queueItem({ id: current.queueHeadId }).move({ lane: 'steer' });\n };\n const retryableRefusal = readRetryableRunRefusal(runs.error) !== null;\n const autoContinueOptions = autoContinue === true ? {} : autoContinue || null;\n\n /**\n * Re-send the entry under its own id on its own lane: the host replaces the\n * queued message's content in place, leaving its queue position and lane\n * untouched (a same-id send never dispatches).\n */\n const saveEdit = (\n item: StatewireThread.RunsQueueEntry,\n lane: 'queue' | 'steer',\n text: string,\n metadata?: Record<string, unknown>,\n ): void => {\n setEditingId(null);\n setEditingText('');\n const command = buildQueueEditCommand({ item, lane, runId, text, metadata });\n if (command !== null) sendCommand(command);\n };\n\n /**\n * Retry/Discard act on a rendered lane snapshot that can trail the session\n * record; acting on an entry statewire already dropped throws. Nothing is\n * lost in that race, so it is recorded instead of crashing the click.\n * Returns whether the action went.\n */\n const runFailedSendAction = ({\n action,\n messageId,\n run,\n }: {\n action: 'retry' | 'discard';\n messageId: string;\n run: (actions: StatewireFailedActions) => void;\n }): boolean => {\n try {\n run(requireStatewireFailedActions(aui.thread().getState().extras));\n return true;\n } catch (error) {\n if (!(error instanceof Error) || !isFailedSendEntryRace(error)) throw error;\n onEvent?.({\n type: 'failed-send-action-raced',\n threadId,\n messageId,\n action,\n error: error.message,\n });\n return false;\n }\n };\n\n /**\n * A failed message's Retry: the host puts its per-send context back first\n * (`onBeforeRetry`), synchronously with the re-send. A host that holds it (a\n * promise: a send with another context is still on its way) is asked again\n * once that settles, while the message is still in the failed lane; a click\n * meanwhile does nothing, and a tray gone meanwhile leaves the row as it was.\n */\n const retryFailedSend = (messageId: string, held = 0): void => {\n const heldRetries = heldRetriesRef.current;\n if (held === 0 && heldRetries.has(messageId)) return;\n heldRetries.delete(messageId);\n if (!mountedRef.current) return;\n if (\n held > 0 &&\n !readStatewireFailedSendLane(aui.thread().getState().extras)?.failed.some(\n (entry) => entry.id === messageId,\n )\n ) {\n return;\n }\n let before: ReturnType<NonNullable<typeof onBeforeRetry>> | undefined;\n try {\n before = onBeforeRetryRef.current?.(messageId);\n } catch {\n // A host's own context step failing never holds the Retry back.\n before = undefined;\n }\n if (isThenable(before) && held < MAX_RETRY_HOLDS) {\n heldRetries.add(messageId);\n const again = (): void => retryFailedSend(messageId, held + 1);\n before.then(again, again);\n return;\n }\n let sent = false;\n try {\n sent = runFailedSendAction({\n action: 'retry',\n messageId,\n run: (actions) => actions.retryFailed(messageId),\n });\n } finally {\n // It did not go after all: the host lets go of what it put back for it.\n try {\n if (!sent && typeof before === 'function') before();\n } catch {\n // The host's own step failing changes nothing here.\n }\n }\n };\n\n const hasOutboxRows =\n outbox !== null && (outboxSnapshot.rows.length > 0 || outboxSnapshot.elsewhere.length > 0);\n const hasLaneRows = rows.length > 0 || failed.length > 0;\n if (!hasLaneRows && !hasOutboxRows) return null;\n\n const renderRowContent = (context: StatewireQueueRowContentContext): ReactNode =>\n renderContent ? renderContent(context) : <QueueRowText text={context.text} />;\n\n return (\n <section\n aria-label=\"Queued messages\"\n className={cn(\n 'aui-statewire-queue w-full rounded-xl border border-border/70 bg-muted/30 px-2 py-1.5',\n classNames?.root,\n )}\n >\n {hasOutboxRows ? (\n <ChatOutboxRows outbox={outbox} snapshot={outboxSnapshot} renderContent={renderRowContent} />\n ) : null}\n {autoContinueOptions ? (\n <QueueAutoContinue\n delayMs={autoContinueOptions.delayMs ?? QUEUE_AUTO_CONTINUE_DELAY_MS}\n queueHeadId={queueHeadId}\n retryableRefusal={retryableRefusal}\n isContinuable={isContinuable}\n status={status}\n threadId={threadId}\n editing={editingId !== null}\n continuedRef={autoContinuedRef}\n onEventRef={onEventRef}\n />\n ) : null}\n {hasLaneRows ? (\n <div className=\"flex items-center gap-1.5\">\n <button\n type=\"button\"\n onClick={() => setExpanded((value) => !value)}\n aria-expanded={expanded}\n aria-controls={listId}\n className=\"flex items-center gap-1 rounded px-1 py-1 font-medium text-muted-foreground text-xs hover:text-foreground\"\n >\n {expanded ? (\n <ChevronDownIcon className=\"size-3.5\" />\n ) : (\n <ChevronRightIcon className=\"size-3.5\" />\n )}\n {rows.length + failed.length} queued\n </button>\n {isContinuable && queueHeadId !== null ? (\n <ContinuePill\n ariaLabel=\"Continue with queued messages\"\n onClick={continueQueue}\n />\n ) : null}\n </div>\n ) : null}\n {expanded && hasLaneRows ? (\n <ul\n id={listId}\n className={cn('max-h-40 overflow-y-auto', classNames?.list)}\n data-testid=\"athena-statewire-queue\"\n >\n {rows.map(({ item, lane }, index) => {\n const text = queueEntryText(item.parts);\n const isUnsettled = isQueueEntryUnsettled(item);\n const isEditing = editingId === item.id;\n const showSteer =\n !isUnsettled && runId !== null && showQueueRowSteer({ lane, isRunning });\n const marker = renderRowMarker?.({ item, lane, index, isUnsettled });\n const editorContext: StatewireQueueEditorContext = {\n value: editingText,\n item,\n onChange: setEditingText,\n onSave: (next, options) => saveEdit(item, lane, next, options?.metadata),\n onCancel: () => {\n setEditingId(null);\n setEditingText('');\n },\n };\n return (\n <li\n key={item.id}\n className=\"group flex items-start gap-2 rounded-md px-1 py-1.5 hover:bg-background\"\n >\n {marker != null ? (\n marker\n ) : isUnsettled ? (\n <Loader2Icon className=\"mt-0.5 size-3.5 shrink-0 animate-spin text-muted-foreground/60\" />\n ) : (\n <CircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-muted-foreground/40\" />\n )}\n {isEditing ? (\n renderEditor ? (\n renderEditor(editorContext)\n ) : (\n <DefaultQueueEditor {...editorContext} />\n )\n ) : (\n renderRowContent({ text, index, item })\n )}\n <div\n className={cn('flex shrink-0 items-center gap-1', isEditing && 'hidden')}\n data-testid=\"statewire-queue-row-actions\"\n >\n {isUnsettled ? (\n <span\n className=\"px-1 text-[10px] text-muted-foreground\"\n data-testid=\"statewire-queued-message-sending\"\n >\n Sending…\n </span>\n ) : null}\n {showSteer ? (\n <button\n type=\"button\"\n aria-label=\"Steer\"\n title=\"Steer the current response: folded into the running turn at its next step, without stopping it.\"\n onClick={() => {\n if (runId === null) return;\n sendCommand({ type: 'run/steer-live', runId, messageId: item.id });\n }}\n className=\"inline-flex items-center gap-1 rounded-full border border-border px-2 py-1 font-medium text-[10px] text-foreground/80 hover:bg-background hover:text-foreground\"\n >\n <ShipWheelIcon className=\"size-2.5\" />\n Steer\n </button>\n ) : null}\n {!isUnsettled ? (\n <button\n type=\"button\"\n aria-label=\"Edit queued message\"\n onClick={() => {\n setEditingId(item.id);\n setEditingText(text);\n }}\n className=\"rounded p-1 text-muted-foreground transition-colors hover:text-primary\"\n >\n <PencilIcon className=\"size-3\" />\n </button>\n ) : null}\n <button\n type=\"button\"\n aria-label=\"Remove queued message\"\n onClick={() => aui.composer.queueItem({ id: item.id }).remove()}\n className={cn(\n 'rounded p-1 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive',\n !showSteer &&\n 'opacity-0 focus-visible:opacity-100 group-hover:opacity-100',\n )}\n >\n <Trash2Icon className=\"size-3\" />\n </button>\n </div>\n </li>\n );\n })}\n {failed.map((item, index) => (\n <li\n key={item.id}\n className=\"group flex items-start gap-2 rounded-md px-1 py-1.5 hover:bg-background\"\n >\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n {renderRowContent({\n text: queueEntryText(item.parts),\n index: rows.length + index,\n item,\n })}\n <div\n className=\"flex shrink-0 items-center gap-1\"\n data-testid=\"statewire-queue-row-actions\"\n >\n <span\n className=\"px-1 text-[10px] text-destructive\"\n title={describeQueueSendFailure(item.sendFailure)}\n >\n Failed to send\n </span>\n <button\n type=\"button\"\n aria-label=\"Retry failed message\"\n onClick={() => retryFailedSend(item.id)}\n className=\"inline-flex items-center gap-1 rounded-full border border-primary/30 px-2 py-1 font-medium text-[10px] text-primary hover:bg-primary/5\"\n >\n <RotateCcwIcon className=\"size-2.5\" />\n Retry\n </button>\n <button\n type=\"button\"\n aria-label=\"Discard failed message\"\n onClick={() =>\n runFailedSendAction({\n action: 'discard',\n messageId: item.id,\n run: (actions) => actions.discardFailed(item.id),\n })\n }\n className=\"rounded p-1 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive\"\n >\n <Trash2Icon className=\"size-3\" />\n </button>\n </div>\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n );\n};\n\n/** Promotes ordinary stranded queue heads once; infrastructure recovery stays server-owned. */\nconst QueueAutoContinue: FC<{\n delayMs: number;\n queueHeadId: string | null;\n retryableRefusal: boolean;\n isContinuable: boolean;\n status: DeepAgentThreadStatus;\n threadId: string | null;\n editing: boolean;\n continuedRef: MutableRefObject<Set<string>>;\n onEventRef: MutableRefObject<((event: StatewireQueueEvent) => void) | undefined>;\n}> = ({\n delayMs,\n queueHeadId,\n retryableRefusal,\n isContinuable,\n status,\n threadId,\n editing,\n continuedRef,\n onEventRef,\n}) => {\n const aui = useAui();\n // The settle that stranded the queue is described by the LAST message's run\n // marker (a marker deeper in history was superseded by a later send). The\n // selectors return primitives so the subscriptions stay shallow-stable.\n const lastMessageMarker = useAuiState((s) => {\n const last = s.thread.messages.at(-1);\n return last ? readRunMarkerFromSourceMessages(last)?.marker : undefined;\n });\n const lastMessageMarkerSource = useAuiState((s) => {\n const last = s.thread.messages.at(-1);\n return last ? readRunMarkerFromSourceMessages(last)?.source : undefined;\n });\n const userStopBlocks = userStopBlocksQueueAutoContinue({\n marker: lastMessageMarker,\n source: lastMessageMarkerSource,\n });\n\n useEffect(() => {\n if (\n !isContinuable ||\n userStopBlocks ||\n retryableRefusal ||\n isServerUpdateStopSource(lastMessageMarkerSource)\n ) return;\n // An open inline edit means the user is mid-revision on some row —\n // dispatching underneath them could send text they are about to change.\n if (editing) return;\n if (queueHeadId === null) return;\n const attemptKey = `${threadId ?? 'unknown'}:${queueHeadId}`;\n if (continuedRef.current.has(attemptKey)) return;\n const timeoutId = setTimeout(() => {\n continuedRef.current.add(attemptKey);\n onEventRef.current?.({ type: 'auto-continued', threadId, status, headEntryId: queueHeadId });\n aui.composer.queueItem({ id: queueHeadId }).move({ lane: 'steer' });\n }, delayMs);\n return () => clearTimeout(timeoutId);\n }, [\n continuedRef,\n aui,\n delayMs,\n editing,\n isContinuable,\n onEventRef,\n queueHeadId,\n retryableRefusal,\n lastMessageMarkerSource,\n status,\n threadId,\n userStopBlocks,\n ]);\n\n return null;\n};\n\n/**\n * The default row body: `[@name](…)` mentions render as chips, not raw\n * markdown links, and the body clamps to two lines. Show more / Show less\n * appears only when the rendered text overflows those two lines, so a short\n * message that wraps in a narrow tray is still caught and a short one gets no\n * dead control.\n */\nconst QueueRowText: FC<{ text: string }> = ({ text }) => {\n const bodyRef = useRef<HTMLParagraphElement>(null);\n const [expanded, setExpanded] = useState(false);\n const [overflows, setOverflows] = useState(false);\n\n useLayoutEffect(() => {\n const body = bodyRef.current;\n // Expanded text has no clamp to overflow; the toggle stays up to collapse it.\n if (!body || expanded) return;\n const measure = (): void => setOverflows(body.scrollHeight > body.clientHeight + 1);\n measure();\n if (typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(measure);\n observer.observe(body);\n return () => observer.disconnect();\n }, [text, expanded]);\n\n if (!text) {\n return <p className=\"min-w-0 flex-1 text-foreground text-xs\">Queued attachment</p>;\n }\n return (\n <div className=\"min-w-0 flex-1\">\n <p\n ref={bodyRef}\n className={cn(\n 'whitespace-pre-wrap break-words text-foreground text-xs leading-relaxed',\n !expanded && 'line-clamp-2',\n )}\n title={overflows && !expanded ? mentionsToPlainText(text) : undefined}\n >\n {parseMentionsInText(text)}\n </p>\n {overflows || expanded ? (\n <button\n type=\"button\"\n aria-expanded={expanded}\n onClick={() => setExpanded((value) => !value)}\n className=\"mt-0.5 font-medium text-[10px] text-muted-foreground hover:text-foreground\"\n >\n {expanded ? 'Show less' : 'Show more'}\n </button>\n ) : null}\n </div>\n );\n};\n\n/** Plain textarea editor: Enter saves, Shift+Enter breaks a line, Escape cancels. */\nconst DefaultQueueEditor: FC<StatewireQueueEditorContext> = ({\n value,\n onChange,\n onSave,\n onCancel,\n}) => {\n const canSave = value.trim().length > 0;\n const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>): void => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n if (canSave) onSave(value);\n } else if (event.key === 'Escape') {\n event.preventDefault();\n onCancel();\n }\n };\n return (\n <div className=\"flex min-w-0 flex-1 items-start gap-1\">\n <textarea\n autoFocus\n aria-label=\"Edit message\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n onKeyDown={handleKeyDown}\n rows={Math.min(6, Math.max(1, value.split('\\n').length))}\n className=\"min-w-0 flex-1 resize-none rounded-md border border-border bg-background px-2 py-1 text-foreground text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring/50\"\n />\n <button\n type=\"button\"\n aria-label=\"Save edit\"\n disabled={!canSave}\n onClick={() => onSave(value)}\n className={cn(\n 'rounded p-1 text-primary transition-colors hover:bg-primary/10',\n !canSave && 'cursor-not-allowed opacity-40',\n )}\n >\n <CheckIcon className=\"size-3.5\" />\n </button>\n <button\n type=\"button\"\n aria-label=\"Cancel edit\"\n onClick={onCancel}\n className=\"rounded p-1 text-muted-foreground transition-colors hover:bg-muted\"\n >\n <XIcon className=\"size-3.5\" />\n </button>\n </div>\n );\n};\n"],"names":["useAuiState","hasStatewireThreadExtras","jsx","useStatewireRuns","queue","useDeepAgentThreadStatus","queueLaneFlags","useAui","useStatewireSendCommand","useId","useState","useRef","useEffect","useDeepAgentChatOutboxContext","useChatOutboxSnapshot","buildStatewireQueueRows","useLayoutEffect","readRetryableRunRefusal","buildQueueEditCommand","requireStatewireFailedActions","isFailedSendEntryRace","readStatewireFailedSendLane","jsxs","cn","ChatOutboxRows","QUEUE_AUTO_CONTINUE_DELAY_MS","ChevronDownIcon","ChevronRightIcon","ContinuePill","queueEntryText","isQueueEntryUnsettled","showQueueRowSteer","Loader2Icon","CircleIcon","ShipWheelIcon","PencilIcon","Trash2Icon","AlertCircleIcon","describeQueueSendFailure","RotateCcwIcon","readRunMarkerFromSourceMessages","userStopBlocksQueueAutoContinue","isServerUpdateStopSource","mentionsToPlainText","CheckIcon","XIcon"],"mappings":"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"}
|
|
@@ -138,5 +138,19 @@ export interface StatewireQueuedMessagesProps {
|
|
|
138
138
|
* Returning `null`/`undefined` keeps the default marker for that row.
|
|
139
139
|
*/
|
|
140
140
|
renderRowMarker?: (context: StatewireQueueRowMarkerContext) => ReactNode;
|
|
141
|
+
/**
|
|
142
|
+
* Called right before a failed message is sent again (its Retry), with its
|
|
143
|
+
* id, so the host can put back the per-send context that message was sent
|
|
144
|
+
* with (e.g. the agents it named) before its command leaves. A promise holds
|
|
145
|
+
* the Retry until it settles, then the host is asked again, unless the
|
|
146
|
+
* message was sent or discarded meanwhile: it can't put that context back
|
|
147
|
+
* while a send with another one is still on its way (every send of a
|
|
148
|
+
* conversation rides one ambient context). A held Retry is held once (a
|
|
149
|
+
* second click does nothing); after {@link MAX_RETRY_HOLDS} holds the message
|
|
150
|
+
* goes regardless, and a hook that throws never holds it back. A function
|
|
151
|
+
* returned is called when the message does not go after all (it left the
|
|
152
|
+
* failed lane first), so the host lets go of what it put back.
|
|
153
|
+
*/
|
|
154
|
+
onBeforeRetry?: (messageId: string) => void | PromiseLike<void> | (() => void);
|
|
141
155
|
}
|
|
142
156
|
export declare const StatewireQueuedMessages: FC<StatewireQueuedMessagesProps>;
|
|
@@ -2,17 +2,21 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useAuiState, useAui } from "@assistant-ui/react";
|
|
3
3
|
import { useStatewireRuns, useStatewireSendCommand } from "@assistant-ui/react-statewire";
|
|
4
4
|
import { ChevronDownIcon, ChevronRightIcon, Loader2Icon, CircleIcon, ShipWheelIcon, PencilIcon, Trash2Icon, AlertCircleIcon, RotateCcwIcon, CheckIcon, XIcon } from "lucide-react";
|
|
5
|
-
import { useId, useState, useRef,
|
|
5
|
+
import { useId, useState, useRef, useEffect, useLayoutEffect } from "react";
|
|
6
6
|
import { parseMentionsInText, mentionsToPlainText } from "../chat-ui/mentions/mention-chip.js";
|
|
7
7
|
import { ContinuePill } from "../chat-ui/messages/continue-pill.js";
|
|
8
8
|
import { ChatOutboxRows } from "./chat-outbox-rows.js";
|
|
9
|
-
import { hasStatewireThreadExtras, requireStatewireFailedActions } from "../agent-runtime/src/thread-extras.js";
|
|
9
|
+
import { hasStatewireThreadExtras, readStatewireFailedSendLane, requireStatewireFailedActions } from "../agent-runtime/src/thread-extras.js";
|
|
10
10
|
import { useDeepAgentThreadStatus } from "../agent-runtime/src/thread-status.js";
|
|
11
11
|
import { useDeepAgentChatOutboxContext, useChatOutboxSnapshot } from "../agent-runtime/src/use-deep-agent-chat-outbox.js";
|
|
12
12
|
import { buildStatewireQueueRows, QUEUE_AUTO_CONTINUE_DELAY_MS, queueEntryText, isQueueEntryUnsettled, describeQueueSendFailure, queueLaneFlags, showQueueRowSteer, isFailedSendEntryRace, userStopBlocksQueueAutoContinue, buildQueueEditCommand } from "../agent-runtime/src/queue.js";
|
|
13
13
|
import { readRetryableRunRefusal } from "../agent-runtime/src/errors.js";
|
|
14
14
|
import { readRunMarkerFromSourceMessages, isServerUpdateStopSource } from "../agent-runtime/src/messages.js";
|
|
15
15
|
import { cn } from "cnfast";
|
|
16
|
+
const MAX_RETRY_HOLDS = 10;
|
|
17
|
+
function isThenable(value) {
|
|
18
|
+
return typeof value === "object" && value !== null && typeof value.then === "function";
|
|
19
|
+
}
|
|
16
20
|
const StatewireQueuedMessages = (props) => {
|
|
17
21
|
const extras = useAuiState((s) => s.thread.extras);
|
|
18
22
|
if (!hasStatewireThreadExtras(extras)) return null;
|
|
@@ -25,7 +29,8 @@ const StatewireQueuedMessagesInner = ({
|
|
|
25
29
|
onEvent,
|
|
26
30
|
renderContent,
|
|
27
31
|
renderEditor,
|
|
28
|
-
renderRowMarker
|
|
32
|
+
renderRowMarker,
|
|
33
|
+
onBeforeRetry
|
|
29
34
|
}) => {
|
|
30
35
|
var _a;
|
|
31
36
|
const runs = useStatewireRuns();
|
|
@@ -42,6 +47,16 @@ const StatewireQueuedMessagesInner = ({
|
|
|
42
47
|
const autoContinuedRef = useRef(/* @__PURE__ */ new Set());
|
|
43
48
|
const onEventRef = useRef(onEvent);
|
|
44
49
|
onEventRef.current = onEvent;
|
|
50
|
+
const onBeforeRetryRef = useRef(onBeforeRetry);
|
|
51
|
+
onBeforeRetryRef.current = onBeforeRetry;
|
|
52
|
+
const heldRetriesRef = useRef(/* @__PURE__ */ new Set());
|
|
53
|
+
const mountedRef = useRef(true);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
mountedRef.current = true;
|
|
56
|
+
return () => {
|
|
57
|
+
mountedRef.current = false;
|
|
58
|
+
};
|
|
59
|
+
}, []);
|
|
45
60
|
const outbox = useDeepAgentChatOutboxContext();
|
|
46
61
|
const outboxSnapshot = useChatOutboxSnapshot(outbox);
|
|
47
62
|
const rows = buildStatewireQueueRows({ queue, steerQueue, isContinuable });
|
|
@@ -70,6 +85,7 @@ const StatewireQueuedMessagesInner = ({
|
|
|
70
85
|
}) => {
|
|
71
86
|
try {
|
|
72
87
|
run(requireStatewireFailedActions(aui.thread().getState().extras));
|
|
88
|
+
return true;
|
|
73
89
|
} catch (error) {
|
|
74
90
|
if (!(error instanceof Error) || !isFailedSendEntryRace(error)) throw error;
|
|
75
91
|
onEvent == null ? void 0 : onEvent({
|
|
@@ -79,6 +95,44 @@ const StatewireQueuedMessagesInner = ({
|
|
|
79
95
|
action,
|
|
80
96
|
error: error.message
|
|
81
97
|
});
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const retryFailedSend = (messageId, held = 0) => {
|
|
102
|
+
var _a2, _b;
|
|
103
|
+
const heldRetries = heldRetriesRef.current;
|
|
104
|
+
if (held === 0 && heldRetries.has(messageId)) return;
|
|
105
|
+
heldRetries.delete(messageId);
|
|
106
|
+
if (!mountedRef.current) return;
|
|
107
|
+
if (held > 0 && !((_a2 = readStatewireFailedSendLane(aui.thread().getState().extras)) == null ? void 0 : _a2.failed.some(
|
|
108
|
+
(entry) => entry.id === messageId
|
|
109
|
+
))) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
let before;
|
|
113
|
+
try {
|
|
114
|
+
before = (_b = onBeforeRetryRef.current) == null ? void 0 : _b.call(onBeforeRetryRef, messageId);
|
|
115
|
+
} catch {
|
|
116
|
+
before = void 0;
|
|
117
|
+
}
|
|
118
|
+
if (isThenable(before) && held < MAX_RETRY_HOLDS) {
|
|
119
|
+
heldRetries.add(messageId);
|
|
120
|
+
const again = () => retryFailedSend(messageId, held + 1);
|
|
121
|
+
before.then(again, again);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
let sent = false;
|
|
125
|
+
try {
|
|
126
|
+
sent = runFailedSendAction({
|
|
127
|
+
action: "retry",
|
|
128
|
+
messageId,
|
|
129
|
+
run: (actions) => actions.retryFailed(messageId)
|
|
130
|
+
});
|
|
131
|
+
} finally {
|
|
132
|
+
try {
|
|
133
|
+
if (!sent && typeof before === "function") before();
|
|
134
|
+
} catch {
|
|
135
|
+
}
|
|
82
136
|
}
|
|
83
137
|
};
|
|
84
138
|
const hasOutboxRows = outbox !== null && (outboxSnapshot.rows.length > 0 || outboxSnapshot.elsewhere.length > 0);
|
|
@@ -258,11 +312,7 @@ const StatewireQueuedMessagesInner = ({
|
|
|
258
312
|
{
|
|
259
313
|
type: "button",
|
|
260
314
|
"aria-label": "Retry failed message",
|
|
261
|
-
onClick: () =>
|
|
262
|
-
action: "retry",
|
|
263
|
-
messageId: item.id,
|
|
264
|
-
run: (actions) => actions.retryFailed(item.id)
|
|
265
|
-
}),
|
|
315
|
+
onClick: () => retryFailedSend(item.id),
|
|
266
316
|
className: "inline-flex items-center gap-1 rounded-full border border-primary/30 px-2 py-1 font-medium text-[10px] text-primary hover:bg-primary/5",
|
|
267
317
|
children: [
|
|
268
318
|
/* @__PURE__ */ jsx(RotateCcwIcon, { className: "size-2.5" }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatewireQueuedMessages.js","sources":["../../src/chat/StatewireQueuedMessages.tsx"],"sourcesContent":["import { useAui, useAuiState } from '@assistant-ui/react';\nimport type { StatewireThread } from '@assistant-ui/react-statewire';\nimport {\n useStatewireRuns,\n useStatewireSendCommand,\n useStatewireState,\n} from '@assistant-ui/react-statewire';\nimport {\n buildQueueEditCommand,\n buildStatewireQueueRows,\n type DeepAgentThreadStatus,\n describeQueueSendFailure,\n hasStatewireThreadExtras,\n isFailedSendEntryRace,\n isQueueEntryUnsettled,\n isServerUpdateStopSource,\n QUEUE_AUTO_CONTINUE_DELAY_MS,\n queueEntryText,\n queueLaneFlags,\n readDeepAgentStreamValues,\n readRetryableRunRefusal,\n readRunMarkerFromSourceMessages,\n requireStatewireFailedActions,\n type StatewireFailedActions,\n showQueueRowSteer,\n useChatOutboxSnapshot,\n useDeepAgentChatOutboxContext,\n useDeepAgentThreadStatus,\n userStopBlocksQueueAutoContinue,\n} from '@athenaintel/agent-runtime';\nimport {\n AlertCircleIcon,\n CheckIcon,\n ChevronDownIcon,\n ChevronRightIcon,\n CircleIcon,\n Loader2Icon,\n PencilIcon,\n RotateCcwIcon,\n ShipWheelIcon,\n Trash2Icon,\n XIcon,\n} from 'lucide-react';\nimport {\n type FC,\n type KeyboardEvent,\n type MutableRefObject,\n type ReactNode,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { mentionsToPlainText, parseMentionsInText } from '../chat-ui/mentions/mention-chip';\nimport { ContinuePill } from '../chat-ui/messages/continue-pill';\nimport { cn } from '../lib/utils';\nimport { ChatOutboxRows } from './chat-outbox-rows';\n\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /**\n * The ⚡ on a queued row (`DeepAgentThread.run_prioritize`). With\n * `priority: true` the host moves the entry to the head of the queue\n * lane (behind entries prioritized before it), records it durably, and\n * the live run ends at its next model-call boundary — after the\n * in-flight tool chain, never mid-tool — so the settle delivers the\n * entry on top of the finished tool results instead of after the whole\n * turn. `priority: false` withdraws the request and leaves the entry\n * where it is.\n */\n runPrioritize: {\n type: 'run/prioritize';\n runId: string;\n messageId: string;\n priority: boolean;\n };\n /**\n * \"Steer\" on a queued row (`DeepAgentThread.run_steer_live`) — what\n * ChatGPT and Codex call Steer, versus Queue. The host moves the entry\n * to the steer lane and records it as a live steer, so the running\n * turn is NOT cancelled: at its next model call — after the in-flight\n * tool chain, never mid-tool — the run drains the entry into its own\n * context as a user turn and continues. Everything the run produces\n * from then on lands after the steered message. Mirrors `run/steer`'s\n * params (exactly one of `message` or `messageId`).\n */\n runSteerLive: {\n type: 'run/steer-live';\n runId: string;\n messageId: string;\n };\n }\n }\n}\n\n/**\n * The one queued-messages tray for the server-owned statewire queue and steer\n * lanes, mounted by the SDK's `AthenaChat`, the Chrome side panel, the Office\n * task pane, and Olympus.\n *\n * A message sent before the live run has produced any output is a double\n * text: the host folds it into the run's turn (`run/enqueue` steers it and\n * the run redispatches with both messages), so it never lists here. A\n * message sent once the run is answering queues behind it. Rows offer\n * \"Steer\" (`run/steer-live` — the host parks the entry on the steer lane as a\n * live steer and the running turn drains it into its own context at its next\n * model call, so the run continues with it; ChatGPT's Steer versus Queue),\n * inline edit (re-sent under the entry's own id on its own lane, which the\n * host folds as an in-place content update), and remove (`run/dequeue`).\n * While the thread rests stopped/errored, stranded steer-lane entries list\n * ahead of the queue (they dispatch first, as one batch) and a Continue pill\n * steer-promotes the queue head — a steer entry moved onto its own lane is a\n * no-op, so a steer-only rest state gets no dead button.\n *\n * A row whose send has not settled yet (`isQueueEntryUnsettled` — this\n * client's optimistic fold, not a host-admitted lane entry) renders as\n * \"Sending…\" with no acting affordances: admission is server-side and can\n * still refuse the message. Failed run sends (`runs.failed`) list after the\n * lanes with Retry (`retryFailed`) and Discard (`discardFailed`).\n *\n * With `autoContinue`, an ordinary stranded settle promotes the queue head\n * once after `QUEUE_AUTO_CONTINUE_DELAY_MS`. User stops remain manual;\n * infrastructure pauses and retryable dispatch refusals recover on the server.\n *\n * Renders nothing on the legacy transport or when every lane is empty.\n */\n\nexport type StatewireQueueEvent =\n | {\n type: 'auto-continued';\n threadId: string | null;\n status: DeepAgentThreadStatus;\n headEntryId: string;\n }\n | {\n type: 'failed-send-action-raced';\n threadId: string | null;\n messageId: string;\n action: 'retry' | 'discard';\n error: string;\n };\n\nexport interface StatewireQueueRowContentContext {\n text: string;\n index: number;\n item: StatewireThread.RunsQueueEntry;\n}\n\nexport interface StatewireQueueRowMarkerContext {\n item: StatewireThread.RunsQueueEntry;\n lane: 'queue' | 'steer';\n index: number;\n /** This client's optimistic fold, not yet admitted by the host (renders \"Sending…\"). */\n isUnsettled: boolean;\n}\n\nexport interface StatewireQueueEditorContext {\n value: string;\n /** The entry being edited, for an editor that reads its metadata (e.g. the composer markdown it was sent from). */\n item: StatewireThread.RunsQueueEntry;\n onChange: (value: string) => void;\n /**\n * Save the edit; a blank or unchanged message sends nothing but closes the\n * editor. `metadata`, when given, replaces the entry's message metadata.\n */\n onSave: (text: string, options?: { metadata?: Record<string, unknown> }) => void;\n onCancel: () => void;\n}\n\nexport interface StatewireQueuedMessagesProps {\n /** Surface-styling overrides merged onto the default classes. */\n classNames?: {\n /** The tray container. */\n root?: string;\n /** The row list. */\n list?: string;\n };\n /**\n * Steer-promote a stranded queue head automatically after a settle (see the\n * component docs). Off by default: a host opts in to dispatching runs on the\n * user's behalf. Pass `{ delayMs }` to tune the grace before the promotion\n * (defaults to `QUEUE_AUTO_CONTINUE_DELAY_MS`).\n */\n autoContinue?: boolean | { delayMs?: number };\n /** Identifies the thread for once-per-entry auto-continue attempts and events. */\n threadId?: string | null;\n /** Telemetry sink for the tray's notable moments. */\n onEvent?: (event: StatewireQueueEvent) => void;\n /** Replace the plain-text row body (e.g. a mention-aware renderer). */\n renderContent?: (context: StatewireQueueRowContentContext) => ReactNode;\n /** Replace the plain textarea inline editor (e.g. the host's composer editor). */\n renderEditor?: (context: StatewireQueueEditorContext) => ReactNode;\n /**\n * Replace a lane row's leading marker (the bullet, or the spinner while the\n * send is unsettled) — e.g. the submitter's avatar on a shared thread.\n * Returning `null`/`undefined` keeps the default marker for that row.\n */\n renderRowMarker?: (context: StatewireQueueRowMarkerContext) => ReactNode;\n}\n\nexport const StatewireQueuedMessages: FC<StatewireQueuedMessagesProps> = (props) => {\n const extras = useAuiState((s) => s.thread.extras);\n if (!hasStatewireThreadExtras(extras)) return null;\n return <StatewireQueuedMessagesInner {...props} />;\n};\n\nconst StatewireQueuedMessagesInner: FC<StatewireQueuedMessagesProps> = ({\n classNames,\n autoContinue = false,\n threadId = null,\n onEvent,\n renderContent,\n renderEditor,\n renderRowMarker,\n}) => {\n // The QUEUE lane only: composer.queue prepends the steer lane, whose entries\n // already render in the message list. A non-empty queue implies a live run\n // entry (the host retires runId only once both lanes drain), so the row\n // controls can always send.\n const runs = useStatewireRuns();\n const { queue, steerQueue, runId, epoch } = runs;\n // `failed` joined the runs projection in react-statewire 0.24; a projection\n // without it (an older lib, a stubbed runs read) must not crash the tray.\n const failed = runs.failed ?? [];\n const status = useDeepAgentThreadStatus();\n const { isRunning, isContinuable } = queueLaneFlags(status);\n const aui = useAui();\n const sendCommand = useStatewireSendCommand();\n const listId = useId();\n const [expanded, setExpanded] = useState(true);\n const [editingId, setEditingId] = useState<string | null>(null);\n const [editingText, setEditingText] = useState('');\n // Head entries already auto-promoted once on this mount: an attempt whose\n // continue run dies and re-strands the SAME entry must not loop — the manual\n // Continue pill is the fallback for a repeatedly failing dispatch. Kept on\n // the tray (not the auto-continue child) so it survives the empty-lane\n // renders between a promotion and its outcome.\n const autoContinuedRef = useRef<Set<string>>(new Set());\n const onEventRef = useRef(onEvent);\n onEventRef.current = onEvent;\n // Messages typed while Athena couldn't be reached (the host's chat outbox), shown above the\n // lanes until they are sent, cancelled or discarded.\n const outbox = useDeepAgentChatOutboxContext();\n const outboxSnapshot = useChatOutboxSnapshot(outbox);\n\n const rows = buildStatewireQueueRows({ queue, steerQueue, isContinuable });\n // Continue promotes the QUEUE head only: a queue→steer move dispatches the\n // stranded steer lane plus this entry, while a steer entry moved onto its\n // own lane is a no-op.\n const queueHeadId = queue[0]?.id ?? null;\n const continuationRef = useRef({ aui, threadId, runId, epoch, queueHeadId, isContinuable });\n useLayoutEffect(() => {\n continuationRef.current = { aui, threadId, runId, epoch, queueHeadId, isContinuable };\n }, [aui, threadId, runId, epoch, queueHeadId, isContinuable]);\n\n const continueQueue = (): void => {\n const current = continuationRef.current;\n // Draft recovery may remove the old head during the pill's exit animation.\n // Continue the surviving queue only within the clicked runtime/dispatch.\n if (\n current.aui !== aui || current.threadId !== threadId ||\n current.runId !== runId || current.epoch !== epoch ||\n !current.isContinuable || current.queueHeadId === null\n ) return;\n aui.composer.queueItem({ id: current.queueHeadId }).move({ lane: 'steer' });\n };\n const retryableRefusal = readRetryableRunRefusal(runs.error) !== null;\n const autoContinueOptions = autoContinue === true ? {} : autoContinue || null;\n\n /**\n * Re-send the entry under its own id on its own lane: the host replaces the\n * queued message's content in place, leaving its queue position and lane\n * untouched (a same-id send never dispatches).\n */\n const saveEdit = (\n item: StatewireThread.RunsQueueEntry,\n lane: 'queue' | 'steer',\n text: string,\n metadata?: Record<string, unknown>,\n ): void => {\n setEditingId(null);\n setEditingText('');\n const command = buildQueueEditCommand({ item, lane, runId, text, metadata });\n if (command !== null) sendCommand(command);\n };\n\n /**\n * Retry/Discard act on a rendered lane snapshot that can trail the session\n * record; acting on an entry statewire already dropped throws. Nothing is\n * lost in that race, so it is recorded instead of crashing the click.\n */\n const runFailedSendAction = ({\n action,\n messageId,\n run,\n }: {\n action: 'retry' | 'discard';\n messageId: string;\n run: (actions: StatewireFailedActions) => void;\n }): void => {\n try {\n run(requireStatewireFailedActions(aui.thread().getState().extras));\n } catch (error) {\n if (!(error instanceof Error) || !isFailedSendEntryRace(error)) throw error;\n onEvent?.({\n type: 'failed-send-action-raced',\n threadId,\n messageId,\n action,\n error: error.message,\n });\n }\n };\n\n const hasOutboxRows =\n outbox !== null && (outboxSnapshot.rows.length > 0 || outboxSnapshot.elsewhere.length > 0);\n const hasLaneRows = rows.length > 0 || failed.length > 0;\n if (!hasLaneRows && !hasOutboxRows) return null;\n\n const renderRowContent = (context: StatewireQueueRowContentContext): ReactNode =>\n renderContent ? renderContent(context) : <QueueRowText text={context.text} />;\n\n return (\n <section\n aria-label=\"Queued messages\"\n className={cn(\n 'aui-statewire-queue w-full rounded-xl border border-border/70 bg-muted/30 px-2 py-1.5',\n classNames?.root,\n )}\n >\n {hasOutboxRows ? (\n <ChatOutboxRows outbox={outbox} snapshot={outboxSnapshot} renderContent={renderRowContent} />\n ) : null}\n {autoContinueOptions ? (\n <QueueAutoContinue\n delayMs={autoContinueOptions.delayMs ?? QUEUE_AUTO_CONTINUE_DELAY_MS}\n queueHeadId={queueHeadId}\n retryableRefusal={retryableRefusal}\n isContinuable={isContinuable}\n status={status}\n threadId={threadId}\n editing={editingId !== null}\n continuedRef={autoContinuedRef}\n onEventRef={onEventRef}\n />\n ) : null}\n {hasLaneRows ? (\n <div className=\"flex items-center gap-1.5\">\n <button\n type=\"button\"\n onClick={() => setExpanded((value) => !value)}\n aria-expanded={expanded}\n aria-controls={listId}\n className=\"flex items-center gap-1 rounded px-1 py-1 font-medium text-muted-foreground text-xs hover:text-foreground\"\n >\n {expanded ? (\n <ChevronDownIcon className=\"size-3.5\" />\n ) : (\n <ChevronRightIcon className=\"size-3.5\" />\n )}\n {rows.length + failed.length} queued\n </button>\n {isContinuable && queueHeadId !== null ? (\n <ContinuePill\n ariaLabel=\"Continue with queued messages\"\n onClick={continueQueue}\n />\n ) : null}\n </div>\n ) : null}\n {expanded && hasLaneRows ? (\n <ul\n id={listId}\n className={cn('max-h-40 overflow-y-auto', classNames?.list)}\n data-testid=\"athena-statewire-queue\"\n >\n {rows.map(({ item, lane }, index) => {\n const text = queueEntryText(item.parts);\n const isUnsettled = isQueueEntryUnsettled(item);\n const isEditing = editingId === item.id;\n const showSteer =\n !isUnsettled && runId !== null && showQueueRowSteer({ lane, isRunning });\n const marker = renderRowMarker?.({ item, lane, index, isUnsettled });\n const editorContext: StatewireQueueEditorContext = {\n value: editingText,\n item,\n onChange: setEditingText,\n onSave: (next, options) => saveEdit(item, lane, next, options?.metadata),\n onCancel: () => {\n setEditingId(null);\n setEditingText('');\n },\n };\n return (\n <li\n key={item.id}\n className=\"group flex items-start gap-2 rounded-md px-1 py-1.5 hover:bg-background\"\n >\n {marker != null ? (\n marker\n ) : isUnsettled ? (\n <Loader2Icon className=\"mt-0.5 size-3.5 shrink-0 animate-spin text-muted-foreground/60\" />\n ) : (\n <CircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-muted-foreground/40\" />\n )}\n {isEditing ? (\n renderEditor ? (\n renderEditor(editorContext)\n ) : (\n <DefaultQueueEditor {...editorContext} />\n )\n ) : (\n renderRowContent({ text, index, item })\n )}\n <div\n className={cn('flex shrink-0 items-center gap-1', isEditing && 'hidden')}\n data-testid=\"statewire-queue-row-actions\"\n >\n {isUnsettled ? (\n <span\n className=\"px-1 text-[10px] text-muted-foreground\"\n data-testid=\"statewire-queued-message-sending\"\n >\n Sending…\n </span>\n ) : null}\n {showSteer ? (\n <button\n type=\"button\"\n aria-label=\"Steer\"\n title=\"Steer the current response: folded into the running turn at its next step, without stopping it.\"\n onClick={() => {\n if (runId === null) return;\n sendCommand({ type: 'run/steer-live', runId, messageId: item.id });\n }}\n className=\"inline-flex items-center gap-1 rounded-full border border-border px-2 py-1 font-medium text-[10px] text-foreground/80 hover:bg-background hover:text-foreground\"\n >\n <ShipWheelIcon className=\"size-2.5\" />\n Steer\n </button>\n ) : null}\n {!isUnsettled ? (\n <button\n type=\"button\"\n aria-label=\"Edit queued message\"\n onClick={() => {\n setEditingId(item.id);\n setEditingText(text);\n }}\n className=\"rounded p-1 text-muted-foreground transition-colors hover:text-primary\"\n >\n <PencilIcon className=\"size-3\" />\n </button>\n ) : null}\n <button\n type=\"button\"\n aria-label=\"Remove queued message\"\n onClick={() => aui.composer.queueItem({ id: item.id }).remove()}\n className={cn(\n 'rounded p-1 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive',\n !showSteer &&\n 'opacity-0 focus-visible:opacity-100 group-hover:opacity-100',\n )}\n >\n <Trash2Icon className=\"size-3\" />\n </button>\n </div>\n </li>\n );\n })}\n {failed.map((item, index) => (\n <li\n key={item.id}\n className=\"group flex items-start gap-2 rounded-md px-1 py-1.5 hover:bg-background\"\n >\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n {renderRowContent({\n text: queueEntryText(item.parts),\n index: rows.length + index,\n item,\n })}\n <div\n className=\"flex shrink-0 items-center gap-1\"\n data-testid=\"statewire-queue-row-actions\"\n >\n <span\n className=\"px-1 text-[10px] text-destructive\"\n title={describeQueueSendFailure(item.sendFailure)}\n >\n Failed to send\n </span>\n <button\n type=\"button\"\n aria-label=\"Retry failed message\"\n onClick={() =>\n runFailedSendAction({\n action: 'retry',\n messageId: item.id,\n run: (actions) => actions.retryFailed(item.id),\n })\n }\n className=\"inline-flex items-center gap-1 rounded-full border border-primary/30 px-2 py-1 font-medium text-[10px] text-primary hover:bg-primary/5\"\n >\n <RotateCcwIcon className=\"size-2.5\" />\n Retry\n </button>\n <button\n type=\"button\"\n aria-label=\"Discard failed message\"\n onClick={() =>\n runFailedSendAction({\n action: 'discard',\n messageId: item.id,\n run: (actions) => actions.discardFailed(item.id),\n })\n }\n className=\"rounded p-1 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive\"\n >\n <Trash2Icon className=\"size-3\" />\n </button>\n </div>\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n );\n};\n\n/** Promotes ordinary stranded queue heads once; infrastructure recovery stays server-owned. */\nconst QueueAutoContinue: FC<{\n delayMs: number;\n queueHeadId: string | null;\n retryableRefusal: boolean;\n isContinuable: boolean;\n status: DeepAgentThreadStatus;\n threadId: string | null;\n editing: boolean;\n continuedRef: MutableRefObject<Set<string>>;\n onEventRef: MutableRefObject<((event: StatewireQueueEvent) => void) | undefined>;\n}> = ({\n delayMs,\n queueHeadId,\n retryableRefusal,\n isContinuable,\n status,\n threadId,\n editing,\n continuedRef,\n onEventRef,\n}) => {\n const aui = useAui();\n // The settle that stranded the queue is described by the LAST message's run\n // marker (a marker deeper in history was superseded by a later send). The\n // selectors return primitives so the subscriptions stay shallow-stable.\n const lastMessageMarker = useAuiState((s) => {\n const last = s.thread.messages.at(-1);\n return last ? readRunMarkerFromSourceMessages(last)?.marker : undefined;\n });\n const lastMessageMarkerSource = useAuiState((s) => {\n const last = s.thread.messages.at(-1);\n return last ? readRunMarkerFromSourceMessages(last)?.source : undefined;\n });\n const userStopBlocks = userStopBlocksQueueAutoContinue({\n marker: lastMessageMarker,\n source: lastMessageMarkerSource,\n });\n\n useEffect(() => {\n if (\n !isContinuable ||\n userStopBlocks ||\n retryableRefusal ||\n isServerUpdateStopSource(lastMessageMarkerSource)\n ) return;\n // An open inline edit means the user is mid-revision on some row —\n // dispatching underneath them could send text they are about to change.\n if (editing) return;\n if (queueHeadId === null) return;\n const attemptKey = `${threadId ?? 'unknown'}:${queueHeadId}`;\n if (continuedRef.current.has(attemptKey)) return;\n const timeoutId = setTimeout(() => {\n continuedRef.current.add(attemptKey);\n onEventRef.current?.({ type: 'auto-continued', threadId, status, headEntryId: queueHeadId });\n aui.composer.queueItem({ id: queueHeadId }).move({ lane: 'steer' });\n }, delayMs);\n return () => clearTimeout(timeoutId);\n }, [\n continuedRef,\n aui,\n delayMs,\n editing,\n isContinuable,\n onEventRef,\n queueHeadId,\n retryableRefusal,\n lastMessageMarkerSource,\n status,\n threadId,\n userStopBlocks,\n ]);\n\n return null;\n};\n\n/**\n * The default row body: `[@name](…)` mentions render as chips, not raw\n * markdown links, and the body clamps to two lines. Show more / Show less\n * appears only when the rendered text overflows those two lines, so a short\n * message that wraps in a narrow tray is still caught and a short one gets no\n * dead control.\n */\nconst QueueRowText: FC<{ text: string }> = ({ text }) => {\n const bodyRef = useRef<HTMLParagraphElement>(null);\n const [expanded, setExpanded] = useState(false);\n const [overflows, setOverflows] = useState(false);\n\n useLayoutEffect(() => {\n const body = bodyRef.current;\n // Expanded text has no clamp to overflow; the toggle stays up to collapse it.\n if (!body || expanded) return;\n const measure = (): void => setOverflows(body.scrollHeight > body.clientHeight + 1);\n measure();\n if (typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(measure);\n observer.observe(body);\n return () => observer.disconnect();\n }, [text, expanded]);\n\n if (!text) {\n return <p className=\"min-w-0 flex-1 text-foreground text-xs\">Queued attachment</p>;\n }\n return (\n <div className=\"min-w-0 flex-1\">\n <p\n ref={bodyRef}\n className={cn(\n 'whitespace-pre-wrap break-words text-foreground text-xs leading-relaxed',\n !expanded && 'line-clamp-2',\n )}\n title={overflows && !expanded ? mentionsToPlainText(text) : undefined}\n >\n {parseMentionsInText(text)}\n </p>\n {overflows || expanded ? (\n <button\n type=\"button\"\n aria-expanded={expanded}\n onClick={() => setExpanded((value) => !value)}\n className=\"mt-0.5 font-medium text-[10px] text-muted-foreground hover:text-foreground\"\n >\n {expanded ? 'Show less' : 'Show more'}\n </button>\n ) : null}\n </div>\n );\n};\n\n/** Plain textarea editor: Enter saves, Shift+Enter breaks a line, Escape cancels. */\nconst DefaultQueueEditor: FC<StatewireQueueEditorContext> = ({\n value,\n onChange,\n onSave,\n onCancel,\n}) => {\n const canSave = value.trim().length > 0;\n const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>): void => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n if (canSave) onSave(value);\n } else if (event.key === 'Escape') {\n event.preventDefault();\n onCancel();\n }\n };\n return (\n <div className=\"flex min-w-0 flex-1 items-start gap-1\">\n <textarea\n autoFocus\n aria-label=\"Edit message\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n onKeyDown={handleKeyDown}\n rows={Math.min(6, Math.max(1, value.split('\\n').length))}\n className=\"min-w-0 flex-1 resize-none rounded-md border border-border bg-background px-2 py-1 text-foreground text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring/50\"\n />\n <button\n type=\"button\"\n aria-label=\"Save edit\"\n disabled={!canSave}\n onClick={() => onSave(value)}\n className={cn(\n 'rounded p-1 text-primary transition-colors hover:bg-primary/10',\n !canSave && 'cursor-not-allowed opacity-40',\n )}\n >\n <CheckIcon className=\"size-3.5\" />\n </button>\n <button\n type=\"button\"\n aria-label=\"Cancel edit\"\n onClick={onCancel}\n className=\"rounded p-1 text-muted-foreground transition-colors hover:bg-muted\"\n >\n <XIcon className=\"size-3.5\" />\n </button>\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"StatewireQueuedMessages.js","sources":["../../src/chat/StatewireQueuedMessages.tsx"],"sourcesContent":["import { useAui, useAuiState } from '@assistant-ui/react';\nimport type { StatewireThread } from '@assistant-ui/react-statewire';\nimport {\n useStatewireRuns,\n useStatewireSendCommand,\n useStatewireState,\n} from '@assistant-ui/react-statewire';\nimport {\n buildQueueEditCommand,\n buildStatewireQueueRows,\n type DeepAgentThreadStatus,\n describeQueueSendFailure,\n hasStatewireThreadExtras,\n isFailedSendEntryRace,\n isQueueEntryUnsettled,\n isServerUpdateStopSource,\n QUEUE_AUTO_CONTINUE_DELAY_MS,\n queueEntryText,\n queueLaneFlags,\n readDeepAgentStreamValues,\n readRetryableRunRefusal,\n readRunMarkerFromSourceMessages,\n readStatewireFailedSendLane,\n requireStatewireFailedActions,\n type StatewireFailedActions,\n showQueueRowSteer,\n useChatOutboxSnapshot,\n useDeepAgentChatOutboxContext,\n useDeepAgentThreadStatus,\n userStopBlocksQueueAutoContinue,\n} from '@athenaintel/agent-runtime';\nimport {\n AlertCircleIcon,\n CheckIcon,\n ChevronDownIcon,\n ChevronRightIcon,\n CircleIcon,\n Loader2Icon,\n PencilIcon,\n RotateCcwIcon,\n ShipWheelIcon,\n Trash2Icon,\n XIcon,\n} from 'lucide-react';\nimport {\n type FC,\n type KeyboardEvent,\n type MutableRefObject,\n type ReactNode,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { mentionsToPlainText, parseMentionsInText } from '../chat-ui/mentions/mention-chip';\nimport { ContinuePill } from '../chat-ui/messages/continue-pill';\nimport { cn } from '../lib/utils';\nimport { ChatOutboxRows } from './chat-outbox-rows';\n\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /**\n * The ⚡ on a queued row (`DeepAgentThread.run_prioritize`). With\n * `priority: true` the host moves the entry to the head of the queue\n * lane (behind entries prioritized before it), records it durably, and\n * the live run ends at its next model-call boundary — after the\n * in-flight tool chain, never mid-tool — so the settle delivers the\n * entry on top of the finished tool results instead of after the whole\n * turn. `priority: false` withdraws the request and leaves the entry\n * where it is.\n */\n runPrioritize: {\n type: 'run/prioritize';\n runId: string;\n messageId: string;\n priority: boolean;\n };\n /**\n * \"Steer\" on a queued row (`DeepAgentThread.run_steer_live`) — what\n * ChatGPT and Codex call Steer, versus Queue. The host moves the entry\n * to the steer lane and records it as a live steer, so the running\n * turn is NOT cancelled: at its next model call — after the in-flight\n * tool chain, never mid-tool — the run drains the entry into its own\n * context as a user turn and continues. Everything the run produces\n * from then on lands after the steered message. Mirrors `run/steer`'s\n * params (exactly one of `message` or `messageId`).\n */\n runSteerLive: {\n type: 'run/steer-live';\n runId: string;\n messageId: string;\n };\n }\n }\n}\n\n/**\n * The one queued-messages tray for the server-owned statewire queue and steer\n * lanes, mounted by the SDK's `AthenaChat`, the Chrome side panel, the Office\n * task pane, and Olympus.\n *\n * A message sent before the live run has produced any output is a double\n * text: the host folds it into the run's turn (`run/enqueue` steers it and\n * the run redispatches with both messages), so it never lists here. A\n * message sent once the run is answering queues behind it. Rows offer\n * \"Steer\" (`run/steer-live` — the host parks the entry on the steer lane as a\n * live steer and the running turn drains it into its own context at its next\n * model call, so the run continues with it; ChatGPT's Steer versus Queue),\n * inline edit (re-sent under the entry's own id on its own lane, which the\n * host folds as an in-place content update), and remove (`run/dequeue`).\n * While the thread rests stopped/errored, stranded steer-lane entries list\n * ahead of the queue (they dispatch first, as one batch) and a Continue pill\n * steer-promotes the queue head — a steer entry moved onto its own lane is a\n * no-op, so a steer-only rest state gets no dead button.\n *\n * A row whose send has not settled yet (`isQueueEntryUnsettled` — this\n * client's optimistic fold, not a host-admitted lane entry) renders as\n * \"Sending…\" with no acting affordances: admission is server-side and can\n * still refuse the message. Failed run sends (`runs.failed`) list after the\n * lanes with Retry (`retryFailed`) and Discard (`discardFailed`).\n *\n * With `autoContinue`, an ordinary stranded settle promotes the queue head\n * once after `QUEUE_AUTO_CONTINUE_DELAY_MS`. User stops remain manual;\n * infrastructure pauses and retryable dispatch refusals recover on the server.\n *\n * Renders nothing on the legacy transport or when every lane is empty.\n */\n\nexport type StatewireQueueEvent =\n | {\n type: 'auto-continued';\n threadId: string | null;\n status: DeepAgentThreadStatus;\n headEntryId: string;\n }\n | {\n type: 'failed-send-action-raced';\n threadId: string | null;\n messageId: string;\n action: 'retry' | 'discard';\n error: string;\n };\n\nexport interface StatewireQueueRowContentContext {\n text: string;\n index: number;\n item: StatewireThread.RunsQueueEntry;\n}\n\nexport interface StatewireQueueRowMarkerContext {\n item: StatewireThread.RunsQueueEntry;\n lane: 'queue' | 'steer';\n index: number;\n /** This client's optimistic fold, not yet admitted by the host (renders \"Sending…\"). */\n isUnsettled: boolean;\n}\n\nexport interface StatewireQueueEditorContext {\n value: string;\n /** The entry being edited, for an editor that reads its metadata (e.g. the composer markdown it was sent from). */\n item: StatewireThread.RunsQueueEntry;\n onChange: (value: string) => void;\n /**\n * Save the edit; a blank or unchanged message sends nothing but closes the\n * editor. `metadata`, when given, replaces the entry's message metadata.\n */\n onSave: (text: string, options?: { metadata?: Record<string, unknown> }) => void;\n onCancel: () => void;\n}\n\nexport interface StatewireQueuedMessagesProps {\n /** Surface-styling overrides merged onto the default classes. */\n classNames?: {\n /** The tray container. */\n root?: string;\n /** The row list. */\n list?: string;\n };\n /**\n * Steer-promote a stranded queue head automatically after a settle (see the\n * component docs). Off by default: a host opts in to dispatching runs on the\n * user's behalf. Pass `{ delayMs }` to tune the grace before the promotion\n * (defaults to `QUEUE_AUTO_CONTINUE_DELAY_MS`).\n */\n autoContinue?: boolean | { delayMs?: number };\n /** Identifies the thread for once-per-entry auto-continue attempts and events. */\n threadId?: string | null;\n /** Telemetry sink for the tray's notable moments. */\n onEvent?: (event: StatewireQueueEvent) => void;\n /** Replace the plain-text row body (e.g. a mention-aware renderer). */\n renderContent?: (context: StatewireQueueRowContentContext) => ReactNode;\n /** Replace the plain textarea inline editor (e.g. the host's composer editor). */\n renderEditor?: (context: StatewireQueueEditorContext) => ReactNode;\n /**\n * Replace a lane row's leading marker (the bullet, or the spinner while the\n * send is unsettled) — e.g. the submitter's avatar on a shared thread.\n * Returning `null`/`undefined` keeps the default marker for that row.\n */\n renderRowMarker?: (context: StatewireQueueRowMarkerContext) => ReactNode;\n /**\n * Called right before a failed message is sent again (its Retry), with its\n * id, so the host can put back the per-send context that message was sent\n * with (e.g. the agents it named) before its command leaves. A promise holds\n * the Retry until it settles, then the host is asked again, unless the\n * message was sent or discarded meanwhile: it can't put that context back\n * while a send with another one is still on its way (every send of a\n * conversation rides one ambient context). A held Retry is held once (a\n * second click does nothing); after {@link MAX_RETRY_HOLDS} holds the message\n * goes regardless, and a hook that throws never holds it back. A function\n * returned is called when the message does not go after all (it left the\n * failed lane first), so the host lets go of what it put back.\n */\n onBeforeRetry?: (messageId: string) => void | PromiseLike<void> | (() => void);\n}\n\n/** How many times a host may hold one Retry (`onBeforeRetry`'s promise) before it goes regardless. */\nconst MAX_RETRY_HOLDS = 10;\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { then?: unknown }).then === 'function'\n );\n}\n\nexport const StatewireQueuedMessages: FC<StatewireQueuedMessagesProps> = (props) => {\n const extras = useAuiState((s) => s.thread.extras);\n if (!hasStatewireThreadExtras(extras)) return null;\n return <StatewireQueuedMessagesInner {...props} />;\n};\n\nconst StatewireQueuedMessagesInner: FC<StatewireQueuedMessagesProps> = ({\n classNames,\n autoContinue = false,\n threadId = null,\n onEvent,\n renderContent,\n renderEditor,\n renderRowMarker,\n onBeforeRetry,\n}) => {\n // The QUEUE lane only: composer.queue prepends the steer lane, whose entries\n // already render in the message list. A non-empty queue implies a live run\n // entry (the host retires runId only once both lanes drain), so the row\n // controls can always send.\n const runs = useStatewireRuns();\n const { queue, steerQueue, runId, epoch } = runs;\n // `failed` joined the runs projection in react-statewire 0.24; a projection\n // without it (an older lib, a stubbed runs read) must not crash the tray.\n const failed = runs.failed ?? [];\n const status = useDeepAgentThreadStatus();\n const { isRunning, isContinuable } = queueLaneFlags(status);\n const aui = useAui();\n const sendCommand = useStatewireSendCommand();\n const listId = useId();\n const [expanded, setExpanded] = useState(true);\n const [editingId, setEditingId] = useState<string | null>(null);\n const [editingText, setEditingText] = useState('');\n // Head entries already auto-promoted once on this mount: an attempt whose\n // continue run dies and re-strands the SAME entry must not loop — the manual\n // Continue pill is the fallback for a repeatedly failing dispatch. Kept on\n // the tray (not the auto-continue child) so it survives the empty-lane\n // renders between a promotion and its outcome.\n const autoContinuedRef = useRef<Set<string>>(new Set());\n const onEventRef = useRef(onEvent);\n onEventRef.current = onEvent;\n const onBeforeRetryRef = useRef(onBeforeRetry);\n onBeforeRetryRef.current = onBeforeRetry;\n // The messages whose Retry the host is holding (`onBeforeRetry`'s promise).\n const heldRetriesRef = useRef<Set<string>>(new Set());\n // A Retry the host held goes on only while the tray is still there.\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n // Messages typed while Athena couldn't be reached (the host's chat outbox), shown above the\n // lanes until they are sent, cancelled or discarded.\n const outbox = useDeepAgentChatOutboxContext();\n const outboxSnapshot = useChatOutboxSnapshot(outbox);\n\n const rows = buildStatewireQueueRows({ queue, steerQueue, isContinuable });\n // Continue promotes the QUEUE head only: a queue→steer move dispatches the\n // stranded steer lane plus this entry, while a steer entry moved onto its\n // own lane is a no-op.\n const queueHeadId = queue[0]?.id ?? null;\n const continuationRef = useRef({ aui, threadId, runId, epoch, queueHeadId, isContinuable });\n useLayoutEffect(() => {\n continuationRef.current = { aui, threadId, runId, epoch, queueHeadId, isContinuable };\n }, [aui, threadId, runId, epoch, queueHeadId, isContinuable]);\n\n const continueQueue = (): void => {\n const current = continuationRef.current;\n // Draft recovery may remove the old head during the pill's exit animation.\n // Continue the surviving queue only within the clicked runtime/dispatch.\n if (\n current.aui !== aui || current.threadId !== threadId ||\n current.runId !== runId || current.epoch !== epoch ||\n !current.isContinuable || current.queueHeadId === null\n ) return;\n aui.composer.queueItem({ id: current.queueHeadId }).move({ lane: 'steer' });\n };\n const retryableRefusal = readRetryableRunRefusal(runs.error) !== null;\n const autoContinueOptions = autoContinue === true ? {} : autoContinue || null;\n\n /**\n * Re-send the entry under its own id on its own lane: the host replaces the\n * queued message's content in place, leaving its queue position and lane\n * untouched (a same-id send never dispatches).\n */\n const saveEdit = (\n item: StatewireThread.RunsQueueEntry,\n lane: 'queue' | 'steer',\n text: string,\n metadata?: Record<string, unknown>,\n ): void => {\n setEditingId(null);\n setEditingText('');\n const command = buildQueueEditCommand({ item, lane, runId, text, metadata });\n if (command !== null) sendCommand(command);\n };\n\n /**\n * Retry/Discard act on a rendered lane snapshot that can trail the session\n * record; acting on an entry statewire already dropped throws. Nothing is\n * lost in that race, so it is recorded instead of crashing the click.\n * Returns whether the action went.\n */\n const runFailedSendAction = ({\n action,\n messageId,\n run,\n }: {\n action: 'retry' | 'discard';\n messageId: string;\n run: (actions: StatewireFailedActions) => void;\n }): boolean => {\n try {\n run(requireStatewireFailedActions(aui.thread().getState().extras));\n return true;\n } catch (error) {\n if (!(error instanceof Error) || !isFailedSendEntryRace(error)) throw error;\n onEvent?.({\n type: 'failed-send-action-raced',\n threadId,\n messageId,\n action,\n error: error.message,\n });\n return false;\n }\n };\n\n /**\n * A failed message's Retry: the host puts its per-send context back first\n * (`onBeforeRetry`), synchronously with the re-send. A host that holds it (a\n * promise: a send with another context is still on its way) is asked again\n * once that settles, while the message is still in the failed lane; a click\n * meanwhile does nothing, and a tray gone meanwhile leaves the row as it was.\n */\n const retryFailedSend = (messageId: string, held = 0): void => {\n const heldRetries = heldRetriesRef.current;\n if (held === 0 && heldRetries.has(messageId)) return;\n heldRetries.delete(messageId);\n if (!mountedRef.current) return;\n if (\n held > 0 &&\n !readStatewireFailedSendLane(aui.thread().getState().extras)?.failed.some(\n (entry) => entry.id === messageId,\n )\n ) {\n return;\n }\n let before: ReturnType<NonNullable<typeof onBeforeRetry>> | undefined;\n try {\n before = onBeforeRetryRef.current?.(messageId);\n } catch {\n // A host's own context step failing never holds the Retry back.\n before = undefined;\n }\n if (isThenable(before) && held < MAX_RETRY_HOLDS) {\n heldRetries.add(messageId);\n const again = (): void => retryFailedSend(messageId, held + 1);\n before.then(again, again);\n return;\n }\n let sent = false;\n try {\n sent = runFailedSendAction({\n action: 'retry',\n messageId,\n run: (actions) => actions.retryFailed(messageId),\n });\n } finally {\n // It did not go after all: the host lets go of what it put back for it.\n try {\n if (!sent && typeof before === 'function') before();\n } catch {\n // The host's own step failing changes nothing here.\n }\n }\n };\n\n const hasOutboxRows =\n outbox !== null && (outboxSnapshot.rows.length > 0 || outboxSnapshot.elsewhere.length > 0);\n const hasLaneRows = rows.length > 0 || failed.length > 0;\n if (!hasLaneRows && !hasOutboxRows) return null;\n\n const renderRowContent = (context: StatewireQueueRowContentContext): ReactNode =>\n renderContent ? renderContent(context) : <QueueRowText text={context.text} />;\n\n return (\n <section\n aria-label=\"Queued messages\"\n className={cn(\n 'aui-statewire-queue w-full rounded-xl border border-border/70 bg-muted/30 px-2 py-1.5',\n classNames?.root,\n )}\n >\n {hasOutboxRows ? (\n <ChatOutboxRows outbox={outbox} snapshot={outboxSnapshot} renderContent={renderRowContent} />\n ) : null}\n {autoContinueOptions ? (\n <QueueAutoContinue\n delayMs={autoContinueOptions.delayMs ?? QUEUE_AUTO_CONTINUE_DELAY_MS}\n queueHeadId={queueHeadId}\n retryableRefusal={retryableRefusal}\n isContinuable={isContinuable}\n status={status}\n threadId={threadId}\n editing={editingId !== null}\n continuedRef={autoContinuedRef}\n onEventRef={onEventRef}\n />\n ) : null}\n {hasLaneRows ? (\n <div className=\"flex items-center gap-1.5\">\n <button\n type=\"button\"\n onClick={() => setExpanded((value) => !value)}\n aria-expanded={expanded}\n aria-controls={listId}\n className=\"flex items-center gap-1 rounded px-1 py-1 font-medium text-muted-foreground text-xs hover:text-foreground\"\n >\n {expanded ? (\n <ChevronDownIcon className=\"size-3.5\" />\n ) : (\n <ChevronRightIcon className=\"size-3.5\" />\n )}\n {rows.length + failed.length} queued\n </button>\n {isContinuable && queueHeadId !== null ? (\n <ContinuePill\n ariaLabel=\"Continue with queued messages\"\n onClick={continueQueue}\n />\n ) : null}\n </div>\n ) : null}\n {expanded && hasLaneRows ? (\n <ul\n id={listId}\n className={cn('max-h-40 overflow-y-auto', classNames?.list)}\n data-testid=\"athena-statewire-queue\"\n >\n {rows.map(({ item, lane }, index) => {\n const text = queueEntryText(item.parts);\n const isUnsettled = isQueueEntryUnsettled(item);\n const isEditing = editingId === item.id;\n const showSteer =\n !isUnsettled && runId !== null && showQueueRowSteer({ lane, isRunning });\n const marker = renderRowMarker?.({ item, lane, index, isUnsettled });\n const editorContext: StatewireQueueEditorContext = {\n value: editingText,\n item,\n onChange: setEditingText,\n onSave: (next, options) => saveEdit(item, lane, next, options?.metadata),\n onCancel: () => {\n setEditingId(null);\n setEditingText('');\n },\n };\n return (\n <li\n key={item.id}\n className=\"group flex items-start gap-2 rounded-md px-1 py-1.5 hover:bg-background\"\n >\n {marker != null ? (\n marker\n ) : isUnsettled ? (\n <Loader2Icon className=\"mt-0.5 size-3.5 shrink-0 animate-spin text-muted-foreground/60\" />\n ) : (\n <CircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-muted-foreground/40\" />\n )}\n {isEditing ? (\n renderEditor ? (\n renderEditor(editorContext)\n ) : (\n <DefaultQueueEditor {...editorContext} />\n )\n ) : (\n renderRowContent({ text, index, item })\n )}\n <div\n className={cn('flex shrink-0 items-center gap-1', isEditing && 'hidden')}\n data-testid=\"statewire-queue-row-actions\"\n >\n {isUnsettled ? (\n <span\n className=\"px-1 text-[10px] text-muted-foreground\"\n data-testid=\"statewire-queued-message-sending\"\n >\n Sending…\n </span>\n ) : null}\n {showSteer ? (\n <button\n type=\"button\"\n aria-label=\"Steer\"\n title=\"Steer the current response: folded into the running turn at its next step, without stopping it.\"\n onClick={() => {\n if (runId === null) return;\n sendCommand({ type: 'run/steer-live', runId, messageId: item.id });\n }}\n className=\"inline-flex items-center gap-1 rounded-full border border-border px-2 py-1 font-medium text-[10px] text-foreground/80 hover:bg-background hover:text-foreground\"\n >\n <ShipWheelIcon className=\"size-2.5\" />\n Steer\n </button>\n ) : null}\n {!isUnsettled ? (\n <button\n type=\"button\"\n aria-label=\"Edit queued message\"\n onClick={() => {\n setEditingId(item.id);\n setEditingText(text);\n }}\n className=\"rounded p-1 text-muted-foreground transition-colors hover:text-primary\"\n >\n <PencilIcon className=\"size-3\" />\n </button>\n ) : null}\n <button\n type=\"button\"\n aria-label=\"Remove queued message\"\n onClick={() => aui.composer.queueItem({ id: item.id }).remove()}\n className={cn(\n 'rounded p-1 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive',\n !showSteer &&\n 'opacity-0 focus-visible:opacity-100 group-hover:opacity-100',\n )}\n >\n <Trash2Icon className=\"size-3\" />\n </button>\n </div>\n </li>\n );\n })}\n {failed.map((item, index) => (\n <li\n key={item.id}\n className=\"group flex items-start gap-2 rounded-md px-1 py-1.5 hover:bg-background\"\n >\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n {renderRowContent({\n text: queueEntryText(item.parts),\n index: rows.length + index,\n item,\n })}\n <div\n className=\"flex shrink-0 items-center gap-1\"\n data-testid=\"statewire-queue-row-actions\"\n >\n <span\n className=\"px-1 text-[10px] text-destructive\"\n title={describeQueueSendFailure(item.sendFailure)}\n >\n Failed to send\n </span>\n <button\n type=\"button\"\n aria-label=\"Retry failed message\"\n onClick={() => retryFailedSend(item.id)}\n className=\"inline-flex items-center gap-1 rounded-full border border-primary/30 px-2 py-1 font-medium text-[10px] text-primary hover:bg-primary/5\"\n >\n <RotateCcwIcon className=\"size-2.5\" />\n Retry\n </button>\n <button\n type=\"button\"\n aria-label=\"Discard failed message\"\n onClick={() =>\n runFailedSendAction({\n action: 'discard',\n messageId: item.id,\n run: (actions) => actions.discardFailed(item.id),\n })\n }\n className=\"rounded p-1 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive\"\n >\n <Trash2Icon className=\"size-3\" />\n </button>\n </div>\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n );\n};\n\n/** Promotes ordinary stranded queue heads once; infrastructure recovery stays server-owned. */\nconst QueueAutoContinue: FC<{\n delayMs: number;\n queueHeadId: string | null;\n retryableRefusal: boolean;\n isContinuable: boolean;\n status: DeepAgentThreadStatus;\n threadId: string | null;\n editing: boolean;\n continuedRef: MutableRefObject<Set<string>>;\n onEventRef: MutableRefObject<((event: StatewireQueueEvent) => void) | undefined>;\n}> = ({\n delayMs,\n queueHeadId,\n retryableRefusal,\n isContinuable,\n status,\n threadId,\n editing,\n continuedRef,\n onEventRef,\n}) => {\n const aui = useAui();\n // The settle that stranded the queue is described by the LAST message's run\n // marker (a marker deeper in history was superseded by a later send). The\n // selectors return primitives so the subscriptions stay shallow-stable.\n const lastMessageMarker = useAuiState((s) => {\n const last = s.thread.messages.at(-1);\n return last ? readRunMarkerFromSourceMessages(last)?.marker : undefined;\n });\n const lastMessageMarkerSource = useAuiState((s) => {\n const last = s.thread.messages.at(-1);\n return last ? readRunMarkerFromSourceMessages(last)?.source : undefined;\n });\n const userStopBlocks = userStopBlocksQueueAutoContinue({\n marker: lastMessageMarker,\n source: lastMessageMarkerSource,\n });\n\n useEffect(() => {\n if (\n !isContinuable ||\n userStopBlocks ||\n retryableRefusal ||\n isServerUpdateStopSource(lastMessageMarkerSource)\n ) return;\n // An open inline edit means the user is mid-revision on some row —\n // dispatching underneath them could send text they are about to change.\n if (editing) return;\n if (queueHeadId === null) return;\n const attemptKey = `${threadId ?? 'unknown'}:${queueHeadId}`;\n if (continuedRef.current.has(attemptKey)) return;\n const timeoutId = setTimeout(() => {\n continuedRef.current.add(attemptKey);\n onEventRef.current?.({ type: 'auto-continued', threadId, status, headEntryId: queueHeadId });\n aui.composer.queueItem({ id: queueHeadId }).move({ lane: 'steer' });\n }, delayMs);\n return () => clearTimeout(timeoutId);\n }, [\n continuedRef,\n aui,\n delayMs,\n editing,\n isContinuable,\n onEventRef,\n queueHeadId,\n retryableRefusal,\n lastMessageMarkerSource,\n status,\n threadId,\n userStopBlocks,\n ]);\n\n return null;\n};\n\n/**\n * The default row body: `[@name](…)` mentions render as chips, not raw\n * markdown links, and the body clamps to two lines. Show more / Show less\n * appears only when the rendered text overflows those two lines, so a short\n * message that wraps in a narrow tray is still caught and a short one gets no\n * dead control.\n */\nconst QueueRowText: FC<{ text: string }> = ({ text }) => {\n const bodyRef = useRef<HTMLParagraphElement>(null);\n const [expanded, setExpanded] = useState(false);\n const [overflows, setOverflows] = useState(false);\n\n useLayoutEffect(() => {\n const body = bodyRef.current;\n // Expanded text has no clamp to overflow; the toggle stays up to collapse it.\n if (!body || expanded) return;\n const measure = (): void => setOverflows(body.scrollHeight > body.clientHeight + 1);\n measure();\n if (typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(measure);\n observer.observe(body);\n return () => observer.disconnect();\n }, [text, expanded]);\n\n if (!text) {\n return <p className=\"min-w-0 flex-1 text-foreground text-xs\">Queued attachment</p>;\n }\n return (\n <div className=\"min-w-0 flex-1\">\n <p\n ref={bodyRef}\n className={cn(\n 'whitespace-pre-wrap break-words text-foreground text-xs leading-relaxed',\n !expanded && 'line-clamp-2',\n )}\n title={overflows && !expanded ? mentionsToPlainText(text) : undefined}\n >\n {parseMentionsInText(text)}\n </p>\n {overflows || expanded ? (\n <button\n type=\"button\"\n aria-expanded={expanded}\n onClick={() => setExpanded((value) => !value)}\n className=\"mt-0.5 font-medium text-[10px] text-muted-foreground hover:text-foreground\"\n >\n {expanded ? 'Show less' : 'Show more'}\n </button>\n ) : null}\n </div>\n );\n};\n\n/** Plain textarea editor: Enter saves, Shift+Enter breaks a line, Escape cancels. */\nconst DefaultQueueEditor: FC<StatewireQueueEditorContext> = ({\n value,\n onChange,\n onSave,\n onCancel,\n}) => {\n const canSave = value.trim().length > 0;\n const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>): void => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n if (canSave) onSave(value);\n } else if (event.key === 'Escape') {\n event.preventDefault();\n onCancel();\n }\n };\n return (\n <div className=\"flex min-w-0 flex-1 items-start gap-1\">\n <textarea\n autoFocus\n aria-label=\"Edit message\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n onKeyDown={handleKeyDown}\n rows={Math.min(6, Math.max(1, value.split('\\n').length))}\n className=\"min-w-0 flex-1 resize-none rounded-md border border-border bg-background px-2 py-1 text-foreground text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring/50\"\n />\n <button\n type=\"button\"\n aria-label=\"Save edit\"\n disabled={!canSave}\n onClick={() => onSave(value)}\n className={cn(\n 'rounded p-1 text-primary transition-colors hover:bg-primary/10',\n !canSave && 'cursor-not-allowed opacity-40',\n )}\n >\n <CheckIcon className=\"size-3.5\" />\n </button>\n <button\n type=\"button\"\n aria-label=\"Cancel edit\"\n onClick={onCancel}\n className=\"rounded p-1 text-muted-foreground transition-colors hover:bg-muted\"\n >\n <XIcon className=\"size-3.5\" />\n </button>\n </div>\n );\n};\n"],"names":["_a"],"mappings":";;;;;;;;;;;;;;;AA2NA,MAAM,kBAAkB;AAExB,SAAS,WAAW,OAA+C;AACjE,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA6B,SAAS;AAElD;AAEO,MAAM,0BAA4D,CAAC,UAAU;AAClF,QAAM,SAAS,YAAY,CAAC,MAAM,EAAE,OAAO,MAAM;AACjD,MAAI,CAAC,yBAAyB,MAAM,EAAG,QAAO;AAC9C,SAAO,oBAAC,8BAAA,EAA8B,GAAG,MAAA,CAAO;AAClD;AAEA,MAAM,+BAAiE,CAAC;AAAA,EACtE;AAAA,EACA,eAAe;AAAA,EACf,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;;AAKJ,QAAM,OAAO,iBAAA;AACb,QAAM,EAAE,OAAO,YAAY,OAAO,UAAU;AAG5C,QAAM,SAAS,KAAK,UAAU,CAAA;AAC9B,QAAM,SAAS,yBAAA;AACf,QAAM,EAAE,WAAW,kBAAkB,eAAe,MAAM;AAC1D,QAAM,MAAM,OAAA;AACZ,QAAM,cAAc,wBAAA;AACpB,QAAM,SAAS,MAAA;AACf,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,IAAI;AAC7C,QAAM,CAAC,WAAW,YAAY,IAAI,SAAwB,IAAI;AAC9D,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,EAAE;AAMjD,QAAM,mBAAmB,OAAoB,oBAAI,KAAK;AACtD,QAAM,aAAa,OAAO,OAAO;AACjC,aAAW,UAAU;AACrB,QAAM,mBAAmB,OAAO,aAAa;AAC7C,mBAAiB,UAAU;AAE3B,QAAM,iBAAiB,OAAoB,oBAAI,KAAK;AAEpD,QAAM,aAAa,OAAO,IAAI;AAC9B,YAAU,MAAM;AACd,eAAW,UAAU;AACrB,WAAO,MAAM;AACX,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF,GAAG,CAAA,CAAE;AAGL,QAAM,SAAS,8BAAA;AACf,QAAM,iBAAiB,sBAAsB,MAAM;AAEnD,QAAM,OAAO,wBAAwB,EAAE,OAAO,YAAY,eAAe;AAIzE,QAAM,gBAAc,WAAM,CAAC,MAAP,mBAAU,OAAM;AACpC,QAAM,kBAAkB,OAAO,EAAE,KAAK,UAAU,OAAO,OAAO,aAAa,eAAe;AAC1F,kBAAgB,MAAM;AACpB,oBAAgB,UAAU,EAAE,KAAK,UAAU,OAAO,OAAO,aAAa,cAAA;AAAA,EACxE,GAAG,CAAC,KAAK,UAAU,OAAO,OAAO,aAAa,aAAa,CAAC;AAE5D,QAAM,gBAAgB,MAAY;AAChC,UAAM,UAAU,gBAAgB;AAGhC,QACE,QAAQ,QAAQ,OAAO,QAAQ,aAAa,YAC5C,QAAQ,UAAU,SAAS,QAAQ,UAAU,SAC7C,CAAC,QAAQ,iBAAiB,QAAQ,gBAAgB,KAClD;AACF,QAAI,SAAS,UAAU,EAAE,IAAI,QAAQ,YAAA,CAAa,EAAE,KAAK,EAAE,MAAM,QAAA,CAAS;AAAA,EAC5E;AACA,QAAM,mBAAmB,wBAAwB,KAAK,KAAK,MAAM;AACjE,QAAM,sBAAsB,iBAAiB,OAAO,CAAA,IAAK,gBAAgB;AAOzE,QAAM,WAAW,CACf,MACA,MACA,MACA,aACS;AACT,iBAAa,IAAI;AACjB,mBAAe,EAAE;AACjB,UAAM,UAAU,sBAAsB,EAAE,MAAM,MAAM,OAAO,MAAM,UAAU;AAC3E,QAAI,YAAY,KAAM,aAAY,OAAO;AAAA,EAC3C;AAQA,QAAM,sBAAsB,CAAC;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,EAAA,MAKa;AACb,QAAI;AACF,UAAI,8BAA8B,IAAI,OAAA,EAAS,SAAA,EAAW,MAAM,CAAC;AACjE,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,EAAE,iBAAiB,UAAU,CAAC,sBAAsB,KAAK,EAAG,OAAM;AACtE,yCAAU;AAAA,QACR,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,MAAM;AAAA,MAAA;AAEf,aAAO;AAAA,IACT;AAAA,EACF;AASA,QAAM,kBAAkB,CAAC,WAAmB,OAAO,MAAY;;AAC7D,UAAM,cAAc,eAAe;AACnC,QAAI,SAAS,KAAK,YAAY,IAAI,SAAS,EAAG;AAC9C,gBAAY,OAAO,SAAS;AAC5B,QAAI,CAAC,WAAW,QAAS;AACzB,QACE,OAAO,KACP,GAACA,MAAA,4BAA4B,IAAI,OAAA,EAAS,SAAA,EAAW,MAAM,MAA1D,gBAAAA,IAA6D,OAAO;AAAA,MACnE,CAAC,UAAU,MAAM,OAAO;AAAA,QAE1B;AACA;AAAA,IACF;AACA,QAAI;AACJ,QAAI;AACF,gBAAS,sBAAiB,YAAjB,0CAA2B;AAAA,IACtC,QAAQ;AAEN,eAAS;AAAA,IACX;AACA,QAAI,WAAW,MAAM,KAAK,OAAO,iBAAiB;AAChD,kBAAY,IAAI,SAAS;AACzB,YAAM,QAAQ,MAAY,gBAAgB,WAAW,OAAO,CAAC;AAC7D,aAAO,KAAK,OAAO,KAAK;AACxB;AAAA,IACF;AACA,QAAI,OAAO;AACX,QAAI;AACF,aAAO,oBAAoB;AAAA,QACzB,QAAQ;AAAA,QACR;AAAA,QACA,KAAK,CAAC,YAAY,QAAQ,YAAY,SAAS;AAAA,MAAA,CAChD;AAAA,IACH,UAAA;AAEE,UAAI;AACF,YAAI,CAAC,QAAQ,OAAO,WAAW,WAAY,QAAA;AAAA,MAC7C,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,QAAM,gBACJ,WAAW,SAAS,eAAe,KAAK,SAAS,KAAK,eAAe,UAAU,SAAS;AAC1F,QAAM,cAAc,KAAK,SAAS,KAAK,OAAO,SAAS;AACvD,MAAI,CAAC,eAAe,CAAC,cAAe,QAAO;AAE3C,QAAM,mBAAmB,CAAC,YACxB,gBAAgB,cAAc,OAAO,IAAI,oBAAC,cAAA,EAAa,MAAM,QAAQ,KAAA,CAAM;AAE7E,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,cAAW;AAAA,MACX,WAAW;AAAA,QACT;AAAA,QACA,yCAAY;AAAA,MAAA;AAAA,MAGb,UAAA;AAAA,QAAA,oCACE,gBAAA,EAAe,QAAgB,UAAU,gBAAgB,eAAe,kBAAkB,IACzF;AAAA,QACH,sBACC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,SAAS,oBAAoB,WAAW;AAAA,YACxC;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,SAAS,cAAc;AAAA,YACvB,cAAc;AAAA,YACd;AAAA,UAAA;AAAA,QAAA,IAEA;AAAA,QACH,cACC,qBAAC,OAAA,EAAI,WAAU,6BACb,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,YAAY,CAAC,UAAU,CAAC,KAAK;AAAA,cAC5C,iBAAe;AAAA,cACf,iBAAe;AAAA,cACf,WAAU;AAAA,cAET,UAAA;AAAA,gBAAA,WACC,oBAAC,mBAAgB,WAAU,WAAA,CAAW,IAEtC,oBAAC,kBAAA,EAAiB,WAAU,WAAA,CAAW;AAAA,gBAExC,KAAK,SAAS,OAAO;AAAA,gBAAO;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAE9B,iBAAiB,gBAAgB,OAChC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS;AAAA,YAAA;AAAA,UAAA,IAET;AAAA,QAAA,EAAA,CACN,IACE;AAAA,QACH,YAAY,cACX;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,IAAI;AAAA,YACJ,WAAW,GAAG,4BAA4B,yCAAY,IAAI;AAAA,YAC1D,eAAY;AAAA,YAEX,UAAA;AAAA,cAAA,KAAK,IAAI,CAAC,EAAE,MAAM,KAAA,GAAQ,UAAU;AACnC,sBAAM,OAAO,eAAe,KAAK,KAAK;AACtC,sBAAM,cAAc,sBAAsB,IAAI;AAC9C,sBAAM,YAAY,cAAc,KAAK;AACrC,sBAAM,YACJ,CAAC,eAAe,UAAU,QAAQ,kBAAkB,EAAE,MAAM,WAAW;AACzE,sBAAM,SAAS,mDAAkB,EAAE,MAAM,MAAM,OAAO;AACtD,sBAAM,gBAA6C;AAAA,kBACjD,OAAO;AAAA,kBACP;AAAA,kBACA,UAAU;AAAA,kBACV,QAAQ,CAAC,MAAM,YAAY,SAAS,MAAM,MAAM,MAAM,mCAAS,QAAQ;AAAA,kBACvE,UAAU,MAAM;AACd,iCAAa,IAAI;AACjB,mCAAe,EAAE;AAAA,kBACnB;AAAA,gBAAA;AAEF,uBACE;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBAEC,WAAU;AAAA,oBAET,UAAA;AAAA,sBAAA,UAAU,OACT,SACE,cACF,oBAAC,aAAA,EAAY,WAAU,iEAAA,CAAiE,IAExF,oBAAC,YAAA,EAAW,WAAU,oDAAA,CAAoD;AAAA,sBAE3E,YACC,eACE,aAAa,aAAa,IAE1B,oBAAC,oBAAA,EAAoB,GAAG,cAAA,CAAe,IAGzC,iBAAiB,EAAE,MAAM,OAAO,MAAM;AAAA,sBAExC;AAAA,wBAAC;AAAA,wBAAA;AAAA,0BACC,WAAW,GAAG,oCAAoC,aAAa,QAAQ;AAAA,0BACvE,eAAY;AAAA,0BAEX,UAAA;AAAA,4BAAA,cACC;AAAA,8BAAC;AAAA,8BAAA;AAAA,gCACC,WAAU;AAAA,gCACV,eAAY;AAAA,gCACb,UAAA;AAAA,8BAAA;AAAA,4BAAA,IAGC;AAAA,4BACH,YACC;AAAA,8BAAC;AAAA,8BAAA;AAAA,gCACC,MAAK;AAAA,gCACL,cAAW;AAAA,gCACX,OAAM;AAAA,gCACN,SAAS,MAAM;AACb,sCAAI,UAAU,KAAM;AACpB,8CAAY,EAAE,MAAM,kBAAkB,OAAO,WAAW,KAAK,IAAI;AAAA,gCACnE;AAAA,gCACA,WAAU;AAAA,gCAEV,UAAA;AAAA,kCAAA,oBAAC,eAAA,EAAc,WAAU,WAAA,CAAW;AAAA,kCAAE;AAAA,gCAAA;AAAA,8BAAA;AAAA,4BAAA,IAGtC;AAAA,4BACH,CAAC,cACA;AAAA,8BAAC;AAAA,8BAAA;AAAA,gCACC,MAAK;AAAA,gCACL,cAAW;AAAA,gCACX,SAAS,MAAM;AACb,+CAAa,KAAK,EAAE;AACpB,iDAAe,IAAI;AAAA,gCACrB;AAAA,gCACA,WAAU;AAAA,gCAEV,UAAA,oBAAC,YAAA,EAAW,WAAU,SAAA,CAAS;AAAA,8BAAA;AAAA,4BAAA,IAE/B;AAAA,4BACJ;AAAA,8BAAC;AAAA,8BAAA;AAAA,gCACC,MAAK;AAAA,gCACL,cAAW;AAAA,gCACX,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE,IAAI,KAAK,IAAI,EAAE,OAAA;AAAA,gCACvD,WAAW;AAAA,kCACT;AAAA,kCACA,CAAC,aACC;AAAA,gCAAA;AAAA,gCAGJ,UAAA,oBAAC,YAAA,EAAW,WAAU,SAAA,CAAS;AAAA,8BAAA;AAAA,4BAAA;AAAA,0BACjC;AAAA,wBAAA;AAAA,sBAAA;AAAA,oBACF;AAAA,kBAAA;AAAA,kBAvEK,KAAK;AAAA,gBAAA;AAAA,cA0EhB,CAAC;AAAA,cACA,OAAO,IAAI,CAAC,MAAM,UACjB;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBAEC,WAAU;AAAA,kBAEV,UAAA;AAAA,oBAAA,oBAAC,iBAAA,EAAgB,WAAU,4CAAA,CAA4C;AAAA,oBACtE,iBAAiB;AAAA,sBAChB,MAAM,eAAe,KAAK,KAAK;AAAA,sBAC/B,OAAO,KAAK,SAAS;AAAA,sBACrB;AAAA,oBAAA,CACD;AAAA,oBACD;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBACC,WAAU;AAAA,wBACV,eAAY;AAAA,wBAEZ,UAAA;AAAA,0BAAA;AAAA,4BAAC;AAAA,4BAAA;AAAA,8BACC,WAAU;AAAA,8BACV,OAAO,yBAAyB,KAAK,WAAW;AAAA,8BACjD,UAAA;AAAA,4BAAA;AAAA,0BAAA;AAAA,0BAGD;AAAA,4BAAC;AAAA,4BAAA;AAAA,8BACC,MAAK;AAAA,8BACL,cAAW;AAAA,8BACX,SAAS,MAAM,gBAAgB,KAAK,EAAE;AAAA,8BACtC,WAAU;AAAA,8BAEV,UAAA;AAAA,gCAAA,oBAAC,eAAA,EAAc,WAAU,WAAA,CAAW;AAAA,gCAAE;AAAA,8BAAA;AAAA,4BAAA;AAAA,0BAAA;AAAA,0BAGxC;AAAA,4BAAC;AAAA,4BAAA;AAAA,8BACC,MAAK;AAAA,8BACL,cAAW;AAAA,8BACX,SAAS,MACP,oBAAoB;AAAA,gCAClB,QAAQ;AAAA,gCACR,WAAW,KAAK;AAAA,gCAChB,KAAK,CAAC,YAAY,QAAQ,cAAc,KAAK,EAAE;AAAA,8BAAA,CAChD;AAAA,8BAEH,WAAU;AAAA,8BAEV,UAAA,oBAAC,YAAA,EAAW,WAAU,SAAA,CAAS;AAAA,4BAAA;AAAA,0BAAA;AAAA,wBACjC;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBACF;AAAA,gBAAA;AAAA,gBA1CK,KAAK;AAAA,cAAA,CA4Cb;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA,IAED;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGV;AAGA,MAAM,oBAUD,CAAC;AAAA,EACJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,MAAM,OAAA;AAIZ,QAAM,oBAAoB,YAAY,CAAC,MAAM;;AAC3C,UAAM,OAAO,EAAE,OAAO,SAAS,GAAG,EAAE;AACpC,WAAO,QAAO,qCAAgC,IAAI,MAApC,mBAAuC,SAAS;AAAA,EAChE,CAAC;AACD,QAAM,0BAA0B,YAAY,CAAC,MAAM;;AACjD,UAAM,OAAO,EAAE,OAAO,SAAS,GAAG,EAAE;AACpC,WAAO,QAAO,qCAAgC,IAAI,MAApC,mBAAuC,SAAS;AAAA,EAChE,CAAC;AACD,QAAM,iBAAiB,gCAAgC;AAAA,IACrD,QAAQ;AAAA,IACR,QAAQ;AAAA,EAAA,CACT;AAED,YAAU,MAAM;AACd,QACE,CAAC,iBACD,kBACA,oBACA,yBAAyB,uBAAuB,EAChD;AAGF,QAAI,QAAS;AACb,QAAI,gBAAgB,KAAM;AAC1B,UAAM,aAAa,GAAG,YAAY,SAAS,IAAI,WAAW;AAC1D,QAAI,aAAa,QAAQ,IAAI,UAAU,EAAG;AAC1C,UAAM,YAAY,WAAW,MAAM;;AACjC,mBAAa,QAAQ,IAAI,UAAU;AACnC,uBAAW,YAAX,oCAAqB,EAAE,MAAM,kBAAkB,UAAU,QAAQ,aAAa;AAC9E,UAAI,SAAS,UAAU,EAAE,IAAI,aAAa,EAAE,KAAK,EAAE,MAAM,SAAS;AAAA,IACpE,GAAG,OAAO;AACV,WAAO,MAAM,aAAa,SAAS;AAAA,EACrC,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AAED,SAAO;AACT;AASA,MAAM,eAAqC,CAAC,EAAE,WAAW;AACvD,QAAM,UAAU,OAA6B,IAAI;AACjD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAEhD,kBAAgB,MAAM;AACpB,UAAM,OAAO,QAAQ;AAErB,QAAI,CAAC,QAAQ,SAAU;AACvB,UAAM,UAAU,MAAY,aAAa,KAAK,eAAe,KAAK,eAAe,CAAC;AAClF,YAAA;AACA,QAAI,OAAO,mBAAmB,YAAa;AAC3C,UAAM,WAAW,IAAI,eAAe,OAAO;AAC3C,aAAS,QAAQ,IAAI;AACrB,WAAO,MAAM,SAAS,WAAA;AAAA,EACxB,GAAG,CAAC,MAAM,QAAQ,CAAC;AAEnB,MAAI,CAAC,MAAM;AACT,WAAO,oBAAC,KAAA,EAAE,WAAU,0CAAyC,UAAA,qBAAiB;AAAA,EAChF;AACA,SACE,qBAAC,OAAA,EAAI,WAAU,kBACb,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK;AAAA,QACL,WAAW;AAAA,UACT;AAAA,UACA,CAAC,YAAY;AAAA,QAAA;AAAA,QAEf,OAAO,aAAa,CAAC,WAAW,oBAAoB,IAAI,IAAI;AAAA,QAE3D,8BAAoB,IAAI;AAAA,MAAA;AAAA,IAAA;AAAA,IAE1B,aAAa,WACZ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,iBAAe;AAAA,QACf,SAAS,MAAM,YAAY,CAAC,UAAU,CAAC,KAAK;AAAA,QAC5C,WAAU;AAAA,QAET,qBAAW,cAAc;AAAA,MAAA;AAAA,IAAA,IAE1B;AAAA,EAAA,GACN;AAEJ;AAGA,MAAM,qBAAsD,CAAC;AAAA,EAC3D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,UAAU,MAAM,KAAA,EAAO,SAAS;AACtC,QAAM,gBAAgB,CAAC,UAAoD;AACzE,QAAI,MAAM,QAAQ,WAAW,CAAC,MAAM,UAAU;AAC5C,YAAM,eAAA;AACN,UAAI,gBAAgB,KAAK;AAAA,IAC3B,WAAW,MAAM,QAAQ,UAAU;AACjC,YAAM,eAAA;AACN,eAAA;AAAA,IACF;AAAA,EACF;AACA,SACE,qBAAC,OAAA,EAAI,WAAU,yCACb,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAS;AAAA,QACT,cAAW;AAAA,QACX;AAAA,QACA,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,QAChD,WAAW;AAAA,QACX,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,MAAM,IAAI,EAAE,MAAM,CAAC;AAAA,QACvD,WAAU;AAAA,MAAA;AAAA,IAAA;AAAA,IAEZ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,UAAU,CAAC;AAAA,QACX,SAAS,MAAM,OAAO,KAAK;AAAA,QAC3B,WAAW;AAAA,UACT;AAAA,UACA,CAAC,WAAW;AAAA,QAAA;AAAA,QAGd,UAAA,oBAAC,WAAA,EAAU,WAAU,WAAA,CAAW;AAAA,MAAA;AAAA,IAAA;AAAA,IAElC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,SAAS;AAAA,QACT,WAAU;AAAA,QAEV,UAAA,oBAAC,OAAA,EAAM,WAAU,WAAA,CAAW;AAAA,MAAA;AAAA,IAAA;AAAA,EAC9B,GACF;AAEJ;"}
|
|
@@ -21,12 +21,16 @@ const WaitingOnYouBanner = (props) => {
|
|
|
21
21
|
};
|
|
22
22
|
const WaitingOnYouBannerWithApproval = ({ attention, fallbackMessage, ...props }) => {
|
|
23
23
|
var _a, _b, _c;
|
|
24
|
-
const { request, hitl, liveHitl } = useStatewireApprovalRequest.useStatewireApprovalRequest();
|
|
24
|
+
const { request, hitl, actionRequests, liveHitl, liveActionRequests } = useStatewireApprovalRequest.useStatewireApprovalRequest();
|
|
25
25
|
const pending = request !== void 0 || liveHitl !== null;
|
|
26
26
|
const payload = hitl ?? liveHitl;
|
|
27
27
|
const toolName = ((_a = payload == null ? void 0 : payload.context) == null ? void 0 : _a.tool_name) ?? ((_b = payload == null ? void 0 : payload.context) == null ? void 0 : _b.tool_id);
|
|
28
28
|
const pendingCount = ((_c = payload == null ? void 0 : payload.context) == null ? void 0 : _c.pending_action_count) ?? 1;
|
|
29
|
-
const
|
|
29
|
+
const title = interrupts.pendingApprovalTitle({
|
|
30
|
+
hitl: payload,
|
|
31
|
+
actionRequests: hitl ? actionRequests : liveActionRequests
|
|
32
|
+
});
|
|
33
|
+
const approvalSummary = !pending ? null : title ? title.headline : payload && pendingCount === 1 && toolName ? `${toolName} requires approval before it runs.` : interrupts.readInterruptMessage(request ? request.payload : liveHitl, fallbackMessage);
|
|
30
34
|
return /* @__PURE__ */ jsxRuntime.jsx(WaitingOnYouBannerView, { attention, approvalSummary, ...props });
|
|
31
35
|
};
|
|
32
36
|
const WaitingOnYouBannerView = ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WaitingOnYouBanner.cjs","sources":["../../src/chat/WaitingOnYouBanner.tsx"],"sourcesContent":["import { useAuiState } from '@assistant-ui/react';\nimport {
|
|
1
|
+
{"version":3,"file":"WaitingOnYouBanner.cjs","sources":["../../src/chat/WaitingOnYouBanner.tsx"],"sourcesContent":["import { useAuiState } from '@assistant-ui/react';\nimport {\n hasStatewireThreadExtras,\n pendingApprovalTitle,\n readInterruptMessage,\n} from '@athenaintel/agent-runtime';\nimport { HandIcon } from 'lucide-react';\nimport { type FC, useCallback, useRef } from 'react';\nimport { THREAD_VIEWPORT_ATTR } from '../chat-ui/thread/statewire-history-edge';\nimport { cn } from '../lib/utils';\nimport {\n type AthenaSessionAttention,\n useAthenaSessionAttention,\n} from '../threads/use-athena-session-attention';\nimport { useStatewireApprovalRequest } from './use-statewire-approval-request';\n\n/** The CSS class `StatewireApprovalCard` puts on its section; the banner scrolls to it. */\nconst APPROVAL_CARD_SELECTOR = '.aui-approval-card';\n\nexport interface WaitingOnYouBannerProps {\n /** Applied to the outer wrapper (host padding); the banner itself is width-capped inside it. */\n className?: string;\n /** Copy shown when a parked interrupt carries no message. */\n fallbackMessage?: string;\n}\n\n/**\n * Persistent top-of-thread banner for a session that is waiting on the\n * viewer: shown while the active thread's attention is `needs_you` (from the\n * thread list) or while the approval hook reports a pending request. The text\n * is the server's next action, else a summary of the pending request; a\n * click scrolls to the approval card (or to the composer when there is no\n * card). It never duplicates the card's decision buttons — the card stays the\n * one place a request is answered. Renders nothing otherwise.\n */\nexport const WaitingOnYouBanner: FC<WaitingOnYouBannerProps> = (props) => {\n const extras = useAuiState((s) => s.thread.extras);\n const attention = useAthenaSessionAttention();\n // `useStatewireApprovalRequest` needs a statewire aui scope (it throws\n // outside one), so the approval leg mounts only once the thread extras are.\n if (!hasStatewireThreadExtras(extras)) {\n return <WaitingOnYouBannerView attention={attention} approvalSummary={null} {...props} />;\n }\n return <WaitingOnYouBannerWithApproval attention={attention} {...props} />;\n};\n\nconst WaitingOnYouBannerWithApproval: FC<\n WaitingOnYouBannerProps & { attention: AthenaSessionAttention | null }\n> = ({ attention, fallbackMessage, ...props }) => {\n const { request, hitl, actionRequests, liveHitl, liveActionRequests } =\n useStatewireApprovalRequest();\n const pending = request !== undefined || liveHitl !== null;\n const payload = hitl ?? liveHitl;\n const toolName = payload?.context?.tool_name ?? payload?.context?.tool_id;\n const pendingCount = payload?.context?.pending_action_count ?? 1;\n // The card's own title, when its lone call's envelope gives it one.\n const title = pendingApprovalTitle({\n hitl: payload,\n actionRequests: hitl ? actionRequests : liveActionRequests,\n });\n const approvalSummary = !pending\n ? null\n : title\n ? title.headline\n : payload && pendingCount === 1 && toolName\n ? `${toolName} requires approval before it runs.`\n : readInterruptMessage(request ? request.payload : liveHitl, fallbackMessage);\n return <WaitingOnYouBannerView attention={attention} approvalSummary={approvalSummary} {...props} />;\n};\n\nexport interface WaitingOnYouBannerViewProps {\n attention: Pick<AthenaSessionAttention, 'attention' | 'nextAction'> | null;\n /** Summary of the pending approval, or `null` when nothing is parked. */\n approvalSummary: string | null;\n className?: string;\n}\n\n/**\n * The banner itself, over already-resolved inputs — the pure presenter\n * `WaitingOnYouBanner` binds to the thread list and the approval hook.\n */\nexport const WaitingOnYouBannerView: FC<WaitingOnYouBannerViewProps> = ({\n attention,\n approvalSummary,\n className,\n}) => {\n const rootRef = useRef<HTMLDivElement>(null);\n const scrollToApproval = useCallback(() => {\n const root = rootRef.current;\n if (!root) return;\n // The nearest ancestor that holds the thread viewport is the chat panel;\n // the card lives in that viewport's sticky footer.\n let scope: HTMLElement | null = root.parentElement;\n while (scope && scope.querySelector(`[${THREAD_VIEWPORT_ATTR}]`) === null) {\n scope = scope.parentElement;\n }\n const container: ParentNode = scope ?? root.ownerDocument;\n const card = container.querySelector<HTMLElement>(APPROVAL_CARD_SELECTOR);\n if (card) {\n card.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n return;\n }\n const viewport = container.querySelector<HTMLElement>(`[${THREAD_VIEWPORT_ATTR}]`);\n viewport?.scrollTo({ top: viewport.scrollHeight, behavior: 'smooth' });\n }, []);\n\n const needsYou = attention?.attention === 'needs_you';\n const pending = approvalSummary !== null;\n if (!needsYou && !pending) return null;\n const text =\n attention?.nextAction?.trim() || approvalSummary || 'This session is waiting on you.';\n\n return (\n <div ref={rootRef} className={cn('aui-waiting-on-you', className)}>\n <div\n role=\"status\"\n data-testid=\"waiting-on-you-banner\"\n data-pending-approval={pending || undefined}\n className=\"mx-auto w-full max-w-(--thread-max-width) rounded-xl border border-amber-300 bg-amber-50 text-amber-900\"\n >\n <button\n type=\"button\"\n onClick={scrollToApproval}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left text-xs transition-colors hover:bg-amber-100/70\"\n >\n <HandIcon className=\"size-4 shrink-0\" aria-hidden=\"true\" />\n <span className=\"shrink-0 font-semibold\">Waiting on you</span>\n <span className=\"min-w-0 flex-1 truncate text-amber-800\">{text}</span>\n {pending ? (\n <span className=\"shrink-0 font-medium underline-offset-2 hover:underline\">\n Review\n </span>\n ) : null}\n </button>\n </div>\n </div>\n );\n};\n"],"names":["useAuiState","useAthenaSessionAttention","hasStatewireThreadExtras","jsx","useStatewireApprovalRequest","pendingApprovalTitle","readInterruptMessage","useRef","useCallback","THREAD_VIEWPORT_ATTR","cn","jsxs","HandIcon"],"mappings":";;;;;;;;;;;;AAiBA,MAAM,yBAAyB;AAkBxB,MAAM,qBAAkD,CAAC,UAAU;AACxE,QAAM,SAASA,MAAAA,YAAY,CAAC,MAAM,EAAE,OAAO,MAAM;AACjD,QAAM,YAAYC,0BAAAA,0BAAA;AAGlB,MAAI,CAACC,aAAAA,yBAAyB,MAAM,GAAG;AACrC,0CAAQ,wBAAA,EAAuB,WAAsB,iBAAiB,MAAO,GAAG,OAAO;AAAA,EACzF;AACA,SAAOC,2BAAAA,IAAC,gCAAA,EAA+B,WAAuB,GAAG,MAAA,CAAO;AAC1E;AAEA,MAAM,iCAEF,CAAC,EAAE,WAAW,iBAAiB,GAAG,YAAY;;AAChD,QAAM,EAAE,SAAS,MAAM,gBAAgB,UAAU,mBAAA,IAC/CC,wDAAA;AACF,QAAM,UAAU,YAAY,UAAa,aAAa;AACtD,QAAM,UAAU,QAAQ;AACxB,QAAM,aAAW,wCAAS,YAAT,mBAAkB,gBAAa,wCAAS,YAAT,mBAAkB;AAClE,QAAM,iBAAe,wCAAS,YAAT,mBAAkB,yBAAwB;AAE/D,QAAM,QAAQC,WAAAA,qBAAqB;AAAA,IACjC,MAAM;AAAA,IACN,gBAAgB,OAAO,iBAAiB;AAAA,EAAA,CACzC;AACD,QAAM,kBAAkB,CAAC,UACrB,OACA,QACE,MAAM,WACN,WAAW,iBAAiB,KAAK,WAC/B,GAAG,QAAQ,uCACXC,WAAAA,qBAAqB,UAAU,QAAQ,UAAU,UAAU,eAAe;AAClF,SAAOH,2BAAAA,IAAC,wBAAA,EAAuB,WAAsB,iBAAmC,GAAG,OAAO;AACpG;AAaO,MAAM,yBAA0D,CAAC;AAAA,EACtE;AAAA,EACA;AAAA,EACA;AACF,MAAM;;AACJ,QAAM,UAAUI,WAAAA,OAAuB,IAAI;AAC3C,QAAM,mBAAmBC,WAAAA,YAAY,MAAM;AACzC,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AAGX,QAAI,QAA4B,KAAK;AACrC,WAAO,SAAS,MAAM,cAAc,IAAIC,yCAAoB,GAAG,MAAM,MAAM;AACzE,cAAQ,MAAM;AAAA,IAChB;AACA,UAAM,YAAwB,SAAS,KAAK;AAC5C,UAAM,OAAO,UAAU,cAA2B,sBAAsB;AACxE,QAAI,MAAM;AACR,WAAK,eAAe,EAAE,UAAU,UAAU,OAAO,WAAW;AAC5D;AAAA,IACF;AACA,UAAM,WAAW,UAAU,cAA2B,IAAIA,qBAAAA,oBAAoB,GAAG;AACjF,yCAAU,SAAS,EAAE,KAAK,SAAS,cAAc,UAAU;EAC7D,GAAG,CAAA,CAAE;AAEL,QAAM,YAAW,uCAAW,eAAc;AAC1C,QAAM,UAAU,oBAAoB;AACpC,MAAI,CAAC,YAAY,CAAC,QAAS,QAAO;AAClC,QAAM,SACJ,4CAAW,eAAX,mBAAuB,WAAU,mBAAmB;AAEtD,SACEN,+BAAC,SAAI,KAAK,SAAS,WAAWO,OAAAA,GAAG,sBAAsB,SAAS,GAC9D,UAAAP,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,eAAY;AAAA,MACZ,yBAAuB,WAAW;AAAA,MAClC,WAAU;AAAA,MAEV,UAAAQ,2BAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,WAAU;AAAA,UAEV,UAAA;AAAA,YAAAR,2BAAAA,IAACS,YAAAA,UAAA,EAAS,WAAU,mBAAkB,eAAY,QAAO;AAAA,YACzDT,2BAAAA,IAAC,QAAA,EAAK,WAAU,0BAAyB,UAAA,kBAAc;AAAA,YACvDA,2BAAAA,IAAC,QAAA,EAAK,WAAU,0CAA0C,UAAA,MAAK;AAAA,YAC9D,UACCA,2BAAAA,IAAC,QAAA,EAAK,WAAU,2DAA0D,oBAE1E,IACE;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IACN;AAAA,EAAA,GAEJ;AAEJ;;;"}
|