@athenaintel/react 0.43.0 → 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 +215 -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/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 +14 -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 -25
- 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 -25
- 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 +547 -124
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +129 -10
- package/dist/agent-runtime/src/use-deep-agent-voice.js +487 -64
- 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 +52 -36
- package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.d.ts +19 -4
- package/dist/chat/super-grouping/SuperGroupingCard.js +29 -13
- 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 +73 -40
- package/dist/chat/super-grouping/ToolTimeline.cjs.map +1 -1
- package/dist/chat/super-grouping/ToolTimeline.d.ts +10 -2
- package/dist/chat/super-grouping/ToolTimeline.js +69 -36
- 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 +5 -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/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 +4 -4
- package/dist/chat-ui/mentions/mention-chip.cjs.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 +3 -3
- package/dist/chat-ui/mentions/use-mention-asset.cjs.map +1 -1
- 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 +2 -2
- package/dist/chat-ui/rich-text/chat-link.cjs.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 +6 -6
- package/dist/chat-ui/rich-text/chat-node-views.cjs.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/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 +51 -51
- package/dist/threads/statewire-thread-list.cjs.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-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":"decision-checks.cjs","sources":["../../../../agent-runtime/src/decision-checks.ts"],"sourcesContent":["/**\n * \"Confirm with your passkey\" for surfaces that can't run the passkey prompt\n * themselves (identity row 0b.9, PR C): the phone, Midas, the Chrome\n * extension, the Office add-ins and SDK apps on another origin.\n *\n * A passkey belongs to the deployment's web host, so the check runs there, in\n * the system browser. The surface asks agora for a check over the decisions\n * on its screen (`POST /api/passkeys/decision-checks/requests`), opens the\n * verification URL it gets back, and collects the token once the person\n * confirmed on the web app's check page. It then sends its decision with that\n * token, as the web app does: `X-Athena-Decision-Check` on REST and GraphQL,\n * `decisionCheck` on statewire's `run/input` and `run/lane-input`.\n *\n * Framework-free: React hosts wrap {@link runBrowserDecisionCheck} in a\n * TanStack mutation; the CLI and the phone call it as they are.\n *\n * Every outcome is a value, never a rejection. While checks are report-only\n * (PR D enforces them) the decision goes ahead whatever this resolves, with\n * the token only when the person confirmed.\n */\n\n/** The header a REST or GraphQL decide call carries its check token in. */\nexport const DECISION_CHECK_HEADER = 'X-Athena-Decision-Check';\n\n/** The most decisions one check covers: a screen's worth. */\nexport const MAX_DECISIONS_PER_CHECK = 25;\n\n/** What kind of decision a descriptor describes (agora's `DecisionKind`). */\nexport const DecisionCheckKind = {\n APPROVAL_DECIDE: 'approval_decide',\n AUTOMATION_APPROVAL_DECIDE: 'automation_approval_decide',\n CHAT_APPROVAL_ANSWER: 'chat_approval_answer',\n} as const;\n\nexport type DecisionCheckKind = (typeof DecisionCheckKind)[keyof typeof DecisionCheckKind];\n\n/**\n * One decision a check covers, exactly as its decide call sends it: agora\n * builds the same item from the decide call and asks whether the token covers\n * it. `editedPayload` is the JSON value itself, never a hash of it.\n */\nexport interface DecisionCheckDescriptor {\n readonly kind: string;\n readonly targetIds: readonly string[];\n readonly option: string;\n readonly editedPayload?: unknown;\n readonly standingDuration?: string;\n}\n\n/** Which surface asks, as the check page shows it. */\nexport type DecisionCheckClientKind =\n | 'cli'\n | 'desktop'\n | 'mobile'\n | 'chrome_extension'\n | 'office_addin'\n | 'sdk';\n\nexport interface DecisionCheckClient {\n readonly kind: DecisionCheckClientKind;\n /** A short name for this device or app (\"Pat's MacBook\"), shown on the page. */\n readonly label?: string;\n}\n\nconst CHECKPOINT_NAMESPACE = 'athena-deep-agent:';\n\n/** A thread id the way agora names chat answers: without the checkpoint namespace. */\nexport function bareDecisionThreadId(threadId: string): string {\n return threadId.startsWith(CHECKPOINT_NAMESPACE)\n ? threadId.slice(CHECKPOINT_NAMESPACE.length)\n : threadId;\n}\n\n/**\n * A chat answer as statewire carries it: a `run/input` resume of one parked\n * request, or the lane decisions of a `run/lane-input`.\n */\nexport type StatewireAnswerForCheck =\n | { readonly kind: 'input'; readonly requestId: string; readonly value: unknown }\n | { readonly kind: 'lanes'; readonly laneDecisions: Readonly<Record<string, unknown>> };\n\n/**\n * The decisions one statewire answer makes: `chat_approval_answer` on\n * `<thread>:<requestId>` with the resume value as its payload, or one per lane\n * on `<thread>:<lane interrupt id>` with that lane's decision as its payload.\n */\nexport function statewireAnswerDescriptors({\n threadId,\n answer,\n}: {\n threadId: string;\n answer: StatewireAnswerForCheck;\n}): DecisionCheckDescriptor[] {\n const thread = bareDecisionThreadId(threadId);\n if (answer.kind === 'input') {\n return [\n {\n kind: DecisionCheckKind.CHAT_APPROVAL_ANSWER,\n targetIds: [`${thread}:${answer.requestId}`],\n option: 'resume',\n editedPayload: answer.value,\n },\n ];\n }\n return Object.entries(answer.laneDecisions).map(([interruptId, decision]) => ({\n kind: DecisionCheckKind.CHAT_APPROVAL_ANSWER,\n targetIds: [`${thread}:${interruptId}`],\n option: 'resume',\n editedPayload: decision,\n }));\n}\n\n/**\n * The phone's respond route (`POST /mobile/approvals/{thread}/respond`, also\n * the comment thread's inline approval): a `decisions` map is option\n * `decisions` with the map as its payload; otherwise the option is the action\n * and the payload its edited `tool_args`.\n */\nexport function respondDecisionDescriptor({\n threadId,\n toolCallId,\n action,\n toolArgs,\n decisions,\n}: {\n threadId: string;\n toolCallId: string;\n action?: string;\n toolArgs?: unknown;\n decisions?: Readonly<Record<string, unknown>>;\n}): DecisionCheckDescriptor {\n const target = `${bareDecisionThreadId(threadId)}:${toolCallId}`;\n if (decisions !== undefined && Object.keys(decisions).length > 0) {\n return {\n kind: DecisionCheckKind.CHAT_APPROVAL_ANSWER,\n targetIds: [target],\n option: 'decisions',\n editedPayload: decisions,\n };\n }\n return {\n kind: DecisionCheckKind.CHAT_APPROVAL_ANSWER,\n targetIds: [target],\n option: action ?? 'decisions',\n ...(toolArgs !== undefined && toolArgs !== null ? { editedPayload: toolArgs } : {}),\n };\n}\n\n/**\n * How a browser check went. Every outcome but `confirmed` sends the decision\n * without a token while checks are report-only; the surface decides what to\n * tell the person (a nudge to set up a passkey for `no_passkey`).\n */\nexport type BrowserDecisionCheckOutcome =\n | { readonly status: 'confirmed'; readonly token: string }\n | { readonly status: 'no_passkey' }\n | { readonly status: 'cancelled' }\n | { readonly status: 'unsupported' }\n | { readonly status: 'unavailable' }\n | { readonly status: 'expired' }\n | { readonly status: 'failed'; readonly message: string };\n\n/** What the surface shows while the person finishes in the browser. */\nexport interface PendingBrowserDecisionCheck {\n readonly userCode: string;\n readonly verificationUrl: string;\n readonly expiresAt: Date;\n}\n\n/**\n * The surface's authenticated request to agora: `path` is absolute from the\n * API root (`/api/passkeys/...`). The host adds its base URL and credential\n * (the person's sign-in, or the device key) and returns the raw response.\n */\nexport type AgoraFetch = (path: string, init: RequestInit) => Promise<Response>;\n\nexport interface RunBrowserDecisionCheckOptions {\n readonly decisions: readonly DecisionCheckDescriptor[];\n readonly client: DecisionCheckClient;\n readonly agoraFetch: AgoraFetch;\n /** Open the check page in the system browser or a new tab. */\n readonly openUrl: (url: string) => void | Promise<void>;\n /** An app link the page sends the person back to once they answered. */\n readonly returnUrl?: string;\n /** Told when the browser is open (with the code to show), and `null` once it settled. */\n readonly onPending?: (pending: PendingBrowserDecisionCheck | null) => void;\n /** Aborting gives up waiting: the decision goes without a token (`cancelled`). */\n readonly signal?: AbortSignal;\n /** Injectable for tests. */\n readonly sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n readonly now?: () => number;\n}\n\nconst REQUESTS_PATH = '/api/passkeys/decision-checks/requests';\nconst DEFAULT_INTERVAL_MS = 2_000;\nconst MIN_INTERVAL_MS = 1_000;\n/** A transient collect failure is retried; this many in a row gives up. */\nconst MAX_COLLECT_FAILURES = 5;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nasync function readJson(response: Response): Promise<Record<string, unknown> | null> {\n try {\n const body: unknown = await response.json();\n return isRecord(body) ? body : null;\n } catch {\n return null;\n }\n}\n\nfunction defaultSleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve();\n return;\n }\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n resolve();\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** Tell the host about the open check; a host callback that throws changes nothing here. */\nfunction notifyPending(\n options: RunBrowserDecisionCheckOptions,\n pending: PendingBrowserDecisionCheck | null,\n): void {\n try {\n options.onPending?.(pending);\n } catch (error) {\n console.warn('[decision-check] the pending notice failed:', messageOf(error));\n }\n}\n\ninterface OpenedCheck {\n readonly requestId: string;\n readonly pollSecret: string;\n readonly userCode: string;\n readonly verificationUrl: string;\n readonly expiresAt: Date;\n readonly intervalMs: number;\n}\n\nfunction openedCheck(body: Record<string, unknown> | null): OpenedCheck | null {\n if (body === null) return null;\n const { request_id, poll_secret, user_code, verification_url, expires_at, interval_seconds } =\n body;\n if (\n typeof request_id !== 'string' ||\n typeof poll_secret !== 'string' ||\n typeof user_code !== 'string' ||\n typeof verification_url !== 'string' ||\n typeof expires_at !== 'string'\n ) {\n return null;\n }\n const expiresAt = new Date(expires_at);\n if (Number.isNaN(expiresAt.getTime())) return null;\n const seconds = typeof interval_seconds === 'number' ? interval_seconds : 0;\n return {\n requestId: request_id,\n pollSecret: poll_secret,\n userCode: user_code,\n verificationUrl: verification_url,\n expiresAt,\n intervalMs: seconds > 0 ? Math.max(MIN_INTERVAL_MS, seconds * 1_000) : DEFAULT_INTERVAL_MS,\n };\n}\n\nasync function openRequest(\n options: RunBrowserDecisionCheckOptions,\n): Promise<OpenedCheck | BrowserDecisionCheckOutcome> {\n let response: Response;\n try {\n response = await options.agoraFetch(REQUESTS_PATH, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n decisions: options.decisions,\n client: options.client,\n ...(options.returnUrl ? { return_url: options.returnUrl } : {}),\n }),\n signal: options.signal,\n });\n } catch (error) {\n if (options.signal?.aborted) return { status: 'cancelled' };\n return { status: 'failed', message: messageOf(error) };\n }\n // 404: an agora before browser checks; 503: none can be minted here.\n if (response.status === 404 || response.status === 503) return { status: 'unavailable' };\n if (!response.ok) {\n return { status: 'failed', message: `The check could not start (${response.status}).` };\n }\n return openedCheck(await readJson(response)) ?? {\n status: 'failed',\n message: 'The check could not start.',\n };\n}\n\nfunction settledOutcome(body: Record<string, unknown> | null): BrowserDecisionCheckOutcome | null {\n if (body === null) return null;\n if (body.status === 'confirmed' && typeof body.check_token === 'string' && body.check_token) {\n return { status: 'confirmed', token: body.check_token };\n }\n if (body.status === 'declined') {\n switch (body.reason) {\n case 'no_passkey':\n return { status: 'no_passkey' };\n case 'unsupported':\n return { status: 'unsupported' };\n case 'failed':\n return { status: 'failed', message: 'The passkey check failed in the browser.' };\n default:\n return { status: 'cancelled' };\n }\n }\n return null;\n}\n\n/**\n * Ask the person to confirm `decisions` with their passkey in the system\n * browser, and wait for the answer: the token when they confirmed, or why\n * there is none. Never rejects.\n */\nexport async function runBrowserDecisionCheck(\n options: RunBrowserDecisionCheckOptions,\n): Promise<BrowserDecisionCheckOutcome> {\n if (options.decisions.length === 0) return { status: 'failed', message: 'Nothing to confirm.' };\n if (options.decisions.length > MAX_DECISIONS_PER_CHECK) {\n return {\n status: 'failed',\n message: `One check confirms up to ${MAX_DECISIONS_PER_CHECK} decisions.`,\n };\n }\n const sleep = options.sleep ?? defaultSleep;\n const now = options.now ?? Date.now;\n const opened = await openRequest(options);\n if ('status' in opened) return opened;\n\n notifyPending(options, {\n userCode: opened.userCode,\n verificationUrl: opened.verificationUrl,\n expiresAt: opened.expiresAt,\n });\n try {\n try {\n await options.openUrl(opened.verificationUrl);\n } catch (error) {\n // The page can still be opened by hand from the link the surface shows.\n console.warn('[decision-check] could not open the browser:', messageOf(error));\n }\n let failures = 0;\n while (now() < opened.expiresAt.getTime()) {\n await sleep(opened.intervalMs, options.signal);\n if (options.signal?.aborted) return { status: 'cancelled' };\n let response: Response;\n try {\n response = await options.agoraFetch(\n `${REQUESTS_PATH}/${encodeURIComponent(opened.requestId)}/collect`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ poll_secret: opened.pollSecret }),\n signal: options.signal,\n },\n );\n } catch (error) {\n if (options.signal?.aborted) return { status: 'cancelled' };\n failures += 1;\n if (failures >= MAX_COLLECT_FAILURES) return { status: 'failed', message: messageOf(error) };\n continue;\n }\n // Unknown, expired or already collected: nothing more will come.\n if (response.status === 404) return { status: 'expired' };\n if (!response.ok) {\n failures += 1;\n if (failures >= MAX_COLLECT_FAILURES) {\n return { status: 'failed', message: `The check could not finish (${response.status}).` };\n }\n continue;\n }\n failures = 0;\n const settled = settledOutcome(await readJson(response));\n if (settled !== null) return settled;\n }\n return { status: 'expired' };\n } finally {\n notifyPending(options, null);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Confirm with your passkey" for surfaces that can't run the passkey prompt
|
|
3
|
+
* themselves (identity row 0b.9, PR C): the phone, Midas, the Chrome
|
|
4
|
+
* extension, the Office add-ins and SDK apps on another origin.
|
|
5
|
+
*
|
|
6
|
+
* A passkey belongs to the deployment's web host, so the check runs there, in
|
|
7
|
+
* the system browser. The surface asks agora for a check over the decisions
|
|
8
|
+
* on its screen (`POST /api/passkeys/decision-checks/requests`), opens the
|
|
9
|
+
* verification URL it gets back, and collects the token once the person
|
|
10
|
+
* confirmed on the web app's check page. It then sends its decision with that
|
|
11
|
+
* token, as the web app does: `X-Athena-Decision-Check` on REST and GraphQL,
|
|
12
|
+
* `decisionCheck` on statewire's `run/input` and `run/lane-input`.
|
|
13
|
+
*
|
|
14
|
+
* Framework-free: React hosts wrap {@link runBrowserDecisionCheck} in a
|
|
15
|
+
* TanStack mutation; the CLI and the phone call it as they are.
|
|
16
|
+
*
|
|
17
|
+
* Every outcome is a value, never a rejection. While checks are report-only
|
|
18
|
+
* (PR D enforces them) the decision goes ahead whatever this resolves, with
|
|
19
|
+
* the token only when the person confirmed.
|
|
20
|
+
*/
|
|
21
|
+
/** The header a REST or GraphQL decide call carries its check token in. */
|
|
22
|
+
export declare const DECISION_CHECK_HEADER = "X-Athena-Decision-Check";
|
|
23
|
+
/** The most decisions one check covers: a screen's worth. */
|
|
24
|
+
export declare const MAX_DECISIONS_PER_CHECK = 25;
|
|
25
|
+
/** What kind of decision a descriptor describes (agora's `DecisionKind`). */
|
|
26
|
+
export declare const DecisionCheckKind: {
|
|
27
|
+
readonly APPROVAL_DECIDE: 'approval_decide';
|
|
28
|
+
readonly AUTOMATION_APPROVAL_DECIDE: 'automation_approval_decide';
|
|
29
|
+
readonly CHAT_APPROVAL_ANSWER: 'chat_approval_answer';
|
|
30
|
+
};
|
|
31
|
+
export type DecisionCheckKind = (typeof DecisionCheckKind)[keyof typeof DecisionCheckKind];
|
|
32
|
+
/**
|
|
33
|
+
* One decision a check covers, exactly as its decide call sends it: agora
|
|
34
|
+
* builds the same item from the decide call and asks whether the token covers
|
|
35
|
+
* it. `editedPayload` is the JSON value itself, never a hash of it.
|
|
36
|
+
*/
|
|
37
|
+
export interface DecisionCheckDescriptor {
|
|
38
|
+
readonly kind: string;
|
|
39
|
+
readonly targetIds: readonly string[];
|
|
40
|
+
readonly option: string;
|
|
41
|
+
readonly editedPayload?: unknown;
|
|
42
|
+
readonly standingDuration?: string;
|
|
43
|
+
}
|
|
44
|
+
/** Which surface asks, as the check page shows it. */
|
|
45
|
+
export type DecisionCheckClientKind = 'cli' | 'desktop' | 'mobile' | 'chrome_extension' | 'office_addin' | 'sdk';
|
|
46
|
+
export interface DecisionCheckClient {
|
|
47
|
+
readonly kind: DecisionCheckClientKind;
|
|
48
|
+
/** A short name for this device or app ("Pat's MacBook"), shown on the page. */
|
|
49
|
+
readonly label?: string;
|
|
50
|
+
}
|
|
51
|
+
/** A thread id the way agora names chat answers: without the checkpoint namespace. */
|
|
52
|
+
export declare function bareDecisionThreadId(threadId: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* A chat answer as statewire carries it: a `run/input` resume of one parked
|
|
55
|
+
* request, or the lane decisions of a `run/lane-input`.
|
|
56
|
+
*/
|
|
57
|
+
export type StatewireAnswerForCheck = {
|
|
58
|
+
readonly kind: 'input';
|
|
59
|
+
readonly requestId: string;
|
|
60
|
+
readonly value: unknown;
|
|
61
|
+
} | {
|
|
62
|
+
readonly kind: 'lanes';
|
|
63
|
+
readonly laneDecisions: Readonly<Record<string, unknown>>;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* The decisions one statewire answer makes: `chat_approval_answer` on
|
|
67
|
+
* `<thread>:<requestId>` with the resume value as its payload, or one per lane
|
|
68
|
+
* on `<thread>:<lane interrupt id>` with that lane's decision as its payload.
|
|
69
|
+
*/
|
|
70
|
+
export declare function statewireAnswerDescriptors({ threadId, answer, }: {
|
|
71
|
+
threadId: string;
|
|
72
|
+
answer: StatewireAnswerForCheck;
|
|
73
|
+
}): DecisionCheckDescriptor[];
|
|
74
|
+
/**
|
|
75
|
+
* The phone's respond route (`POST /mobile/approvals/{thread}/respond`, also
|
|
76
|
+
* the comment thread's inline approval): a `decisions` map is option
|
|
77
|
+
* `decisions` with the map as its payload; otherwise the option is the action
|
|
78
|
+
* and the payload its edited `tool_args`.
|
|
79
|
+
*/
|
|
80
|
+
export declare function respondDecisionDescriptor({ threadId, toolCallId, action, toolArgs, decisions, }: {
|
|
81
|
+
threadId: string;
|
|
82
|
+
toolCallId: string;
|
|
83
|
+
action?: string;
|
|
84
|
+
toolArgs?: unknown;
|
|
85
|
+
decisions?: Readonly<Record<string, unknown>>;
|
|
86
|
+
}): DecisionCheckDescriptor;
|
|
87
|
+
/**
|
|
88
|
+
* How a browser check went. Every outcome but `confirmed` sends the decision
|
|
89
|
+
* without a token while checks are report-only; the surface decides what to
|
|
90
|
+
* tell the person (a nudge to set up a passkey for `no_passkey`).
|
|
91
|
+
*/
|
|
92
|
+
export type BrowserDecisionCheckOutcome = {
|
|
93
|
+
readonly status: 'confirmed';
|
|
94
|
+
readonly token: string;
|
|
95
|
+
} | {
|
|
96
|
+
readonly status: 'no_passkey';
|
|
97
|
+
} | {
|
|
98
|
+
readonly status: 'cancelled';
|
|
99
|
+
} | {
|
|
100
|
+
readonly status: 'unsupported';
|
|
101
|
+
} | {
|
|
102
|
+
readonly status: 'unavailable';
|
|
103
|
+
} | {
|
|
104
|
+
readonly status: 'expired';
|
|
105
|
+
} | {
|
|
106
|
+
readonly status: 'failed';
|
|
107
|
+
readonly message: string;
|
|
108
|
+
};
|
|
109
|
+
/** What the surface shows while the person finishes in the browser. */
|
|
110
|
+
export interface PendingBrowserDecisionCheck {
|
|
111
|
+
readonly userCode: string;
|
|
112
|
+
readonly verificationUrl: string;
|
|
113
|
+
readonly expiresAt: Date;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The surface's authenticated request to agora: `path` is absolute from the
|
|
117
|
+
* API root (`/api/passkeys/...`). The host adds its base URL and credential
|
|
118
|
+
* (the person's sign-in, or the device key) and returns the raw response.
|
|
119
|
+
*/
|
|
120
|
+
export type AgoraFetch = (path: string, init: RequestInit) => Promise<Response>;
|
|
121
|
+
export interface RunBrowserDecisionCheckOptions {
|
|
122
|
+
readonly decisions: readonly DecisionCheckDescriptor[];
|
|
123
|
+
readonly client: DecisionCheckClient;
|
|
124
|
+
readonly agoraFetch: AgoraFetch;
|
|
125
|
+
/** Open the check page in the system browser or a new tab. */
|
|
126
|
+
readonly openUrl: (url: string) => void | Promise<void>;
|
|
127
|
+
/** An app link the page sends the person back to once they answered. */
|
|
128
|
+
readonly returnUrl?: string;
|
|
129
|
+
/** Told when the browser is open (with the code to show), and `null` once it settled. */
|
|
130
|
+
readonly onPending?: (pending: PendingBrowserDecisionCheck | null) => void;
|
|
131
|
+
/** Aborting gives up waiting: the decision goes without a token (`cancelled`). */
|
|
132
|
+
readonly signal?: AbortSignal;
|
|
133
|
+
/** Injectable for tests. */
|
|
134
|
+
readonly sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
135
|
+
readonly now?: () => number;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Ask the person to confirm `decisions` with their passkey in the system
|
|
139
|
+
* browser, and wait for the answer: the token when they confirmed, or why
|
|
140
|
+
* there is none. Never rejects.
|
|
141
|
+
*/
|
|
142
|
+
export declare function runBrowserDecisionCheck(options: RunBrowserDecisionCheckOptions): Promise<BrowserDecisionCheckOutcome>;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
const MAX_DECISIONS_PER_CHECK = 25;
|
|
2
|
+
const DecisionCheckKind = {
|
|
3
|
+
CHAT_APPROVAL_ANSWER: "chat_approval_answer"
|
|
4
|
+
};
|
|
5
|
+
const CHECKPOINT_NAMESPACE = "athena-deep-agent:";
|
|
6
|
+
function bareDecisionThreadId(threadId) {
|
|
7
|
+
return threadId.startsWith(CHECKPOINT_NAMESPACE) ? threadId.slice(CHECKPOINT_NAMESPACE.length) : threadId;
|
|
8
|
+
}
|
|
9
|
+
function statewireAnswerDescriptors({
|
|
10
|
+
threadId,
|
|
11
|
+
answer
|
|
12
|
+
}) {
|
|
13
|
+
const thread = bareDecisionThreadId(threadId);
|
|
14
|
+
if (answer.kind === "input") {
|
|
15
|
+
return [
|
|
16
|
+
{
|
|
17
|
+
kind: DecisionCheckKind.CHAT_APPROVAL_ANSWER,
|
|
18
|
+
targetIds: [`${thread}:${answer.requestId}`],
|
|
19
|
+
option: "resume",
|
|
20
|
+
editedPayload: answer.value
|
|
21
|
+
}
|
|
22
|
+
];
|
|
23
|
+
}
|
|
24
|
+
return Object.entries(answer.laneDecisions).map(([interruptId, decision]) => ({
|
|
25
|
+
kind: DecisionCheckKind.CHAT_APPROVAL_ANSWER,
|
|
26
|
+
targetIds: [`${thread}:${interruptId}`],
|
|
27
|
+
option: "resume",
|
|
28
|
+
editedPayload: decision
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
const REQUESTS_PATH = "/api/passkeys/decision-checks/requests";
|
|
32
|
+
const DEFAULT_INTERVAL_MS = 2e3;
|
|
33
|
+
const MIN_INTERVAL_MS = 1e3;
|
|
34
|
+
const MAX_COLLECT_FAILURES = 5;
|
|
35
|
+
function isRecord(value) {
|
|
36
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37
|
+
}
|
|
38
|
+
async function readJson(response) {
|
|
39
|
+
try {
|
|
40
|
+
const body = await response.json();
|
|
41
|
+
return isRecord(body) ? body : null;
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function defaultSleep(ms, signal) {
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
if (signal == null ? void 0 : signal.aborted) {
|
|
49
|
+
resolve();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const timer = setTimeout(() => {
|
|
53
|
+
signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
|
|
54
|
+
resolve();
|
|
55
|
+
}, ms);
|
|
56
|
+
const onAbort = () => {
|
|
57
|
+
clearTimeout(timer);
|
|
58
|
+
resolve();
|
|
59
|
+
};
|
|
60
|
+
signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function messageOf(error) {
|
|
64
|
+
return error instanceof Error ? error.message : String(error);
|
|
65
|
+
}
|
|
66
|
+
function notifyPending(options, pending) {
|
|
67
|
+
var _a;
|
|
68
|
+
try {
|
|
69
|
+
(_a = options.onPending) == null ? void 0 : _a.call(options, pending);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.warn("[decision-check] the pending notice failed:", messageOf(error));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function openedCheck(body) {
|
|
75
|
+
if (body === null) return null;
|
|
76
|
+
const { request_id, poll_secret, user_code, verification_url, expires_at, interval_seconds } = body;
|
|
77
|
+
if (typeof request_id !== "string" || typeof poll_secret !== "string" || typeof user_code !== "string" || typeof verification_url !== "string" || typeof expires_at !== "string") {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const expiresAt = new Date(expires_at);
|
|
81
|
+
if (Number.isNaN(expiresAt.getTime())) return null;
|
|
82
|
+
const seconds = typeof interval_seconds === "number" ? interval_seconds : 0;
|
|
83
|
+
return {
|
|
84
|
+
requestId: request_id,
|
|
85
|
+
pollSecret: poll_secret,
|
|
86
|
+
userCode: user_code,
|
|
87
|
+
verificationUrl: verification_url,
|
|
88
|
+
expiresAt,
|
|
89
|
+
intervalMs: seconds > 0 ? Math.max(MIN_INTERVAL_MS, seconds * 1e3) : DEFAULT_INTERVAL_MS
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async function openRequest(options) {
|
|
93
|
+
var _a;
|
|
94
|
+
let response;
|
|
95
|
+
try {
|
|
96
|
+
response = await options.agoraFetch(REQUESTS_PATH, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: { "Content-Type": "application/json" },
|
|
99
|
+
body: JSON.stringify({
|
|
100
|
+
decisions: options.decisions,
|
|
101
|
+
client: options.client,
|
|
102
|
+
...options.returnUrl ? { return_url: options.returnUrl } : {}
|
|
103
|
+
}),
|
|
104
|
+
signal: options.signal
|
|
105
|
+
});
|
|
106
|
+
} catch (error) {
|
|
107
|
+
if ((_a = options.signal) == null ? void 0 : _a.aborted) return { status: "cancelled" };
|
|
108
|
+
return { status: "failed", message: messageOf(error) };
|
|
109
|
+
}
|
|
110
|
+
if (response.status === 404 || response.status === 503) return { status: "unavailable" };
|
|
111
|
+
if (!response.ok) {
|
|
112
|
+
return { status: "failed", message: `The check could not start (${response.status}).` };
|
|
113
|
+
}
|
|
114
|
+
return openedCheck(await readJson(response)) ?? {
|
|
115
|
+
status: "failed",
|
|
116
|
+
message: "The check could not start."
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function settledOutcome(body) {
|
|
120
|
+
if (body === null) return null;
|
|
121
|
+
if (body.status === "confirmed" && typeof body.check_token === "string" && body.check_token) {
|
|
122
|
+
return { status: "confirmed", token: body.check_token };
|
|
123
|
+
}
|
|
124
|
+
if (body.status === "declined") {
|
|
125
|
+
switch (body.reason) {
|
|
126
|
+
case "no_passkey":
|
|
127
|
+
return { status: "no_passkey" };
|
|
128
|
+
case "unsupported":
|
|
129
|
+
return { status: "unsupported" };
|
|
130
|
+
case "failed":
|
|
131
|
+
return { status: "failed", message: "The passkey check failed in the browser." };
|
|
132
|
+
default:
|
|
133
|
+
return { status: "cancelled" };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
async function runBrowserDecisionCheck(options) {
|
|
139
|
+
var _a, _b;
|
|
140
|
+
if (options.decisions.length === 0) return { status: "failed", message: "Nothing to confirm." };
|
|
141
|
+
if (options.decisions.length > MAX_DECISIONS_PER_CHECK) {
|
|
142
|
+
return {
|
|
143
|
+
status: "failed",
|
|
144
|
+
message: `One check confirms up to ${MAX_DECISIONS_PER_CHECK} decisions.`
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
const sleep = options.sleep ?? defaultSleep;
|
|
148
|
+
const now = options.now ?? Date.now;
|
|
149
|
+
const opened = await openRequest(options);
|
|
150
|
+
if ("status" in opened) return opened;
|
|
151
|
+
notifyPending(options, {
|
|
152
|
+
userCode: opened.userCode,
|
|
153
|
+
verificationUrl: opened.verificationUrl,
|
|
154
|
+
expiresAt: opened.expiresAt
|
|
155
|
+
});
|
|
156
|
+
try {
|
|
157
|
+
try {
|
|
158
|
+
await options.openUrl(opened.verificationUrl);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
console.warn("[decision-check] could not open the browser:", messageOf(error));
|
|
161
|
+
}
|
|
162
|
+
let failures = 0;
|
|
163
|
+
while (now() < opened.expiresAt.getTime()) {
|
|
164
|
+
await sleep(opened.intervalMs, options.signal);
|
|
165
|
+
if ((_a = options.signal) == null ? void 0 : _a.aborted) return { status: "cancelled" };
|
|
166
|
+
let response;
|
|
167
|
+
try {
|
|
168
|
+
response = await options.agoraFetch(
|
|
169
|
+
`${REQUESTS_PATH}/${encodeURIComponent(opened.requestId)}/collect`,
|
|
170
|
+
{
|
|
171
|
+
method: "POST",
|
|
172
|
+
headers: { "Content-Type": "application/json" },
|
|
173
|
+
body: JSON.stringify({ poll_secret: opened.pollSecret }),
|
|
174
|
+
signal: options.signal
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if ((_b = options.signal) == null ? void 0 : _b.aborted) return { status: "cancelled" };
|
|
179
|
+
failures += 1;
|
|
180
|
+
if (failures >= MAX_COLLECT_FAILURES) return { status: "failed", message: messageOf(error) };
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (response.status === 404) return { status: "expired" };
|
|
184
|
+
if (!response.ok) {
|
|
185
|
+
failures += 1;
|
|
186
|
+
if (failures >= MAX_COLLECT_FAILURES) {
|
|
187
|
+
return { status: "failed", message: `The check could not finish (${response.status}).` };
|
|
188
|
+
}
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
failures = 0;
|
|
192
|
+
const settled = settledOutcome(await readJson(response));
|
|
193
|
+
if (settled !== null) return settled;
|
|
194
|
+
}
|
|
195
|
+
return { status: "expired" };
|
|
196
|
+
} finally {
|
|
197
|
+
notifyPending(options, null);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
export {
|
|
201
|
+
DecisionCheckKind,
|
|
202
|
+
MAX_DECISIONS_PER_CHECK,
|
|
203
|
+
bareDecisionThreadId,
|
|
204
|
+
runBrowserDecisionCheck,
|
|
205
|
+
statewireAnswerDescriptors
|
|
206
|
+
};
|
|
207
|
+
//# sourceMappingURL=decision-checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision-checks.js","sources":["../../../../agent-runtime/src/decision-checks.ts"],"sourcesContent":["/**\n * \"Confirm with your passkey\" for surfaces that can't run the passkey prompt\n * themselves (identity row 0b.9, PR C): the phone, Midas, the Chrome\n * extension, the Office add-ins and SDK apps on another origin.\n *\n * A passkey belongs to the deployment's web host, so the check runs there, in\n * the system browser. The surface asks agora for a check over the decisions\n * on its screen (`POST /api/passkeys/decision-checks/requests`), opens the\n * verification URL it gets back, and collects the token once the person\n * confirmed on the web app's check page. It then sends its decision with that\n * token, as the web app does: `X-Athena-Decision-Check` on REST and GraphQL,\n * `decisionCheck` on statewire's `run/input` and `run/lane-input`.\n *\n * Framework-free: React hosts wrap {@link runBrowserDecisionCheck} in a\n * TanStack mutation; the CLI and the phone call it as they are.\n *\n * Every outcome is a value, never a rejection. While checks are report-only\n * (PR D enforces them) the decision goes ahead whatever this resolves, with\n * the token only when the person confirmed.\n */\n\n/** The header a REST or GraphQL decide call carries its check token in. */\nexport const DECISION_CHECK_HEADER = 'X-Athena-Decision-Check';\n\n/** The most decisions one check covers: a screen's worth. */\nexport const MAX_DECISIONS_PER_CHECK = 25;\n\n/** What kind of decision a descriptor describes (agora's `DecisionKind`). */\nexport const DecisionCheckKind = {\n APPROVAL_DECIDE: 'approval_decide',\n AUTOMATION_APPROVAL_DECIDE: 'automation_approval_decide',\n CHAT_APPROVAL_ANSWER: 'chat_approval_answer',\n} as const;\n\nexport type DecisionCheckKind = (typeof DecisionCheckKind)[keyof typeof DecisionCheckKind];\n\n/**\n * One decision a check covers, exactly as its decide call sends it: agora\n * builds the same item from the decide call and asks whether the token covers\n * it. `editedPayload` is the JSON value itself, never a hash of it.\n */\nexport interface DecisionCheckDescriptor {\n readonly kind: string;\n readonly targetIds: readonly string[];\n readonly option: string;\n readonly editedPayload?: unknown;\n readonly standingDuration?: string;\n}\n\n/** Which surface asks, as the check page shows it. */\nexport type DecisionCheckClientKind =\n | 'cli'\n | 'desktop'\n | 'mobile'\n | 'chrome_extension'\n | 'office_addin'\n | 'sdk';\n\nexport interface DecisionCheckClient {\n readonly kind: DecisionCheckClientKind;\n /** A short name for this device or app (\"Pat's MacBook\"), shown on the page. */\n readonly label?: string;\n}\n\nconst CHECKPOINT_NAMESPACE = 'athena-deep-agent:';\n\n/** A thread id the way agora names chat answers: without the checkpoint namespace. */\nexport function bareDecisionThreadId(threadId: string): string {\n return threadId.startsWith(CHECKPOINT_NAMESPACE)\n ? threadId.slice(CHECKPOINT_NAMESPACE.length)\n : threadId;\n}\n\n/**\n * A chat answer as statewire carries it: a `run/input` resume of one parked\n * request, or the lane decisions of a `run/lane-input`.\n */\nexport type StatewireAnswerForCheck =\n | { readonly kind: 'input'; readonly requestId: string; readonly value: unknown }\n | { readonly kind: 'lanes'; readonly laneDecisions: Readonly<Record<string, unknown>> };\n\n/**\n * The decisions one statewire answer makes: `chat_approval_answer` on\n * `<thread>:<requestId>` with the resume value as its payload, or one per lane\n * on `<thread>:<lane interrupt id>` with that lane's decision as its payload.\n */\nexport function statewireAnswerDescriptors({\n threadId,\n answer,\n}: {\n threadId: string;\n answer: StatewireAnswerForCheck;\n}): DecisionCheckDescriptor[] {\n const thread = bareDecisionThreadId(threadId);\n if (answer.kind === 'input') {\n return [\n {\n kind: DecisionCheckKind.CHAT_APPROVAL_ANSWER,\n targetIds: [`${thread}:${answer.requestId}`],\n option: 'resume',\n editedPayload: answer.value,\n },\n ];\n }\n return Object.entries(answer.laneDecisions).map(([interruptId, decision]) => ({\n kind: DecisionCheckKind.CHAT_APPROVAL_ANSWER,\n targetIds: [`${thread}:${interruptId}`],\n option: 'resume',\n editedPayload: decision,\n }));\n}\n\n/**\n * The phone's respond route (`POST /mobile/approvals/{thread}/respond`, also\n * the comment thread's inline approval): a `decisions` map is option\n * `decisions` with the map as its payload; otherwise the option is the action\n * and the payload its edited `tool_args`.\n */\nexport function respondDecisionDescriptor({\n threadId,\n toolCallId,\n action,\n toolArgs,\n decisions,\n}: {\n threadId: string;\n toolCallId: string;\n action?: string;\n toolArgs?: unknown;\n decisions?: Readonly<Record<string, unknown>>;\n}): DecisionCheckDescriptor {\n const target = `${bareDecisionThreadId(threadId)}:${toolCallId}`;\n if (decisions !== undefined && Object.keys(decisions).length > 0) {\n return {\n kind: DecisionCheckKind.CHAT_APPROVAL_ANSWER,\n targetIds: [target],\n option: 'decisions',\n editedPayload: decisions,\n };\n }\n return {\n kind: DecisionCheckKind.CHAT_APPROVAL_ANSWER,\n targetIds: [target],\n option: action ?? 'decisions',\n ...(toolArgs !== undefined && toolArgs !== null ? { editedPayload: toolArgs } : {}),\n };\n}\n\n/**\n * How a browser check went. Every outcome but `confirmed` sends the decision\n * without a token while checks are report-only; the surface decides what to\n * tell the person (a nudge to set up a passkey for `no_passkey`).\n */\nexport type BrowserDecisionCheckOutcome =\n | { readonly status: 'confirmed'; readonly token: string }\n | { readonly status: 'no_passkey' }\n | { readonly status: 'cancelled' }\n | { readonly status: 'unsupported' }\n | { readonly status: 'unavailable' }\n | { readonly status: 'expired' }\n | { readonly status: 'failed'; readonly message: string };\n\n/** What the surface shows while the person finishes in the browser. */\nexport interface PendingBrowserDecisionCheck {\n readonly userCode: string;\n readonly verificationUrl: string;\n readonly expiresAt: Date;\n}\n\n/**\n * The surface's authenticated request to agora: `path` is absolute from the\n * API root (`/api/passkeys/...`). The host adds its base URL and credential\n * (the person's sign-in, or the device key) and returns the raw response.\n */\nexport type AgoraFetch = (path: string, init: RequestInit) => Promise<Response>;\n\nexport interface RunBrowserDecisionCheckOptions {\n readonly decisions: readonly DecisionCheckDescriptor[];\n readonly client: DecisionCheckClient;\n readonly agoraFetch: AgoraFetch;\n /** Open the check page in the system browser or a new tab. */\n readonly openUrl: (url: string) => void | Promise<void>;\n /** An app link the page sends the person back to once they answered. */\n readonly returnUrl?: string;\n /** Told when the browser is open (with the code to show), and `null` once it settled. */\n readonly onPending?: (pending: PendingBrowserDecisionCheck | null) => void;\n /** Aborting gives up waiting: the decision goes without a token (`cancelled`). */\n readonly signal?: AbortSignal;\n /** Injectable for tests. */\n readonly sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n readonly now?: () => number;\n}\n\nconst REQUESTS_PATH = '/api/passkeys/decision-checks/requests';\nconst DEFAULT_INTERVAL_MS = 2_000;\nconst MIN_INTERVAL_MS = 1_000;\n/** A transient collect failure is retried; this many in a row gives up. */\nconst MAX_COLLECT_FAILURES = 5;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nasync function readJson(response: Response): Promise<Record<string, unknown> | null> {\n try {\n const body: unknown = await response.json();\n return isRecord(body) ? body : null;\n } catch {\n return null;\n }\n}\n\nfunction defaultSleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve();\n return;\n }\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n resolve();\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** Tell the host about the open check; a host callback that throws changes nothing here. */\nfunction notifyPending(\n options: RunBrowserDecisionCheckOptions,\n pending: PendingBrowserDecisionCheck | null,\n): void {\n try {\n options.onPending?.(pending);\n } catch (error) {\n console.warn('[decision-check] the pending notice failed:', messageOf(error));\n }\n}\n\ninterface OpenedCheck {\n readonly requestId: string;\n readonly pollSecret: string;\n readonly userCode: string;\n readonly verificationUrl: string;\n readonly expiresAt: Date;\n readonly intervalMs: number;\n}\n\nfunction openedCheck(body: Record<string, unknown> | null): OpenedCheck | null {\n if (body === null) return null;\n const { request_id, poll_secret, user_code, verification_url, expires_at, interval_seconds } =\n body;\n if (\n typeof request_id !== 'string' ||\n typeof poll_secret !== 'string' ||\n typeof user_code !== 'string' ||\n typeof verification_url !== 'string' ||\n typeof expires_at !== 'string'\n ) {\n return null;\n }\n const expiresAt = new Date(expires_at);\n if (Number.isNaN(expiresAt.getTime())) return null;\n const seconds = typeof interval_seconds === 'number' ? interval_seconds : 0;\n return {\n requestId: request_id,\n pollSecret: poll_secret,\n userCode: user_code,\n verificationUrl: verification_url,\n expiresAt,\n intervalMs: seconds > 0 ? Math.max(MIN_INTERVAL_MS, seconds * 1_000) : DEFAULT_INTERVAL_MS,\n };\n}\n\nasync function openRequest(\n options: RunBrowserDecisionCheckOptions,\n): Promise<OpenedCheck | BrowserDecisionCheckOutcome> {\n let response: Response;\n try {\n response = await options.agoraFetch(REQUESTS_PATH, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n decisions: options.decisions,\n client: options.client,\n ...(options.returnUrl ? { return_url: options.returnUrl } : {}),\n }),\n signal: options.signal,\n });\n } catch (error) {\n if (options.signal?.aborted) return { status: 'cancelled' };\n return { status: 'failed', message: messageOf(error) };\n }\n // 404: an agora before browser checks; 503: none can be minted here.\n if (response.status === 404 || response.status === 503) return { status: 'unavailable' };\n if (!response.ok) {\n return { status: 'failed', message: `The check could not start (${response.status}).` };\n }\n return openedCheck(await readJson(response)) ?? {\n status: 'failed',\n message: 'The check could not start.',\n };\n}\n\nfunction settledOutcome(body: Record<string, unknown> | null): BrowserDecisionCheckOutcome | null {\n if (body === null) return null;\n if (body.status === 'confirmed' && typeof body.check_token === 'string' && body.check_token) {\n return { status: 'confirmed', token: body.check_token };\n }\n if (body.status === 'declined') {\n switch (body.reason) {\n case 'no_passkey':\n return { status: 'no_passkey' };\n case 'unsupported':\n return { status: 'unsupported' };\n case 'failed':\n return { status: 'failed', message: 'The passkey check failed in the browser.' };\n default:\n return { status: 'cancelled' };\n }\n }\n return null;\n}\n\n/**\n * Ask the person to confirm `decisions` with their passkey in the system\n * browser, and wait for the answer: the token when they confirmed, or why\n * there is none. Never rejects.\n */\nexport async function runBrowserDecisionCheck(\n options: RunBrowserDecisionCheckOptions,\n): Promise<BrowserDecisionCheckOutcome> {\n if (options.decisions.length === 0) return { status: 'failed', message: 'Nothing to confirm.' };\n if (options.decisions.length > MAX_DECISIONS_PER_CHECK) {\n return {\n status: 'failed',\n message: `One check confirms up to ${MAX_DECISIONS_PER_CHECK} decisions.`,\n };\n }\n const sleep = options.sleep ?? defaultSleep;\n const now = options.now ?? Date.now;\n const opened = await openRequest(options);\n if ('status' in opened) return opened;\n\n notifyPending(options, {\n userCode: opened.userCode,\n verificationUrl: opened.verificationUrl,\n expiresAt: opened.expiresAt,\n });\n try {\n try {\n await options.openUrl(opened.verificationUrl);\n } catch (error) {\n // The page can still be opened by hand from the link the surface shows.\n console.warn('[decision-check] could not open the browser:', messageOf(error));\n }\n let failures = 0;\n while (now() < opened.expiresAt.getTime()) {\n await sleep(opened.intervalMs, options.signal);\n if (options.signal?.aborted) return { status: 'cancelled' };\n let response: Response;\n try {\n response = await options.agoraFetch(\n `${REQUESTS_PATH}/${encodeURIComponent(opened.requestId)}/collect`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ poll_secret: opened.pollSecret }),\n signal: options.signal,\n },\n );\n } catch (error) {\n if (options.signal?.aborted) return { status: 'cancelled' };\n failures += 1;\n if (failures >= MAX_COLLECT_FAILURES) return { status: 'failed', message: messageOf(error) };\n continue;\n }\n // Unknown, expired or already collected: nothing more will come.\n if (response.status === 404) return { status: 'expired' };\n if (!response.ok) {\n failures += 1;\n if (failures >= MAX_COLLECT_FAILURES) {\n return { status: 'failed', message: `The check could not finish (${response.status}).` };\n }\n continue;\n }\n failures = 0;\n const settled = settledOutcome(await readJson(response));\n if (settled !== null) return settled;\n }\n return { status: 'expired' };\n } finally {\n notifyPending(options, null);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -64,6 +64,12 @@ export declare const desktopHandoffViewSchema: z.ZodObject<{
|
|
|
64
64
|
reason: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
65
65
|
}, z.core.$strip>>;
|
|
66
66
|
}, z.core.$strip>>;
|
|
67
|
+
origin: z.ZodOptional<z.ZodString>;
|
|
68
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
69
|
+
text: "text";
|
|
70
|
+
voice: "voice";
|
|
71
|
+
}>>;
|
|
72
|
+
draft: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
67
73
|
}, z.core.$strip>;
|
|
68
74
|
export type DesktopHandoffView = z.infer<typeof desktopHandoffViewSchema>;
|
|
69
75
|
export declare const desktopHandoffLaunchSchema: z.ZodObject<{
|
|
@@ -117,6 +123,12 @@ export declare const createDesktopHandoffResponseSchema: z.ZodObject<{
|
|
|
117
123
|
reason: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
118
124
|
}, z.core.$strip>>;
|
|
119
125
|
}, z.core.$strip>>;
|
|
126
|
+
origin: z.ZodOptional<z.ZodString>;
|
|
127
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
128
|
+
text: "text";
|
|
129
|
+
voice: "voice";
|
|
130
|
+
}>>;
|
|
131
|
+
draft: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
120
132
|
}, z.core.$strip>;
|
|
121
133
|
launch: z.ZodObject<{
|
|
122
134
|
kind: z.ZodLiteral<"desktop">;
|
|
@@ -38,6 +38,23 @@ function readRunStartRefusal(error) {
|
|
|
38
38
|
status: typeof status === "number" ? status : null
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
+
const VOICE_REJECTION_REASONS = /* @__PURE__ */ new Set([
|
|
42
|
+
"no-voice",
|
|
43
|
+
"not-voice-owner",
|
|
44
|
+
"voice-active",
|
|
45
|
+
"voice-stale-session",
|
|
46
|
+
"voice-unavailable",
|
|
47
|
+
"voice-not-enabled",
|
|
48
|
+
"voice-model-transport",
|
|
49
|
+
"text-too-long"
|
|
50
|
+
]);
|
|
51
|
+
function isVoiceCommandRejection(error) {
|
|
52
|
+
var _a;
|
|
53
|
+
const failure = error == null ? void 0 : error.failure;
|
|
54
|
+
if ((failure == null ? void 0 : failure.fate) !== "rejected") return false;
|
|
55
|
+
const reason = (_a = failure.payload) == null ? void 0 : _a.reason;
|
|
56
|
+
return typeof reason === "string" && VOICE_REJECTION_REASONS.has(reason);
|
|
57
|
+
}
|
|
41
58
|
function statewireRejectionCode(error) {
|
|
42
59
|
var _a;
|
|
43
60
|
const detail = (_a = statewireRejectionPayload(error)) == null ? void 0 : _a.detail;
|
|
@@ -133,6 +150,7 @@ exports.isConversationArchivedRejection = isConversationArchivedRejection;
|
|
|
133
150
|
exports.isLegacyThreadReadOnlyRejection = isLegacyThreadReadOnlyRejection;
|
|
134
151
|
exports.isStatewireChannelTeardown = isStatewireChannelTeardown;
|
|
135
152
|
exports.isStatewireExpiredVerdict = isStatewireExpiredVerdict;
|
|
153
|
+
exports.isVoiceCommandRejection = isVoiceCommandRejection;
|
|
136
154
|
exports.projectDeepAgentConnection = projectDeepAgentConnection;
|
|
137
155
|
exports.readRetryableCommandRejection = readRetryableCommandRejection;
|
|
138
156
|
exports.readRetryableRunRefusal = readRetryableRunRefusal;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.cjs","sources":["../../../../agent-runtime/src/errors.ts"],"sourcesContent":["import type { StatewireClient } from 'statewire';\nimport type { DeepAgentConnectionState } from './types';\n\n/** Structured payload attached to a server-rejected Statewire command. */\nexport interface StatewireRejectionPayload {\n status: number;\n detail: unknown;\n}\n\n/** Return a rejected command's structured `{ status, detail }` payload. */\nexport function statewireRejectionPayload(error: unknown): StatewireRejectionPayload | null {\n const failure = (error as { failure?: { fate?: unknown; payload?: unknown } } | null)?.failure;\n if (failure?.fate !== 'rejected') return null;\n\n const payload = failure.payload as { status?: unknown; detail?: unknown } | undefined;\n if (typeof payload?.status !== 'number') return null;\n return { status: payload.status, detail: payload.detail };\n}\n\n/**\n * The server's human-readable reason for a rejected command — `detail.message`\n * (or a plain-string `detail`) — else `null`. Hosts surface it as send\n * feedback so the user sees the actionable cause instead of the generic\n * client-side `command rejected (<status>)`.\n */\nexport function statewireRejectionDetailMessage(error: unknown): string | null {\n const detail = statewireRejectionPayload(error)?.detail;\n if (typeof detail === 'string') return detail.length > 0 ? detail : null;\n if (detail === null || typeof detail !== 'object' || Array.isArray(detail)) return null;\n const message = (detail as { message?: unknown }).message;\n return typeof message === 'string' && message.length > 0 ? message : null;\n}\n\n/**\n * A structured, retryable refusal the host recorded as the run error\n * (`runs.error`): the dispatch never started — the pod or instance was\n * closing (`pod_draining`) — and the entries stayed in their lanes for the\n * thread's next placement. Distinct from a rejected COMMAND\n * ({@link statewireRejectionPayload}): this is the shape harness-sdk writes\n * when the run executor raises the rejection, so it lives on the replicated\n * run entry, not on a command settle.\n */\nexport interface RetryableRunRefusal {\n /** The structured `detail.code` (`pod_draining`). */\n code: string;\n /** The server's human-readable reason, when it sent one. */\n message: string | null;\n}\n\n/** The `{ code, message, retryable: true }` detail of a structured refusal, or `null`. */\nfunction readRetryableDetail(detail: unknown): { code: string; message: string | null } | null {\n if (detail === null || typeof detail !== 'object' || Array.isArray(detail)) return null;\n const { code, message, retryable } = detail as {\n code?: unknown;\n message?: unknown;\n retryable?: unknown;\n };\n if (retryable !== true || typeof code !== 'string' || code.length === 0) return null;\n return { code, message: typeof message === 'string' && message.length > 0 ? message : null };\n}\n\nexport function readRetryableRunRefusal(error: unknown): RetryableRunRefusal | null {\n if (error === null || typeof error !== 'object' || Array.isArray(error)) return null;\n return readRetryableDetail((error as { detail?: unknown }).detail);\n}\n\n/**\n * The `detail.code` agora answers when a send names another channel of the\n * collab agent a session started on (`collab_agent_bridge.py`): a session\n * keeps its channel — the SDK app's Agent / Ask mode — for its lifetime, and\n * the way to the other mode is a new session. Wire-frozen.\n */\nexport const COLLAB_AGENT_CHANNEL_SESSION_MISMATCH = 'collab_agent_channel_session_mismatch';\n\n/**\n * A structured refusal the host recorded as the run error when the run could\n * not START: the run executor raised the gate's `{status, detail: {code,\n * message}}` envelope (agora's `_status_reject`) before it accepted the\n * dispatched input, so the message went back to its lane and the thread rests\n * `error` with it still queued. Unlike a retryable refusal\n * ({@link readRetryableRunRefusal}) nothing will dispatch it later: resending\n * the same input is refused the same way, so the server's message is the only\n * explanation the person gets.\n */\nexport interface RunStartRefusal {\n /** The structured `detail.code` (`collab_agent_channel_session_mismatch`, …). */\n code: string;\n /** The server's human-readable reason, when it sent one. */\n message: string | null;\n /** The HTTP-style status the gate raised with, when recorded. */\n status: number | null;\n}\n\n/**\n * The non-retryable structured refusal off a replicated run error\n * (`runs.error`), or `null` — for a run that failed while it was running (a\n * plain `{message}`), a retryable refusal, or no error at all.\n */\nexport function readRunStartRefusal(error: unknown): RunStartRefusal | null {\n if (error === null || typeof error !== 'object' || Array.isArray(error)) return null;\n const { detail, status } = error as { detail?: unknown; status?: unknown };\n if (detail === null || typeof detail !== 'object' || Array.isArray(detail)) return null;\n const { code, message, retryable } = detail as {\n code?: unknown;\n message?: unknown;\n retryable?: unknown;\n };\n if (retryable === true || typeof code !== 'string' || code.length === 0) return null;\n return {\n code,\n message: typeof message === 'string' && message.length > 0 ? message : null,\n status: typeof status === 'number' ? status : null,\n };\n}\n\n/** The structured `detail.code` of a rejected command, or `null`. */\nexport function statewireRejectionCode(error: unknown): string | null {\n const detail = statewireRejectionPayload(error)?.detail;\n if (detail === null || typeof detail !== 'object' || Array.isArray(detail)) return null;\n const code = (detail as { code?: unknown }).code;\n return typeof code === 'string' && code.length > 0 ? code : null;\n}\n\n/**\n * A structured, retryable refusal of a COMMAND, read off its rejection\n * ({@link statewireRejectionPayload}): the host's `_structured_reject(...,\n * retryable=True)` envelope — `command_auth_context_expired` when a pod\n * replacement dropped the socket-scoped auth a replayed command needed,\n * `pod_draining` when the host was closing. The command never ran, and the\n * host itself says a resend after the reconnect will; `detail.code` is the\n * wire-frozen contract clients classify on. Same shape as\n * {@link readRetryableRunRefusal}, which reads it off a replicated run entry.\n */\nexport interface RetryableCommandRejection {\n /** The structured `detail.code`. */\n code: string;\n /** The server's human-readable reason, when it sent one. */\n message: string | null;\n}\n\nexport function readRetryableCommandRejection(error: unknown): RetryableCommandRejection | null {\n const payload = statewireRejectionPayload(error);\n return payload === null ? null : readRetryableDetail(payload.detail);\n}\n\n/** The host's `detail.code` for a command replayed onto a pod that could not restore its auth context. */\nexport const STATEWIRE_COMMAND_AUTH_CONTEXT_EXPIRED = 'command_auth_context_expired';\n\n/**\n * Whether a rejected command hit the host's fail-closed auth recovery: the\n * command was replayed onto a replacement pod that could not restore the\n * attach's auth context, so it was refused unrun (503, retryable). The\n * reconnect already under way restores the context; a single resend after it\n * is the recovery, not a failure to report.\n */\nexport function isStatewireCommandAuthContextExpired(error: unknown): boolean {\n const payload = statewireRejectionPayload(error);\n return (\n payload?.status === 503 &&\n readRetryableDetail(payload.detail)?.code === STATEWIRE_COMMAND_AUTH_CONTEXT_EXPIRED\n );\n}\n\n/**\n * The `detail.code` agora answers for a write to an archived (trashed)\n * conversation (`host_rejects._conversation_archived_reject`, a 409): it\n * takes no new turns, config writes or approval answers until it is\n * restored, and stopping still works. Wire-frozen.\n */\nexport const CONVERSATION_ARCHIVED = 'conversation_archived';\n\n/** What a person is told when that refusal comes back (the server says the same). */\nexport const CONVERSATION_ARCHIVED_MESSAGE =\n 'This conversation is archived. Restore it to continue.';\n\n/**\n * Whether a rejected command was refused because the conversation is archived\n * ({@link CONVERSATION_ARCHIVED}). Not retriable: nothing changes until a\n * restore, so callers show {@link CONVERSATION_ARCHIVED_MESSAGE} rather than a\n * \"try again\".\n */\nexport function isConversationArchivedRejection(error: unknown): boolean {\n return statewireRejectionCode(error) === CONVERSATION_ARCHIVED;\n}\n\n/**\n * Whether a rejected command hit the legacy-thread dispatch fence: the\n * structured 409 the server answers when an out-of-band run is writing a\n * pre-cutover thread (or its adoption failed). A per-send failure — the\n * snapshot never carries a standing read-only flag.\n */\nexport function isLegacyThreadReadOnlyRejection(error: unknown): boolean {\n const payload = statewireRejectionPayload(error);\n if (payload?.status !== 409) return false;\n\n const detail = payload.detail as { code?: unknown } | undefined;\n return detail?.code === 'legacy_thread_read_only';\n}\n\n/**\n * Whether a rejected command was refused because its rewind anchor no longer\n * matches the host's parent for the edited message (`wrong-anchor`).\n *\n * A retry/edit resubmit is dispatched optimistically, so this rejection lands\n * after the UI already cleared its edit affordances: the turn simply never\n * re-runs. Callers use this to tell the user the resubmit was dropped instead\n * of leaving a console-only failure.\n */\nexport function isStatewireRewindAnchorRejection(error: unknown): boolean {\n const failure = (error as { failure?: { fate?: unknown; payload?: unknown } } | null | undefined)\n ?.failure;\n if (failure?.fate !== 'rejected') return false;\n return (failure.payload as { reason?: unknown } | undefined)?.reason === 'wrong-anchor';\n}\n\n/**\n * Whether a statewire send failure is the host's `expired` verdict\n * (`result-unavailable`): the command's seq was at or below the host's\n * admitted watermark and no retained result was left for it. Either the\n * command ran and settled but the client re-asked for the answer (a resend\n * after the stream came back) only after the host had let the retained result\n * go, or the seq was already admitted and the command was absorbed as a\n * duplicate without ever running — a client whose shared session record fell\n * behind the watermark stays there until a reconnect re-syncs it. The library\n * never reruns the command on replay, so for an idempotent read the answer is\n * simply gone — asking again is the correct reaction, not reporting a failure;\n * a write cannot assume it was applied.\n */\nexport function isStatewireExpiredVerdict(error: unknown): boolean {\n const failure = (error as { failure?: { fate?: unknown; cause?: unknown } | null | undefined })\n ?.failure;\n return failure?.fate === 'expired' && failure.cause === 'server';\n}\n\n/**\n * Whether a statewire send failure is a local channel death rather than a\n * command error.\n *\n * The library's contract for `SendFailure.cause`: `\"server\"` is the server's\n * own answer; every other cause is \"a channel death the client settled\n * locally\" — `unmount`, `stream-gone`, and `session-lost`. A thread switch\n * settles every in-flight command that way, so logging these at error level\n * reports two failures for an ordinary switch and buries the ones that mean\n * something.\n *\n * Channel health is already surfaced where it belongs: the connection\n * indicator renders the connection state. This\n * predicate only decides the log level.\n */\nexport function isStatewireChannelTeardown(error: unknown): boolean {\n const cause = (error as { failure?: { cause?: unknown } } | null | undefined)?.failure?.cause;\n return typeof cause === 'string' && cause !== 'server';\n}\n\n/**\n * The low-cardinality reason a statewire send settled as transport weather\n * rather than a defect, or `null` when the failure is a real error.\n *\n * Three families qualify: a channel death the client settled locally\n * ({@link isStatewireChannelTeardown} — the cause: `unmount`, `stream-gone`,\n * `session-lost`), the host's `expired` verdict\n * ({@link isStatewireExpiredVerdict} — the answer outlived the host's\n * retention before the post-reconnect resend collected it), and a retryable\n * structured rejection ({@link readRetryableCommandRejection} — its code: the\n * host asked for a resend). In every case the sender's own retry or poll is\n * the recovery and the connection indicator already shows the channel, so\n * error reporting counts the outcome instead of paging on it. Handler\n * failures, crashes, and non-retryable rejections stay `null`: those are\n * defects to page on.\n */\nexport function statewireTransportOutcome(error: unknown): string | null {\n const cause = (error as { failure?: { cause?: unknown } } | null | undefined)?.failure?.cause;\n if (typeof cause === 'string' && cause !== 'server') return cause;\n if (isStatewireExpiredVerdict(error)) return 'expired';\n return readRetryableCommandRejection(error)?.code ?? null;\n}\n\nconst sanitizeConnectionMessage = (message: string): string | undefined => {\n const printable = Array.from(message, (character) => {\n const code = character.charCodeAt(0);\n return code < 32 || code === 127 ? ' ' : character;\n })\n .join('')\n .replace(/\\s+/g, ' ')\n .trim();\n return printable ? printable.slice(0, 200) : undefined;\n};\n\n/** Preserve the Statewire lifecycle and sanitize host detail for display. */\nexport function projectDeepAgentConnection(\n connection: StatewireClient.ConnectionState\n): DeepAgentConnectionState {\n const message =\n 'message' in connection && typeof connection.message === 'string'\n ? sanitizeConnectionMessage(connection.message)\n : undefined;\n switch (connection.status) {\n case 'standby':\n return {\n status: connection.status,\n reason: connection.reason,\n degraded: connection.degraded,\n ...(message !== undefined && { message }),\n };\n case 'connecting':\n case 'connected':\n return { status: connection.status, degraded: connection.degraded };\n case 'retrying':\n return {\n status: connection.status,\n degraded: connection.degraded,\n attempt: connection.attempt,\n ...(connection.cause !== undefined && { cause: connection.cause }),\n ...(connection.code !== undefined && { code: connection.code }),\n ...(connection.nextRetryAt !== undefined && { nextRetryAt: connection.nextRetryAt }),\n ...(connection.lastError !== undefined && { lastError: connection.lastError }),\n ...(message !== undefined && { message }),\n };\n case 'stopped':\n return {\n status: connection.status,\n degraded: connection.degraded,\n reason: connection.reason,\n ...(connection.payload !== undefined && { payload: connection.payload }),\n ...(message !== undefined && { message }),\n };\n default:\n return unknownConnectionStatus(connection);\n }\n}\n\n/** Compile-time exhaustiveness: reachable only when the library grows a status this build does not project. */\nfunction unknownConnectionStatus(connection: never): never {\n throw new Error(\n `statewire: unknown connection status ${JSON.stringify(\n (connection as { status?: unknown }).status\n )}`\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"errors.cjs","sources":["../../../../agent-runtime/src/errors.ts"],"sourcesContent":["import type { StatewireClient } from 'statewire';\nimport type { DeepAgentConnectionState } from './types';\n\n/** Structured payload attached to a server-rejected Statewire command. */\nexport interface StatewireRejectionPayload {\n status: number;\n detail: unknown;\n}\n\n/** Return a rejected command's structured `{ status, detail }` payload. */\nexport function statewireRejectionPayload(error: unknown): StatewireRejectionPayload | null {\n const failure = (error as { failure?: { fate?: unknown; payload?: unknown } } | null)?.failure;\n if (failure?.fate !== 'rejected') return null;\n\n const payload = failure.payload as { status?: unknown; detail?: unknown } | undefined;\n if (typeof payload?.status !== 'number') return null;\n return { status: payload.status, detail: payload.detail };\n}\n\n/**\n * The server's human-readable reason for a rejected command — `detail.message`\n * (or a plain-string `detail`) — else `null`. Hosts surface it as send\n * feedback so the user sees the actionable cause instead of the generic\n * client-side `command rejected (<status>)`.\n */\nexport function statewireRejectionDetailMessage(error: unknown): string | null {\n const detail = statewireRejectionPayload(error)?.detail;\n if (typeof detail === 'string') return detail.length > 0 ? detail : null;\n if (detail === null || typeof detail !== 'object' || Array.isArray(detail)) return null;\n const message = (detail as { message?: unknown }).message;\n return typeof message === 'string' && message.length > 0 ? message : null;\n}\n\n/**\n * A structured, retryable refusal the host recorded as the run error\n * (`runs.error`): the dispatch never started — the pod or instance was\n * closing (`pod_draining`) — and the entries stayed in their lanes for the\n * thread's next placement. Distinct from a rejected COMMAND\n * ({@link statewireRejectionPayload}): this is the shape harness-sdk writes\n * when the run executor raises the rejection, so it lives on the replicated\n * run entry, not on a command settle.\n */\nexport interface RetryableRunRefusal {\n /** The structured `detail.code` (`pod_draining`). */\n code: string;\n /** The server's human-readable reason, when it sent one. */\n message: string | null;\n}\n\n/** The `{ code, message, retryable: true }` detail of a structured refusal, or `null`. */\nfunction readRetryableDetail(detail: unknown): { code: string; message: string | null } | null {\n if (detail === null || typeof detail !== 'object' || Array.isArray(detail)) return null;\n const { code, message, retryable } = detail as {\n code?: unknown;\n message?: unknown;\n retryable?: unknown;\n };\n if (retryable !== true || typeof code !== 'string' || code.length === 0) return null;\n return { code, message: typeof message === 'string' && message.length > 0 ? message : null };\n}\n\nexport function readRetryableRunRefusal(error: unknown): RetryableRunRefusal | null {\n if (error === null || typeof error !== 'object' || Array.isArray(error)) return null;\n return readRetryableDetail((error as { detail?: unknown }).detail);\n}\n\n/**\n * The `detail.code` agora answers when a send names another channel of the\n * collab agent a session started on (`collab_agent_bridge.py`): a session\n * keeps its channel — the SDK app's Agent / Ask mode — for its lifetime, and\n * the way to the other mode is a new session. Wire-frozen.\n */\nexport const COLLAB_AGENT_CHANNEL_SESSION_MISMATCH = 'collab_agent_channel_session_mismatch';\n\n/**\n * A structured refusal the host recorded as the run error when the run could\n * not START: the run executor raised the gate's `{status, detail: {code,\n * message}}` envelope (agora's `_status_reject`) before it accepted the\n * dispatched input, so the message went back to its lane and the thread rests\n * `error` with it still queued. Unlike a retryable refusal\n * ({@link readRetryableRunRefusal}) nothing will dispatch it later: resending\n * the same input is refused the same way, so the server's message is the only\n * explanation the person gets.\n */\nexport interface RunStartRefusal {\n /** The structured `detail.code` (`collab_agent_channel_session_mismatch`, …). */\n code: string;\n /** The server's human-readable reason, when it sent one. */\n message: string | null;\n /** The HTTP-style status the gate raised with, when recorded. */\n status: number | null;\n}\n\n/**\n * The non-retryable structured refusal off a replicated run error\n * (`runs.error`), or `null` — for a run that failed while it was running (a\n * plain `{message}`), a retryable refusal, or no error at all.\n */\nexport function readRunStartRefusal(error: unknown): RunStartRefusal | null {\n if (error === null || typeof error !== 'object' || Array.isArray(error)) return null;\n const { detail, status } = error as { detail?: unknown; status?: unknown };\n if (detail === null || typeof detail !== 'object' || Array.isArray(detail)) return null;\n const { code, message, retryable } = detail as {\n code?: unknown;\n message?: unknown;\n retryable?: unknown;\n };\n if (retryable === true || typeof code !== 'string' || code.length === 0) return null;\n return {\n code,\n message: typeof message === 'string' && message.length > 0 ? message : null,\n status: typeof status === 'number' ? status : null,\n };\n}\n\n/**\n * The `payload.reason` codes agora's voice manager rejects `voice/*` commands\n * with (harness-sdk's `_reject` and `voice_host.py`). Wire-frozen.\n */\nconst VOICE_REJECTION_REASONS: ReadonlySet<string> = new Set([\n 'no-voice',\n 'not-voice-owner',\n 'voice-active',\n 'voice-stale-session',\n 'voice-unavailable',\n 'voice-not-enabled',\n 'voice-model-transport',\n 'text-too-long',\n]);\n\n/**\n * Whether a rejected command was a `voice/*` command, by its voice manager\n * `payload.reason`. The voice controller owns those outcomes (it settles to\n * idle, falls back to a typed send, or shows its own notice), so a chat's\n * \"Message was not sent\" banner must not repeat them: no message was sent.\n */\nexport function isVoiceCommandRejection(error: unknown): boolean {\n const failure = (error as { failure?: { fate?: unknown; payload?: unknown } } | null)?.failure;\n if (failure?.fate !== 'rejected') return false;\n const reason = (failure.payload as { reason?: unknown } | null | undefined)?.reason;\n return typeof reason === 'string' && VOICE_REJECTION_REASONS.has(reason);\n}\n\n/** The structured `detail.code` of a rejected command, or `null`. */\nexport function statewireRejectionCode(error: unknown): string | null {\n const detail = statewireRejectionPayload(error)?.detail;\n if (detail === null || typeof detail !== 'object' || Array.isArray(detail)) return null;\n const code = (detail as { code?: unknown }).code;\n return typeof code === 'string' && code.length > 0 ? code : null;\n}\n\n/**\n * A structured, retryable refusal of a COMMAND, read off its rejection\n * ({@link statewireRejectionPayload}): the host's `_structured_reject(...,\n * retryable=True)` envelope — `command_auth_context_expired` when a pod\n * replacement dropped the socket-scoped auth a replayed command needed,\n * `pod_draining` when the host was closing. The command never ran, and the\n * host itself says a resend after the reconnect will; `detail.code` is the\n * wire-frozen contract clients classify on. Same shape as\n * {@link readRetryableRunRefusal}, which reads it off a replicated run entry.\n */\nexport interface RetryableCommandRejection {\n /** The structured `detail.code`. */\n code: string;\n /** The server's human-readable reason, when it sent one. */\n message: string | null;\n}\n\nexport function readRetryableCommandRejection(error: unknown): RetryableCommandRejection | null {\n const payload = statewireRejectionPayload(error);\n return payload === null ? null : readRetryableDetail(payload.detail);\n}\n\n/** The host's `detail.code` for a command replayed onto a pod that could not restore its auth context. */\nexport const STATEWIRE_COMMAND_AUTH_CONTEXT_EXPIRED = 'command_auth_context_expired';\n\n/**\n * Whether a rejected command hit the host's fail-closed auth recovery: the\n * command was replayed onto a replacement pod that could not restore the\n * attach's auth context, so it was refused unrun (503, retryable). The\n * reconnect already under way restores the context; a single resend after it\n * is the recovery, not a failure to report.\n */\nexport function isStatewireCommandAuthContextExpired(error: unknown): boolean {\n const payload = statewireRejectionPayload(error);\n return (\n payload?.status === 503 &&\n readRetryableDetail(payload.detail)?.code === STATEWIRE_COMMAND_AUTH_CONTEXT_EXPIRED\n );\n}\n\n/**\n * The `detail.code` agora answers for a write to an archived (trashed)\n * conversation (`host_rejects._conversation_archived_reject`, a 409): it\n * takes no new turns, config writes or approval answers until it is\n * restored, and stopping still works. Wire-frozen.\n */\nexport const CONVERSATION_ARCHIVED = 'conversation_archived';\n\n/** What a person is told when that refusal comes back (the server says the same). */\nexport const CONVERSATION_ARCHIVED_MESSAGE =\n 'This conversation is archived. Restore it to continue.';\n\n/**\n * Whether a rejected command was refused because the conversation is archived\n * ({@link CONVERSATION_ARCHIVED}). Not retriable: nothing changes until a\n * restore, so callers show {@link CONVERSATION_ARCHIVED_MESSAGE} rather than a\n * \"try again\".\n */\nexport function isConversationArchivedRejection(error: unknown): boolean {\n return statewireRejectionCode(error) === CONVERSATION_ARCHIVED;\n}\n\n/**\n * Whether a rejected command hit the legacy-thread dispatch fence: the\n * structured 409 the server answers when an out-of-band run is writing a\n * pre-cutover thread (or its adoption failed). A per-send failure — the\n * snapshot never carries a standing read-only flag.\n */\nexport function isLegacyThreadReadOnlyRejection(error: unknown): boolean {\n const payload = statewireRejectionPayload(error);\n if (payload?.status !== 409) return false;\n\n const detail = payload.detail as { code?: unknown } | undefined;\n return detail?.code === 'legacy_thread_read_only';\n}\n\n/**\n * Whether a rejected command was refused because its rewind anchor no longer\n * matches the host's parent for the edited message (`wrong-anchor`).\n *\n * A retry/edit resubmit is dispatched optimistically, so this rejection lands\n * after the UI already cleared its edit affordances: the turn simply never\n * re-runs. Callers use this to tell the user the resubmit was dropped instead\n * of leaving a console-only failure.\n */\nexport function isStatewireRewindAnchorRejection(error: unknown): boolean {\n const failure = (error as { failure?: { fate?: unknown; payload?: unknown } } | null | undefined)\n ?.failure;\n if (failure?.fate !== 'rejected') return false;\n return (failure.payload as { reason?: unknown } | undefined)?.reason === 'wrong-anchor';\n}\n\n/**\n * Whether a statewire send failure is the host's `expired` verdict\n * (`result-unavailable`): the command's seq was at or below the host's\n * admitted watermark and no retained result was left for it. Either the\n * command ran and settled but the client re-asked for the answer (a resend\n * after the stream came back) only after the host had let the retained result\n * go, or the seq was already admitted and the command was absorbed as a\n * duplicate without ever running — a client whose shared session record fell\n * behind the watermark stays there until a reconnect re-syncs it. The library\n * never reruns the command on replay, so for an idempotent read the answer is\n * simply gone — asking again is the correct reaction, not reporting a failure;\n * a write cannot assume it was applied.\n */\nexport function isStatewireExpiredVerdict(error: unknown): boolean {\n const failure = (error as { failure?: { fate?: unknown; cause?: unknown } | null | undefined })\n ?.failure;\n return failure?.fate === 'expired' && failure.cause === 'server';\n}\n\n/**\n * Whether a statewire send failure is a local channel death rather than a\n * command error.\n *\n * The library's contract for `SendFailure.cause`: `\"server\"` is the server's\n * own answer; every other cause is \"a channel death the client settled\n * locally\" — `unmount`, `stream-gone`, and `session-lost`. A thread switch\n * settles every in-flight command that way, so logging these at error level\n * reports two failures for an ordinary switch and buries the ones that mean\n * something.\n *\n * Channel health is already surfaced where it belongs: the connection\n * indicator renders the connection state. This\n * predicate only decides the log level.\n */\nexport function isStatewireChannelTeardown(error: unknown): boolean {\n const cause = (error as { failure?: { cause?: unknown } } | null | undefined)?.failure?.cause;\n return typeof cause === 'string' && cause !== 'server';\n}\n\n/**\n * The low-cardinality reason a statewire send settled as transport weather\n * rather than a defect, or `null` when the failure is a real error.\n *\n * Three families qualify: a channel death the client settled locally\n * ({@link isStatewireChannelTeardown} — the cause: `unmount`, `stream-gone`,\n * `session-lost`), the host's `expired` verdict\n * ({@link isStatewireExpiredVerdict} — the answer outlived the host's\n * retention before the post-reconnect resend collected it), and a retryable\n * structured rejection ({@link readRetryableCommandRejection} — its code: the\n * host asked for a resend). In every case the sender's own retry or poll is\n * the recovery and the connection indicator already shows the channel, so\n * error reporting counts the outcome instead of paging on it. Handler\n * failures, crashes, and non-retryable rejections stay `null`: those are\n * defects to page on.\n */\nexport function statewireTransportOutcome(error: unknown): string | null {\n const cause = (error as { failure?: { cause?: unknown } } | null | undefined)?.failure?.cause;\n if (typeof cause === 'string' && cause !== 'server') return cause;\n if (isStatewireExpiredVerdict(error)) return 'expired';\n return readRetryableCommandRejection(error)?.code ?? null;\n}\n\nconst sanitizeConnectionMessage = (message: string): string | undefined => {\n const printable = Array.from(message, (character) => {\n const code = character.charCodeAt(0);\n return code < 32 || code === 127 ? ' ' : character;\n })\n .join('')\n .replace(/\\s+/g, ' ')\n .trim();\n return printable ? printable.slice(0, 200) : undefined;\n};\n\n/** Preserve the Statewire lifecycle and sanitize host detail for display. */\nexport function projectDeepAgentConnection(\n connection: StatewireClient.ConnectionState\n): DeepAgentConnectionState {\n const message =\n 'message' in connection && typeof connection.message === 'string'\n ? sanitizeConnectionMessage(connection.message)\n : undefined;\n switch (connection.status) {\n case 'standby':\n return {\n status: connection.status,\n reason: connection.reason,\n degraded: connection.degraded,\n ...(message !== undefined && { message }),\n };\n case 'connecting':\n case 'connected':\n return { status: connection.status, degraded: connection.degraded };\n case 'retrying':\n return {\n status: connection.status,\n degraded: connection.degraded,\n attempt: connection.attempt,\n ...(connection.cause !== undefined && { cause: connection.cause }),\n ...(connection.code !== undefined && { code: connection.code }),\n ...(connection.nextRetryAt !== undefined && { nextRetryAt: connection.nextRetryAt }),\n ...(connection.lastError !== undefined && { lastError: connection.lastError }),\n ...(message !== undefined && { message }),\n };\n case 'stopped':\n return {\n status: connection.status,\n degraded: connection.degraded,\n reason: connection.reason,\n ...(connection.payload !== undefined && { payload: connection.payload }),\n ...(message !== undefined && { message }),\n };\n default:\n return unknownConnectionStatus(connection);\n }\n}\n\n/** Compile-time exhaustiveness: reachable only when the library grows a status this build does not project. */\nfunction unknownConnectionStatus(connection: never): never {\n throw new Error(\n `statewire: unknown connection status ${JSON.stringify(\n (connection as { status?: unknown }).status\n )}`\n );\n}\n"],"names":[],"mappings":";;AAUO,SAAS,0BAA0B,OAAkD;AAC1F,QAAM,UAAW,+BAAsE;AACvF,OAAI,mCAAS,UAAS,WAAY,QAAO;AAEzC,QAAM,UAAU,QAAQ;AACxB,MAAI,QAAO,mCAAS,YAAW,SAAU,QAAO;AAChD,SAAO,EAAE,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,OAAA;AACnD;AAQO,SAAS,gCAAgC,OAA+B;;AAC7E,QAAM,UAAS,+BAA0B,KAAK,MAA/B,mBAAkC;AACjD,MAAI,OAAO,WAAW,iBAAiB,OAAO,SAAS,IAAI,SAAS;AACpE,MAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,EAAG,QAAO;AACnF,QAAM,UAAW,OAAiC;AAClD,SAAO,OAAO,YAAY,YAAY,QAAQ,SAAS,IAAI,UAAU;AACvE;AAmBA,SAAS,oBAAoB,QAAkE;AAC7F,MAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,EAAG,QAAO;AACnF,QAAM,EAAE,MAAM,SAAS,UAAA,IAAc;AAKrC,MAAI,cAAc,QAAQ,OAAO,SAAS,YAAY,KAAK,WAAW,EAAG,QAAO;AAChF,SAAO,EAAE,MAAM,SAAS,OAAO,YAAY,YAAY,QAAQ,SAAS,IAAI,UAAU,KAAA;AACxF;AAEO,SAAS,wBAAwB,OAA4C;AAClF,MAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO;AAChF,SAAO,oBAAqB,MAA+B,MAAM;AACnE;AAQO,MAAM,wCAAwC;AA0B9C,SAAS,oBAAoB,OAAwC;AAC1E,MAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO;AAChF,QAAM,EAAE,QAAQ,OAAA,IAAW;AAC3B,MAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,EAAG,QAAO;AACnF,QAAM,EAAE,MAAM,SAAS,UAAA,IAAc;AAKrC,MAAI,cAAc,QAAQ,OAAO,SAAS,YAAY,KAAK,WAAW,EAAG,QAAO;AAChF,SAAO;AAAA,IACL;AAAA,IACA,SAAS,OAAO,YAAY,YAAY,QAAQ,SAAS,IAAI,UAAU;AAAA,IACvE,QAAQ,OAAO,WAAW,WAAW,SAAS;AAAA,EAAA;AAElD;AAMA,MAAM,8CAAmD,IAAI;AAAA,EAC3D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAQM,SAAS,wBAAwB,OAAyB;;AAC/D,QAAM,UAAW,+BAAsE;AACvF,OAAI,mCAAS,UAAS,WAAY,QAAO;AACzC,QAAM,UAAU,aAAQ,YAAR,mBAA6D;AAC7E,SAAO,OAAO,WAAW,YAAY,wBAAwB,IAAI,MAAM;AACzE;AAGO,SAAS,uBAAuB,OAA+B;;AACpE,QAAM,UAAS,+BAA0B,KAAK,MAA/B,mBAAkC;AACjD,MAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,EAAG,QAAO;AACnF,QAAM,OAAQ,OAA8B;AAC5C,SAAO,OAAO,SAAS,YAAY,KAAK,SAAS,IAAI,OAAO;AAC9D;AAmBO,SAAS,8BAA8B,OAAkD;AAC9F,QAAM,UAAU,0BAA0B,KAAK;AAC/C,SAAO,YAAY,OAAO,OAAO,oBAAoB,QAAQ,MAAM;AACrE;AA0BO,MAAM,wBAAwB;AAG9B,MAAM,gCACX;AAQK,SAAS,gCAAgC,OAAyB;AACvE,SAAO,uBAAuB,KAAK,MAAM;AAC3C;AAQO,SAAS,gCAAgC,OAAyB;AACvE,QAAM,UAAU,0BAA0B,KAAK;AAC/C,OAAI,mCAAS,YAAW,IAAK,QAAO;AAEpC,QAAM,SAAS,QAAQ;AACvB,UAAO,iCAAQ,UAAS;AAC1B;AA+BO,SAAS,0BAA0B,OAAyB;AACjE,QAAM,UAAW,+BACb;AACJ,UAAO,mCAAS,UAAS,aAAa,QAAQ,UAAU;AAC1D;AAiBO,SAAS,2BAA2B,OAAyB;;AAClE,QAAM,SAAS,oCAAgE,YAAhE,mBAAyE;AACxF,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAkBO,SAAS,0BAA0B,OAA+B;;AACvE,QAAM,SAAS,oCAAgE,YAAhE,mBAAyE;AACxF,MAAI,OAAO,UAAU,YAAY,UAAU,SAAU,QAAO;AAC5D,MAAI,0BAA0B,KAAK,EAAG,QAAO;AAC7C,WAAO,mCAA8B,KAAK,MAAnC,mBAAsC,SAAQ;AACvD;AAEA,MAAM,4BAA4B,CAAC,YAAwC;AACzE,QAAM,YAAY,MAAM,KAAK,SAAS,CAAC,cAAc;AACnD,UAAM,OAAO,UAAU,WAAW,CAAC;AACnC,WAAO,OAAO,MAAM,SAAS,MAAM,MAAM;AAAA,EAC3C,CAAC,EACE,KAAK,EAAE,EACP,QAAQ,QAAQ,GAAG,EACnB,KAAA;AACH,SAAO,YAAY,UAAU,MAAM,GAAG,GAAG,IAAI;AAC/C;AAGO,SAAS,2BACd,YAC0B;AAC1B,QAAM,UACJ,aAAa,cAAc,OAAO,WAAW,YAAY,WACrD,0BAA0B,WAAW,OAAO,IAC5C;AACN,UAAQ,WAAW,QAAA;AAAA,IACjB,KAAK;AACH,aAAO;AAAA,QACL,QAAQ,WAAW;AAAA,QACnB,QAAQ,WAAW;AAAA,QACnB,UAAU,WAAW;AAAA,QACrB,GAAI,YAAY,UAAa,EAAE,QAAA;AAAA,MAAQ;AAAA,IAE3C,KAAK;AAAA,IACL,KAAK;AACH,aAAO,EAAE,QAAQ,WAAW,QAAQ,UAAU,WAAW,SAAA;AAAA,IAC3D,KAAK;AACH,aAAO;AAAA,QACL,QAAQ,WAAW;AAAA,QACnB,UAAU,WAAW;AAAA,QACrB,SAAS,WAAW;AAAA,QACpB,GAAI,WAAW,UAAU,UAAa,EAAE,OAAO,WAAW,MAAA;AAAA,QAC1D,GAAI,WAAW,SAAS,UAAa,EAAE,MAAM,WAAW,KAAA;AAAA,QACxD,GAAI,WAAW,gBAAgB,UAAa,EAAE,aAAa,WAAW,YAAA;AAAA,QACtE,GAAI,WAAW,cAAc,UAAa,EAAE,WAAW,WAAW,UAAA;AAAA,QAClE,GAAI,YAAY,UAAa,EAAE,QAAA;AAAA,MAAQ;AAAA,IAE3C,KAAK;AACH,aAAO;AAAA,QACL,QAAQ,WAAW;AAAA,QACnB,UAAU,WAAW;AAAA,QACrB,QAAQ,WAAW;AAAA,QACnB,GAAI,WAAW,YAAY,UAAa,EAAE,SAAS,WAAW,QAAA;AAAA,QAC9D,GAAI,YAAY,UAAa,EAAE,QAAA;AAAA,MAAQ;AAAA,IAE3C;AACE,aAAO,wBAAwB,UAAU;AAAA,EAAA;AAE/C;AAGA,SAAS,wBAAwB,YAA0B;AACzD,QAAM,IAAI;AAAA,IACR,wCAAwC,KAAK;AAAA,MAC1C,WAAoC;AAAA,IAAA,CACtC;AAAA,EAAA;AAEL;;;;;;;;;;;;;;;;;"}
|
|
@@ -61,6 +61,13 @@ export interface RunStartRefusal {
|
|
|
61
61
|
* plain `{message}`), a retryable refusal, or no error at all.
|
|
62
62
|
*/
|
|
63
63
|
export declare function readRunStartRefusal(error: unknown): RunStartRefusal | null;
|
|
64
|
+
/**
|
|
65
|
+
* Whether a rejected command was a `voice/*` command, by its voice manager
|
|
66
|
+
* `payload.reason`. The voice controller owns those outcomes (it settles to
|
|
67
|
+
* idle, falls back to a typed send, or shows its own notice), so a chat's
|
|
68
|
+
* "Message was not sent" banner must not repeat them: no message was sent.
|
|
69
|
+
*/
|
|
70
|
+
export declare function isVoiceCommandRejection(error: unknown): boolean;
|
|
64
71
|
/** The structured `detail.code` of a rejected command, or `null`. */
|
|
65
72
|
export declare function statewireRejectionCode(error: unknown): string | null;
|
|
66
73
|
/**
|
|
@@ -36,6 +36,23 @@ function readRunStartRefusal(error) {
|
|
|
36
36
|
status: typeof status === "number" ? status : null
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
+
const VOICE_REJECTION_REASONS = /* @__PURE__ */ new Set([
|
|
40
|
+
"no-voice",
|
|
41
|
+
"not-voice-owner",
|
|
42
|
+
"voice-active",
|
|
43
|
+
"voice-stale-session",
|
|
44
|
+
"voice-unavailable",
|
|
45
|
+
"voice-not-enabled",
|
|
46
|
+
"voice-model-transport",
|
|
47
|
+
"text-too-long"
|
|
48
|
+
]);
|
|
49
|
+
function isVoiceCommandRejection(error) {
|
|
50
|
+
var _a;
|
|
51
|
+
const failure = error == null ? void 0 : error.failure;
|
|
52
|
+
if ((failure == null ? void 0 : failure.fate) !== "rejected") return false;
|
|
53
|
+
const reason = (_a = failure.payload) == null ? void 0 : _a.reason;
|
|
54
|
+
return typeof reason === "string" && VOICE_REJECTION_REASONS.has(reason);
|
|
55
|
+
}
|
|
39
56
|
function statewireRejectionCode(error) {
|
|
40
57
|
var _a;
|
|
41
58
|
const detail = (_a = statewireRejectionPayload(error)) == null ? void 0 : _a.detail;
|
|
@@ -132,6 +149,7 @@ export {
|
|
|
132
149
|
isLegacyThreadReadOnlyRejection,
|
|
133
150
|
isStatewireChannelTeardown,
|
|
134
151
|
isStatewireExpiredVerdict,
|
|
152
|
+
isVoiceCommandRejection,
|
|
135
153
|
projectDeepAgentConnection,
|
|
136
154
|
readRetryableCommandRejection,
|
|
137
155
|
readRetryableRunRefusal,
|