@athenaintel/react 0.42.2 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +225 -3
- package/dist/agent-runtime/src/answer-label.cjs +137 -0
- package/dist/agent-runtime/src/answer-label.cjs.map +1 -0
- package/dist/agent-runtime/src/answer-label.d.ts +104 -0
- package/dist/agent-runtime/src/answer-label.js +137 -0
- package/dist/agent-runtime/src/answer-label.js.map +1 -0
- package/dist/agent-runtime/src/answer-rows.cjs +180 -0
- package/dist/agent-runtime/src/answer-rows.cjs.map +1 -0
- package/dist/agent-runtime/src/answer-rows.d.ts +86 -0
- package/dist/agent-runtime/src/answer-rows.js +180 -0
- package/dist/agent-runtime/src/answer-rows.js.map +1 -0
- package/dist/agent-runtime/src/client-tool-bridge.cjs +15 -15
- package/dist/agent-runtime/src/client-tool-bridge.cjs.map +1 -1
- package/dist/agent-runtime/src/conversation-index.cjs +8 -8
- package/dist/agent-runtime/src/conversation-index.cjs.map +1 -1
- package/dist/agent-runtime/src/conversation-list-groups.d.ts +74 -0
- package/dist/agent-runtime/src/decision-checks.cjs +207 -0
- package/dist/agent-runtime/src/decision-checks.cjs.map +1 -0
- package/dist/agent-runtime/src/decision-checks.d.ts +142 -0
- package/dist/agent-runtime/src/decision-checks.js +207 -0
- package/dist/agent-runtime/src/decision-checks.js.map +1 -0
- package/dist/agent-runtime/src/desktop-handoff.d.ts +12 -0
- package/dist/agent-runtime/src/errors.cjs +18 -0
- package/dist/agent-runtime/src/errors.cjs.map +1 -1
- package/dist/agent-runtime/src/errors.d.ts +7 -0
- package/dist/agent-runtime/src/errors.js +18 -0
- package/dist/agent-runtime/src/errors.js.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs +12 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +6 -6
- package/dist/agent-runtime/src/generated/runconfig-contract.js +12 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/agent-runtime/src/handoff-arrival.cjs +60 -0
- package/dist/agent-runtime/src/handoff-arrival.cjs.map +1 -0
- package/dist/agent-runtime/src/handoff-arrival.d.ts +46 -0
- package/dist/agent-runtime/src/handoff-arrival.js +60 -0
- package/dist/agent-runtime/src/handoff-arrival.js.map +1 -0
- package/dist/agent-runtime/src/index.d.ts +15 -8
- package/dist/agent-runtime/src/interrupts.cjs +43 -18
- package/dist/agent-runtime/src/interrupts.cjs.map +1 -1
- package/dist/agent-runtime/src/interrupts.d.ts +19 -2
- package/dist/agent-runtime/src/interrupts.js +28 -3
- package/dist/agent-runtime/src/interrupts.js.map +1 -1
- package/dist/agent-runtime/src/lane-history.cjs +8 -8
- package/dist/agent-runtime/src/lane-history.cjs.map +1 -1
- package/dist/agent-runtime/src/messages.cjs +43 -8
- package/dist/agent-runtime/src/messages.cjs.map +1 -1
- package/dist/agent-runtime/src/messages.d.ts +25 -3
- package/dist/agent-runtime/src/messages.js +43 -8
- package/dist/agent-runtime/src/messages.js.map +1 -1
- package/dist/agent-runtime/src/offline-status.cjs +36 -0
- package/dist/agent-runtime/src/offline-status.cjs.map +1 -0
- package/dist/agent-runtime/src/offline-status.d.ts +118 -3
- package/dist/agent-runtime/src/offline-status.js +36 -0
- package/dist/agent-runtime/src/offline-status.js.map +1 -0
- package/dist/agent-runtime/src/queue.cjs +0 -9
- package/dist/agent-runtime/src/queue.cjs.map +1 -1
- package/dist/agent-runtime/src/queue.js +0 -9
- package/dist/agent-runtime/src/queue.js.map +1 -1
- package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +9 -9
- package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
- package/dist/agent-runtime/src/runtime-catalog.cjs +42 -0
- package/dist/agent-runtime/src/runtime-catalog.cjs.map +1 -0
- package/dist/agent-runtime/src/runtime-catalog.d.ts +35 -0
- package/dist/agent-runtime/src/runtime-catalog.js +42 -0
- package/dist/agent-runtime/src/runtime-catalog.js.map +1 -0
- package/dist/agent-runtime/src/runtime-messages.cjs.map +1 -1
- package/dist/agent-runtime/src/runtime-messages.d.ts +1 -1
- package/dist/agent-runtime/src/runtime-messages.js.map +1 -1
- package/dist/agent-runtime/src/runtime.d.ts +40 -0
- package/dist/agent-runtime/src/statewire-suspended.cjs +3 -3
- package/dist/agent-runtime/src/statewire-suspended.cjs.map +1 -1
- package/dist/agent-runtime/src/subagents.cjs +32 -2
- package/dist/agent-runtime/src/subagents.cjs.map +1 -1
- package/dist/agent-runtime/src/subagents.d.ts +9 -0
- package/dist/agent-runtime/src/subagents.js +30 -0
- package/dist/agent-runtime/src/subagents.js.map +1 -1
- package/dist/agent-runtime/src/thread-driver.cjs +67 -0
- package/dist/agent-runtime/src/thread-driver.cjs.map +1 -0
- package/dist/agent-runtime/src/thread-driver.d.ts +49 -0
- package/dist/agent-runtime/src/thread-driver.js +67 -0
- package/dist/agent-runtime/src/thread-driver.js.map +1 -0
- package/dist/agent-runtime/src/thread-handoff-flow-machine.d.ts +172 -0
- package/dist/agent-runtime/src/thread-handoff-protocol.d.ts +756 -0
- package/dist/agent-runtime/src/thread-handoff-qr.d.ts +11 -0
- package/dist/agent-runtime/src/thread-handoff.d.ts +3 -364
- package/dist/agent-runtime/src/thread-status.cjs +3 -3
- package/dist/agent-runtime/src/thread-status.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.cjs +210 -33
- package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.d.ts +12 -0
- package/dist/agent-runtime/src/tool-metadata.js +210 -33
- package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
- package/dist/agent-runtime/src/tool-names.cjs +2 -0
- package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-names.d.ts +2 -0
- package/dist/agent-runtime/src/tool-names.js +2 -0
- package/dist/agent-runtime/src/tool-names.js.map +1 -1
- package/dist/agent-runtime/src/types.d.ts +10 -2
- package/dist/agent-runtime/src/use-conversation-list.cjs +11 -11
- package/dist/agent-runtime/src/use-conversation-list.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs +24 -19
- 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 +2 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js +6 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-config.cjs +14 -14
- package/dist/agent-runtime/src/use-deep-agent-config.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs +6 -6
- package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +16 -16
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs +45 -45
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs +572 -134
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +137 -10
- package/dist/agent-runtime/src/use-deep-agent-voice.js +514 -76
- package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs +26 -26
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs.map +1 -1
- package/dist/agent-runtime/src/use-historical-edit-attachments.cjs +4 -4
- package/dist/agent-runtime/src/use-historical-edit-attachments.cjs.map +1 -1
- package/dist/agent-runtime/src/use-thread-handoff-flow.d.ts +28 -26
- package/dist/agent-runtime/src/voice-media.cjs +117 -0
- package/dist/agent-runtime/src/voice-media.cjs.map +1 -0
- package/dist/agent-runtime/src/voice-media.d.ts +49 -0
- package/dist/agent-runtime/src/voice-media.js +117 -0
- package/dist/agent-runtime/src/voice-media.js.map +1 -0
- package/dist/agent-runtime/src/voice-wire-types.d.ts +32 -0
- package/dist/assets/AssetPanel.cjs +11 -11
- package/dist/assets/AssetPanel.cjs.map +1 -1
- package/dist/assets/AthenaAssetEmbed.cjs +11 -9
- package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
- package/dist/assets/AthenaAssetEmbed.d.ts +7 -0
- package/dist/assets/AthenaAssetEmbed.js +4 -2
- package/dist/assets/AthenaAssetEmbed.js.map +1 -1
- package/dist/assets/AthenaLayout.cjs +16 -16
- package/dist/assets/AthenaLayout.cjs.map +1 -1
- package/dist/assets/use-asset-content.cjs +4 -4
- package/dist/assets/use-asset-content.cjs.map +1 -1
- package/dist/assets/use-asset-embed.cjs +14 -7
- package/dist/assets/use-asset-embed.cjs.map +1 -1
- package/dist/assets/use-asset-embed.d.ts +11 -1
- package/dist/assets/use-asset-embed.js +10 -3
- package/dist/assets/use-asset-embed.js.map +1 -1
- package/dist/auth/AthenaAuthContext.cjs +3 -3
- package/dist/auth/AthenaAuthContext.cjs.map +1 -1
- package/dist/auth/AthenaAuthProvider.cjs +8 -8
- package/dist/auth/AthenaAuthProvider.cjs.map +1 -1
- package/dist/auth/AthenaCredentialSourceContext.cjs +5 -5
- package/dist/auth/AthenaCredentialSourceContext.cjs.map +1 -1
- package/dist/auth/AthenaSSOProvider.cjs +14 -14
- package/dist/auth/AthenaSSOProvider.cjs.map +1 -1
- package/dist/auth/credential-source.cjs +26 -13
- package/dist/auth/credential-source.cjs.map +1 -1
- package/dist/auth/credential-source.d.ts +8 -0
- package/dist/auth/credential-source.js +26 -13
- package/dist/auth/credential-source.js.map +1 -1
- package/dist/catalog/agent-model-options.cjs +25 -17
- package/dist/catalog/agent-model-options.cjs.map +1 -1
- package/dist/catalog/agent-model-options.d.ts +38 -5
- package/dist/catalog/agent-model-options.js +25 -17
- package/dist/catalog/agent-model-options.js.map +1 -1
- package/dist/catalog/channel-refusal.cjs +36 -0
- package/dist/catalog/channel-refusal.cjs.map +1 -0
- package/dist/catalog/channel-refusal.d.ts +29 -0
- package/dist/catalog/channel-refusal.js +36 -0
- package/dist/catalog/channel-refusal.js.map +1 -0
- package/dist/catalog/chat-pickers.cjs +60 -24
- package/dist/catalog/chat-pickers.cjs.map +1 -1
- package/dist/catalog/chat-pickers.d.ts +12 -2
- package/dist/catalog/chat-pickers.js +56 -20
- package/dist/catalog/chat-pickers.js.map +1 -1
- package/dist/catalog/runtime-catalog.cjs +89 -23
- package/dist/catalog/runtime-catalog.cjs.map +1 -1
- package/dist/catalog/runtime-catalog.d.ts +8 -2
- package/dist/catalog/runtime-catalog.js +83 -17
- package/dist/catalog/runtime-catalog.js.map +1 -1
- package/dist/catalog/use-athena-chat-mode.cjs +12 -12
- package/dist/catalog/use-athena-chat-mode.cjs.map +1 -1
- package/dist/chat/AthenaChat.cjs +155 -67
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.d.ts +42 -2
- package/dist/chat/AthenaChat.js +106 -18
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/AthenaChatErrorBoundary.cjs +3 -3
- package/dist/chat/AthenaChatErrorBoundary.cjs.map +1 -1
- package/dist/chat/DrivingOnChip.cjs +23 -0
- package/dist/chat/DrivingOnChip.cjs.map +1 -0
- package/dist/chat/DrivingOnChip.d.ts +17 -0
- package/dist/chat/DrivingOnChip.js +23 -0
- package/dist/chat/DrivingOnChip.js.map +1 -0
- package/dist/chat/StatewireApprovalCard.cjs +125 -31
- package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
- package/dist/chat/StatewireApprovalCard.d.ts +73 -1
- package/dist/chat/StatewireApprovalCard.js +115 -21
- package/dist/chat/StatewireApprovalCard.js.map +1 -1
- package/dist/chat/StatewireClientToolBridge.cjs +2 -2
- package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
- package/dist/chat/StatewireQueuedMessages.cjs +25 -63
- package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
- package/dist/chat/StatewireQueuedMessages.d.ts +11 -13
- package/dist/chat/StatewireQueuedMessages.js +16 -54
- package/dist/chat/StatewireQueuedMessages.js.map +1 -1
- package/dist/chat/WaitingOnYouBanner.cjs +3 -3
- package/dist/chat/WaitingOnYouBanner.cjs.map +1 -1
- package/dist/chat/athena-chat-welcome.cjs +2 -2
- package/dist/chat/athena-chat-welcome.cjs.map +1 -1
- package/dist/chat/athena-citation-links.cjs +5 -5
- package/dist/chat/athena-citation-links.cjs.map +1 -1
- package/dist/chat/athena-composer-controls.cjs +26 -16
- package/dist/chat/athena-composer-controls.cjs.map +1 -1
- package/dist/chat/athena-composer-controls.d.ts +6 -0
- package/dist/chat/athena-composer-controls.js +26 -16
- package/dist/chat/athena-composer-controls.js.map +1 -1
- package/dist/chat/athena-turn-end-status.cjs +42 -0
- package/dist/chat/athena-turn-end-status.cjs.map +1 -0
- package/dist/chat/athena-turn-end-status.d.ts +24 -0
- package/dist/chat/athena-turn-end-status.js +42 -0
- package/dist/chat/athena-turn-end-status.js.map +1 -0
- package/dist/chat/browser-decision-check.cjs +131 -0
- package/dist/chat/browser-decision-check.cjs.map +1 -0
- package/dist/chat/browser-decision-check.d.ts +61 -0
- package/dist/chat/browser-decision-check.js +131 -0
- package/dist/chat/browser-decision-check.js.map +1 -0
- package/dist/chat/chat-outbox-rows.cjs +3 -3
- package/dist/chat/chat-outbox-rows.cjs.map +1 -1
- package/dist/chat/chat-voice-controls.cjs +93 -28
- package/dist/chat/chat-voice-controls.cjs.map +1 -1
- package/dist/chat/chat-voice-controls.d.ts +36 -2
- package/dist/chat/chat-voice-controls.js +89 -24
- package/dist/chat/chat-voice-controls.js.map +1 -1
- package/dist/chat/composer-keyboard-hint.cjs +5 -5
- package/dist/chat/composer-keyboard-hint.cjs.map +1 -1
- package/dist/chat/device-operation.cjs +29 -0
- package/dist/chat/device-operation.cjs.map +1 -0
- package/dist/chat/device-operation.d.ts +34 -0
- package/dist/chat/device-operation.js +29 -0
- package/dist/chat/device-operation.js.map +1 -0
- package/dist/chat/super-grouping/CollapsibleGroup.cjs +14 -14
- package/dist/chat/super-grouping/CollapsibleGroup.cjs.map +1 -1
- package/dist/chat/super-grouping/GroupedMessageParts.cjs +4 -4
- package/dist/chat/super-grouping/GroupedMessageParts.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.cjs +60 -38
- package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.d.ts +24 -4
- package/dist/chat/super-grouping/SuperGroupingCard.js +37 -15
- package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs +32 -32
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.js +3 -3
- package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
- package/dist/chat/super-grouping/ToolTimeline.cjs +97 -37
- package/dist/chat/super-grouping/ToolTimeline.cjs.map +1 -1
- package/dist/chat/super-grouping/ToolTimeline.d.ts +14 -2
- package/dist/chat/super-grouping/ToolTimeline.js +94 -34
- package/dist/chat/super-grouping/ToolTimeline.js.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.cjs +47 -12
- package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.d.ts +21 -0
- package/dist/chat/super-grouping/activity-timeline.js +47 -12
- package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
- package/dist/chat/super-grouping/grouping-function.cjs +4 -0
- package/dist/chat/super-grouping/grouping-function.cjs.map +1 -1
- package/dist/chat/super-grouping/grouping-function.d.ts +7 -0
- package/dist/chat/super-grouping/grouping-function.js +5 -1
- package/dist/chat/super-grouping/grouping-function.js.map +1 -1
- package/dist/chat/super-grouping/index.cjs +6 -0
- package/dist/chat/super-grouping/index.cjs.map +1 -1
- package/dist/chat/super-grouping/index.d.ts +6 -2
- package/dist/chat/super-grouping/index.js +7 -1
- package/dist/chat/super-grouping/index.js.map +1 -1
- package/dist/chat/super-grouping/timeline-step.cjs +61 -2
- package/dist/chat/super-grouping/timeline-step.cjs.map +1 -1
- package/dist/chat/super-grouping/timeline-step.d.ts +13 -1
- package/dist/chat/super-grouping/timeline-step.js +61 -2
- package/dist/chat/super-grouping/timeline-step.js.map +1 -1
- package/dist/chat/super-grouping/tool-part-placement.cjs +17 -0
- package/dist/chat/super-grouping/tool-part-placement.cjs.map +1 -0
- package/dist/chat/super-grouping/tool-part-placement.d.ts +22 -0
- package/dist/chat/super-grouping/tool-part-placement.js +17 -0
- package/dist/chat/super-grouping/tool-part-placement.js.map +1 -0
- package/dist/chat/thread-scroll-to-bottom.cjs +2 -2
- package/dist/chat/thread-scroll-to-bottom.cjs.map +1 -1
- package/dist/chat/thread-scroll-to-bottom.d.ts +10 -7
- package/dist/chat/thread-scroll-to-bottom.js +2 -2
- package/dist/chat/thread-scroll-to-bottom.js.map +1 -1
- package/dist/chat/tooltip-icon-button.cjs +2 -2
- package/dist/chat/tooltip-icon-button.cjs.map +1 -1
- package/dist/chat/use-athena-voice-live.cjs +11 -0
- package/dist/chat/use-athena-voice-live.cjs.map +1 -0
- package/dist/chat/use-athena-voice-live.d.ts +11 -0
- package/dist/chat/use-athena-voice-live.js +11 -0
- package/dist/chat/use-athena-voice-live.js.map +1 -0
- package/dist/chat/use-statewire-approval-request.cjs +56 -24
- package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
- package/dist/chat/use-statewire-approval-request.d.ts +33 -4
- package/dist/chat/use-statewire-approval-request.js +41 -9
- package/dist/chat/use-statewire-approval-request.js.map +1 -1
- package/dist/chat-ui/auth/sign-in-card.cjs +2 -2
- package/dist/chat-ui/auth/sign-in-card.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.cjs +138 -107
- package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.d.ts +20 -4
- package/dist/chat-ui/composer/tiptap-composer.js +85 -54
- package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
- package/dist/chat-ui/header/conversation-history-panel.cjs +49 -23
- package/dist/chat-ui/header/conversation-history-panel.cjs.map +1 -1
- package/dist/chat-ui/header/conversation-history-panel.d.ts +12 -1
- package/dist/chat-ui/header/conversation-history-panel.js +38 -12
- package/dist/chat-ui/header/conversation-history-panel.js.map +1 -1
- package/dist/chat-ui/index.cjs +18 -0
- package/dist/chat-ui/index.cjs.map +1 -1
- package/dist/chat-ui/index.d.ts +7 -1
- package/dist/chat-ui/index.js +18 -0
- package/dist/chat-ui/index.js.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.cjs +147 -38
- package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.d.ts +17 -1
- package/dist/chat-ui/mentions/mention-chip.js +146 -37
- package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.cjs +10 -9
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.js +3 -2
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-popup.cjs +2 -2
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-popup.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-list.cjs +29 -6
- package/dist/chat-ui/mentions/suggestions/components/menu-list.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-list.d.ts +7 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-list.js +25 -2
- package/dist/chat-ui/mentions/suggestions/components/menu-list.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/use-keyboard-navigation.cjs +2 -2
- package/dist/chat-ui/mentions/suggestions/components/use-keyboard-navigation.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/use-menu-navigation.cjs +2 -2
- package/dist/chat-ui/mentions/suggestions/components/use-menu-navigation.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +3 -3
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.cjs +56 -2
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.d.ts +12 -0
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.js +56 -2
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +24 -3
- package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.d.ts +7 -0
- package/dist/chat-ui/mentions/suggestions/data/sources/index.js +24 -3
- package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs +35 -13
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.d.ts +15 -1
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js +28 -6
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.cjs +9 -6
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.d.ts +3 -0
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.js +5 -2
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.js.map +1 -1
- package/dist/chat-ui/mentions/use-account-workspace-id.cjs +45 -10
- package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -1
- package/dist/chat-ui/mentions/use-account-workspace-id.d.ts +24 -1
- package/dist/chat-ui/mentions/use-account-workspace-id.js +46 -11
- package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -1
- package/dist/chat-ui/mentions/use-member-avatar.cjs +4 -4
- package/dist/chat-ui/mentions/use-member-avatar.cjs.map +1 -1
- package/dist/chat-ui/mentions/use-mention-asset.cjs +140 -0
- package/dist/chat-ui/mentions/use-mention-asset.cjs.map +1 -0
- package/dist/chat-ui/mentions/use-mention-asset.d.ts +16 -0
- package/dist/chat-ui/mentions/use-mention-asset.js +140 -0
- package/dist/chat-ui/mentions/use-mention-asset.js.map +1 -0
- package/dist/chat-ui/messages/answer-label.cjs +42 -0
- package/dist/chat-ui/messages/answer-label.cjs.map +1 -0
- package/dist/chat-ui/messages/answer-label.d.ts +33 -0
- package/dist/chat-ui/messages/answer-label.js +42 -0
- package/dist/chat-ui/messages/answer-label.js.map +1 -0
- package/dist/chat-ui/messages/arrival-animation.cjs +13 -0
- package/dist/chat-ui/messages/arrival-animation.cjs.map +1 -0
- package/dist/chat-ui/messages/arrival-animation.d.ts +14 -0
- package/dist/chat-ui/messages/arrival-animation.js +13 -0
- package/dist/chat-ui/messages/arrival-animation.js.map +1 -0
- package/dist/chat-ui/messages/continue-pill.cjs +5 -5
- package/dist/chat-ui/messages/continue-pill.cjs.map +1 -1
- package/dist/chat-ui/messages/handoff-arrival-divider.cjs +44 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.cjs.map +1 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.d.ts +17 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.js +44 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.js.map +1 -0
- package/dist/chat-ui/messages/message-actions-config.cjs +3 -3
- package/dist/chat-ui/messages/message-actions-config.cjs.map +1 -1
- package/dist/chat-ui/messages/message-components.cjs +8 -4
- package/dist/chat-ui/messages/message-components.cjs.map +1 -1
- package/dist/chat-ui/messages/message-components.js +5 -1
- package/dist/chat-ui/messages/message-components.js.map +1 -1
- package/dist/chat-ui/messages/message-images.cjs +66 -0
- package/dist/chat-ui/messages/message-images.cjs.map +1 -0
- package/dist/chat-ui/messages/message-images.d.ts +16 -0
- package/dist/chat-ui/messages/message-images.js +66 -0
- package/dist/chat-ui/messages/message-images.js.map +1 -0
- package/dist/chat-ui/messages/user-edit-composer.cjs +2 -2
- package/dist/chat-ui/messages/user-edit-composer.cjs.map +1 -1
- package/dist/chat-ui/messages/wake-marker.cjs +3 -3
- package/dist/chat-ui/messages/wake-marker.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-link.cjs +7 -6
- package/dist/chat-ui/rich-text/chat-link.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-link.d.ts +2 -3
- package/dist/chat-ui/rich-text/chat-link.js +6 -5
- package/dist/chat-ui/rich-text/chat-link.js.map +1 -1
- package/dist/chat-ui/rich-text/chat-message-body.cjs +8 -8
- package/dist/chat-ui/rich-text/chat-message-body.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-node-views.cjs +7 -6
- package/dist/chat-ui/rich-text/chat-node-views.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-node-views.js +1 -0
- package/dist/chat-ui/rich-text/chat-node-views.js.map +1 -1
- package/dist/chat-ui/rich-text/dom-output-spec.cjs +2 -2
- package/dist/chat-ui/rich-text/dom-output-spec.cjs.map +1 -1
- package/dist/chat-ui/statewire.cjs +3 -0
- package/dist/chat-ui/statewire.cjs.map +1 -1
- package/dist/chat-ui/statewire.d.ts +2 -1
- package/dist/chat-ui/statewire.js +3 -0
- package/dist/chat-ui/statewire.js.map +1 -1
- package/dist/chat-ui/thread/chat-thread-shell.cjs +43 -14
- package/dist/chat-ui/thread/chat-thread-shell.cjs.map +1 -1
- package/dist/chat-ui/thread/chat-thread-shell.d.ts +16 -2
- package/dist/chat-ui/thread/chat-thread-shell.js +35 -6
- package/dist/chat-ui/thread/chat-thread-shell.js.map +1 -1
- package/dist/chat-ui/thread/composer-send-or-stop.cjs +30 -20
- package/dist/chat-ui/thread/composer-send-or-stop.cjs.map +1 -1
- package/dist/chat-ui/thread/composer-send-or-stop.d.ts +8 -0
- package/dist/chat-ui/thread/composer-send-or-stop.js +29 -19
- package/dist/chat-ui/thread/composer-send-or-stop.js.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.cjs +20 -21
- package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.js +3 -4
- package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
- package/dist/chat-ui/thread/thread-loading-overlay.cjs +5 -5
- package/dist/chat-ui/thread/thread-loading-overlay.cjs.map +1 -1
- package/dist/collab/client.cjs +40 -3
- package/dist/collab/client.cjs.map +1 -1
- package/dist/collab/client.d.ts +25 -0
- package/dist/collab/client.js +40 -3
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/document-status.cjs +150 -0
- package/dist/collab/document-status.cjs.map +1 -0
- package/dist/collab/document-status.d.ts +68 -0
- package/dist/collab/document-status.js +150 -0
- package/dist/collab/document-status.js.map +1 -0
- package/dist/collab/index.cjs +7 -0
- package/dist/collab/index.cjs.map +1 -1
- package/dist/collab/index.d.ts +6 -1
- package/dist/collab/index.js +7 -0
- package/dist/collab/index.js.map +1 -1
- package/dist/collab/presence-react.cjs +11 -11
- package/dist/collab/presence-react.cjs.map +1 -1
- package/dist/collab/react.cjs +6 -6
- package/dist/collab/react.cjs.map +1 -1
- package/dist/composer/AttachmentContext.cjs +24 -11
- package/dist/composer/AttachmentContext.cjs.map +1 -1
- package/dist/composer/AttachmentContext.js +18 -5
- package/dist/composer/AttachmentContext.js.map +1 -1
- package/dist/composer/ComposerAttachmentPreview.cjs +78 -23
- package/dist/composer/ComposerAttachmentPreview.cjs.map +1 -1
- package/dist/composer/ComposerAttachmentPreview.d.ts +5 -3
- package/dist/composer/ComposerAttachmentPreview.js +79 -24
- package/dist/composer/ComposerAttachmentPreview.js.map +1 -1
- package/dist/composer/ComposerDropZone.cjs +7 -7
- package/dist/composer/ComposerDropZone.cjs.map +1 -1
- package/dist/composer/FileUploadButton.cjs +37 -22
- package/dist/composer/FileUploadButton.cjs.map +1 -1
- package/dist/composer/FileUploadButton.d.ts +6 -0
- package/dist/composer/FileUploadButton.js +34 -19
- package/dist/composer/FileUploadButton.js.map +1 -1
- package/dist/composer/QuoteContext.cjs +8 -8
- package/dist/composer/QuoteContext.cjs.map +1 -1
- package/dist/composer/composer-handoff.cjs +4 -4
- package/dist/composer/composer-handoff.cjs.map +1 -1
- package/dist/composer/useAppendToComposer.cjs +4 -4
- package/dist/composer/useAppendToComposer.cjs.map +1 -1
- package/dist/composer/useAttachFiles.cjs +23 -6
- package/dist/composer/useAttachFiles.cjs.map +1 -1
- package/dist/composer/useAttachFiles.d.ts +15 -7
- package/dist/composer/useAttachFiles.js +22 -5
- package/dist/composer/useAttachFiles.js.map +1 -1
- package/dist/composer/useComposerAttachment.cjs +4 -4
- package/dist/composer/useComposerAttachment.cjs.map +1 -1
- package/dist/composer/useFileUpload.cjs +21 -16
- package/dist/composer/useFileUpload.cjs.map +1 -1
- package/dist/composer/useFileUpload.d.ts +12 -0
- package/dist/composer/useFileUpload.js +12 -7
- package/dist/composer/useFileUpload.js.map +1 -1
- package/dist/composer/useReadComposerDraft.cjs +2 -2
- package/dist/composer/useReadComposerDraft.cjs.map +1 -1
- package/dist/composer/useSendMessage.cjs +4 -4
- package/dist/composer/useSendMessage.cjs.map +1 -1
- package/dist/diagnostics/useAthenaDiagnostics.cjs +4 -4
- package/dist/diagnostics/useAthenaDiagnostics.cjs.map +1 -1
- package/dist/dictation/audio-level-history.cjs +3 -3
- package/dist/dictation/audio-level-history.cjs.map +1 -1
- package/dist/dictation/dictation-controls.cjs +24 -20
- package/dist/dictation/dictation-controls.cjs.map +1 -1
- package/dist/dictation/dictation-controls.d.ts +6 -1
- package/dist/dictation/dictation-controls.js +24 -20
- package/dist/dictation/dictation-controls.js.map +1 -1
- package/dist/dictation/use-athena-dictation-engine.cjs +3 -3
- package/dist/dictation/use-athena-dictation-engine.cjs.map +1 -1
- package/dist/dictation/use-dictation.cjs +22 -22
- package/dist/dictation/use-dictation.cjs.map +1 -1
- package/dist/index.cjs +26 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +15 -3
- package/dist/index.js +26 -2
- package/dist/index.js.map +1 -1
- package/dist/keryx-http/src/receive-only-socket.cjs +40 -0
- package/dist/keryx-http/src/receive-only-socket.cjs.map +1 -0
- package/dist/keryx-http/src/receive-only-socket.d.ts +27 -0
- package/dist/keryx-http/src/receive-only-socket.js +40 -0
- package/dist/keryx-http/src/receive-only-socket.js.map +1 -0
- package/dist/keryx-http/src/update-attributions.cjs +111 -0
- package/dist/keryx-http/src/update-attributions.cjs.map +1 -0
- package/dist/keryx-http/src/update-attributions.d.ts +75 -0
- package/dist/keryx-http/src/update-attributions.js +111 -0
- package/dist/keryx-http/src/update-attributions.js.map +1 -0
- package/dist/lib/owner-document.cjs +6 -6
- package/dist/lib/owner-document.cjs.map +1 -1
- package/dist/lib/use-athena-rest-query.cjs +4 -4
- package/dist/lib/use-athena-rest-query.cjs.map +1 -1
- package/dist/lib/use-document-active.cjs +4 -4
- package/dist/lib/use-document-active.cjs.map +1 -1
- package/dist/lib/use-prefers-reduced-motion.cjs +2 -2
- package/dist/lib/use-prefers-reduced-motion.cjs.map +1 -1
- package/dist/offline/offline-history.cjs +7 -7
- package/dist/offline/offline-history.cjs.map +1 -1
- package/dist/provider/AthenaContext.cjs +3 -3
- package/dist/provider/AthenaContext.cjs.map +1 -1
- package/dist/provider/AthenaProvider.cjs +116 -79
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.js +40 -3
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/provider/PostHogProvider.cjs +2 -2
- package/dist/provider/PostHogProvider.cjs.map +1 -1
- package/dist/provider/agent-selection-context.cjs +2 -2
- package/dist/provider/agent-selection-context.cjs.map +1 -1
- package/dist/provider/chat-mode-context.cjs +2 -2
- package/dist/provider/chat-mode-context.cjs.map +1 -1
- package/dist/provider/session-persistence-context.cjs +10 -0
- package/dist/provider/session-persistence-context.cjs.map +1 -0
- package/dist/provider/session-persistence-context.d.ts +15 -0
- package/dist/provider/session-persistence-context.js +10 -0
- package/dist/provider/session-persistence-context.js.map +1 -0
- package/dist/provider/statewire-history-context.cjs +4 -4
- package/dist/provider/statewire-history-context.cjs.map +1 -1
- package/dist/provider/statewire-lifecycle-context.cjs +3 -3
- package/dist/provider/statewire-lifecycle-context.cjs.map +1 -1
- package/dist/provider/statewire-window-context.cjs +3 -3
- package/dist/provider/statewire-window-context.cjs.map +1 -1
- package/dist/provider/theme-style-context.cjs +3 -3
- package/dist/provider/theme-style-context.cjs.map +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/references/src/tool-option-schemas.d.ts +0 -34
- package/dist/runtime/StatewireThreadConfigLaneSync.cjs +10 -10
- package/dist/runtime/StatewireThreadConfigLaneSync.cjs.map +1 -1
- package/dist/runtime/auth-refusal-restart.cjs +7 -7
- package/dist/runtime/auth-refusal-restart.cjs.map +1 -1
- package/dist/runtime/auth.cjs +13 -13
- package/dist/runtime/auth.cjs.map +1 -1
- package/dist/runtime/statewire-lifecycle.cjs +1 -0
- package/dist/runtime/statewire-lifecycle.cjs.map +1 -1
- package/dist/runtime/statewire-lifecycle.d.ts +3 -1
- package/dist/runtime/statewire-lifecycle.js +2 -1
- package/dist/runtime/statewire-lifecycle.js.map +1 -1
- package/dist/runtime/statewire-server-lane-context.cjs +2 -2
- package/dist/runtime/statewire-server-lane-context.cjs.map +1 -1
- package/dist/runtime/statewire-session-lane.cjs +4 -4
- package/dist/runtime/statewire-session-lane.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs +10 -8
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.d.ts +2 -0
- package/dist/runtime/useAthenaStatewireRuntime.js +2 -0
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/threads/Inbox.cjs +8 -8
- package/dist/threads/Inbox.cjs.map +1 -1
- package/dist/threads/SessionList.cjs +9 -9
- package/dist/threads/SessionList.cjs.map +1 -1
- package/dist/threads/SessionsPage.cjs +11 -11
- package/dist/threads/SessionsPage.cjs.map +1 -1
- package/dist/threads/index-triggered-refresh.cjs +10 -10
- package/dist/threads/index-triggered-refresh.cjs.map +1 -1
- package/dist/threads/mark-viewed-thread-read.cjs +12 -12
- package/dist/threads/mark-viewed-thread-read.cjs.map +1 -1
- package/dist/threads/offline-session-list.cjs +3 -3
- package/dist/threads/offline-session-list.cjs.map +1 -1
- package/dist/threads/session-list-tab-share.cjs +5 -5
- package/dist/threads/session-list-tab-share.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.cjs +55 -51
- package/dist/threads/statewire-thread-list.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.js +6 -2
- package/dist/threads/statewire-thread-list.js.map +1 -1
- package/dist/threads/thread-id-context.cjs +5 -5
- package/dist/threads/thread-id-context.cjs.map +1 -1
- package/dist/threads/use-athena-session-attention.cjs +2 -2
- package/dist/threads/use-athena-session-attention.cjs.map +1 -1
- package/dist/threads/use-athena-sessions.cjs +10 -10
- package/dist/threads/use-athena-sessions.cjs.map +1 -1
- package/dist/threads/use-athena-thread-model.cjs +3 -3
- package/dist/threads/use-athena-thread-model.cjs.map +1 -1
- package/dist/threads/use-rest-conversation-history.cjs +3 -3
- package/dist/threads/use-rest-conversation-history.cjs.map +1 -1
- package/dist/threads/use-statewire-conversation-history.cjs +8 -8
- package/dist/threads/use-statewire-conversation-history.cjs.map +1 -1
- package/dist/threads/use-thread-archive.cjs +9 -9
- package/dist/threads/use-thread-archive.cjs.map +1 -1
- package/dist/threads/use-thread-favorite.cjs +2 -2
- package/dist/threads/use-thread-favorite.cjs.map +1 -1
- package/dist/threads/use-thread-field-override.cjs +20 -20
- package/dist/threads/use-thread-field-override.cjs.map +1 -1
- package/dist/threads/use-thread-read-state.cjs +4 -4
- package/dist/threads/use-thread-read-state.cjs.map +1 -1
- package/dist/threads/use-thread-rename.cjs +2 -2
- package/dist/threads/use-thread-rename.cjs.map +1 -1
- package/dist/threads/useAthenaThreadManager.cjs +2 -2
- package/dist/threads/useAthenaThreadManager.cjs.map +1 -1
- package/dist/tools/NestedPtcMessages.cjs +6 -6
- package/dist/tools/NestedPtcMessages.cjs.map +1 -1
- package/dist/tools/append-document-tool-ui.cjs +7 -7
- package/dist/tools/append-document-tool-ui.cjs.map +1 -1
- package/dist/tools/file-tool-uis.cjs +2 -2
- package/dist/tools/file-tool-uis.cjs.map +1 -1
- package/dist/tools/misc-tool-uis.cjs +2 -2
- package/dist/tools/misc-tool-uis.cjs.map +1 -1
- package/dist/tools/primitives.cjs +6 -6
- package/dist/tools/primitives.cjs.map +1 -1
- package/dist/tools/read-asset-tool-ui.cjs +6 -6
- package/dist/tools/read-asset-tool-ui.cjs.map +1 -1
- package/dist/tools/subagent-task-tool-ui.cjs +21 -21
- package/dist/tools/subagent-task-tool-ui.cjs.map +1 -1
- package/dist/tools/test-recording-tool-uis.cjs +16 -16
- package/dist/tools/test-recording-tool-uis.cjs.map +1 -1
- package/dist/tools/todo-plan-store.cjs +4 -4
- package/dist/tools/todo-plan-store.cjs.map +1 -1
- package/dist/tools/tool-appearance.cjs +3 -3
- package/dist/tools/tool-appearance.cjs.map +1 -1
- package/dist/tools/tool-fallback.cjs +14 -14
- package/dist/tools/tool-fallback.cjs.map +1 -1
- package/dist/tools/tool-summary.cjs +0 -2
- package/dist/tools/tool-summary.cjs.map +1 -1
- package/dist/tools/tool-summary.js +0 -2
- package/dist/tools/tool-summary.js.map +1 -1
- package/dist/tools/tool-uis.cjs +74 -74
- package/dist/tools/tool-uis.cjs.map +1 -1
- package/dist/tools/use-elapsed-seconds.cjs +3 -3
- package/dist/tools/use-elapsed-seconds.cjs.map +1 -1
- package/dist/tools/write-todos-tool-ui.cjs +9 -9
- package/dist/tools/write-todos-tool-ui.cjs.map +1 -1
- package/dist/ui/image-viewer.cjs +382 -0
- package/dist/ui/image-viewer.cjs.map +1 -0
- package/dist/ui/image-viewer.d.ts +50 -0
- package/dist/ui/image-viewer.js +382 -0
- package/dist/ui/image-viewer.js.map +1 -0
- package/dist/voice/chat.cjs +6 -0
- package/dist/voice/chat.cjs.map +1 -1
- package/dist/voice/chat.d.ts +1 -1
- package/dist/voice/chat.js +8 -2
- package/dist/voice/livekit-join.cjs +52 -101
- package/dist/voice/livekit-join.cjs.map +1 -1
- package/dist/voice/livekit-join.d.ts +1 -6
- package/dist/voice/livekit-join.js +52 -101
- package/dist/voice/livekit-join.js.map +1 -1
- package/dist/voice/livekit.cjs.map +1 -1
- package/dist/voice/livekit.d.ts +11 -1
- package/dist/voice/livekit.js.map +1 -1
- package/dist/voice/use-athena-voice-session.cjs +34 -34
- package/dist/voice/use-athena-voice-session.cjs.map +1 -1
- package/dist/workbench/ComputerLiveDesktop.cjs +13 -13
- package/dist/workbench/ComputerLiveDesktop.cjs.map +1 -1
- package/dist/workbench/SessionWorkbench.cjs +22 -22
- package/dist/workbench/SessionWorkbench.cjs.map +1 -1
- package/dist/workbench/session-workbench-context.cjs +3 -3
- package/dist/workbench/session-workbench-context.cjs.map +1 -1
- package/dist/workbench/session-workbench-panes.cjs +8 -8
- package/dist/workbench/session-workbench-panes.cjs.map +1 -1
- package/dist/workbench/workbench-layout-context.cjs +3 -3
- package/dist/workbench/workbench-layout-context.cjs.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"answer-rows.js","sources":["../../../../agent-runtime/src/answer-rows.ts"],"sourcesContent":["import type { LangChainMessage } from '@assistant-ui/react-langgraph';\nimport { answerRowRunId, readLangChainAnswer } from './answer-label';\n\n/**\n * One row per answering agent (identity v7 D13: several agents answer one\n * message, each in its own turn for its author).\n *\n * assistant-ui joins consecutive assistant messages into one row unless their\n * `metadata.runId` differs (`chunkExternalMessages` in `@assistant-ui/core`).\n * The agents that answer one message answer in turn, with nothing between\n * them, so without a run id per answer every agent's answer lands in one row.\n * This module gives each AI message the answerer it belongs to, which the\n * converter turns into `metadata.runId` (`convertDeepAgentLangChainMessage`):\n *\n * - a stamped answer: its `answered_by` stamp (agent and principal), written by\n * agora when its model turn lands;\n * - an answer still streaming while several agents answer: the agent the\n * host's record says is answering (`addressedTurn`, replicated statewire\n * state), for every message after the message its turn began after. The\n * stamp lands only once a model turn finishes, so reading the record is what\n * keeps a next agent's answer in its own row from its first token instead of\n * joining the previous agent's row and jumping out when its stamp lands;\n * - anything else (an answer written before the stamp existed, a reused one,\n * a run marker): the answerer of the AI message before it in the same turn,\n * else of the first one after it.\n *\n * Only a turn (the messages between two people's messages) whose answers come\n * from two or more answerers is given run ids: a 1:1 chat, a turn one agent\n * answered and every transcript written before the stamp keep their messages'\n * identity and convert exactly as before.\n */\n\n/** Statewire state key of the message several agents are answering (agora `several_agents.ADDRESSED_TURN_STATE_KEY`). */\nexport const ADDRESSED_TURN_STATE_KEY = 'addressedTurn';\n\n/** The record version this reader understands (agora `several_agents.RECORD_VERSION`). */\nconst ADDRESSED_TURN_RECORD_VERSION = 1;\n\n/** At most this many agents answer one message (agora `agent_refs.MAX_ADDRESSED_AGENTS`). */\nconst MAX_ADDRESSED_AGENTS = 8;\n\nconst AGENT_KEY_PATTERN = /^(collab_agent|assistant):\\S+$/;\n\n/** How one agent's turn of a message several agents answer ended. */\nexport interface DeepAgentAddressedOutcome {\n /** The agent's key (`collab_agent:<asset id>`, `assistant:<principal id>`). */\n agent: string;\n outcome: 'answered' | 'failed' | 'refused';\n /** A refusal's code (e.g. `conversation_history_recheck_required`); `null` otherwise. */\n code: string | null;\n}\n\n/** The message several agents are answering, as the host's replicated record holds it. */\nexport interface DeepAgentAddressedTurn {\n /** Whom every agent of the message answers for: the author's principal id. */\n authorId: string;\n /** The named agents' keys, in the order they answer. */\n agents: readonly string[];\n /** The index in {@link agents} of the agent answering now. */\n position: number;\n /** The message the answering agent's turn began after; `null` for the first agent. */\n anchor: string | null;\n /** Each finished agent's outcome, in order. */\n outcomes: readonly DeepAgentAddressedOutcome[];\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst isAgentKey = (value: unknown): value is string =>\n typeof value === 'string' && AGENT_KEY_PATTERN.test(value);\n\n/** One finished agent's outcome, read as agora reads it: an outcome it doesn't know is a failure. */\nfunction readOutcome(value: unknown): DeepAgentAddressedOutcome | null {\n if (!isRecord(value)) return null;\n const { outcome } = value;\n return {\n agent: String(value.agent),\n outcome: outcome === 'answered' || outcome === 'refused' ? outcome : 'failed',\n code: typeof value.code === 'string' && value.code.length > 0 ? value.code : null,\n };\n}\n\n/**\n * The record of the message several agents are answering, off the replicated\n * state value (`state.addressedTurn`); `null` while none is (agora clears it\n * once the last agent settled) and for anything this reader can't trust,\n * mirroring agora's own `read_record`: another version, a malformed field, an\n * agent key it can't read, a position outside the list.\n */\nexport function readDeepAgentAddressedTurn(value: unknown): DeepAgentAddressedTurn | null {\n if (!isRecord(value) || value.v !== ADDRESSED_TURN_RECORD_VERSION) return null;\n const { author, author_id: authorId, agents, position, anchor, outcomes, started } = value;\n if (typeof author !== 'string' || author.length === 0) return null;\n if (typeof authorId !== 'string' || authorId.length === 0) return null;\n if (started !== undefined && typeof started !== 'boolean') return null;\n if (\n !Array.isArray(agents) ||\n agents.length < 2 ||\n agents.length > MAX_ADDRESSED_AGENTS ||\n !agents.every(isAgentKey)\n ) {\n return null;\n }\n if (typeof position !== 'number' || !Number.isInteger(position)) return null;\n if (position < 0 || position >= agents.length) return null;\n if (anchor !== null && anchor !== undefined && (typeof anchor !== 'string' || !anchor)) {\n return null;\n }\n if (!Array.isArray(outcomes)) return null;\n const finished = outcomes.map(readOutcome);\n if (finished.some((outcome) => outcome === null)) return null;\n return {\n authorId,\n agents,\n position,\n anchor: anchor ?? null,\n outcomes: finished.filter((outcome): outcome is DeepAgentAddressedOutcome => outcome !== null),\n };\n}\n\n/** Where an AI message carries the answerer its row is keyed by (see {@link readAnswerRowKey}). */\nconst ANSWER_ROW_KEY = Symbol.for('@athenaintel/agent-runtime/answer-row');\n\n/**\n * The answerer an AI message's row is keyed by, as {@link withAnswerRows} put\n * it on the message; `undefined` for a message it left alone. The converter\n * passes it on as the row's `metadata.runId`.\n */\nexport function readAnswerRowKey(message: LangChainMessage): string | undefined {\n const key: unknown = Reflect.get(message, ANSWER_ROW_KEY);\n return typeof key === 'string' ? key : undefined;\n}\n\n/**\n * The keyed copy of each message, one per message and key: the conversion\n * caches by message identity, so an unchanged message must yield the same\n * keyed object on every pass, and a message whose key changed must yield a\n * new one (it converts again with its new run id).\n */\nconst keyedMessages = new WeakMap<LangChainMessage, { key: string; message: LangChainMessage }>();\n\nfunction withAnswerRowKey(message: LangChainMessage, key: string): LangChainMessage {\n const cached = keyedMessages.get(message);\n if (cached?.key === key) return cached.message;\n const keyed: LangChainMessage = { ...message };\n // A symbol never reaches JSON, so a keyed message sent back to agora (a\n // branch, an edit) carries nothing it didn't receive.\n Reflect.set(keyed, ANSWER_ROW_KEY, key);\n keyedMessages.set(message, { key, message: keyed });\n return keyed;\n}\n\n/**\n * Each AI message's stamped answerer key (`null` when unstamped), cached by\n * message object: the messages handed to {@link withAnswerRows} keep their\n * object while unchanged, so a streamed token reads only the stamp of the\n * message it changed.\n */\nconst stampKeys = new WeakMap<LangChainMessage, string | null>();\n\nfunction stampedAnswererKey(message: LangChainMessage): string | null {\n const cached = stampKeys.get(message);\n if (cached !== undefined) return cached;\n const answer = readLangChainAnswer(message);\n const key = answer === null ? null : answerRowRunId(answer.agent, answer.for_id);\n stampKeys.set(message, key);\n return key;\n}\n\n/** The id of the row a next agent of a message several agents answer shows before its first token. */\nexport const NEXT_AGENT_PENDING_MESSAGE_ID = '__athena_deep_agent_pending_next_agent__';\n\n/** The pending row for each answerer key: one object per key, so the row keeps its identity. */\nconst nextAgentPlaceholders = new Map<string, LangChainMessage>();\n\nfunction nextAgentPlaceholder(key: string): LangChainMessage {\n const cached = nextAgentPlaceholders.get(key);\n if (cached !== undefined) return cached;\n // Empty content with an explicit running status: the thread's thinking\n // status keys on a running assistant row with no parts, as the first\n // agent's pending row does (`withPendingAssistantMessage`).\n const placeholder: LangChainMessage = {\n type: 'ai',\n content: [],\n id: NEXT_AGENT_PENDING_MESSAGE_ID,\n status: { type: 'running' },\n };\n Reflect.set(placeholder, ANSWER_ROW_KEY, key);\n Object.freeze(placeholder);\n // Bounded by the answerers a client meets; each entry is a few strings.\n if (nextAgentPlaceholders.size >= 64) nextAgentPlaceholders.clear();\n nextAgentPlaceholders.set(key, placeholder);\n return placeholder;\n}\n\nconst isTurnBoundary = (message: LangChainMessage): boolean =>\n message.type === 'human' || message.type === 'system';\n\n/** The agent answering now, from the message its turn began after on. */\ninterface AnsweringAgent {\n key: string;\n anchorIndex: number;\n}\n\nfunction answeringAgent({\n messages,\n addressedTurn,\n}: {\n messages: readonly LangChainMessage[];\n addressedTurn: DeepAgentAddressedTurn | null;\n}): AnsweringAgent | null {\n // The first agent answers the message itself: its run brings the message as\n // input, so its answer starts its own row anyway.\n if (addressedTurn === null || addressedTurn.position === 0 || addressedTurn.anchor === null) {\n return null;\n }\n const agent = addressedTurn.agents[addressedTurn.position];\n if (agent === undefined) return null;\n // The anchor is the transcript's last message when the agent's turn began:\n // read from the tail.\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n const message = messages[index];\n if (message === undefined) continue;\n if (message.id === addressedTurn.anchor) {\n return { key: answerRowRunId(agent, addressedTurn.authorId), anchorIndex: index };\n }\n // A person's message after the anchor means the record is stale.\n if (isTurnBoundary(message)) return null;\n }\n return null;\n}\n\n/**\n * Key one turn's AI messages (`messages[start..end)`) by their answerer when\n * two or more answerers wrote them; `null` otherwise.\n */\nfunction turnKeys({\n messages,\n start,\n end,\n answering,\n}: {\n messages: readonly LangChainMessage[];\n start: number;\n end: number;\n answering: AnsweringAgent | null;\n}): (string | null)[] | null {\n const keys: (string | null)[] = [];\n let first: string | null = null;\n let several = false;\n // The answering agent's own stamp, once one of its answers carries it: its\n // later messages follow that stamp, so a record and a stamp spelling the\n // author apart never split one agent's answer in two.\n let answeringStamp: string | null = null;\n for (let index = start; index < end; index += 1) {\n const message = messages[index];\n if (message?.type !== 'ai') {\n keys.push(null);\n continue;\n }\n const answeringKey =\n answering !== null && index > answering.anchorIndex ? answering.key : null;\n let key = stampedAnswererKey(message);\n if (key !== null && answeringKey !== null) answeringStamp = key;\n else if (key === null && answeringKey !== null) key = answeringStamp ?? answeringKey;\n keys.push(key);\n if (key === null) continue;\n if (first === null) first = key;\n else if (key !== first) several = true;\n }\n if (!several) return null;\n // An AI message nobody stamped joins the answerer before it in the turn,\n // else the first one after it.\n let previous: string | null = null;\n for (let offset = 0; offset < keys.length; offset += 1) {\n if (messages[start + offset]?.type !== 'ai') continue;\n const key = keys[offset] ?? null;\n if (key === null) keys[offset] = previous;\n else previous = key;\n }\n let next: string | null = null;\n for (let offset = keys.length - 1; offset >= 0; offset -= 1) {\n if (messages[start + offset]?.type !== 'ai') continue;\n const key = keys[offset] ?? null;\n if (key === null) keys[offset] = next;\n else next = key;\n }\n return keys;\n}\n\n/**\n * The messages with every answer of a turn several agents answered keyed by\n * its answerer (see the module comment), so each agent's answer converts into\n * a row of its own; the same array when no turn needs it.\n *\n * While a next agent is answering (`addressedTurn` past its first agent) and\n * the run is live but the agent hasn't sent its first token, its row shows as\n * pending (a running placeholder, {@link NEXT_AGENT_PENDING_MESSAGE_ID}), as the\n * first agent's does.\n *\n * O(the messages) per pass, with no allocation for a transcript nobody but one\n * answerer per turn wrote.\n */\nexport function withAnswerRows({\n messages,\n addressedTurn,\n isRunning,\n}: {\n messages: LangChainMessage[];\n addressedTurn: DeepAgentAddressedTurn | null;\n isRunning: boolean;\n}): LangChainMessage[] {\n const answering = answeringAgent({ messages, addressedTurn });\n const pending =\n answering !== null &&\n isRunning &&\n !messages.slice(answering.anchorIndex + 1).some((message) => message.type === 'ai');\n const sources = pending ? [...messages, nextAgentPlaceholder(answering.key)] : messages;\n let keyed: LangChainMessage[] | null = null;\n let start = 0;\n for (let index = 0; index <= sources.length; index += 1) {\n const message = sources[index];\n if (message !== undefined && !isTurnBoundary(message)) continue;\n if (index - start > 1) {\n const keys = turnKeys({ messages: sources, start, end: index, answering });\n if (keys !== null) {\n for (const [offset, key] of keys.entries()) {\n const source = sources[start + offset];\n if (key === null || source === undefined || readAnswerRowKey(source) === key) continue;\n keyed ??= [...sources];\n keyed[start + offset] = withAnswerRowKey(source, key);\n }\n }\n }\n start = index + 1;\n }\n return keyed ?? sources;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const
|
|
3
|
+
const require$$0 = require("react");
|
|
4
4
|
const clientTools = require("./client-tools.cjs");
|
|
5
5
|
const CLIENT_TOOL_WRITE_DECLINED_MESSAGE = "The user declined this edit. Do not retry it; ask the user how to proceed.";
|
|
6
6
|
function defaultMissingClientToolMessage(toolName) {
|
|
@@ -91,7 +91,7 @@ async function executeClientToolBatch(options) {
|
|
|
91
91
|
}
|
|
92
92
|
function useStatewireClientToolBridge(options) {
|
|
93
93
|
const { threadId, tracker, inputRequests, logLabel = "[AthenaSDK]" } = options;
|
|
94
|
-
const optionsRef =
|
|
94
|
+
const optionsRef = require$$0.useRef(options);
|
|
95
95
|
optionsRef.current = options;
|
|
96
96
|
const toolNames = new Set(options.tools.map((tool) => tool.name));
|
|
97
97
|
const pendingRequest = inputRequests == null ? void 0 : inputRequests.find((request) => {
|
|
@@ -100,13 +100,13 @@ function useStatewireClientToolBridge(options) {
|
|
|
100
100
|
if (!clientTools.isClientToolInterrupt(payload)) return false;
|
|
101
101
|
return tracker.getCachedResume(clientToolClaimKey(threadId, request.id)) !== void 0 || payload.context.requests.every((call) => toolNames.has(call.tool_name));
|
|
102
102
|
});
|
|
103
|
-
const ownedClaimsRef =
|
|
104
|
-
const startedClaimsRef =
|
|
105
|
-
const resumeOwnerRef =
|
|
106
|
-
const resumeClaimsRef =
|
|
107
|
-
const resumeTimersRef =
|
|
108
|
-
const activeRef =
|
|
109
|
-
const releaseClaim =
|
|
103
|
+
const ownedClaimsRef = require$$0.useRef(/* @__PURE__ */ new Set());
|
|
104
|
+
const startedClaimsRef = require$$0.useRef(/* @__PURE__ */ new Set());
|
|
105
|
+
const resumeOwnerRef = require$$0.useRef(Symbol("client-tool-resume-owner"));
|
|
106
|
+
const resumeClaimsRef = require$$0.useRef(/* @__PURE__ */ new Set());
|
|
107
|
+
const resumeTimersRef = require$$0.useRef(/* @__PURE__ */ new Map());
|
|
108
|
+
const activeRef = require$$0.useRef(true);
|
|
109
|
+
const releaseClaim = require$$0.useCallback(
|
|
110
110
|
(claim) => {
|
|
111
111
|
const owned = ownedClaimsRef.current.delete(claim);
|
|
112
112
|
startedClaimsRef.current.delete(claim);
|
|
@@ -114,7 +114,7 @@ function useStatewireClientToolBridge(options) {
|
|
|
114
114
|
},
|
|
115
115
|
[tracker]
|
|
116
116
|
);
|
|
117
|
-
const stopResumeReplay =
|
|
117
|
+
const stopResumeReplay = require$$0.useCallback(
|
|
118
118
|
(claim) => {
|
|
119
119
|
const timerEntry = resumeTimersRef.current.get(claim);
|
|
120
120
|
if (timerEntry) clearTimeout(timerEntry.timer);
|
|
@@ -125,7 +125,7 @@ function useStatewireClientToolBridge(options) {
|
|
|
125
125
|
},
|
|
126
126
|
[tracker]
|
|
127
127
|
);
|
|
128
|
-
|
|
128
|
+
require$$0.useEffect(() => {
|
|
129
129
|
activeRef.current = true;
|
|
130
130
|
const ownedClaims = ownedClaimsRef.current;
|
|
131
131
|
const startedClaims = startedClaimsRef.current;
|
|
@@ -141,9 +141,9 @@ function useStatewireClientToolBridge(options) {
|
|
|
141
141
|
}
|
|
142
142
|
};
|
|
143
143
|
}, [stopResumeReplay, tracker]);
|
|
144
|
-
const liveRequestIdsRef =
|
|
144
|
+
const liveRequestIdsRef = require$$0.useRef(/* @__PURE__ */ new Set());
|
|
145
145
|
liveRequestIdsRef.current = new Set((inputRequests ?? []).map((request) => request.id));
|
|
146
|
-
const startResumeReplay =
|
|
146
|
+
const startResumeReplay = require$$0.useCallback(
|
|
147
147
|
(claim, requestId) => {
|
|
148
148
|
if (!activeRef.current || resumeClaimsRef.current.has(claim)) return;
|
|
149
149
|
if (!tracker.claimResumeReplay(claim, resumeOwnerRef.current)) return;
|
|
@@ -187,7 +187,7 @@ function useStatewireClientToolBridge(options) {
|
|
|
187
187
|
},
|
|
188
188
|
[logLabel, stopResumeReplay, tracker]
|
|
189
189
|
);
|
|
190
|
-
const executeRequest =
|
|
190
|
+
const executeRequest = require$$0.useCallback(
|
|
191
191
|
async (request) => {
|
|
192
192
|
const payload = request.payload;
|
|
193
193
|
if (!clientTools.isClientToolInterrupt(payload)) return;
|
|
@@ -253,7 +253,7 @@ function useStatewireClientToolBridge(options) {
|
|
|
253
253
|
},
|
|
254
254
|
[logLabel, releaseClaim, startResumeReplay, threadId, tracker]
|
|
255
255
|
);
|
|
256
|
-
|
|
256
|
+
require$$0.useEffect(() => {
|
|
257
257
|
if (!pendingRequest) return;
|
|
258
258
|
const claim = clientToolClaimKey(threadId, pendingRequest.id);
|
|
259
259
|
if (!tracker.claim(claim)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-tool-bridge.cjs","sources":["../../../../agent-runtime/src/client-tool-bridge.ts"],"sourcesContent":["/**\n * The statewire client-tool bridge loop, shared by every surface that executes\n * frontend tool calls (Olympus, the React SDK, the Office add-in, mobile).\n *\n * Tools declared through `runConfig.custom.client_tools` have no backend\n * implementation: a call parks the run on an interrupt that arrives as a\n * statewire input request. A bridge with handlers for the whole batch claims\n * it (exactly-once per ownership domain), runs those handlers, and resumes\n * with per-call result envelopes. Other attached tabs leave it for the\n * executing surface; a thrown handler still returns an actionable error.\n *\n * Wire-adjacent correctness invariants this module owns, so they can never\n * drift apart per surface again:\n * - exactly-once claim per request, with un-claim on every path that did NOT\n * run any handler (abandoned before execution, consent dismissed, unmount\n * before the first handler) so a re-emitted request is executable instead\n * of stranding the run;\n * - once a batch has STARTED executing handlers, its claim is never released\n * by unmount: handlers cannot be cancelled, so releasing would let another\n * mount re-claim the re-emitted request and re-execute side effects that\n * already ran (double-executing a mutating tool). The completed wire-safe\n * result is cached and may be replayed across reconnects/remounts instead;\n * - liveness checks between awaits (the run can be stopped or answered\n * elsewhere while a handler runs) so a stale request is never resumed;\n * - per-call JSON wire-safety, so one unrepresentable handler result answers\n * that one call with an error instead of failing the whole batch.\n *\n * Like `interrupts.ts`, this is parameterized rather than self-wiring: the\n * host component reads `useStatewireRuns().inputRequests` and\n * `useStatewireSendCommand()` itself (both mockable per surface) and passes\n * them in, together with its ownership tracker and write-consent policy.\n */\n\nimport type { StatewireThread } from '@assistant-ui/react-statewire';\nimport { useCallback, useEffect, useRef } from 'react';\nimport {\n type ClientToolCallRequest,\n type ClientToolRequestTracker,\n type ClientToolResultEnvelope,\n clientToolCallArgs,\n clientToolErrorEnvelope,\n clientToolResultsResumeValue,\n clientToolSuccessEnvelope,\n isClientToolInterrupt,\n} from './client-tools';\n\n/** A locally executable tool, normalized across the per-surface tool shapes. */\nexport interface ClientToolBridgeTool {\n /** Snake_case tool id the model calls (e.g. `update_sheet_range`). */\n name: string;\n /** Mutating tools gate on the surface's write-consent flow (`confirmWrites`). */\n requiresWrite?: boolean;\n run: (\n args: Record<string, unknown>,\n context: { toolCallId: string },\n ) => Promise<unknown>;\n}\n\n/**\n * Batch write-consent outcome. `proceed` runs the write calls, `declined`\n * answers them with the declined message while reads still run, `abandoned`\n * releases the claim without resuming (the request died, or the consent UI was\n * dismissed by the run moving on). Grant persistence (a thread set, a stored\n * preference) is the surface's own policy, applied inside its callback.\n */\nexport type ClientToolWriteConsentDecision = 'proceed' | 'declined' | 'abandoned';\n\nexport interface ClientToolCallSettledEvent {\n toolName: string;\n status: 'success' | 'error' | 'declined';\n errorType?: string;\n}\n\n/** Default resume error for a write call the user declined. */\nexport const CLIENT_TOOL_WRITE_DECLINED_MESSAGE =\n 'The user declined this edit. Do not retry it; ask the user how to proceed.';\n\n/** Default resume error for a call naming a tool this surface does not have. */\nexport function defaultMissingClientToolMessage(toolName: string): string {\n return `This surface has no tool named '${toolName}'.`;\n}\n\n/** Statewire request ids are unique per run, but a thread scope keeps a\n * process-wide claim unambiguous when two conversations are open at once. */\nexport function clientToolClaimKey(threadId: string, requestId: string): string {\n return `${threadId}:${requestId}`;\n}\n\nconst CLIENT_TOOL_RESUME_RETRY_DELAYS_MS = [2_000, 5_000, 10_000, 15_000, 30_000];\nconst MAX_CLIENT_TOOL_RESUME_ATTEMPTS = 25;\n\nfunction clientToolResumeRetryDelayMs(attemptNumber: number): number {\n const index = Math.min(\n Math.max(attemptNumber - 1, 0),\n CLIENT_TOOL_RESUME_RETRY_DELAYS_MS.length - 1,\n );\n return CLIENT_TOOL_RESUME_RETRY_DELAYS_MS[index] ?? 30_000;\n}\n\n/**\n * A wire-safe copy of a handler's return value: handlers can return values\n * JSON cannot represent (DOM nodes, host objects, bigints), which must never\n * reach the transport. Throws for an unrepresentable value so the caller can\n * answer that one call with an error instead of stranding the whole batch.\n */\nexport function jsonSafeClientToolResult(value: unknown): unknown {\n const serialized = JSON.stringify(value);\n return serialized === undefined ? null : JSON.parse(serialized);\n}\n\n/** A parked, unanswered client-tool input request. */\nexport function isPendingClientToolRequest(\n request: StatewireThread.InputRequestState,\n): request is StatewireThread.CustomInputRequest {\n if (request.type !== 'interrupt' || 'response' in request) return false;\n return isClientToolInterrupt((request as { payload?: unknown }).payload);\n}\n\nexport interface ExecuteClientToolBatchOptions {\n calls: readonly ClientToolCallRequest[];\n tools: readonly ClientToolBridgeTool[];\n /** Whether the parked request still exists and this surface may answer it.\n * Checked before consent resolution, before every call, and before the\n * results are handed back for resume. */\n isLive: () => boolean;\n /** Batch write gate; absent means writes run without consent (surfaces that\n * only register read tools). Called once per batch, before any handler. */\n confirmWrites?: (batch: {\n writeToolNames: readonly string[];\n }) => Promise<ClientToolWriteConsentDecision>;\n writeDeclinedMessage?: string;\n missingToolMessage?: (toolName: string) => string;\n /** Per-call telemetry (the Office add-in's tool events). */\n onCallSettled?: (event: ClientToolCallSettledEvent) => void;\n /**\n * Called once, after the write-consent gate resolves and immediately before\n * the first handler runs — the point where side effects begin. There is no\n * await between this callback and the first handler invocation, so a caller\n * marking \"execution started\" here can never miss a handler that ran.\n */\n onExecutionStart?: () => void;\n}\n\n/**\n * Execute one batched client-tool park: consent, per-call execution with\n * wire-safe envelopes, liveness aborts. Returns the per-interrupt result map\n * to resume with, or `null` when the batch was abandoned (the request died,\n * consent was abandoned, or the surface went away) — the caller must release\n * its claim and must NOT resume.\n */\nexport async function executeClientToolBatch(\n options: ExecuteClientToolBatchOptions,\n): Promise<Record<string, ClientToolResultEnvelope> | null> {\n const {\n calls,\n tools,\n isLive,\n confirmWrites,\n writeDeclinedMessage = CLIENT_TOOL_WRITE_DECLINED_MESSAGE,\n missingToolMessage = defaultMissingClientToolMessage,\n onCallSettled,\n onExecutionStart,\n } = options;\n const registry = new Map(tools.map((tool) => [tool.name, tool]));\n\n // One consent covers the whole batch (and whatever scope the surface's\n // callback persists): writes are declined together while reads still run.\n let writesDeclined = false;\n const writeToolNames = calls\n .filter((call) => registry.get(call.tool_name)?.requiresWrite === true)\n .map((call) => call.tool_name);\n if (writeToolNames.length > 0 && confirmWrites) {\n const decision = await confirmWrites({ writeToolNames });\n if (decision === 'abandoned' || !isLive()) {\n // The run was stopped (or answered elsewhere) while consent was\n // pending: abort before any handler mutates the user's asset.\n return null;\n }\n writesDeclined = decision === 'declined';\n }\n\n onExecutionStart?.();\n\n const results: Record<string, ClientToolResultEnvelope> = {};\n for (const call of calls) {\n if (!isLive()) return null;\n const tool = registry.get(call.tool_name);\n let envelope: ClientToolResultEnvelope;\n let status: ClientToolCallSettledEvent['status'] = 'success';\n let errorType: string | undefined;\n if (!tool) {\n envelope = clientToolErrorEnvelope(missingToolMessage(call.tool_name));\n status = 'error';\n errorType = 'UnknownClientTool';\n } else if (tool.requiresWrite === true && writesDeclined) {\n envelope = clientToolErrorEnvelope(writeDeclinedMessage);\n status = 'declined';\n } else {\n try {\n envelope = clientToolSuccessEnvelope(\n jsonSafeClientToolResult(\n await tool.run(clientToolCallArgs(call), {\n toolCallId: call.interrupt_id,\n }),\n ),\n );\n } catch (error) {\n envelope = clientToolErrorEnvelope(error);\n status = 'error';\n errorType = error instanceof Error ? error.name : typeof error;\n }\n }\n results[call.interrupt_id] = envelope;\n onCallSettled?.({\n toolName: call.tool_name,\n status,\n ...(errorType !== undefined ? { errorType } : {}),\n });\n }\n\n // Abandoned mid-flight: resuming a dead request would error, and a\n // re-emitted one must be executable again.\n return isLive() ? results : null;\n}\n\nexport interface UseStatewireClientToolBridgeOptions {\n threadId: string;\n tools: readonly ClientToolBridgeTool[];\n /**\n * Ownership domain for parked-request claims. Pass a module-scoped tracker\n * to make ownership process-wide across every mount of the surface (two\n * mounted surfaces of one conversation execute each request exactly once),\n * or a per-mount tracker to scope ownership to one mounted bridge.\n */\n tracker: ClientToolRequestTracker;\n /** The surface's `useStatewireRuns().inputRequests` read. */\n inputRequests: readonly StatewireThread.InputRequestState[] | undefined;\n /** Dispatch the `run/input` resume on the surface's transport. The value is\n * already wire-safe (per-call JSON round-trip inside the batch engine). */\n /** Dispatch the answer and settle only once the Statewire host accepts or\n * rejects the command. The bridge deliberately keeps replaying while this\n * promise is pending: `run/input` removes the request optimistically before\n * the server has accepted the answer. */\n sendResume: (\n requestId: string,\n value: Record<string, unknown>,\n ) => PromiseLike<unknown>;\n /** Batch write gate, with the parked request's id so the surface can close\n * its consent UI the instant that request disappears. */\n confirmWrites?: (batch: {\n requestId: string;\n writeToolNames: readonly string[];\n }) => Promise<ClientToolWriteConsentDecision>;\n writeDeclinedMessage?: string;\n missingToolMessage?: (toolName: string) => string;\n onCallSettled?: (event: ClientToolCallSettledEvent) => void;\n /** Log prefix for resume-dispatch failures. */\n logLabel?: string;\n}\n\n/**\n * The claim lifecycle around {@link executeClientToolBatch}: claim the pending\n * request once per ownership domain, execute, resume — releasing the claim on\n * every path that ran no handler, so re-emitted requests recover.\n *\n * Unmount splits by whether side effects began:\n * - a claim whose batch has NOT started executing (claimed this tick, or\n * parked on write consent) is released, so another mount — or a remount —\n * can execute the re-emitted request instead of stranding the parked run;\n * - a claim whose batch HAS started stays held: handlers cannot be cancelled,\n * so releasing would let a sibling mount re-claim and re-execute a mutation\n * whose side effects already ran. The detached execution caches its result\n * and attempts one resume through its captured transport; a later mount can\n * replay the same result without repeating the side effect.\n */\nexport function useStatewireClientToolBridge(\n options: UseStatewireClientToolBridgeOptions,\n): void {\n const { threadId, tracker, inputRequests, logLabel = '[AthenaSDK]' } = options;\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const toolNames = new Set(options.tools.map((tool) => tool.name));\n const pendingRequest = inputRequests?.find((request) => {\n if (!isPendingClientToolRequest(request)) return false;\n const payload = (request as StatewireThread.CustomInputRequest).payload;\n if (!isClientToolInterrupt(payload)) return false;\n // Every attached tab sees the same park. An observer without these tools\n // must not claim it and race the executing surface with an unknown-tool\n // error (for example, Olympus watching an Excel conversation).\n // A cached result already belongs to this tracker and can be replayed\n // without loading its handlers again.\n return (\n tracker.getCachedResume(clientToolClaimKey(threadId, request.id)) !== undefined ||\n payload.context.requests.every((call) => toolNames.has(call.tool_name))\n );\n });\n\n // Claims this bridge holds but has not resumed, split by whether their\n // batch has begun running handlers. The ref Set instances are stable (only\n // their contents mutate), so the unmount cleanup sees every claim.\n const ownedClaimsRef = useRef<Set<string>>(new Set());\n const startedClaimsRef = useRef<Set<string>>(new Set());\n const resumeOwnerRef = useRef(Symbol('client-tool-resume-owner'));\n const resumeClaimsRef = useRef<Set<string>>(new Set());\n const resumeTimersRef = useRef<\n Map<string, { requestId: string; timer: ReturnType<typeof setTimeout> }>\n >(new Map());\n const activeRef = useRef(true);\n const releaseClaim = useCallback(\n (claim: string) => {\n // Release the shared tracker entry only while THIS mount still owns it.\n // A detached batch can settle after the unmount cleanup already released\n // (and disowned) its claim; by then the tracker entry may belong to\n // another mount that claimed, executed, and resumed — releasing it here\n // would let a stale re-emission of the same request execute again.\n const owned = ownedClaimsRef.current.delete(claim);\n startedClaimsRef.current.delete(claim);\n if (owned) tracker.release(claim);\n },\n [tracker],\n );\n const stopResumeReplay = useCallback(\n (claim: string) => {\n const timerEntry = resumeTimersRef.current.get(claim);\n if (timerEntry) clearTimeout(timerEntry.timer);\n resumeTimersRef.current.delete(claim);\n if (resumeClaimsRef.current.delete(claim)) {\n tracker.releaseResumeReplay(claim, resumeOwnerRef.current);\n }\n },\n [tracker],\n );\n useEffect(() => {\n activeRef.current = true;\n const ownedClaims = ownedClaimsRef.current;\n const startedClaims = startedClaimsRef.current;\n return () => {\n activeRef.current = false;\n for (const claim of Array.from(resumeClaimsRef.current)) {\n stopResumeReplay(claim);\n }\n for (const claim of ownedClaims) {\n // Started batches keep their claim — their detached execution settles\n // it (resume, or release on a failed dispatch). Releasing here would\n // double-execute the side effects that already ran.\n if (startedClaims.has(claim)) continue;\n ownedClaims.delete(claim);\n tracker.release(claim);\n }\n };\n }, [stopResumeReplay, tracker]);\n\n // Handlers (and consent) are async, so the run can be stopped or the request\n // answered elsewhere while we await. The live ids let us abandon an\n // unfinished local execution when its request is no longer present. Once a\n // result is cached, only command settlement may stop its replay: Statewire\n // removes submitted requests optimistically before the host accepts them.\n const liveRequestIdsRef = useRef<ReadonlySet<string>>(new Set());\n liveRequestIdsRef.current = new Set((inputRequests ?? []).map((request) => request.id));\n\n const startResumeReplay = useCallback(\n (claim: string, requestId: string) => {\n if (!activeRef.current || resumeClaimsRef.current.has(claim)) return;\n if (!tracker.claimResumeReplay(claim, resumeOwnerRef.current)) return;\n resumeClaimsRef.current.add(claim);\n\n const dispatch = (): void => {\n resumeTimersRef.current.delete(claim);\n if (!activeRef.current) {\n stopResumeReplay(claim);\n return;\n }\n const attempt = tracker.takeResumeAttempt(claim, {\n owner: resumeOwnerRef.current,\n maxAttempts: MAX_CLIENT_TOOL_RESUME_ATTEMPTS,\n });\n if (!attempt) {\n stopResumeReplay(claim);\n return;\n }\n\n try {\n const settled = optionsRef.current.sendResume(requestId, attempt.value);\n // A fulfilled command result is the authoritative acknowledgement:\n // the host accepted and applied the answer. The local input request\n // disappearing is NOT an acknowledgement because the Statewire\n // reducer does that optimistically as soon as the command is\n // submitted.\n void Promise.resolve(settled).then(\n () => {\n // Keep the execution claim, but discard the cached result once\n // the host accepts it. A stale pending-request render can no\n // longer replay the command or re-execute the local mutation.\n tracker.settleResume(claim);\n stopResumeReplay(claim);\n },\n (error) => {\n // A rejected attempt may have raced another still-pending\n // replay. Keep the bounded loop alive; any accepted sibling\n // stops it, while the global attempt cap prevents storms.\n console.error(`${logLabel} failed to resume client tool results:`, error);\n },\n );\n } catch (error) {\n // Keep the cached result and retry it. Re-executing a mutating local\n // handler would be unsafe; replaying its id-stamped result is safe.\n console.error(`${logLabel} failed to resume client tool results:`, error);\n }\n\n if (\n attempt.attemptNumber >= MAX_CLIENT_TOOL_RESUME_ATTEMPTS ||\n !activeRef.current ||\n !resumeClaimsRef.current.has(claim)\n ) {\n stopResumeReplay(claim);\n return;\n }\n const timer = setTimeout(dispatch, clientToolResumeRetryDelayMs(attempt.attemptNumber));\n resumeTimersRef.current.set(claim, { requestId, timer });\n };\n\n dispatch();\n },\n [logLabel, stopResumeReplay, tracker],\n );\n\n const executeRequest = useCallback(\n async (request: StatewireThread.CustomInputRequest) => {\n const payload = request.payload;\n if (!isClientToolInterrupt(payload)) return;\n const claim = clientToolClaimKey(threadId, request.id);\n const {\n tools,\n confirmWrites,\n writeDeclinedMessage,\n missingToolMessage,\n onCallSettled,\n sendResume,\n } = optionsRef.current;\n\n const results = await executeClientToolBatch({\n calls: payload.context.requests,\n tools,\n // Live while the request still exists AND this surface may answer it:\n // mounted, or already past the point of no return (handlers started —\n // the detached execution must finish and settle, never re-execute).\n // After unmount the request-id snapshot freezes at its last observed\n // state, which keeps a started batch's own request visible to it.\n isLive: () =>\n liveRequestIdsRef.current.has(request.id) &&\n (activeRef.current || startedClaimsRef.current.has(claim)),\n onExecutionStart: () => {\n startedClaimsRef.current.add(claim);\n },\n ...(confirmWrites\n ? {\n confirmWrites: ({ writeToolNames }: { writeToolNames: readonly string[] }) =>\n confirmWrites({ requestId: request.id, writeToolNames }),\n }\n : {}),\n ...(writeDeclinedMessage !== undefined ? { writeDeclinedMessage } : {}),\n ...(missingToolMessage ? { missingToolMessage } : {}),\n ...(onCallSettled ? { onCallSettled } : {}),\n });\n if (results === null) {\n releaseClaim(claim);\n return;\n }\n\n const resumeValue = clientToolResultsResumeValue(results);\n tracker.cacheResume(claim, resumeValue);\n // Execution is complete, but the exactly-once claim remains. A pending\n // re-emission must replay this cached value, never run the handlers again.\n ownedClaimsRef.current.delete(claim);\n startedClaimsRef.current.delete(claim);\n\n if (!activeRef.current) {\n // The handler crossed an unmount. Preserve the pre-existing best-effort\n // settle through its captured transport, but leave the cached result\n // available for a later mount if this dispatch is lost.\n if (tracker.claimResumeReplay(claim, resumeOwnerRef.current)) {\n const attempt = tracker.takeResumeAttempt(claim, {\n owner: resumeOwnerRef.current,\n maxAttempts: MAX_CLIENT_TOOL_RESUME_ATTEMPTS,\n });\n if (attempt) {\n try {\n void Promise.resolve(sendResume(request.id, attempt.value)).then(\n () => tracker.settleResume(claim),\n (error) => {\n console.error(`${logLabel} failed to resume client tool results:`, error);\n },\n );\n } catch (error) {\n console.error(`${logLabel} failed to resume client tool results:`, error);\n }\n }\n // Ownership only fences this best-effort dispatch; a future mount\n // may claim and replay the cached value if it did not settle.\n tracker.releaseResumeReplay(claim, resumeOwnerRef.current);\n }\n return;\n }\n\n startResumeReplay(claim, request.id);\n },\n [logLabel, releaseClaim, startResumeReplay, threadId, tracker],\n );\n\n useEffect(() => {\n if (!pendingRequest) return;\n const claim = clientToolClaimKey(threadId, pendingRequest.id);\n if (!tracker.claim(claim)) {\n // The local handler already ran. This is the reconnect/remount path:\n // replay its cached answer instead of double-executing the side effect.\n if (tracker.getCachedResume(claim)) {\n startResumeReplay(claim, pendingRequest.id);\n }\n return;\n }\n ownedClaimsRef.current.add(claim);\n void executeRequest(pendingRequest);\n }, [executeRequest, pendingRequest, startResumeReplay, threadId, tracker]);\n}\n"],"names":["isClientToolInterrupt","clientToolErrorEnvelope","clientToolSuccessEnvelope","clientToolCallArgs","useRef","useCallback","useEffect","clientToolResultsResumeValue"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client-tool-bridge.cjs","sources":["../../../../agent-runtime/src/client-tool-bridge.ts"],"sourcesContent":["/**\n * The statewire client-tool bridge loop, shared by every surface that executes\n * frontend tool calls (Olympus, the React SDK, the Office add-in, mobile).\n *\n * Tools declared through `runConfig.custom.client_tools` have no backend\n * implementation: a call parks the run on an interrupt that arrives as a\n * statewire input request. A bridge with handlers for the whole batch claims\n * it (exactly-once per ownership domain), runs those handlers, and resumes\n * with per-call result envelopes. Other attached tabs leave it for the\n * executing surface; a thrown handler still returns an actionable error.\n *\n * Wire-adjacent correctness invariants this module owns, so they can never\n * drift apart per surface again:\n * - exactly-once claim per request, with un-claim on every path that did NOT\n * run any handler (abandoned before execution, consent dismissed, unmount\n * before the first handler) so a re-emitted request is executable instead\n * of stranding the run;\n * - once a batch has STARTED executing handlers, its claim is never released\n * by unmount: handlers cannot be cancelled, so releasing would let another\n * mount re-claim the re-emitted request and re-execute side effects that\n * already ran (double-executing a mutating tool). The completed wire-safe\n * result is cached and may be replayed across reconnects/remounts instead;\n * - liveness checks between awaits (the run can be stopped or answered\n * elsewhere while a handler runs) so a stale request is never resumed;\n * - per-call JSON wire-safety, so one unrepresentable handler result answers\n * that one call with an error instead of failing the whole batch.\n *\n * Like `interrupts.ts`, this is parameterized rather than self-wiring: the\n * host component reads `useStatewireRuns().inputRequests` and\n * `useStatewireSendCommand()` itself (both mockable per surface) and passes\n * them in, together with its ownership tracker and write-consent policy.\n */\n\nimport type { StatewireThread } from '@assistant-ui/react-statewire';\nimport { useCallback, useEffect, useRef } from 'react';\nimport {\n type ClientToolCallRequest,\n type ClientToolRequestTracker,\n type ClientToolResultEnvelope,\n clientToolCallArgs,\n clientToolErrorEnvelope,\n clientToolResultsResumeValue,\n clientToolSuccessEnvelope,\n isClientToolInterrupt,\n} from './client-tools';\n\n/** A locally executable tool, normalized across the per-surface tool shapes. */\nexport interface ClientToolBridgeTool {\n /** Snake_case tool id the model calls (e.g. `update_sheet_range`). */\n name: string;\n /** Mutating tools gate on the surface's write-consent flow (`confirmWrites`). */\n requiresWrite?: boolean;\n run: (\n args: Record<string, unknown>,\n context: { toolCallId: string },\n ) => Promise<unknown>;\n}\n\n/**\n * Batch write-consent outcome. `proceed` runs the write calls, `declined`\n * answers them with the declined message while reads still run, `abandoned`\n * releases the claim without resuming (the request died, or the consent UI was\n * dismissed by the run moving on). Grant persistence (a thread set, a stored\n * preference) is the surface's own policy, applied inside its callback.\n */\nexport type ClientToolWriteConsentDecision = 'proceed' | 'declined' | 'abandoned';\n\nexport interface ClientToolCallSettledEvent {\n toolName: string;\n status: 'success' | 'error' | 'declined';\n errorType?: string;\n}\n\n/** Default resume error for a write call the user declined. */\nexport const CLIENT_TOOL_WRITE_DECLINED_MESSAGE =\n 'The user declined this edit. Do not retry it; ask the user how to proceed.';\n\n/** Default resume error for a call naming a tool this surface does not have. */\nexport function defaultMissingClientToolMessage(toolName: string): string {\n return `This surface has no tool named '${toolName}'.`;\n}\n\n/** Statewire request ids are unique per run, but a thread scope keeps a\n * process-wide claim unambiguous when two conversations are open at once. */\nexport function clientToolClaimKey(threadId: string, requestId: string): string {\n return `${threadId}:${requestId}`;\n}\n\nconst CLIENT_TOOL_RESUME_RETRY_DELAYS_MS = [2_000, 5_000, 10_000, 15_000, 30_000];\nconst MAX_CLIENT_TOOL_RESUME_ATTEMPTS = 25;\n\nfunction clientToolResumeRetryDelayMs(attemptNumber: number): number {\n const index = Math.min(\n Math.max(attemptNumber - 1, 0),\n CLIENT_TOOL_RESUME_RETRY_DELAYS_MS.length - 1,\n );\n return CLIENT_TOOL_RESUME_RETRY_DELAYS_MS[index] ?? 30_000;\n}\n\n/**\n * A wire-safe copy of a handler's return value: handlers can return values\n * JSON cannot represent (DOM nodes, host objects, bigints), which must never\n * reach the transport. Throws for an unrepresentable value so the caller can\n * answer that one call with an error instead of stranding the whole batch.\n */\nexport function jsonSafeClientToolResult(value: unknown): unknown {\n const serialized = JSON.stringify(value);\n return serialized === undefined ? null : JSON.parse(serialized);\n}\n\n/** A parked, unanswered client-tool input request. */\nexport function isPendingClientToolRequest(\n request: StatewireThread.InputRequestState,\n): request is StatewireThread.CustomInputRequest {\n if (request.type !== 'interrupt' || 'response' in request) return false;\n return isClientToolInterrupt((request as { payload?: unknown }).payload);\n}\n\nexport interface ExecuteClientToolBatchOptions {\n calls: readonly ClientToolCallRequest[];\n tools: readonly ClientToolBridgeTool[];\n /** Whether the parked request still exists and this surface may answer it.\n * Checked before consent resolution, before every call, and before the\n * results are handed back for resume. */\n isLive: () => boolean;\n /** Batch write gate; absent means writes run without consent (surfaces that\n * only register read tools). Called once per batch, before any handler. */\n confirmWrites?: (batch: {\n writeToolNames: readonly string[];\n }) => Promise<ClientToolWriteConsentDecision>;\n writeDeclinedMessage?: string;\n missingToolMessage?: (toolName: string) => string;\n /** Per-call telemetry (the Office add-in's tool events). */\n onCallSettled?: (event: ClientToolCallSettledEvent) => void;\n /**\n * Called once, after the write-consent gate resolves and immediately before\n * the first handler runs — the point where side effects begin. There is no\n * await between this callback and the first handler invocation, so a caller\n * marking \"execution started\" here can never miss a handler that ran.\n */\n onExecutionStart?: () => void;\n}\n\n/**\n * Execute one batched client-tool park: consent, per-call execution with\n * wire-safe envelopes, liveness aborts. Returns the per-interrupt result map\n * to resume with, or `null` when the batch was abandoned (the request died,\n * consent was abandoned, or the surface went away) — the caller must release\n * its claim and must NOT resume.\n */\nexport async function executeClientToolBatch(\n options: ExecuteClientToolBatchOptions,\n): Promise<Record<string, ClientToolResultEnvelope> | null> {\n const {\n calls,\n tools,\n isLive,\n confirmWrites,\n writeDeclinedMessage = CLIENT_TOOL_WRITE_DECLINED_MESSAGE,\n missingToolMessage = defaultMissingClientToolMessage,\n onCallSettled,\n onExecutionStart,\n } = options;\n const registry = new Map(tools.map((tool) => [tool.name, tool]));\n\n // One consent covers the whole batch (and whatever scope the surface's\n // callback persists): writes are declined together while reads still run.\n let writesDeclined = false;\n const writeToolNames = calls\n .filter((call) => registry.get(call.tool_name)?.requiresWrite === true)\n .map((call) => call.tool_name);\n if (writeToolNames.length > 0 && confirmWrites) {\n const decision = await confirmWrites({ writeToolNames });\n if (decision === 'abandoned' || !isLive()) {\n // The run was stopped (or answered elsewhere) while consent was\n // pending: abort before any handler mutates the user's asset.\n return null;\n }\n writesDeclined = decision === 'declined';\n }\n\n onExecutionStart?.();\n\n const results: Record<string, ClientToolResultEnvelope> = {};\n for (const call of calls) {\n if (!isLive()) return null;\n const tool = registry.get(call.tool_name);\n let envelope: ClientToolResultEnvelope;\n let status: ClientToolCallSettledEvent['status'] = 'success';\n let errorType: string | undefined;\n if (!tool) {\n envelope = clientToolErrorEnvelope(missingToolMessage(call.tool_name));\n status = 'error';\n errorType = 'UnknownClientTool';\n } else if (tool.requiresWrite === true && writesDeclined) {\n envelope = clientToolErrorEnvelope(writeDeclinedMessage);\n status = 'declined';\n } else {\n try {\n envelope = clientToolSuccessEnvelope(\n jsonSafeClientToolResult(\n await tool.run(clientToolCallArgs(call), {\n toolCallId: call.interrupt_id,\n }),\n ),\n );\n } catch (error) {\n envelope = clientToolErrorEnvelope(error);\n status = 'error';\n errorType = error instanceof Error ? error.name : typeof error;\n }\n }\n results[call.interrupt_id] = envelope;\n onCallSettled?.({\n toolName: call.tool_name,\n status,\n ...(errorType !== undefined ? { errorType } : {}),\n });\n }\n\n // Abandoned mid-flight: resuming a dead request would error, and a\n // re-emitted one must be executable again.\n return isLive() ? results : null;\n}\n\nexport interface UseStatewireClientToolBridgeOptions {\n threadId: string;\n tools: readonly ClientToolBridgeTool[];\n /**\n * Ownership domain for parked-request claims. Pass a module-scoped tracker\n * to make ownership process-wide across every mount of the surface (two\n * mounted surfaces of one conversation execute each request exactly once),\n * or a per-mount tracker to scope ownership to one mounted bridge.\n */\n tracker: ClientToolRequestTracker;\n /** The surface's `useStatewireRuns().inputRequests` read. */\n inputRequests: readonly StatewireThread.InputRequestState[] | undefined;\n /** Dispatch the `run/input` resume on the surface's transport. The value is\n * already wire-safe (per-call JSON round-trip inside the batch engine). */\n /** Dispatch the answer and settle only once the Statewire host accepts or\n * rejects the command. The bridge deliberately keeps replaying while this\n * promise is pending: `run/input` removes the request optimistically before\n * the server has accepted the answer. */\n sendResume: (\n requestId: string,\n value: Record<string, unknown>,\n ) => PromiseLike<unknown>;\n /** Batch write gate, with the parked request's id so the surface can close\n * its consent UI the instant that request disappears. */\n confirmWrites?: (batch: {\n requestId: string;\n writeToolNames: readonly string[];\n }) => Promise<ClientToolWriteConsentDecision>;\n writeDeclinedMessage?: string;\n missingToolMessage?: (toolName: string) => string;\n onCallSettled?: (event: ClientToolCallSettledEvent) => void;\n /** Log prefix for resume-dispatch failures. */\n logLabel?: string;\n}\n\n/**\n * The claim lifecycle around {@link executeClientToolBatch}: claim the pending\n * request once per ownership domain, execute, resume — releasing the claim on\n * every path that ran no handler, so re-emitted requests recover.\n *\n * Unmount splits by whether side effects began:\n * - a claim whose batch has NOT started executing (claimed this tick, or\n * parked on write consent) is released, so another mount — or a remount —\n * can execute the re-emitted request instead of stranding the parked run;\n * - a claim whose batch HAS started stays held: handlers cannot be cancelled,\n * so releasing would let a sibling mount re-claim and re-execute a mutation\n * whose side effects already ran. The detached execution caches its result\n * and attempts one resume through its captured transport; a later mount can\n * replay the same result without repeating the side effect.\n */\nexport function useStatewireClientToolBridge(\n options: UseStatewireClientToolBridgeOptions,\n): void {\n const { threadId, tracker, inputRequests, logLabel = '[AthenaSDK]' } = options;\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const toolNames = new Set(options.tools.map((tool) => tool.name));\n const pendingRequest = inputRequests?.find((request) => {\n if (!isPendingClientToolRequest(request)) return false;\n const payload = (request as StatewireThread.CustomInputRequest).payload;\n if (!isClientToolInterrupt(payload)) return false;\n // Every attached tab sees the same park. An observer without these tools\n // must not claim it and race the executing surface with an unknown-tool\n // error (for example, Olympus watching an Excel conversation).\n // A cached result already belongs to this tracker and can be replayed\n // without loading its handlers again.\n return (\n tracker.getCachedResume(clientToolClaimKey(threadId, request.id)) !== undefined ||\n payload.context.requests.every((call) => toolNames.has(call.tool_name))\n );\n });\n\n // Claims this bridge holds but has not resumed, split by whether their\n // batch has begun running handlers. The ref Set instances are stable (only\n // their contents mutate), so the unmount cleanup sees every claim.\n const ownedClaimsRef = useRef<Set<string>>(new Set());\n const startedClaimsRef = useRef<Set<string>>(new Set());\n const resumeOwnerRef = useRef(Symbol('client-tool-resume-owner'));\n const resumeClaimsRef = useRef<Set<string>>(new Set());\n const resumeTimersRef = useRef<\n Map<string, { requestId: string; timer: ReturnType<typeof setTimeout> }>\n >(new Map());\n const activeRef = useRef(true);\n const releaseClaim = useCallback(\n (claim: string) => {\n // Release the shared tracker entry only while THIS mount still owns it.\n // A detached batch can settle after the unmount cleanup already released\n // (and disowned) its claim; by then the tracker entry may belong to\n // another mount that claimed, executed, and resumed — releasing it here\n // would let a stale re-emission of the same request execute again.\n const owned = ownedClaimsRef.current.delete(claim);\n startedClaimsRef.current.delete(claim);\n if (owned) tracker.release(claim);\n },\n [tracker],\n );\n const stopResumeReplay = useCallback(\n (claim: string) => {\n const timerEntry = resumeTimersRef.current.get(claim);\n if (timerEntry) clearTimeout(timerEntry.timer);\n resumeTimersRef.current.delete(claim);\n if (resumeClaimsRef.current.delete(claim)) {\n tracker.releaseResumeReplay(claim, resumeOwnerRef.current);\n }\n },\n [tracker],\n );\n useEffect(() => {\n activeRef.current = true;\n const ownedClaims = ownedClaimsRef.current;\n const startedClaims = startedClaimsRef.current;\n return () => {\n activeRef.current = false;\n for (const claim of Array.from(resumeClaimsRef.current)) {\n stopResumeReplay(claim);\n }\n for (const claim of ownedClaims) {\n // Started batches keep their claim — their detached execution settles\n // it (resume, or release on a failed dispatch). Releasing here would\n // double-execute the side effects that already ran.\n if (startedClaims.has(claim)) continue;\n ownedClaims.delete(claim);\n tracker.release(claim);\n }\n };\n }, [stopResumeReplay, tracker]);\n\n // Handlers (and consent) are async, so the run can be stopped or the request\n // answered elsewhere while we await. The live ids let us abandon an\n // unfinished local execution when its request is no longer present. Once a\n // result is cached, only command settlement may stop its replay: Statewire\n // removes submitted requests optimistically before the host accepts them.\n const liveRequestIdsRef = useRef<ReadonlySet<string>>(new Set());\n liveRequestIdsRef.current = new Set((inputRequests ?? []).map((request) => request.id));\n\n const startResumeReplay = useCallback(\n (claim: string, requestId: string) => {\n if (!activeRef.current || resumeClaimsRef.current.has(claim)) return;\n if (!tracker.claimResumeReplay(claim, resumeOwnerRef.current)) return;\n resumeClaimsRef.current.add(claim);\n\n const dispatch = (): void => {\n resumeTimersRef.current.delete(claim);\n if (!activeRef.current) {\n stopResumeReplay(claim);\n return;\n }\n const attempt = tracker.takeResumeAttempt(claim, {\n owner: resumeOwnerRef.current,\n maxAttempts: MAX_CLIENT_TOOL_RESUME_ATTEMPTS,\n });\n if (!attempt) {\n stopResumeReplay(claim);\n return;\n }\n\n try {\n const settled = optionsRef.current.sendResume(requestId, attempt.value);\n // A fulfilled command result is the authoritative acknowledgement:\n // the host accepted and applied the answer. The local input request\n // disappearing is NOT an acknowledgement because the Statewire\n // reducer does that optimistically as soon as the command is\n // submitted.\n void Promise.resolve(settled).then(\n () => {\n // Keep the execution claim, but discard the cached result once\n // the host accepts it. A stale pending-request render can no\n // longer replay the command or re-execute the local mutation.\n tracker.settleResume(claim);\n stopResumeReplay(claim);\n },\n (error) => {\n // A rejected attempt may have raced another still-pending\n // replay. Keep the bounded loop alive; any accepted sibling\n // stops it, while the global attempt cap prevents storms.\n console.error(`${logLabel} failed to resume client tool results:`, error);\n },\n );\n } catch (error) {\n // Keep the cached result and retry it. Re-executing a mutating local\n // handler would be unsafe; replaying its id-stamped result is safe.\n console.error(`${logLabel} failed to resume client tool results:`, error);\n }\n\n if (\n attempt.attemptNumber >= MAX_CLIENT_TOOL_RESUME_ATTEMPTS ||\n !activeRef.current ||\n !resumeClaimsRef.current.has(claim)\n ) {\n stopResumeReplay(claim);\n return;\n }\n const timer = setTimeout(dispatch, clientToolResumeRetryDelayMs(attempt.attemptNumber));\n resumeTimersRef.current.set(claim, { requestId, timer });\n };\n\n dispatch();\n },\n [logLabel, stopResumeReplay, tracker],\n );\n\n const executeRequest = useCallback(\n async (request: StatewireThread.CustomInputRequest) => {\n const payload = request.payload;\n if (!isClientToolInterrupt(payload)) return;\n const claim = clientToolClaimKey(threadId, request.id);\n const {\n tools,\n confirmWrites,\n writeDeclinedMessage,\n missingToolMessage,\n onCallSettled,\n sendResume,\n } = optionsRef.current;\n\n const results = await executeClientToolBatch({\n calls: payload.context.requests,\n tools,\n // Live while the request still exists AND this surface may answer it:\n // mounted, or already past the point of no return (handlers started —\n // the detached execution must finish and settle, never re-execute).\n // After unmount the request-id snapshot freezes at its last observed\n // state, which keeps a started batch's own request visible to it.\n isLive: () =>\n liveRequestIdsRef.current.has(request.id) &&\n (activeRef.current || startedClaimsRef.current.has(claim)),\n onExecutionStart: () => {\n startedClaimsRef.current.add(claim);\n },\n ...(confirmWrites\n ? {\n confirmWrites: ({ writeToolNames }: { writeToolNames: readonly string[] }) =>\n confirmWrites({ requestId: request.id, writeToolNames }),\n }\n : {}),\n ...(writeDeclinedMessage !== undefined ? { writeDeclinedMessage } : {}),\n ...(missingToolMessage ? { missingToolMessage } : {}),\n ...(onCallSettled ? { onCallSettled } : {}),\n });\n if (results === null) {\n releaseClaim(claim);\n return;\n }\n\n const resumeValue = clientToolResultsResumeValue(results);\n tracker.cacheResume(claim, resumeValue);\n // Execution is complete, but the exactly-once claim remains. A pending\n // re-emission must replay this cached value, never run the handlers again.\n ownedClaimsRef.current.delete(claim);\n startedClaimsRef.current.delete(claim);\n\n if (!activeRef.current) {\n // The handler crossed an unmount. Preserve the pre-existing best-effort\n // settle through its captured transport, but leave the cached result\n // available for a later mount if this dispatch is lost.\n if (tracker.claimResumeReplay(claim, resumeOwnerRef.current)) {\n const attempt = tracker.takeResumeAttempt(claim, {\n owner: resumeOwnerRef.current,\n maxAttempts: MAX_CLIENT_TOOL_RESUME_ATTEMPTS,\n });\n if (attempt) {\n try {\n void Promise.resolve(sendResume(request.id, attempt.value)).then(\n () => tracker.settleResume(claim),\n (error) => {\n console.error(`${logLabel} failed to resume client tool results:`, error);\n },\n );\n } catch (error) {\n console.error(`${logLabel} failed to resume client tool results:`, error);\n }\n }\n // Ownership only fences this best-effort dispatch; a future mount\n // may claim and replay the cached value if it did not settle.\n tracker.releaseResumeReplay(claim, resumeOwnerRef.current);\n }\n return;\n }\n\n startResumeReplay(claim, request.id);\n },\n [logLabel, releaseClaim, startResumeReplay, threadId, tracker],\n );\n\n useEffect(() => {\n if (!pendingRequest) return;\n const claim = clientToolClaimKey(threadId, pendingRequest.id);\n if (!tracker.claim(claim)) {\n // The local handler already ran. This is the reconnect/remount path:\n // replay its cached answer instead of double-executing the side effect.\n if (tracker.getCachedResume(claim)) {\n startResumeReplay(claim, pendingRequest.id);\n }\n return;\n }\n ownedClaimsRef.current.add(claim);\n void executeRequest(pendingRequest);\n }, [executeRequest, pendingRequest, startResumeReplay, threadId, tracker]);\n}\n"],"names":["isClientToolInterrupt","clientToolErrorEnvelope","clientToolSuccessEnvelope","clientToolCallArgs","useRef","useCallback","useEffect","clientToolResultsResumeValue"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const tap = require("@assistant-ui/tap");
|
|
4
|
-
const
|
|
4
|
+
const require$$0 = require("react");
|
|
5
5
|
const statewire = require("statewire");
|
|
6
6
|
const authDenial = require("./auth-denial.cjs");
|
|
7
7
|
const errors = require("./errors.cjs");
|
|
@@ -25,13 +25,13 @@ function useConversationIndex({
|
|
|
25
25
|
enabled = true
|
|
26
26
|
}) {
|
|
27
27
|
var _a, _b, _c, _d;
|
|
28
|
-
const headersRef =
|
|
28
|
+
const headersRef = require$$0.useRef(headers);
|
|
29
29
|
headersRef.current = headers;
|
|
30
30
|
const indexId = conversationIndexId({ workspaceId, userId });
|
|
31
|
-
const [parked, setParked] =
|
|
31
|
+
const [parked, setParked] = require$$0.useState(
|
|
32
32
|
null
|
|
33
33
|
);
|
|
34
|
-
const denialRef =
|
|
34
|
+
const denialRef = require$$0.useRef({ indexId, state: authDenial.initialAuthDenialTrackerState() });
|
|
35
35
|
if (denialRef.current.indexId !== indexId) {
|
|
36
36
|
denialRef.current = { indexId, state: authDenial.initialAuthDenialTrackerState() };
|
|
37
37
|
}
|
|
@@ -64,16 +64,16 @@ function useConversationIndex({
|
|
|
64
64
|
denialRef.current.state = denial.state;
|
|
65
65
|
const shouldPark = denial.park;
|
|
66
66
|
const parkMessage = denial.state.message;
|
|
67
|
-
|
|
67
|
+
require$$0.useEffect(() => {
|
|
68
68
|
if (!enabled || !shouldPark) return;
|
|
69
69
|
setParked(
|
|
70
70
|
(prev) => (prev == null ? void 0 : prev.indexId) === indexId ? prev : { indexId, message: parkMessage }
|
|
71
71
|
);
|
|
72
72
|
}, [enabled, shouldPark, parkMessage, indexId]);
|
|
73
|
-
const commandsRef =
|
|
73
|
+
const commandsRef = require$$0.useRef(client.commands);
|
|
74
74
|
commandsRef.current = client.commands;
|
|
75
|
-
const refresh =
|
|
76
|
-
const loadMore =
|
|
75
|
+
const refresh = require$$0.useCallback(() => commandsRef.current.refresh(), []);
|
|
76
|
+
const loadMore = require$$0.useCallback(() => commandsRef.current.load_more(), []);
|
|
77
77
|
return {
|
|
78
78
|
entries: ((_a = client.state) == null ? void 0 : _a.conversations) ?? null,
|
|
79
79
|
hasNextPage: ((_b = client.state) == null ? void 0 : _b.has_more) ?? false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-index.cjs","sources":["../../../../agent-runtime/src/conversation-index.ts"],"sourcesContent":["import { withKey } from '@assistant-ui/tap';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useStatewire, type StatewireClient } from 'statewire';\nimport { initialAuthDenialTrackerState, observeAuthDenial } from './auth-denial';\nimport type { ConversationAttention, ConversationAttentionSource } from './conversation-list';\nimport { projectDeepAgentConnection } from './errors';\nimport { StatewireSuspended } from './statewire-suspended';\nimport { statewireTransport } from './statewire-transport';\nimport type { DeepAgentHeadersResolver } from './use-deep-agent-thread';\n\n/**\n * Client side of the conversation-index statewire (issue #29088): agora\n * replicates the newest page of one viewer's conversation list as one state\n * object, so thread creation / lifecycle / title changes arrive as ops\n * instead of newest-page polling. The replicated rows are renderable and the\n * typed commands extend or refresh the inclusive window; reconnects are free\n * because the protocol's snapshot-first attach IS the newest-page reconcile.\n *\n * A viewer is a `(workspaceId, userId)` pair and every pair is its own\n * instance (`/conversation-index/<workspaceId>-<userId>`): workspaces are\n * tenants, so a tab in one workspace never shares a window with a tab in\n * another, and switching workspaces attaches to a different instance instead\n * of retagging the one other tabs are still reading.\n */\nexport interface ConversationIndexEntry {\n thread_id: string;\n title: string;\n updated_at: string;\n state: string | null;\n runtime: string | null;\n start_channel: string | null;\n asset_type: string;\n asset_id: string | null;\n app_id: string | null;\n trigger_type: string | null;\n last_message_preview: string | null;\n message_count: number | null;\n is_unread: boolean | null;\n /**\n * Canonical status_v2 planes, present once the publishing agora reports them\n * (absent from snapshots replicated by an older pod during a rollout).\n */\n session_status?: string | null;\n run_status?: string | null;\n /**\n * The viewer's attention state and its one-line next action, present once\n * the publishing agora derives them (absent from snapshots replicated by\n * an older pod). Pull-request state is never pushed — it rides the list\n * fetch only (`include_pull_requests`).\n */\n attention?: ConversationAttention | null;\n next_action?: string | null;\n attention_source?: ConversationAttentionSource | null;\n is_favorited?: boolean | null;\n}\n\n/**\n * When one of this viewer's own asset subscriptions on a thread last queued or\n * settled an event: thread id → ISO instant. A contentless \"re-read now\" for\n * Olympus's Watching card, which reads what changed through its own gated\n * query; it never says what changed, who changed it, or where. Absent from an\n * older agora's snapshot.\n */\nexport type ConversationWatchActivity = Readonly<Record<string, string>>;\n\ninterface ConversationIndexState {\n conversations?: ConversationIndexEntry[];\n has_more?: boolean;\n total_count?: number;\n watch_activity?: ConversationWatchActivity;\n}\n\ninterface ConversationIndexCommands {\n [key: string]: (...args: never[]) => unknown;\n refresh(): void;\n load_more(): void;\n}\n\nexport interface UseConversationIndexOptions {\n /** Base URL of the conversation-index host (the `…/v2/conversation-index` mount). */\n baseUrl: string;\n /** The workspace being viewed — half of the instance id. Callers gate mounting on it. */\n workspaceId: string;\n /** The signed-in user's id — the other half. Callers gate mounting on it. */\n userId: string;\n /** Transport selection: SSE when true, WebSocket otherwise. */\n sse?: boolean;\n headers: DeepAgentHeadersResolver;\n /** Park the transport until the caller has a resolved principal. */\n enabled?: boolean;\n}\n\nexport interface UseConversationIndexResult {\n /** Newest-page entries, or `null` until the attach snapshot applies. */\n entries: ConversationIndexEntry[] | null;\n hasNextPage: boolean;\n totalCount: number | null;\n /**\n * The viewer's watch-activity stamps (see {@link ConversationWatchActivity});\n * `null` until the snapshot applies or when the host does not send them.\n */\n watchActivity: ConversationWatchActivity | null;\n connection: StatewireClient.Connection;\n refresh: () => Promise<void>;\n loadMore: () => Promise<void>;\n}\n\n/** The conversation-index host is mounted beside the threads host. */\nexport function conversationIndexUrlFromStatewireUrl(statewireUrl: string): string {\n return statewireUrl.replace(/\\/threads\\/?$/, '/conversation-index');\n}\n\n/** Instance id of one viewer's index; mirrors agora's `conversation_index_id`. */\nexport function conversationIndexId({\n workspaceId,\n userId,\n}: {\n workspaceId: string;\n userId: string;\n}): string {\n return `${workspaceId}-${userId}`;\n}\n\n/**\n * Attach to the live conversation index of one `(workspace, user)` viewer.\n */\nexport function useConversationIndex({\n baseUrl,\n workspaceId,\n userId,\n sse = false,\n headers,\n enabled = true,\n}: UseConversationIndexOptions): UseConversationIndexResult {\n const headersRef = useRef(headers);\n headersRef.current = headers;\n const indexId = conversationIndexId({ workspaceId, userId });\n // Auth-denial park (same policy as the thread transport): the index is a\n // pure push signal, so after a streak of `unauthorized` denials the retry\n // loop stops instead of hammering the attach endpoint every 30s for as long\n // as the tab lives. A remount or the parked connection's `reconnect()`\n // re-arms it.\n const [parked, setParked] = useState<{ indexId: string; message: string | undefined } | null>(\n null\n );\n const denialRef = useRef({ indexId, state: initialAuthDenialTrackerState() });\n if (denialRef.current.indexId !== indexId) {\n denialRef.current = { indexId, state: initialAuthDenialTrackerState() };\n }\n const isParked = parked !== null && parked.indexId === indexId;\n const client = useStatewire<ConversationIndexState | undefined, ConversationIndexCommands>({\n transport: withKey(\n indexId,\n !enabled || isParked\n ? StatewireSuspended<ConversationIndexCommands>({\n message:\n parked?.message ??\n (enabled\n ? 'Conversation index authorization was refused.'\n : 'Conversation index is waiting for a signed-in user and workspace.'),\n ...(enabled\n ? {\n onReconnectRequested: () => {\n denialRef.current = { indexId, state: initialAuthDenialTrackerState() };\n setParked(null);\n },\n }\n : {}),\n })\n : statewireTransport<ConversationIndexState, ConversationIndexCommands>(\n {\n url: `${baseUrl.replace(/\\/+$/, '')}/${encodeURIComponent(indexId)}`,\n headers: (ctx: { staleAuth: boolean }) => headersRef.current(ctx),\n },\n { sse }\n )\n ),\n initialState: undefined,\n });\n // Observing during render is idempotent (the tracker dedupes by attempt\n // number), so a re-render of the same connection state cannot double-count.\n // The tracker consumes the projected vocabulary, never the raw connection.\n const denial = observeAuthDenial(\n denialRef.current.state,\n projectDeepAgentConnection(client.connection)\n );\n denialRef.current.state = denial.state;\n const shouldPark = denial.park;\n const parkMessage = denial.state.message;\n useEffect(() => {\n if (!enabled || !shouldPark) return;\n setParked((prev) =>\n prev?.indexId === indexId ? prev : { indexId, message: parkMessage }\n );\n }, [enabled, shouldPark, parkMessage, indexId]);\n const commandsRef = useRef(client.commands);\n commandsRef.current = client.commands;\n const refresh = useCallback(() => commandsRef.current.refresh(), []);\n const loadMore = useCallback(() => commandsRef.current.load_more(), []);\n return {\n entries: client.state?.conversations ?? null,\n hasNextPage: client.state?.has_more ?? false,\n totalCount: client.state?.total_count ?? null,\n watchActivity: client.state?.watch_activity ?? null,\n connection: client.connection,\n refresh,\n loadMore,\n };\n}\n\n/**\n * Stable change fingerprint over a snapshot's watch-activity stamps: the\n * well-formed `[threadId, instant]` pairs, sorted by thread. An empty string\n * means \"nothing sent yet\" (no snapshot, or a host that predates the stamps),\n * so an effect keyed on it skips; an applied-but-empty map is `'[]'`.\n */\nexport function watchActivityFingerprint(activity: unknown): string {\n if (activity === null || typeof activity !== 'object' || Array.isArray(activity)) return '';\n return JSON.stringify(\n Object.entries(activity)\n .filter((entry): entry is [string, string] => typeof entry[1] === 'string')\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n );\n}\n\n/**\n * Stable change fingerprint over the entries a list surface reacts to. An\n * empty string means \"no snapshot yet\" — effects keyed on the fingerprint\n * should treat it as a no-op rather than an empty list. An applied-but-empty\n * snapshot serializes to `'[]'`, so deleting the last conversation still\n * changes the fingerprint. JSON-encoding keeps arbitrary titles from\n * colliding across field or entry boundaries.\n */\nexport function conversationIndexFingerprint(\n entries: ConversationIndexEntry[] | null\n): string {\n if (entries === null) return '';\n return JSON.stringify(\n entries.map((entry) => [\n entry.thread_id,\n entry.updated_at,\n entry.state,\n entry.title,\n entry.run_status ?? null,\n entry.is_unread ?? null,\n entry.attention ?? null,\n entry.next_action ?? null,\n entry.attention_source ?? null,\n entry.is_favorited ?? null,\n ])\n );\n}\n"],"names":["useRef","useState","initialAuthDenialTrackerState","useStatewire","withKey","StatewireSuspended","statewireTransport","observeAuthDenial","projectDeepAgentConnection","useEffect","useCallback"],"mappings":";;;;;;;;;AA4GO,SAAS,qCAAqC,cAA8B;AACjF,SAAO,aAAa,QAAQ,iBAAiB,qBAAqB;AACpE;AAGO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGW;AACT,SAAO,GAAG,WAAW,IAAI,MAAM;AACjC;AAKO,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA,UAAU;AACZ,GAA4D;;AAC1D,QAAM,aAAaA,MAAAA,OAAO,OAAO;AACjC,aAAW,UAAU;AACrB,QAAM,UAAU,oBAAoB,EAAE,aAAa,QAAQ;AAM3D,QAAM,CAAC,QAAQ,SAAS,IAAIC,MAAAA;AAAAA,IAC1B;AAAA,EAAA;AAEF,QAAM,YAAYD,MAAAA,OAAO,EAAE,SAAS,OAAOE,WAAAA,8BAAA,GAAiC;AAC5E,MAAI,UAAU,QAAQ,YAAY,SAAS;AACzC,cAAU,UAAU,EAAE,SAAS,OAAOA,WAAAA,gCAA8B;AAAA,EACtE;AACA,QAAM,WAAW,WAAW,QAAQ,OAAO,YAAY;AACvD,QAAM,SAASC,UAAAA,aAA4E;AAAA,IACzF,WAAWC,IAAAA;AAAAA,MACT;AAAA,MACA,CAAC,WAAW,WACRC,sCAA8C;AAAA,QAC5C,UACE,iCAAQ,aACP,UACG,kDACA;AAAA,QACN,GAAI,UACA;AAAA,UACE,sBAAsB,MAAM;AAC1B,sBAAU,UAAU,EAAE,SAAS,OAAOH,WAAAA,gCAA8B;AACpE,sBAAU,IAAI;AAAA,UAChB;AAAA,QAAA,IAEF,CAAA;AAAA,MAAC,CACN,IACDI,mBAAAA;AAAAA,QACE;AAAA,UACE,KAAK,GAAG,QAAQ,QAAQ,QAAQ,EAAE,CAAC,IAAI,mBAAmB,OAAO,CAAC;AAAA,UAClE,SAAS,CAAC,QAAgC,WAAW,QAAQ,GAAG;AAAA,QAAA;AAAA,QAElE,EAAE,IAAA;AAAA,MAAI;AAAA,IACR;AAAA,IAEN,cAAc;AAAA,EAAA,CACf;AAID,QAAM,SAASC,WAAAA;AAAAA,IACb,UAAU,QAAQ;AAAA,IAClBC,OAAAA,2BAA2B,OAAO,UAAU;AAAA,EAAA;AAE9C,YAAU,QAAQ,QAAQ,OAAO;AACjC,QAAM,aAAa,OAAO;AAC1B,QAAM,cAAc,OAAO,MAAM;AACjCC,QAAAA,UAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,WAAY;AAC7B;AAAA,MAAU,CAAC,UACT,6BAAM,aAAY,UAAU,OAAO,EAAE,SAAS,SAAS,YAAA;AAAA,IAAY;AAAA,EAEvE,GAAG,CAAC,SAAS,YAAY,aAAa,OAAO,CAAC;AAC9C,QAAM,cAAcT,MAAAA,OAAO,OAAO,QAAQ;AAC1C,cAAY,UAAU,OAAO;AAC7B,QAAM,UAAUU,MAAAA,YAAY,MAAM,YAAY,QAAQ,QAAA,GAAW,EAAE;AACnE,QAAM,WAAWA,MAAAA,YAAY,MAAM,YAAY,QAAQ,UAAA,GAAa,EAAE;AACtE,SAAO;AAAA,IACL,WAAS,YAAO,UAAP,mBAAc,kBAAiB;AAAA,IACxC,eAAa,YAAO,UAAP,mBAAc,aAAY;AAAA,IACvC,cAAY,YAAO,UAAP,mBAAc,gBAAe;AAAA,IACzC,iBAAe,YAAO,UAAP,mBAAc,mBAAkB;AAAA,IAC/C,YAAY,OAAO;AAAA,IACnB;AAAA,IACA;AAAA,EAAA;AAEJ;;;;"}
|
|
1
|
+
{"version":3,"file":"conversation-index.cjs","sources":["../../../../agent-runtime/src/conversation-index.ts"],"sourcesContent":["import { withKey } from '@assistant-ui/tap';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useStatewire, type StatewireClient } from 'statewire';\nimport { initialAuthDenialTrackerState, observeAuthDenial } from './auth-denial';\nimport type { ConversationAttention, ConversationAttentionSource } from './conversation-list';\nimport { projectDeepAgentConnection } from './errors';\nimport { StatewireSuspended } from './statewire-suspended';\nimport { statewireTransport } from './statewire-transport';\nimport type { DeepAgentHeadersResolver } from './use-deep-agent-thread';\n\n/**\n * Client side of the conversation-index statewire (issue #29088): agora\n * replicates the newest page of one viewer's conversation list as one state\n * object, so thread creation / lifecycle / title changes arrive as ops\n * instead of newest-page polling. The replicated rows are renderable and the\n * typed commands extend or refresh the inclusive window; reconnects are free\n * because the protocol's snapshot-first attach IS the newest-page reconcile.\n *\n * A viewer is a `(workspaceId, userId)` pair and every pair is its own\n * instance (`/conversation-index/<workspaceId>-<userId>`): workspaces are\n * tenants, so a tab in one workspace never shares a window with a tab in\n * another, and switching workspaces attaches to a different instance instead\n * of retagging the one other tabs are still reading.\n */\nexport interface ConversationIndexEntry {\n thread_id: string;\n title: string;\n updated_at: string;\n state: string | null;\n runtime: string | null;\n start_channel: string | null;\n asset_type: string;\n asset_id: string | null;\n app_id: string | null;\n trigger_type: string | null;\n last_message_preview: string | null;\n message_count: number | null;\n is_unread: boolean | null;\n /**\n * Canonical status_v2 planes, present once the publishing agora reports them\n * (absent from snapshots replicated by an older pod during a rollout).\n */\n session_status?: string | null;\n run_status?: string | null;\n /**\n * The viewer's attention state and its one-line next action, present once\n * the publishing agora derives them (absent from snapshots replicated by\n * an older pod). Pull-request state is never pushed — it rides the list\n * fetch only (`include_pull_requests`).\n */\n attention?: ConversationAttention | null;\n next_action?: string | null;\n attention_source?: ConversationAttentionSource | null;\n is_favorited?: boolean | null;\n}\n\n/**\n * When one of this viewer's own asset subscriptions on a thread last queued or\n * settled an event: thread id → ISO instant. A contentless \"re-read now\" for\n * Olympus's Watching card, which reads what changed through its own gated\n * query; it never says what changed, who changed it, or where. Absent from an\n * older agora's snapshot.\n */\nexport type ConversationWatchActivity = Readonly<Record<string, string>>;\n\ninterface ConversationIndexState {\n conversations?: ConversationIndexEntry[];\n has_more?: boolean;\n total_count?: number;\n watch_activity?: ConversationWatchActivity;\n}\n\ninterface ConversationIndexCommands {\n [key: string]: (...args: never[]) => unknown;\n refresh(): void;\n load_more(): void;\n}\n\nexport interface UseConversationIndexOptions {\n /** Base URL of the conversation-index host (the `…/v2/conversation-index` mount). */\n baseUrl: string;\n /** The workspace being viewed — half of the instance id. Callers gate mounting on it. */\n workspaceId: string;\n /** The signed-in user's id — the other half. Callers gate mounting on it. */\n userId: string;\n /** Transport selection: SSE when true, WebSocket otherwise. */\n sse?: boolean;\n headers: DeepAgentHeadersResolver;\n /** Park the transport until the caller has a resolved principal. */\n enabled?: boolean;\n}\n\nexport interface UseConversationIndexResult {\n /** Newest-page entries, or `null` until the attach snapshot applies. */\n entries: ConversationIndexEntry[] | null;\n hasNextPage: boolean;\n totalCount: number | null;\n /**\n * The viewer's watch-activity stamps (see {@link ConversationWatchActivity});\n * `null` until the snapshot applies or when the host does not send them.\n */\n watchActivity: ConversationWatchActivity | null;\n connection: StatewireClient.Connection;\n refresh: () => Promise<void>;\n loadMore: () => Promise<void>;\n}\n\n/** The conversation-index host is mounted beside the threads host. */\nexport function conversationIndexUrlFromStatewireUrl(statewireUrl: string): string {\n return statewireUrl.replace(/\\/threads\\/?$/, '/conversation-index');\n}\n\n/** Instance id of one viewer's index; mirrors agora's `conversation_index_id`. */\nexport function conversationIndexId({\n workspaceId,\n userId,\n}: {\n workspaceId: string;\n userId: string;\n}): string {\n return `${workspaceId}-${userId}`;\n}\n\n/**\n * Attach to the live conversation index of one `(workspace, user)` viewer.\n */\nexport function useConversationIndex({\n baseUrl,\n workspaceId,\n userId,\n sse = false,\n headers,\n enabled = true,\n}: UseConversationIndexOptions): UseConversationIndexResult {\n const headersRef = useRef(headers);\n headersRef.current = headers;\n const indexId = conversationIndexId({ workspaceId, userId });\n // Auth-denial park (same policy as the thread transport): the index is a\n // pure push signal, so after a streak of `unauthorized` denials the retry\n // loop stops instead of hammering the attach endpoint every 30s for as long\n // as the tab lives. A remount or the parked connection's `reconnect()`\n // re-arms it.\n const [parked, setParked] = useState<{ indexId: string; message: string | undefined } | null>(\n null\n );\n const denialRef = useRef({ indexId, state: initialAuthDenialTrackerState() });\n if (denialRef.current.indexId !== indexId) {\n denialRef.current = { indexId, state: initialAuthDenialTrackerState() };\n }\n const isParked = parked !== null && parked.indexId === indexId;\n const client = useStatewire<ConversationIndexState | undefined, ConversationIndexCommands>({\n transport: withKey(\n indexId,\n !enabled || isParked\n ? StatewireSuspended<ConversationIndexCommands>({\n message:\n parked?.message ??\n (enabled\n ? 'Conversation index authorization was refused.'\n : 'Conversation index is waiting for a signed-in user and workspace.'),\n ...(enabled\n ? {\n onReconnectRequested: () => {\n denialRef.current = { indexId, state: initialAuthDenialTrackerState() };\n setParked(null);\n },\n }\n : {}),\n })\n : statewireTransport<ConversationIndexState, ConversationIndexCommands>(\n {\n url: `${baseUrl.replace(/\\/+$/, '')}/${encodeURIComponent(indexId)}`,\n headers: (ctx: { staleAuth: boolean }) => headersRef.current(ctx),\n },\n { sse }\n )\n ),\n initialState: undefined,\n });\n // Observing during render is idempotent (the tracker dedupes by attempt\n // number), so a re-render of the same connection state cannot double-count.\n // The tracker consumes the projected vocabulary, never the raw connection.\n const denial = observeAuthDenial(\n denialRef.current.state,\n projectDeepAgentConnection(client.connection)\n );\n denialRef.current.state = denial.state;\n const shouldPark = denial.park;\n const parkMessage = denial.state.message;\n useEffect(() => {\n if (!enabled || !shouldPark) return;\n setParked((prev) =>\n prev?.indexId === indexId ? prev : { indexId, message: parkMessage }\n );\n }, [enabled, shouldPark, parkMessage, indexId]);\n const commandsRef = useRef(client.commands);\n commandsRef.current = client.commands;\n const refresh = useCallback(() => commandsRef.current.refresh(), []);\n const loadMore = useCallback(() => commandsRef.current.load_more(), []);\n return {\n entries: client.state?.conversations ?? null,\n hasNextPage: client.state?.has_more ?? false,\n totalCount: client.state?.total_count ?? null,\n watchActivity: client.state?.watch_activity ?? null,\n connection: client.connection,\n refresh,\n loadMore,\n };\n}\n\n/**\n * Stable change fingerprint over a snapshot's watch-activity stamps: the\n * well-formed `[threadId, instant]` pairs, sorted by thread. An empty string\n * means \"nothing sent yet\" (no snapshot, or a host that predates the stamps),\n * so an effect keyed on it skips; an applied-but-empty map is `'[]'`.\n */\nexport function watchActivityFingerprint(activity: unknown): string {\n if (activity === null || typeof activity !== 'object' || Array.isArray(activity)) return '';\n return JSON.stringify(\n Object.entries(activity)\n .filter((entry): entry is [string, string] => typeof entry[1] === 'string')\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n );\n}\n\n/**\n * Stable change fingerprint over the entries a list surface reacts to. An\n * empty string means \"no snapshot yet\" — effects keyed on the fingerprint\n * should treat it as a no-op rather than an empty list. An applied-but-empty\n * snapshot serializes to `'[]'`, so deleting the last conversation still\n * changes the fingerprint. JSON-encoding keeps arbitrary titles from\n * colliding across field or entry boundaries.\n */\nexport function conversationIndexFingerprint(\n entries: ConversationIndexEntry[] | null\n): string {\n if (entries === null) return '';\n return JSON.stringify(\n entries.map((entry) => [\n entry.thread_id,\n entry.updated_at,\n entry.state,\n entry.title,\n entry.run_status ?? null,\n entry.is_unread ?? null,\n entry.attention ?? null,\n entry.next_action ?? null,\n entry.attention_source ?? null,\n entry.is_favorited ?? null,\n ])\n );\n}\n"],"names":["useRef","useState","initialAuthDenialTrackerState","useStatewire","withKey","StatewireSuspended","statewireTransport","observeAuthDenial","projectDeepAgentConnection","useEffect","useCallback"],"mappings":";;;;;;;;;AA4GO,SAAS,qCAAqC,cAA8B;AACjF,SAAO,aAAa,QAAQ,iBAAiB,qBAAqB;AACpE;AAGO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGW;AACT,SAAO,GAAG,WAAW,IAAI,MAAM;AACjC;AAKO,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA,UAAU;AACZ,GAA4D;;AAC1D,QAAM,aAAaA,WAAAA,OAAO,OAAO;AACjC,aAAW,UAAU;AACrB,QAAM,UAAU,oBAAoB,EAAE,aAAa,QAAQ;AAM3D,QAAM,CAAC,QAAQ,SAAS,IAAIC,WAAAA;AAAAA,IAC1B;AAAA,EAAA;AAEF,QAAM,YAAYD,WAAAA,OAAO,EAAE,SAAS,OAAOE,WAAAA,8BAAA,GAAiC;AAC5E,MAAI,UAAU,QAAQ,YAAY,SAAS;AACzC,cAAU,UAAU,EAAE,SAAS,OAAOA,WAAAA,gCAA8B;AAAA,EACtE;AACA,QAAM,WAAW,WAAW,QAAQ,OAAO,YAAY;AACvD,QAAM,SAASC,UAAAA,aAA4E;AAAA,IACzF,WAAWC,IAAAA;AAAAA,MACT;AAAA,MACA,CAAC,WAAW,WACRC,sCAA8C;AAAA,QAC5C,UACE,iCAAQ,aACP,UACG,kDACA;AAAA,QACN,GAAI,UACA;AAAA,UACE,sBAAsB,MAAM;AAC1B,sBAAU,UAAU,EAAE,SAAS,OAAOH,WAAAA,gCAA8B;AACpE,sBAAU,IAAI;AAAA,UAChB;AAAA,QAAA,IAEF,CAAA;AAAA,MAAC,CACN,IACDI,mBAAAA;AAAAA,QACE;AAAA,UACE,KAAK,GAAG,QAAQ,QAAQ,QAAQ,EAAE,CAAC,IAAI,mBAAmB,OAAO,CAAC;AAAA,UAClE,SAAS,CAAC,QAAgC,WAAW,QAAQ,GAAG;AAAA,QAAA;AAAA,QAElE,EAAE,IAAA;AAAA,MAAI;AAAA,IACR;AAAA,IAEN,cAAc;AAAA,EAAA,CACf;AAID,QAAM,SAASC,WAAAA;AAAAA,IACb,UAAU,QAAQ;AAAA,IAClBC,OAAAA,2BAA2B,OAAO,UAAU;AAAA,EAAA;AAE9C,YAAU,QAAQ,QAAQ,OAAO;AACjC,QAAM,aAAa,OAAO;AAC1B,QAAM,cAAc,OAAO,MAAM;AACjCC,aAAAA,UAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,WAAY;AAC7B;AAAA,MAAU,CAAC,UACT,6BAAM,aAAY,UAAU,OAAO,EAAE,SAAS,SAAS,YAAA;AAAA,IAAY;AAAA,EAEvE,GAAG,CAAC,SAAS,YAAY,aAAa,OAAO,CAAC;AAC9C,QAAM,cAAcT,WAAAA,OAAO,OAAO,QAAQ;AAC1C,cAAY,UAAU,OAAO;AAC7B,QAAM,UAAUU,WAAAA,YAAY,MAAM,YAAY,QAAQ,QAAA,GAAW,EAAE;AACnE,QAAM,WAAWA,WAAAA,YAAY,MAAM,YAAY,QAAQ,UAAA,GAAa,EAAE;AACtE,SAAO;AAAA,IACL,WAAS,YAAO,UAAP,mBAAc,kBAAiB;AAAA,IACxC,eAAa,YAAO,UAAP,mBAAc,aAAY;AAAA,IACvC,cAAY,YAAO,UAAP,mBAAc,gBAAe;AAAA,IACzC,iBAAe,YAAO,UAAP,mBAAc,mBAAkB;AAAA,IAC/C,YAAY,OAAO;AAAA,IACnB;AAAA,IACA;AAAA,EAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { type ConversationAttention } from "./conversation-list";
|
|
2
|
+
/**
|
|
3
|
+
* Pure rules behind the session-list rows' attention affordances: Olympus's
|
|
4
|
+
* Sessions pane and Recent Conversations dropdown and Midas's sessions sidebar
|
|
5
|
+
* render the same indicator, next-action line and group placement from these,
|
|
6
|
+
* so the render tests stay thin and the surfaces cannot disagree
|
|
7
|
+
* (`docs/SESSIONS_LIST_GUIDE.md`, "Session attention").
|
|
8
|
+
*/
|
|
9
|
+
/** The fields a row needs to answer every rule here; a subset of `ConversationItem`. */
|
|
10
|
+
export interface ConversationAttentionInput {
|
|
11
|
+
attention?: ConversationAttention | null;
|
|
12
|
+
runStatus: string | null;
|
|
13
|
+
sessionStatus: string | null;
|
|
14
|
+
state?: string | null;
|
|
15
|
+
nextAction?: string | null;
|
|
16
|
+
isFavorited?: boolean;
|
|
17
|
+
isUnread: boolean;
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The server-derived attention when the transport reports one Olympus knows,
|
|
22
|
+
* else the shared client fallback from the status planes — so a row from an
|
|
23
|
+
* older backend still reads `needs_you` on a human gate and `error` on a
|
|
24
|
+
* failed run.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveConversationAttention(conversation: Pick<ConversationAttentionInput, "attention" | "runStatus" | "sessionStatus" | "state">): ConversationAttention | null;
|
|
27
|
+
/**
|
|
28
|
+
* The one indicator a row shows, in precedence order: a pending action for
|
|
29
|
+
* the viewer beats a live run, which beats the unread dot, which beats
|
|
30
|
+
* "waiting on someone else", which beats a terminal error. `running` is the
|
|
31
|
+
* caller's resolved running state (the live stream signal wins for the open
|
|
32
|
+
* thread), not the attention field, so the spinner keeps today's behaviour.
|
|
33
|
+
*/
|
|
34
|
+
export type ConversationAttentionIndicator = "needs_you" | "running" | "unread" | "watching" | "error" | null;
|
|
35
|
+
export declare function conversationAttentionIndicator({ attention, isRunning, isUnread, }: {
|
|
36
|
+
attention: ConversationAttention | null;
|
|
37
|
+
isRunning: boolean;
|
|
38
|
+
isUnread: boolean;
|
|
39
|
+
}): ConversationAttentionIndicator;
|
|
40
|
+
/** Tone of the next-action line, named after the design tokens that paint it. */
|
|
41
|
+
export type ConversationNextActionTone = "warning" | "success" | "muted" | "destructive";
|
|
42
|
+
export interface ConversationNextAction {
|
|
43
|
+
text: string;
|
|
44
|
+
tone: ConversationNextActionTone;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The row's second line when the server derived a next step: the text as
|
|
48
|
+
* sent (already ≤ 80 characters), toned by what the session asks — orange
|
|
49
|
+
* for `needs_you`, green for `ready`, red for `error`, muted otherwise.
|
|
50
|
+
* `null` when there is nothing to do, so the row shows its timestamp.
|
|
51
|
+
*/
|
|
52
|
+
export declare function conversationNextAction({ attention, nextAction, }: {
|
|
53
|
+
attention: ConversationAttention | null;
|
|
54
|
+
nextAction?: string | null;
|
|
55
|
+
}): ConversationNextAction | null;
|
|
56
|
+
export type ConversationTimeGroup = "Today" | "Yesterday" | "This Week" | "This Month" | "Older";
|
|
57
|
+
/**
|
|
58
|
+
* Where a row lands in the Sessions pane: sessions that need the viewer
|
|
59
|
+
* first, then the viewer's pinned sessions, then everything else by when it
|
|
60
|
+
* last changed. A row appears once, in the FIRST group that applies.
|
|
61
|
+
*/
|
|
62
|
+
export type ConversationListGroup = "Needs you" | "Pinned" | ConversationTimeGroup;
|
|
63
|
+
export declare const CONVERSATION_LIST_GROUP_ORDER: readonly ConversationListGroup[];
|
|
64
|
+
export declare function conversationTimeGroup(dateStr: string, now?: Date): ConversationTimeGroup;
|
|
65
|
+
export declare function conversationListGroupOf(conversation: ConversationAttentionInput, now?: Date): ConversationListGroup;
|
|
66
|
+
export interface ConversationListSection<T extends ConversationAttentionInput> {
|
|
67
|
+
group: ConversationListGroup;
|
|
68
|
+
items: T[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Sections in display order; empty groups are omitted and the list's own
|
|
72
|
+
* newest-first order is kept within each group.
|
|
73
|
+
*/
|
|
74
|
+
export declare function groupConversationsForList<T extends ConversationAttentionInput>(conversations: readonly T[], now?: Date): ConversationListSection<T>[];
|