@athenaintel/react 0.57.1 → 0.59.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 +778 -9
- package/dist/agent-runtime/src/addressed-agents.cjs +16 -0
- package/dist/agent-runtime/src/addressed-agents.cjs.map +1 -0
- package/dist/agent-runtime/src/addressed-agents.d.ts +30 -0
- package/dist/agent-runtime/src/addressed-agents.js +16 -0
- package/dist/agent-runtime/src/addressed-agents.js.map +1 -0
- package/dist/agent-runtime/src/answer-label.cjs +4 -3
- package/dist/agent-runtime/src/answer-label.cjs.map +1 -1
- package/dist/agent-runtime/src/answer-label.d.ts +13 -6
- package/dist/agent-runtime/src/answer-label.js +4 -3
- package/dist/agent-runtime/src/answer-label.js.map +1 -1
- package/dist/agent-runtime/src/chat-outbox-attachments.cjs.map +1 -1
- package/dist/agent-runtime/src/chat-outbox-attachments.d.ts +1 -1
- package/dist/agent-runtime/src/chat-outbox-attachments.js.map +1 -1
- package/dist/agent-runtime/src/chat-outbox-entry.cjs +101 -0
- package/dist/agent-runtime/src/chat-outbox-entry.cjs.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-entry.d.ts +99 -0
- package/dist/agent-runtime/src/chat-outbox-entry.js +101 -0
- package/dist/agent-runtime/src/chat-outbox-entry.js.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-legacy.cjs +252 -0
- package/dist/agent-runtime/src/chat-outbox-legacy.cjs.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-legacy.d.ts +96 -0
- package/dist/agent-runtime/src/chat-outbox-legacy.js +252 -0
- package/dist/agent-runtime/src/chat-outbox-legacy.js.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-policy.cjs +30 -0
- package/dist/agent-runtime/src/chat-outbox-policy.cjs.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-policy.d.ts +42 -0
- package/dist/agent-runtime/src/chat-outbox-policy.js +30 -0
- package/dist/agent-runtime/src/chat-outbox-policy.js.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-storage.cjs +306 -0
- package/dist/agent-runtime/src/chat-outbox-storage.cjs.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-storage.d.ts +194 -0
- package/dist/agent-runtime/src/chat-outbox-storage.js +306 -0
- package/dist/agent-runtime/src/chat-outbox-storage.js.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-thread.cjs +21 -94
- package/dist/agent-runtime/src/chat-outbox-thread.cjs.map +1 -1
- package/dist/agent-runtime/src/chat-outbox-thread.d.ts +22 -18
- package/dist/agent-runtime/src/chat-outbox-thread.js +21 -94
- package/dist/agent-runtime/src/chat-outbox-thread.js.map +1 -1
- package/dist/agent-runtime/src/chat-outbox.cjs +492 -547
- package/dist/agent-runtime/src/chat-outbox.cjs.map +1 -1
- package/dist/agent-runtime/src/chat-outbox.d.ts +110 -142
- package/dist/agent-runtime/src/chat-outbox.js +492 -547
- package/dist/agent-runtime/src/chat-outbox.js.map +1 -1
- package/dist/agent-runtime/src/composer-markdown.cjs.map +1 -1
- package/dist/agent-runtime/src/composer-markdown.d.ts +1 -1
- package/dist/agent-runtime/src/composer-markdown.js.map +1 -1
- package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs +3 -1
- package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
- package/dist/agent-runtime/src/deep-agent-transport-recipe.d.ts +8 -1
- package/dist/agent-runtime/src/deep-agent-transport-recipe.js +3 -1
- package/dist/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
- package/dist/agent-runtime/src/dictation-preferences.d.ts +356 -0
- package/dist/agent-runtime/src/dictation-record.d.ts +279 -0
- package/dist/agent-runtime/src/dictation-session.d.ts +106 -7
- package/dist/agent-runtime/src/dictation-snippets.d.ts +9 -0
- package/dist/agent-runtime/src/dictation-transfer.d.ts +142 -0
- package/dist/agent-runtime/src/edit-command.cjs.map +1 -1
- package/dist/agent-runtime/src/edit-command.d.ts +1 -1
- package/dist/agent-runtime/src/edit-command.js.map +1 -1
- package/dist/agent-runtime/src/errors.cjs +1 -0
- package/dist/agent-runtime/src/errors.cjs.map +1 -1
- package/dist/agent-runtime/src/errors.js +1 -0
- package/dist/agent-runtime/src/errors.js.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs +24 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +3 -3
- package/dist/agent-runtime/src/generated/runconfig-contract.js +24 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/agent-runtime/src/index.d.ts +14 -8
- package/dist/agent-runtime/src/lane-follow.cjs +289 -0
- package/dist/agent-runtime/src/lane-follow.cjs.map +1 -0
- package/dist/agent-runtime/src/lane-follow.js +289 -0
- package/dist/agent-runtime/src/lane-follow.js.map +1 -0
- package/dist/agent-runtime/src/lane-images.cjs +387 -0
- package/dist/agent-runtime/src/lane-images.cjs.map +1 -0
- package/dist/agent-runtime/src/lane-images.js +387 -0
- package/dist/agent-runtime/src/lane-images.js.map +1 -0
- package/dist/agent-runtime/src/message-window.js +1 -1
- package/dist/agent-runtime/src/messages.cjs +19 -1
- package/dist/agent-runtime/src/messages.cjs.map +1 -1
- package/dist/agent-runtime/src/messages.d.ts +8 -0
- package/dist/agent-runtime/src/messages.js +21 -3
- package/dist/agent-runtime/src/messages.js.map +1 -1
- package/dist/agent-runtime/src/named-agents.cjs +301 -0
- package/dist/agent-runtime/src/named-agents.cjs.map +1 -0
- package/dist/agent-runtime/src/named-agents.d.ts +246 -0
- package/dist/agent-runtime/src/named-agents.js +301 -0
- package/dist/agent-runtime/src/named-agents.js.map +1 -0
- package/dist/agent-runtime/src/offline-status.cjs.map +1 -1
- package/dist/agent-runtime/src/offline-status.d.ts +66 -2
- package/dist/agent-runtime/src/offline-status.js.map +1 -1
- package/dist/agent-runtime/src/ptc-subcalls.cjs +41 -0
- package/dist/agent-runtime/src/ptc-subcalls.cjs.map +1 -0
- package/dist/agent-runtime/src/ptc-subcalls.js +41 -0
- package/dist/agent-runtime/src/ptc-subcalls.js.map +1 -0
- package/dist/agent-runtime/src/queue.cjs +2 -2
- package/dist/agent-runtime/src/queue.cjs.map +1 -1
- package/dist/agent-runtime/src/queue.d.ts +20 -25
- package/dist/agent-runtime/src/queue.js +2 -2
- package/dist/agent-runtime/src/queue.js.map +1 -1
- package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +314 -84
- package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
- package/dist/agent-runtime/src/quota-safe-local-storage-session.d.ts +137 -40
- package/dist/agent-runtime/src/quota-safe-local-storage-session.js +318 -88
- package/dist/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
- package/dist/agent-runtime/src/run-send.cjs +54 -0
- package/dist/agent-runtime/src/run-send.cjs.map +1 -0
- package/dist/agent-runtime/src/run-send.d.ts +51 -0
- package/dist/agent-runtime/src/run-send.js +54 -0
- package/dist/agent-runtime/src/run-send.js.map +1 -0
- package/dist/agent-runtime/src/running-tool-placeholder.cjs +6 -0
- package/dist/agent-runtime/src/running-tool-placeholder.cjs.map +1 -1
- package/dist/agent-runtime/src/running-tool-placeholder.js +6 -0
- package/dist/agent-runtime/src/running-tool-placeholder.js.map +1 -1
- package/dist/agent-runtime/src/runtime.d.ts +9 -5
- package/dist/agent-runtime/src/sealed-idb.cjs +64 -0
- package/dist/agent-runtime/src/sealed-idb.cjs.map +1 -1
- package/dist/agent-runtime/src/sealed-idb.d.ts +16 -0
- package/dist/agent-runtime/src/sealed-idb.js +64 -0
- package/dist/agent-runtime/src/sealed-idb.js.map +1 -1
- package/dist/agent-runtime/src/send-recovery.cjs +90 -118
- package/dist/agent-runtime/src/send-recovery.cjs.map +1 -1
- package/dist/agent-runtime/src/send-recovery.d.ts +25 -29
- package/dist/agent-runtime/src/send-recovery.js +90 -118
- package/dist/agent-runtime/src/send-recovery.js.map +1 -1
- package/dist/agent-runtime/src/statewire-diagnostics.d.ts +4 -1
- package/dist/agent-runtime/src/statewire-held-sends.cjs +191 -0
- package/dist/agent-runtime/src/statewire-held-sends.cjs.map +1 -0
- package/dist/agent-runtime/src/statewire-held-sends.d.ts +119 -0
- package/dist/agent-runtime/src/statewire-held-sends.js +191 -0
- package/dist/agent-runtime/src/statewire-held-sends.js.map +1 -0
- package/dist/agent-runtime/src/statewire-state.cjs +4 -0
- package/dist/agent-runtime/src/statewire-state.cjs.map +1 -1
- package/dist/agent-runtime/src/statewire-state.js +4 -0
- package/dist/agent-runtime/src/statewire-state.js.map +1 -1
- package/dist/agent-runtime/src/statewire-transport.cjs +8 -2
- package/dist/agent-runtime/src/statewire-transport.cjs.map +1 -1
- package/dist/agent-runtime/src/statewire-transport.d.ts +14 -5
- package/dist/agent-runtime/src/statewire-transport.js +8 -2
- package/dist/agent-runtime/src/statewire-transport.js.map +1 -1
- package/dist/agent-runtime/src/subagent-transcripts.cjs +1 -23
- package/dist/agent-runtime/src/subagent-transcripts.cjs.map +1 -1
- package/dist/agent-runtime/src/subagent-transcripts.js +3 -25
- package/dist/agent-runtime/src/subagent-transcripts.js.map +1 -1
- package/dist/agent-runtime/src/subagents.cjs +22 -29
- package/dist/agent-runtime/src/subagents.cjs.map +1 -1
- package/dist/agent-runtime/src/subagents.js +23 -30
- package/dist/agent-runtime/src/subagents.js.map +1 -1
- package/dist/agent-runtime/src/thread-extras.cjs +27 -19
- package/dist/agent-runtime/src/thread-extras.cjs.map +1 -1
- package/dist/agent-runtime/src/thread-extras.d.ts +19 -6
- package/dist/agent-runtime/src/thread-extras.js +27 -19
- package/dist/agent-runtime/src/thread-extras.js.map +1 -1
- package/dist/agent-runtime/src/thread-handoff-flow-machine.d.ts +8 -8
- package/dist/agent-runtime/src/tool-metadata.cjs +12 -0
- package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.js +12 -0
- package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
- package/dist/agent-runtime/src/tool-names.cjs +21 -0
- package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-names.d.ts +8 -0
- package/dist/agent-runtime/src/tool-names.js +21 -0
- package/dist/agent-runtime/src/tool-names.js.map +1 -1
- package/dist/agent-runtime/src/typed-interrupt-kinds.cjs +247 -0
- package/dist/agent-runtime/src/typed-interrupt-kinds.cjs.map +1 -0
- package/dist/agent-runtime/src/typed-interrupt-kinds.d.ts +173 -0
- package/dist/agent-runtime/src/typed-interrupt-kinds.js +247 -0
- package/dist/agent-runtime/src/typed-interrupt-kinds.js.map +1 -0
- package/dist/agent-runtime/src/typed-interrupts.cjs +48 -0
- package/dist/agent-runtime/src/typed-interrupts.cjs.map +1 -0
- package/dist/agent-runtime/src/typed-interrupts.d.ts +75 -0
- package/dist/agent-runtime/src/typed-interrupts.js +48 -0
- package/dist/agent-runtime/src/typed-interrupts.js.map +1 -0
- package/dist/agent-runtime/src/types.d.ts +1 -1
- package/dist/agent-runtime/src/use-conversation-list.cjs +1 -0
- package/dist/agent-runtime/src/use-conversation-list.cjs.map +1 -1
- package/dist/agent-runtime/src/use-conversation-list.d.ts +7 -0
- package/dist/agent-runtime/src/use-conversation-list.js +1 -0
- package/dist/agent-runtime/src/use-conversation-list.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs +46 -29
- 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 +14 -22
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js +46 -29
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +78 -14
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +34 -7
- package/dist/agent-runtime/src/use-deep-agent-runtime.js +79 -15
- package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs +16 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.d.ts +7 -2
- package/dist/agent-runtime/src/use-deep-agent-thread.js +16 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs +30 -4
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +22 -4
- package/dist/agent-runtime/src/use-deep-agent-voice.js +30 -4
- package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
- package/dist/agent-runtime/src/withdrawn-turns.d.ts +5 -4
- package/dist/agent-runtime/src/word-device-fit.d.ts +174 -0
- package/dist/agent-runtime/src/work-in.d.ts +127 -0
- package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
- package/dist/assets/AthenaAssetEmbed.d.ts +6 -1
- package/dist/assets/AthenaAssetEmbed.js.map +1 -1
- package/dist/assets/asset-panel-store.cjs +13 -5
- package/dist/assets/asset-panel-store.cjs.map +1 -1
- package/dist/assets/asset-panel-store.d.ts +33 -2
- package/dist/assets/asset-panel-store.js +13 -5
- package/dist/assets/asset-panel-store.js.map +1 -1
- package/dist/auth/AthenaCredentialSourceContext.cjs +11 -0
- package/dist/auth/AthenaCredentialSourceContext.cjs.map +1 -1
- package/dist/auth/AthenaCredentialSourceContext.d.ts +6 -0
- package/dist/auth/AthenaCredentialSourceContext.js +11 -0
- package/dist/auth/AthenaCredentialSourceContext.js.map +1 -1
- package/dist/auth/account-identity.cjs +13 -2
- package/dist/auth/account-identity.cjs.map +1 -1
- package/dist/auth/account-identity.d.ts +9 -0
- package/dist/auth/account-identity.js +13 -2
- package/dist/auth/account-identity.js.map +1 -1
- package/dist/auth/credential-source.cjs +20 -4
- package/dist/auth/credential-source.cjs.map +1 -1
- package/dist/auth/credential-source.d.ts +9 -0
- package/dist/auth/credential-source.js +20 -4
- package/dist/auth/credential-source.js.map +1 -1
- package/dist/catalog/chat-pickers.cjs +31 -0
- package/dist/catalog/chat-pickers.cjs.map +1 -1
- package/dist/catalog/chat-pickers.d.ts +17 -0
- package/dist/catalog/chat-pickers.js +33 -2
- package/dist/catalog/chat-pickers.js.map +1 -1
- package/dist/catalog/runtime-catalog.cjs +63 -3
- package/dist/catalog/runtime-catalog.cjs.map +1 -1
- package/dist/catalog/runtime-catalog.d.ts +63 -3
- package/dist/catalog/runtime-catalog.js +64 -4
- package/dist/catalog/runtime-catalog.js.map +1 -1
- package/dist/chat/AthenaChat.cjs +337 -99
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.d.ts +80 -4
- package/dist/chat/AthenaChat.js +337 -99
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/StatewireApprovalCard.cjs +35 -5
- package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
- package/dist/chat/StatewireApprovalCard.d.ts +55 -2
- package/dist/chat/StatewireApprovalCard.js +37 -7
- package/dist/chat/StatewireApprovalCard.js.map +1 -1
- package/dist/chat/StatewireQueuedMessages.cjs +17 -2
- package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
- package/dist/chat/StatewireQueuedMessages.d.ts +8 -45
- package/dist/chat/StatewireQueuedMessages.js +18 -3
- package/dist/chat/StatewireQueuedMessages.js.map +1 -1
- package/dist/chat/chat-agent-mentions.cjs +70 -0
- package/dist/chat/chat-agent-mentions.cjs.map +1 -0
- package/dist/chat/chat-agent-mentions.d.ts +13 -0
- package/dist/chat/chat-agent-mentions.js +70 -0
- package/dist/chat/chat-agent-mentions.js.map +1 -0
- package/dist/chat/composer-actions.cjs +12 -0
- package/dist/chat/composer-actions.cjs.map +1 -0
- package/dist/chat/composer-actions.d.ts +22 -0
- package/dist/chat/composer-actions.js +12 -0
- package/dist/chat/composer-actions.js.map +1 -0
- package/dist/chat/follow-up-suggestions.cjs +185 -0
- package/dist/chat/follow-up-suggestions.cjs.map +1 -0
- package/dist/chat/follow-up-suggestions.d.ts +64 -0
- package/dist/chat/follow-up-suggestions.js +185 -0
- package/dist/chat/follow-up-suggestions.js.map +1 -0
- package/dist/chat/super-grouping/ToolTimeline.cjs +4 -3
- package/dist/chat/super-grouping/ToolTimeline.cjs.map +1 -1
- package/dist/chat/super-grouping/ToolTimeline.d.ts +7 -3
- package/dist/chat/super-grouping/ToolTimeline.js +4 -3
- package/dist/chat/super-grouping/ToolTimeline.js.map +1 -1
- package/dist/chat/turn-changes.cjs +284 -0
- package/dist/chat/turn-changes.cjs.map +1 -0
- package/dist/chat/turn-changes.d.ts +130 -0
- package/dist/chat/turn-changes.js +284 -0
- package/dist/chat/turn-changes.js.map +1 -0
- package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.cjs +31 -0
- package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.cjs.map +1 -0
- package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.d.ts +31 -0
- package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.js +31 -0
- package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.js.map +1 -0
- package/dist/chat/typed-interrupts/approval-cards.cjs +250 -0
- package/dist/chat/typed-interrupts/approval-cards.cjs.map +1 -0
- package/dist/chat/typed-interrupts/approval-cards.d.ts +22 -0
- package/dist/chat/typed-interrupts/approval-cards.js +250 -0
- package/dist/chat/typed-interrupts/approval-cards.js.map +1 -0
- package/dist/chat/typed-interrupts/form-cards.cjs +289 -0
- package/dist/chat/typed-interrupts/form-cards.cjs.map +1 -0
- package/dist/chat/typed-interrupts/form-cards.d.ts +6 -0
- package/dist/chat/typed-interrupts/form-cards.js +289 -0
- package/dist/chat/typed-interrupts/form-cards.js.map +1 -0
- package/dist/chat/typed-interrupts/interrupt-card-shell.cjs +182 -0
- package/dist/chat/typed-interrupts/interrupt-card-shell.cjs.map +1 -0
- package/dist/chat/typed-interrupts/interrupt-card-shell.d.ts +47 -0
- package/dist/chat/typed-interrupts/interrupt-card-shell.js +182 -0
- package/dist/chat/typed-interrupts/interrupt-card-shell.js.map +1 -0
- package/dist/chat/typed-interrupts/json-schema-form.cjs +388 -0
- package/dist/chat/typed-interrupts/json-schema-form.cjs.map +1 -0
- package/dist/chat/typed-interrupts/json-schema-form.d.ts +33 -0
- package/dist/chat/typed-interrupts/json-schema-form.js +388 -0
- package/dist/chat/typed-interrupts/json-schema-form.js.map +1 -0
- package/dist/chat/typed-interrupts/questionnaire-card.cjs +449 -0
- package/dist/chat/typed-interrupts/questionnaire-card.cjs.map +1 -0
- package/dist/chat/typed-interrupts/questionnaire-card.d.ts +20 -0
- package/dist/chat/typed-interrupts/questionnaire-card.js +449 -0
- package/dist/chat/typed-interrupts/questionnaire-card.js.map +1 -0
- package/dist/chat/typed-interrupts/request-file-card.cjs +159 -0
- package/dist/chat/typed-interrupts/request-file-card.cjs.map +1 -0
- package/dist/chat/typed-interrupts/request-file-card.d.ts +2 -0
- package/dist/chat/typed-interrupts/request-file-card.js +159 -0
- package/dist/chat/typed-interrupts/request-file-card.js.map +1 -0
- package/dist/chat/typed-interrupts/toolkit-selection-card.cjs +189 -0
- package/dist/chat/typed-interrupts/toolkit-selection-card.cjs.map +1 -0
- package/dist/chat/typed-interrupts/toolkit-selection-card.d.ts +23 -0
- package/dist/chat/typed-interrupts/toolkit-selection-card.js +189 -0
- package/dist/chat/typed-interrupts/toolkit-selection-card.js.map +1 -0
- package/dist/chat/typed-interrupts/typed-interrupt-body.cjs +26 -0
- package/dist/chat/typed-interrupts/typed-interrupt-body.cjs.map +1 -0
- package/dist/chat/typed-interrupts/typed-interrupt-body.d.ts +3 -0
- package/dist/chat/typed-interrupts/typed-interrupt-body.js +26 -0
- package/dist/chat/typed-interrupts/typed-interrupt-body.js.map +1 -0
- package/dist/chat/typed-interrupts/typed-interrupt-graphql.cjs +105 -0
- package/dist/chat/typed-interrupts/typed-interrupt-graphql.cjs.map +1 -0
- package/dist/chat/typed-interrupts/typed-interrupt-graphql.d.ts +29 -0
- package/dist/chat/typed-interrupts/typed-interrupt-graphql.js +105 -0
- package/dist/chat/typed-interrupts/typed-interrupt-graphql.js.map +1 -0
- package/dist/chat/typed-interrupts/typed-interrupt-notice.cjs +70 -0
- package/dist/chat/typed-interrupts/typed-interrupt-notice.cjs.map +1 -0
- package/dist/chat/typed-interrupts/typed-interrupt-notice.d.ts +45 -0
- package/dist/chat/typed-interrupts/typed-interrupt-notice.js +70 -0
- package/dist/chat/typed-interrupts/typed-interrupt-notice.js.map +1 -0
- package/dist/chat/typed-interrupts/typed-interrupt-panel.cjs +76 -0
- package/dist/chat/typed-interrupts/typed-interrupt-panel.cjs.map +1 -0
- package/dist/chat/typed-interrupts/typed-interrupt-panel.d.ts +11 -0
- package/dist/chat/typed-interrupts/typed-interrupt-panel.js +76 -0
- package/dist/chat/typed-interrupts/typed-interrupt-panel.js.map +1 -0
- package/dist/chat/typed-interrupts/typed-interrupt-types.d.ts +46 -0
- package/dist/chat/typed-interrupts/use-interrupt-draft.cjs +106 -0
- package/dist/chat/typed-interrupts/use-interrupt-draft.cjs.map +1 -0
- package/dist/chat/typed-interrupts/use-interrupt-draft.d.ts +29 -0
- package/dist/chat/typed-interrupts/use-interrupt-draft.js +106 -0
- package/dist/chat/typed-interrupts/use-interrupt-draft.js.map +1 -0
- package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.cjs +231 -0
- package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.cjs.map +1 -0
- package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.d.ts +66 -0
- package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.js +231 -0
- package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.js.map +1 -0
- package/dist/chat-ui/composer/composer-named-agents.cjs +13 -0
- package/dist/chat-ui/composer/composer-named-agents.cjs.map +1 -0
- package/dist/chat-ui/composer/composer-named-agents.d.ts +20 -0
- package/dist/chat-ui/composer/composer-named-agents.js +13 -0
- package/dist/chat-ui/composer/composer-named-agents.js.map +1 -0
- package/dist/chat-ui/composer/slash-command-menu.cjs +143 -0
- package/dist/chat-ui/composer/slash-command-menu.cjs.map +1 -0
- package/dist/chat-ui/composer/slash-command-menu.d.ts +19 -0
- package/dist/chat-ui/composer/slash-command-menu.js +143 -0
- package/dist/chat-ui/composer/slash-command-menu.js.map +1 -0
- package/dist/chat-ui/composer/slash-commands-extension.cjs +51 -0
- package/dist/chat-ui/composer/slash-commands-extension.cjs.map +1 -0
- package/dist/chat-ui/composer/slash-commands-extension.d.ts +39 -0
- package/dist/chat-ui/composer/slash-commands-extension.js +51 -0
- package/dist/chat-ui/composer/slash-commands-extension.js.map +1 -0
- package/dist/chat-ui/composer/slash-commands.cjs +74 -0
- package/dist/chat-ui/composer/slash-commands.cjs.map +1 -0
- package/dist/chat-ui/composer/slash-commands.d.ts +82 -0
- package/dist/chat-ui/composer/slash-commands.js +74 -0
- package/dist/chat-ui/composer/slash-commands.js.map +1 -0
- package/dist/chat-ui/composer/tiptap-composer.cjs +135 -9
- package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.d.ts +61 -2
- package/dist/chat-ui/composer/tiptap-composer.js +135 -9
- package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
- package/dist/chat-ui/index.cjs +3 -0
- package/dist/chat-ui/index.cjs.map +1 -1
- package/dist/chat-ui/index.d.ts +3 -2
- package/dist/chat-ui/index.js +3 -0
- package/dist/chat-ui/index.js.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.cjs +1 -1
- package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.js +2 -2
- package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
- package/dist/chat-ui/mentions/mention-extension.cjs +8 -1
- package/dist/chat-ui/mentions/mention-extension.cjs.map +1 -1
- package/dist/chat-ui/mentions/mention-extension.js +8 -1
- package/dist/chat-ui/mentions/mention-extension.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/get-scope-name.cjs +1 -0
- package/dist/chat-ui/mentions/suggestions/components/get-scope-name.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/get-scope-name.js +1 -0
- package/dist/chat-ui/mentions/suggestions/components/get-scope-name.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/mention-icon.cjs +2 -0
- package/dist/chat-ui/mentions/suggestions/components/mention-icon.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/mention-icon.js +3 -1
- package/dist/chat-ui/mentions/suggestions/components/mention-icon.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-item.cjs +1 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-item.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-item.js +1 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-item.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +36 -0
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +42 -0
- package/dist/chat-ui/mentions/suggestions/data/api-client.js +36 -0
- package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +235 -19
- package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.d.ts +88 -10
- package/dist/chat-ui/mentions/suggestions/data/sources/index.js +236 -20
- package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/types.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/types.d.ts +27 -1
- package/dist/chat-ui/mentions/suggestions/data/types.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs +56 -5
- 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 +26 -6
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js +57 -6
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.cjs +34 -17
- package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.d.ts +19 -1
- package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.js +35 -18
- package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.js.map +1 -1
- package/dist/chat-ui/statewire.d.ts +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.cjs +15 -0
- package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.d.ts +4 -1
- package/dist/chat-ui/thread/statewire-history-edge.js +15 -0
- package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
- package/dist/collab/client.cjs +17 -5
- package/dist/collab/client.cjs.map +1 -1
- package/dist/collab/client.d.ts +22 -7
- package/dist/collab/client.js +17 -5
- package/dist/collab/client.js.map +1 -1
- package/dist/composer/ComposerAttachedReferences.cjs +119 -0
- package/dist/composer/ComposerAttachedReferences.cjs.map +1 -0
- package/dist/composer/ComposerAttachedReferences.d.ts +26 -0
- package/dist/composer/ComposerAttachedReferences.js +119 -0
- package/dist/composer/ComposerAttachedReferences.js.map +1 -0
- package/dist/composer/ComposerNamedAgents.cjs +63 -0
- package/dist/composer/ComposerNamedAgents.cjs.map +1 -0
- package/dist/composer/ComposerNamedAgents.d.ts +16 -0
- package/dist/composer/ComposerNamedAgents.js +63 -0
- package/dist/composer/ComposerNamedAgents.js.map +1 -0
- package/dist/composer/attached-references.cjs +159 -0
- package/dist/composer/attached-references.cjs.map +1 -0
- package/dist/composer/attached-references.d.ts +86 -0
- package/dist/composer/attached-references.js +159 -0
- package/dist/composer/attached-references.js.map +1 -0
- package/dist/composer/build-composed-message.cjs +14 -7
- package/dist/composer/build-composed-message.cjs.map +1 -1
- package/dist/composer/build-composed-message.d.ts +6 -1
- package/dist/composer/build-composed-message.js +14 -7
- package/dist/composer/build-composed-message.js.map +1 -1
- package/dist/composer/composer-handoff.cjs +6 -2
- package/dist/composer/composer-handoff.cjs.map +1 -1
- package/dist/composer/composer-handoff.d.ts +7 -1
- package/dist/composer/composer-handoff.js +6 -2
- package/dist/composer/composer-handoff.js.map +1 -1
- package/dist/composer/folder-upload.cjs +149 -0
- package/dist/composer/folder-upload.cjs.map +1 -0
- package/dist/composer/folder-upload.d.ts +79 -0
- package/dist/composer/folder-upload.js +149 -0
- package/dist/composer/folder-upload.js.map +1 -0
- package/dist/composer/index.d.ts +1 -1
- package/dist/composer/useAttachToChat.cjs +35 -0
- package/dist/composer/useAttachToChat.cjs.map +1 -0
- package/dist/composer/useAttachToChat.d.ts +54 -0
- package/dist/composer/useAttachToChat.js +35 -0
- package/dist/composer/useAttachToChat.js.map +1 -0
- package/dist/composer/useAttachedReferencesComposerProps.cjs +19 -0
- package/dist/composer/useAttachedReferencesComposerProps.cjs.map +1 -0
- package/dist/composer/useAttachedReferencesComposerProps.d.ts +12 -0
- package/dist/composer/useAttachedReferencesComposerProps.js +19 -0
- package/dist/composer/useAttachedReferencesComposerProps.js.map +1 -0
- package/dist/composer/useFileUpload.cjs +95 -7
- package/dist/composer/useFileUpload.cjs.map +1 -1
- package/dist/composer/useFileUpload.d.ts +21 -2
- package/dist/composer/useFileUpload.js +95 -7
- package/dist/composer/useFileUpload.js.map +1 -1
- package/dist/data/athena-api-error.cjs +125 -0
- package/dist/data/athena-api-error.cjs.map +1 -0
- package/dist/data/athena-api-error.d.ts +96 -0
- package/dist/data/athena-api-error.js +125 -0
- package/dist/data/athena-api-error.js.map +1 -0
- package/dist/data/athena-data-client.cjs +106 -0
- package/dist/data/athena-data-client.cjs.map +1 -0
- package/dist/data/athena-data-client.d.ts +74 -0
- package/dist/data/athena-data-client.js +106 -0
- package/dist/data/athena-data-client.js.map +1 -0
- package/dist/data/athena-member.cjs +93 -0
- package/dist/data/athena-member.cjs.map +1 -0
- package/dist/data/athena-member.d.ts +125 -0
- package/dist/data/athena-member.js +93 -0
- package/dist/data/athena-member.js.map +1 -0
- package/dist/data/athena-request.cjs +458 -0
- package/dist/data/athena-request.cjs.map +1 -0
- package/dist/data/athena-request.d.ts +120 -0
- package/dist/data/athena-request.js +458 -0
- package/dist/data/athena-request.js.map +1 -0
- package/dist/data/use-athena-fetch.cjs +14 -0
- package/dist/data/use-athena-fetch.cjs.map +1 -0
- package/dist/data/use-athena-fetch.d.ts +19 -0
- package/dist/data/use-athena-fetch.js +14 -0
- package/dist/data/use-athena-fetch.js.map +1 -0
- package/dist/data/use-athena-graphql.cjs +66 -0
- package/dist/data/use-athena-graphql.cjs.map +1 -0
- package/dist/data/use-athena-graphql.d.ts +56 -0
- package/dist/data/use-athena-graphql.js +66 -0
- package/dist/data/use-athena-graphql.js.map +1 -0
- package/dist/data/use-athena-rest.cjs +33 -0
- package/dist/data/use-athena-rest.cjs.map +1 -0
- package/dist/data/use-athena-rest.d.ts +21 -0
- package/dist/data/use-athena-rest.js +33 -0
- package/dist/data/use-athena-rest.js.map +1 -0
- package/dist/data/use-semantic-query.cjs +44 -0
- package/dist/data/use-semantic-query.cjs.map +1 -0
- package/dist/data/use-semantic-query.d.ts +92 -0
- package/dist/data/use-semantic-query.js +44 -0
- package/dist/data/use-semantic-query.js.map +1 -0
- package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
- package/dist/diagnostics/athena-diagnostics.d.ts +5 -1
- package/dist/diagnostics/athena-diagnostics.js.map +1 -1
- package/dist/diagnostics/errors.cjs +7 -0
- package/dist/diagnostics/errors.cjs.map +1 -1
- package/dist/diagnostics/errors.d.ts +7 -0
- package/dist/diagnostics/errors.js +7 -0
- package/dist/diagnostics/errors.js.map +1 -1
- package/dist/index.cjs +155 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +72 -13
- package/dist/index.js +148 -4
- package/dist/index.js.map +1 -1
- package/dist/keryx-http/src/initial-sync.cjs +64 -16
- package/dist/keryx-http/src/initial-sync.cjs.map +1 -1
- package/dist/keryx-http/src/initial-sync.d.ts +31 -1
- package/dist/keryx-http/src/initial-sync.js +64 -16
- package/dist/keryx-http/src/initial-sync.js.map +1 -1
- package/dist/keryx-http/src/own-awareness.cjs +20 -0
- package/dist/keryx-http/src/own-awareness.cjs.map +1 -0
- package/dist/keryx-http/src/own-awareness.d.ts +50 -0
- package/dist/keryx-http/src/own-awareness.js +20 -0
- package/dist/keryx-http/src/own-awareness.js.map +1 -0
- package/dist/keryx-http/src/update-attributions.cjs +26 -1
- package/dist/keryx-http/src/update-attributions.cjs.map +1 -1
- package/dist/keryx-http/src/update-attributions.d.ts +10 -1
- package/dist/keryx-http/src/update-attributions.js +26 -1
- package/dist/keryx-http/src/update-attributions.js.map +1 -1
- package/dist/offline/chat-outbox.cjs +262 -26
- package/dist/offline/chat-outbox.cjs.map +1 -1
- package/dist/offline/chat-outbox.d.ts +90 -12
- package/dist/offline/chat-outbox.js +263 -27
- package/dist/offline/chat-outbox.js.map +1 -1
- package/dist/provider/AthenaProvider.cjs +63 -19
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.d.ts +24 -8
- package/dist/provider/AthenaProvider.js +66 -22
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/references/src/anchors/types.cjs +5 -0
- package/dist/references/src/anchors/types.cjs.map +1 -1
- package/dist/references/src/anchors/types.js +5 -0
- package/dist/references/src/anchors/types.js.map +1 -1
- package/dist/references/src/attachable.cjs +149 -0
- package/dist/references/src/attachable.cjs.map +1 -0
- package/dist/references/src/attachable.d.ts +87 -0
- package/dist/references/src/attachable.js +149 -0
- package/dist/references/src/attachable.js.map +1 -0
- package/dist/runtime/StatewirePlanModeLaneSync.cjs +93 -0
- package/dist/runtime/StatewirePlanModeLaneSync.cjs.map +1 -0
- package/dist/runtime/StatewirePlanModeLaneSync.d.ts +34 -0
- package/dist/runtime/StatewirePlanModeLaneSync.js +93 -0
- package/dist/runtime/StatewirePlanModeLaneSync.js.map +1 -0
- package/dist/runtime/StatewireThreadConfigLaneSync.cjs +2 -0
- package/dist/runtime/StatewireThreadConfigLaneSync.cjs.map +1 -1
- package/dist/runtime/StatewireThreadConfigLaneSync.d.ts +4 -0
- package/dist/runtime/StatewireThreadConfigLaneSync.js +2 -0
- package/dist/runtime/StatewireThreadConfigLaneSync.js.map +1 -1
- package/dist/runtime/statewire-plan-mode.cjs +71 -0
- package/dist/runtime/statewire-plan-mode.cjs.map +1 -0
- package/dist/runtime/statewire-plan-mode.d.ts +88 -0
- package/dist/runtime/statewire-plan-mode.js +71 -0
- package/dist/runtime/statewire-plan-mode.js.map +1 -0
- package/dist/runtime/statewire-run-config.cjs +18 -1
- package/dist/runtime/statewire-run-config.cjs.map +1 -1
- package/dist/runtime/statewire-run-config.d.ts +20 -0
- package/dist/runtime/statewire-run-config.js +18 -1
- package/dist/runtime/statewire-run-config.js.map +1 -1
- package/dist/runtime/statewire-session-key.cjs +11 -5
- package/dist/runtime/statewire-session-key.cjs.map +1 -1
- package/dist/runtime/statewire-session-key.d.ts +22 -10
- package/dist/runtime/statewire-session-key.js +11 -5
- package/dist/runtime/statewire-session-key.js.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs +65 -8
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.d.ts +26 -10
- package/dist/runtime/useAthenaStatewireRuntime.js +67 -10
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/search/useAthenaAssets.cjs +394 -0
- package/dist/search/useAthenaAssets.cjs.map +1 -0
- package/dist/search/useAthenaAssets.d.ts +186 -0
- package/dist/search/useAthenaAssets.js +394 -0
- package/dist/search/useAthenaAssets.js.map +1 -0
- package/dist/sheet-range/index.cjs +4 -0
- package/dist/sheet-range/index.cjs.map +1 -1
- package/dist/sheet-range/index.d.ts +4 -2
- package/dist/sheet-range/index.js +4 -0
- package/dist/sheet-range/index.js.map +1 -1
- package/dist/sheet-range/query-range.cjs +102 -0
- package/dist/sheet-range/query-range.cjs.map +1 -0
- package/dist/sheet-range/query-range.d.ts +46 -0
- package/dist/sheet-range/query-range.js +102 -0
- package/dist/sheet-range/query-range.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/subagents/index.cjs +49 -0
- package/dist/subagents/index.cjs.map +1 -0
- package/dist/subagents/index.d.ts +16 -0
- package/dist/subagents/index.js +49 -0
- package/dist/subagents/index.js.map +1 -0
- package/dist/subagents/lane-follow.cjs +19 -0
- package/dist/subagents/lane-follow.cjs.map +1 -0
- package/dist/subagents/lane-follow.d.ts +9 -0
- package/dist/subagents/lane-follow.js +19 -0
- package/dist/subagents/lane-follow.js.map +1 -0
- package/dist/subagents/lane-model.cjs +178 -0
- package/dist/subagents/lane-model.cjs.map +1 -0
- package/dist/subagents/lane-model.d.ts +140 -0
- package/dist/subagents/lane-model.js +178 -0
- package/dist/subagents/lane-model.js.map +1 -0
- package/dist/subagents/lane-parts.cjs +517 -0
- package/dist/subagents/lane-parts.cjs.map +1 -0
- package/dist/subagents/lane-parts.d.ts +130 -0
- package/dist/subagents/lane-parts.js +517 -0
- package/dist/subagents/lane-parts.js.map +1 -0
- package/dist/subagents/subagent-lane-group.cjs +215 -0
- package/dist/subagents/subagent-lane-group.cjs.map +1 -0
- package/dist/subagents/subagent-lane-group.d.ts +67 -0
- package/dist/subagents/subagent-lane-group.js +215 -0
- package/dist/subagents/subagent-lane-group.js.map +1 -0
- package/dist/subagents/subagent-transcript-drawer.cjs +431 -0
- package/dist/subagents/subagent-transcript-drawer.cjs.map +1 -0
- package/dist/subagents/subagent-transcript-drawer.d.ts +78 -0
- package/dist/subagents/subagent-transcript-drawer.js +431 -0
- package/dist/subagents/subagent-transcript-drawer.js.map +1 -0
- package/dist/subagents/task-subagent-group.cjs +115 -0
- package/dist/subagents/task-subagent-group.cjs.map +1 -0
- package/dist/subagents/task-subagent-group.d.ts +36 -0
- package/dist/subagents/task-subagent-group.js +115 -0
- package/dist/subagents/task-subagent-group.js.map +1 -0
- package/dist/subagents/use-omitted-images-in-view.cjs +68 -0
- package/dist/subagents/use-omitted-images-in-view.cjs.map +1 -0
- package/dist/subagents/use-omitted-images-in-view.d.ts +21 -0
- package/dist/subagents/use-omitted-images-in-view.js +68 -0
- package/dist/subagents/use-omitted-images-in-view.js.map +1 -0
- package/dist/threads/Inbox.cjs +2 -2
- package/dist/threads/Inbox.cjs.map +1 -1
- package/dist/threads/SessionList.cjs +27 -24
- package/dist/threads/SessionList.cjs.map +1 -1
- package/dist/threads/SessionList.js +22 -19
- package/dist/threads/SessionList.js.map +1 -1
- package/dist/threads/SessionsPage.cjs +13 -7
- package/dist/threads/SessionsPage.cjs.map +1 -1
- package/dist/threads/SessionsPage.d.ts +10 -1
- package/dist/threads/SessionsPage.js +9 -3
- package/dist/threads/SessionsPage.js.map +1 -1
- package/dist/threads/live-session-rows.cjs +207 -0
- package/dist/threads/live-session-rows.cjs.map +1 -0
- package/dist/threads/live-session-rows.d.ts +175 -0
- package/dist/threads/live-session-rows.js +207 -0
- package/dist/threads/live-session-rows.js.map +1 -0
- package/dist/threads/session-list-model.cjs.map +1 -1
- package/dist/threads/session-list-model.d.ts +2 -1
- package/dist/threads/session-list-model.js.map +1 -1
- package/dist/threads/session-row-parts.cjs +3 -3
- package/dist/threads/session-row-parts.cjs.map +1 -1
- package/dist/threads/sessions-page-model.cjs +13 -5
- package/dist/threads/sessions-page-model.cjs.map +1 -1
- package/dist/threads/sessions-page-model.d.ts +7 -0
- package/dist/threads/sessions-page-model.js +11 -3
- package/dist/threads/sessions-page-model.js.map +1 -1
- package/dist/threads/sessions-page-storage.cjs +8 -8
- package/dist/threads/sessions-page-storage.cjs.map +1 -1
- package/dist/threads/sessions-page-storage.d.ts +5 -1
- package/dist/threads/sessions-page-storage.js +8 -8
- package/dist/threads/sessions-page-storage.js.map +1 -1
- package/dist/threads/statewire-thread-list.cjs +173 -20
- package/dist/threads/statewire-thread-list.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.d.ts +44 -1
- package/dist/threads/statewire-thread-list.js +174 -21
- package/dist/threads/statewire-thread-list.js.map +1 -1
- package/dist/threads/use-athena-sessions.cjs +1 -0
- package/dist/threads/use-athena-sessions.cjs.map +1 -1
- package/dist/threads/use-athena-sessions.d.ts +7 -0
- package/dist/threads/use-athena-sessions.js +1 -0
- package/dist/threads/use-athena-sessions.js.map +1 -1
- package/dist/threads/use-athena-thread-agent.cjs +31 -0
- package/dist/threads/use-athena-thread-agent.cjs.map +1 -0
- package/dist/threads/use-athena-thread-agent.d.ts +38 -0
- package/dist/threads/use-athena-thread-agent.js +31 -0
- package/dist/threads/use-athena-thread-agent.js.map +1 -0
- package/dist/threads/use-athena-thread-plan-mode.cjs +18 -0
- package/dist/threads/use-athena-thread-plan-mode.cjs.map +1 -0
- package/dist/threads/use-athena-thread-plan-mode.d.ts +18 -0
- package/dist/threads/use-athena-thread-plan-mode.js +18 -0
- package/dist/threads/use-athena-thread-plan-mode.js.map +1 -0
- package/dist/threads/use-rest-conversation-history.d.ts +1 -0
- package/dist/tools/agent-creations.cjs +97 -0
- package/dist/tools/agent-creations.cjs.map +1 -0
- package/dist/tools/agent-creations.d.ts +38 -0
- package/dist/tools/agent-creations.js +97 -0
- package/dist/tools/agent-creations.js.map +1 -0
- package/dist/tools/agent-highlights.cjs +100 -0
- package/dist/tools/agent-highlights.cjs.map +1 -0
- package/dist/tools/agent-highlights.d.ts +57 -0
- package/dist/tools/agent-highlights.js +100 -0
- package/dist/tools/agent-highlights.js.map +1 -0
- package/dist/tools/append-document-tool-ui.cjs +1 -0
- package/dist/tools/append-document-tool-ui.cjs.map +1 -1
- package/dist/tools/append-document-tool-ui.d.ts +7 -0
- package/dist/tools/append-document-tool-ui.js +2 -1
- package/dist/tools/append-document-tool-ui.js.map +1 -1
- package/dist/tools/auto-open-tools.cjs +144 -71
- package/dist/tools/auto-open-tools.cjs.map +1 -1
- package/dist/tools/auto-open-tools.d.ts +131 -1
- package/dist/tools/auto-open-tools.js +145 -72
- package/dist/tools/auto-open-tools.js.map +1 -1
- package/dist/tools/browser-tool-uis.cjs +594 -0
- package/dist/tools/browser-tool-uis.cjs.map +1 -0
- package/dist/tools/browser-tool-uis.d.ts +8 -0
- package/dist/tools/browser-tool-uis.js +594 -0
- package/dist/tools/browser-tool-uis.js.map +1 -0
- package/dist/tools/computer-asset-tool-uis.cjs +313 -0
- package/dist/tools/computer-asset-tool-uis.cjs.map +1 -0
- package/dist/tools/computer-asset-tool-uis.d.ts +5 -0
- package/dist/tools/computer-asset-tool-uis.js +313 -0
- package/dist/tools/computer-asset-tool-uis.js.map +1 -0
- package/dist/tools/document-edit-tool-uis.cjs +218 -0
- package/dist/tools/document-edit-tool-uis.cjs.map +1 -0
- package/dist/tools/document-edit-tool-uis.d.ts +40 -0
- package/dist/tools/document-edit-tool-uis.js +218 -0
- package/dist/tools/document-edit-tool-uis.js.map +1 -0
- package/dist/tools/drive-tool-uis.cjs +425 -0
- package/dist/tools/drive-tool-uis.cjs.map +1 -0
- package/dist/tools/drive-tool-uis.d.ts +120 -0
- package/dist/tools/drive-tool-uis.js +425 -0
- package/dist/tools/drive-tool-uis.js.map +1 -0
- package/dist/tools/email-calendar-tool-uis.cjs +789 -0
- package/dist/tools/email-calendar-tool-uis.cjs.map +1 -0
- package/dist/tools/email-calendar-tool-uis.d.ts +129 -0
- package/dist/tools/email-calendar-tool-uis.js +789 -0
- package/dist/tools/email-calendar-tool-uis.js.map +1 -0
- package/dist/tools/ontology-tool-uis.cjs +83 -0
- package/dist/tools/ontology-tool-uis.cjs.map +1 -0
- package/dist/tools/ontology-tool-uis.d.ts +9 -0
- package/dist/tools/ontology-tool-uis.js +83 -0
- package/dist/tools/ontology-tool-uis.js.map +1 -0
- package/dist/tools/orchestration-tool-uis.cjs +586 -0
- package/dist/tools/orchestration-tool-uis.cjs.map +1 -0
- package/dist/tools/orchestration-tool-uis.d.ts +141 -0
- package/dist/tools/orchestration-tool-uis.js +586 -0
- package/dist/tools/orchestration-tool-uis.js.map +1 -0
- package/dist/tools/presentation-edit-tool-uis.cjs +516 -0
- package/dist/tools/presentation-edit-tool-uis.cjs.map +1 -0
- package/dist/tools/presentation-edit-tool-uis.d.ts +73 -0
- package/dist/tools/presentation-edit-tool-uis.js +516 -0
- package/dist/tools/presentation-edit-tool-uis.js.map +1 -0
- package/dist/tools/project-tool-uis.cjs +213 -0
- package/dist/tools/project-tool-uis.cjs.map +1 -0
- package/dist/tools/project-tool-uis.d.ts +14 -0
- package/dist/tools/project-tool-uis.js +213 -0
- package/dist/tools/project-tool-uis.js.map +1 -0
- package/dist/tools/sandbox-tool-uis.cjs +491 -0
- package/dist/tools/sandbox-tool-uis.cjs.map +1 -0
- package/dist/tools/sandbox-tool-uis.d.ts +116 -0
- package/dist/tools/sandbox-tool-uis.js +491 -0
- package/dist/tools/sandbox-tool-uis.js.map +1 -0
- package/dist/tools/sheet-query-tool-ui.cjs +138 -0
- package/dist/tools/sheet-query-tool-ui.cjs.map +1 -0
- package/dist/tools/sheet-query-tool-ui.d.ts +15 -0
- package/dist/tools/sheet-query-tool-ui.js +138 -0
- package/dist/tools/sheet-query-tool-ui.js.map +1 -0
- package/dist/tools/studio-screenshot-tool-uis.cjs +262 -0
- package/dist/tools/studio-screenshot-tool-uis.cjs.map +1 -0
- package/dist/tools/studio-screenshot-tool-uis.d.ts +52 -0
- package/dist/tools/studio-screenshot-tool-uis.js +262 -0
- package/dist/tools/studio-screenshot-tool-uis.js.map +1 -0
- package/dist/tools/subagent-task-tool-ui.cjs +24 -475
- package/dist/tools/subagent-task-tool-ui.cjs.map +1 -1
- package/dist/tools/subagent-task-tool-ui.d.ts +19 -103
- package/dist/tools/subagent-task-tool-ui.js +28 -479
- package/dist/tools/subagent-task-tool-ui.js.map +1 -1
- package/dist/tools/tool-summary.cjs +36 -0
- package/dist/tools/tool-summary.cjs.map +1 -1
- package/dist/tools/tool-summary.js +36 -0
- package/dist/tools/tool-summary.js.map +1 -1
- package/dist/tools/tool-uis.cjs +181 -53
- package/dist/tools/tool-uis.cjs.map +1 -1
- package/dist/tools/tool-uis.d.ts +40 -0
- package/dist/tools/tool-uis.js +183 -55
- package/dist/tools/tool-uis.js.map +1 -1
- package/dist/typed-interrupts/index.cjs +15 -0
- package/dist/typed-interrupts/index.cjs.map +1 -0
- package/dist/typed-interrupts/index.d.ts +20 -0
- package/dist/typed-interrupts/index.js +15 -0
- package/dist/typed-interrupts/index.js.map +1 -0
- package/dist/workbench/session-workbench-panes.cjs +6 -6
- package/dist/workbench/session-workbench-panes.cjs.map +1 -1
- package/package.json +28 -6
- package/dist/agent-runtime/src/chat-outbox-store.cjs +0 -510
- package/dist/agent-runtime/src/chat-outbox-store.cjs.map +0 -1
- package/dist/agent-runtime/src/chat-outbox-store.d.ts +0 -210
- package/dist/agent-runtime/src/chat-outbox-store.js +0 -510
- package/dist/agent-runtime/src/chat-outbox-store.js.map +0 -1
|
@@ -134,6 +134,43 @@ export declare function savingDelayCause({ reachable, connected, writesRefused,
|
|
|
134
134
|
/** Local edits have waited unconfirmed past the stall window on this connection. */
|
|
135
135
|
unconfirmedStalled: boolean;
|
|
136
136
|
}): SavingDelayCause | null;
|
|
137
|
+
/**
|
|
138
|
+
* How long a chat message sent while Athena answers may go unaccepted before it counts as waiting
|
|
139
|
+
* to sync. Athena accepts a send when it takes it, not when its turn ends: 99% of follow-up messages
|
|
140
|
+
* within 3.4 s of the send, and 99% of a chat's first, which also dials, within 5.7 s (production
|
|
141
|
+
* `chat_ttft`, 30 days to 2026-11-07). A send still unaccepted after this is stuck, not on its way.
|
|
142
|
+
*/
|
|
143
|
+
export declare const UNACCEPTED_SEND_STALL_MS = 8000;
|
|
144
|
+
/** Where a chat message a chat outbox lists stands, for {@link messageWaitsToSync}. */
|
|
145
|
+
export interface OutboxMessageStanding {
|
|
146
|
+
/** Athena answers (the app's reachability, never the socket alone). */
|
|
147
|
+
reachable: boolean;
|
|
148
|
+
/**
|
|
149
|
+
* On its way to Athena: sent, or queued to go. `false` while the outbox holds it: typed while
|
|
150
|
+
* Athena couldn't be reached, behind a message that waits, asking after a day, or failed.
|
|
151
|
+
*/
|
|
152
|
+
sending: boolean;
|
|
153
|
+
/** Athena received it, before its answer reached the outbox. */
|
|
154
|
+
received?: boolean;
|
|
155
|
+
/** When it was sent (epoch ms); for one typed while Athena couldn't be reached, when it was typed. */
|
|
156
|
+
sentAt: number;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* When a message on its way starts counting as waiting to sync, should Athena not have accepted it
|
|
160
|
+
* by then ({@link UNACCEPTED_SEND_STALL_MS} after it was sent, while Athena answers); `null` when no
|
|
161
|
+
* time passing changes whether it counts.
|
|
162
|
+
*/
|
|
163
|
+
export declare function messageStartsWaitingAt({ reachable, sending, received, sentAt, }: OutboxMessageStanding): number | null;
|
|
164
|
+
/**
|
|
165
|
+
* Whether a chat message a chat outbox lists counts as waiting to sync, for the status line's
|
|
166
|
+
* count and the "Waiting to sync" list: one the outbox holds, always; one on its way, at once while
|
|
167
|
+
* Athena can't be reached, and while it answers only once it went unaccepted past
|
|
168
|
+
* {@link UNACCEPTED_SEND_STALL_MS}; one Athena received, never. A send that goes as usual, however
|
|
169
|
+
* long its turn runs, shows no status line.
|
|
170
|
+
*/
|
|
171
|
+
export declare function messageWaitsToSync(standing: OutboxMessageStanding & {
|
|
172
|
+
now: number;
|
|
173
|
+
}): boolean;
|
|
137
174
|
/**
|
|
138
175
|
* What the person lost of a document while it was open, when the server checked its room's grant
|
|
139
176
|
* again (Keryx's 4401, after a share changed): `edit`, they may still view it but no longer edit it;
|
|
@@ -177,15 +214,33 @@ export interface OlderVersionChangesCopy extends StatusCopy {
|
|
|
177
214
|
* as when it can't save a cloud document ("You can save a copy to prevent losing your work",
|
|
178
215
|
* `strman`): Save a Copy, and Athena's version, which keeps this device's version on it to compare
|
|
179
216
|
* and copy from until the person discards it. `saveCopy: false` for an editor that offers no Save
|
|
180
|
-
* a Copy of the live document
|
|
217
|
+
* a Copy of the live document. `keepsAside: false` where the device keeps no version of it aside
|
|
218
|
+
* (copies off, an embed): Athena's version then replaces the changes, which the person confirms
|
|
219
|
+
* first (`olderVersionDiscardCopy`). `atRisk`: the device can lose them before the person chooses
|
|
220
|
+
* (`ChangesAtRisk`), said here so the document shows one strip, never a second "Changes not saved".
|
|
181
221
|
*/
|
|
182
|
-
export declare function olderVersionChangesCopy({ device, noun, saveCopy, }: {
|
|
222
|
+
export declare function olderVersionChangesCopy({ device, noun, saveCopy, keepsAside, atRisk, }: {
|
|
183
223
|
device: DeviceNoun;
|
|
184
224
|
/** What the person calls the document ("document", "spreadsheet"). */
|
|
185
225
|
noun: string;
|
|
186
226
|
/** Whether the editor offers Save a Copy beside Athena's version. */
|
|
187
227
|
saveCopy?: boolean;
|
|
228
|
+
/** Whether Athena's version keeps the device's aside, as a version to compare and copy from. */
|
|
229
|
+
keepsAside?: boolean;
|
|
230
|
+
/** How the device could lose the changes before the person chooses, or `null`. */
|
|
231
|
+
atRisk?: ChangesAtRisk | null;
|
|
188
232
|
}): OlderVersionChangesCopy;
|
|
233
|
+
/**
|
|
234
|
+
* What the device asks before Athena's version replaces changes an older version of Athena made,
|
|
235
|
+
* where it keeps no version of them aside (`olderVersionChangesCopy`'s `keepsAside: false`): they
|
|
236
|
+
* are deleted then, so a copy saved first is the only way to keep them.
|
|
237
|
+
*/
|
|
238
|
+
export declare function olderVersionDiscardCopy({ device }: {
|
|
239
|
+
device: DeviceNoun;
|
|
240
|
+
}): StatusCopy & {
|
|
241
|
+
confirm: string;
|
|
242
|
+
cancel: string;
|
|
243
|
+
};
|
|
189
244
|
/**
|
|
190
245
|
* The reason on a control that needs Athena (share, run, upload, invite…),
|
|
191
246
|
* shown disabled while Athena can't be reached rather than failing when used.
|
|
@@ -285,6 +340,15 @@ export declare function offlineAvailabilityCopy({ available, canKeep, device, }:
|
|
|
285
340
|
canKeep: boolean;
|
|
286
341
|
device: DeviceNoun;
|
|
287
342
|
}): LabelCopy;
|
|
343
|
+
/**
|
|
344
|
+
* A history Athena keeps in full (a person's dictations), shown while Athena
|
|
345
|
+
* can't be reached: the list holds only what is kept on the device, and the
|
|
346
|
+
* rest comes back once online. `items` names what the list holds, plural.
|
|
347
|
+
*/
|
|
348
|
+
export declare function historyOnDeviceCopy({ items, device, }: {
|
|
349
|
+
items: string;
|
|
350
|
+
device: DeviceNoun;
|
|
351
|
+
}): string;
|
|
288
352
|
/**
|
|
289
353
|
* The one-time explainer shown the first time the person goes offline, on a
|
|
290
354
|
* surface that keeps work there (`keeping` `device`). A surface that keeps
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"offline-status.js","sources":["../../../../agent-runtime/src/offline-status.ts"],"sourcesContent":["/**\n * Athena's offline language: the one set of states and words every app uses to\n * say where the person stands when the network, or Athena, is out of reach —\n * Olympus, the desktop app, the phone app, the Chrome extension and the Office\n * add-in.\n *\n * The rule the words follow: say what still works before what doesn't. Work\n * done while Athena can't be reached is kept on the device and syncs when\n * Athena is back, so every message leads with that promise. Nothing here is\n * shown while Athena answers and nothing waits; the \"back\" messages are brief.\n *\n * Pure strings and small functions, no UI library: each app draws them its own\n * way (a banner, a header chip, a tooltip, a sheet). Reachability itself is\n * each app's own (the browser's or OS's online flag AND agora answering its\n * health read); this module only names the result.\n */\n\n/** Where the app stands with Athena. */\nexport type ConnectionState =\n /** Athena answers. Nothing is shown. */\n | 'online'\n /** The device has no network. */\n | 'offline'\n /** The network is up but Athena doesn't answer. */\n | 'unreachable'\n /** Athena answers again and what waited is being sent. */\n | 'reconnecting'\n /** Just back, and everything that waited was sent. Shown briefly. */\n | 'synced';\n\n/** Where one document's edits stand, for the chip in its header. */\nexport type DocumentSyncState =\n /** In Athena. */\n | 'saved'\n /** Being sent to Athena. */\n | 'saving'\n /** Kept on this device while Athena can't be reached; syncs when it is back. */\n | 'on-device'\n /** Kept only while this tab or app stays open (no device storage); syncs when Athena is back. */\n | 'in-memory'\n /** Sending what was kept on this device. */\n | 'syncing'\n /** Some changes overlap with Athena's version: the person chooses. */\n | 'needs-review'\n /** The document can no longer take these edits (access or state changed): kept, not sent. */\n | 'view-only'\n /**\n * Athena answers but isn't taking this document's changes for now: it holds the document while it\n * repairs it, or hasn't confirmed the latest changes for longer than usual (`SavingDelayCause`\n * says which). Kept, and saved once Athena takes them. Never said while Athena can't be reached:\n * that is `on-device` or `in-memory`.\n */\n | 'delayed';\n\n/** Why a document's saving is delayed while Athena answers (`DocumentSyncState` `delayed`). */\nexport type SavingDelayCause =\n /** Athena holds the document while it repairs it, and takes no changes to it until then. */\n | 'repairing'\n /** Athena hasn't confirmed the latest changes for longer than usual. */\n | 'unconfirmed';\n\n/** How a sentence names the device the person is on. */\nexport type DeviceNoun =\n | 'this browser'\n | 'this Mac'\n | 'this computer'\n | 'this phone'\n | 'this tablet'\n | 'this device';\n\n/**\n * What the app really keeps of work done while Athena can't be reached, so the\n * words never promise more: `device` (stored on the device, survives closing),\n * `memory` (kept only while this tab or app stays open: a tenant that turns\n * device copies off, or storage the app can't open), `none` (a surface that\n * keeps no work offline at all, like the Chrome side panel).\n */\nexport type OfflineKeeping = 'device' | 'memory' | 'none';\n\n/** A title and the one line under it (a banner, a sheet, a tooltip's heading). */\nexport interface StatusCopy {\n title: string;\n detail: string;\n}\n\n/** A short label for a chip or a disabled control, and its one-line explanation. */\nexport interface LabelCopy {\n label: string;\n detail: string;\n}\n\nfunction plural(count: number, one: string, many: string): string {\n return `${count} ${count === 1 ? one : many}`;\n}\n\n/** What a tab or an app is called when work lasts only while it stays open. */\nfunction openContainer(device: DeviceNoun): string {\n return device === 'this browser' ? 'this tab' : 'the app';\n}\n\n/** The device noun at the start of a sentence (\"This browser can…\"). */\nfunction deviceAtStart(device: DeviceNoun): string {\n return `${device.charAt(0).toUpperCase()}${device.slice(1)}`;\n}\n\n/**\n * The sentence a promise ends with when the device can remove what it keeps before it syncs\n * (`evictable`: a browser that hasn't granted persistent storage, a private window): \"before then\"\n * after a sentence that says when it syncs, \"before it syncs\" after one that doesn't.\n */\nfunction removableBeforeSync({\n device,\n count,\n before = 'then',\n}: {\n device: DeviceNoun;\n count: number;\n before?: 'then' | 'syncing';\n}): string {\n const what = count === 1 ? 'it' : 'them';\n const when = before === 'then' ? 'then' : count === 1 ? 'it syncs' : 'they sync';\n return `${deviceAtStart(device)} can remove ${what} before ${when}.`;\n}\n\n/** The promise after \"You're offline\" / \"Can't reach Athena\", honest to what is kept. */\nfunction keepingPromise({\n keeping,\n device,\n when,\n evictable,\n}: {\n keeping: OfflineKeeping;\n device: DeviceNoun;\n when: string;\n evictable: boolean;\n}): string {\n switch (keeping) {\n case 'device':\n return evictable\n ? `You can keep working. Changes are kept on ${device} and sync ${when}. ${removableBeforeSync({ device, count: 2 })}`\n : `You can keep working. Changes are saved on ${device} and sync ${when}.`;\n case 'memory':\n return `You can keep working, but changes are kept only until you close ${openContainer(device)}. They sync ${when}.`;\n case 'none':\n return `You’re still signed in. This reconnects ${when}.`;\n }\n}\n\n/**\n * The app-wide status line, or `null` while Athena answers and nothing waits.\n * `waiting` counts changes not in Athena yet: while `reconnecting` they are\n * being sent; while `online` they wait for something else (a copy that sends\n * when it is next opened), and the line stays until they are gone.\n * `keeping` is what the app really keeps offline (default `device`). A surface\n * that keeps nothing (`none`) has nothing to sync, so its way back is only\n * \"Back online\", never \"Syncing…\" or \"All changes synced\".\n * `evictable`: the device may remove what it keeps before it syncs (a browser that hasn't granted\n * persistent storage, a private window); only `keeping` `device` says so (default `false`).\n */\nexport function connectionCopy({\n state,\n device,\n waiting = 0,\n keeping = 'device',\n evictable = false,\n}: {\n state: ConnectionState;\n device: DeviceNoun;\n waiting?: number;\n keeping?: OfflineKeeping;\n evictable?: boolean;\n}): StatusCopy | null {\n const atRisk = evictable && keeping === 'device';\n switch (state) {\n case 'online':\n return waiting > 0\n ? {\n title: 'Not synced yet',\n detail: `${plural(waiting, 'change', 'changes')} on ${device} ${waiting === 1 ? 'hasn’t' : 'haven’t'} synced yet.${\n atRisk ? ` ${removableBeforeSync({ device, count: waiting, before: 'syncing' })}` : ''\n }`,\n }\n : null;\n case 'offline':\n return {\n title: 'You’re offline',\n detail: keepingPromise({\n keeping,\n device,\n when: 'when you’re back online',\n evictable: atRisk,\n }),\n };\n case 'unreachable':\n return {\n title: 'Can’t reach Athena',\n detail: keepingPromise({ keeping, device, when: 'when Athena is back', evictable: atRisk }),\n };\n case 'reconnecting':\n if (keeping === 'none') return { title: 'Back online', detail: '' };\n return {\n title: 'Back online',\n detail:\n waiting > 0 ? `Syncing ${plural(waiting, 'change', 'changes')}…` : 'Syncing…',\n };\n case 'synced':\n return keeping === 'none'\n ? { title: 'Back online', detail: '' }\n : { title: 'All changes synced', detail: '' };\n }\n}\n\n/**\n * The line under \"Saving delayed\": why saving waits, and what is kept meanwhile, never promising\n * more than the app keeps.\n */\nfunction savingDelayedDetail({\n delay,\n keeping,\n device,\n}: {\n delay: SavingDelayCause;\n keeping: Exclude<OfflineKeeping, 'none'>;\n device: DeviceNoun;\n}): string {\n if (delay === 'repairing') {\n return keeping === 'memory'\n ? `You can keep working, but your changes are kept only until you close ${openContainer(device)}. They save once Athena finishes repairing this document.`\n : `You can keep working. Your changes are kept on ${device} and save once Athena finishes repairing this document.`;\n }\n return keeping === 'memory'\n ? `Athena is taking longer than usual to save your latest changes. They’re kept only until you close ${openContainer(device)}, so keep it open.`\n : `Athena is taking longer than usual to save your latest changes. They’re kept on ${device} in the meantime.`;\n}\n\n/**\n * What `on-device` says. The desktop app on a Mac speaks as Word, Excel and PowerPoint for Mac do\n * of a cloud document whose changes wait on the Mac (Office's own title-bar words): \"Upload\n * Pending\", and \"Upload Pending (Offline)\" while Athena can't be reached. Every other app says the\n * changes are saved on its device: a browser has no such words (Word for the web can't edit\n * offline), nor does the phone.\n */\nfunction onDeviceCopy({ device, reachable }: { device: DeviceNoun; reachable: boolean }): LabelCopy {\n if (device === 'this Mac') {\n return {\n label: reachable ? 'Upload Pending' : 'Upload Pending (Offline)',\n detail: 'Upload pending. Your changes sync when Athena is back.',\n };\n }\n return {\n label: `Saved on ${device}`,\n detail: `Saved on ${device}. Your changes sync when Athena is back.`,\n };\n}\n\n/**\n * The chip in a document's header, and the line it explains itself with. For `delayed`, `delay`\n * says why (default `unconfirmed`) and `keeping` whether the changes are kept on the device or only\n * while the tab or app stays open (default `device`); every other state ignores both. `reachable`\n * (default `true`) is whether Athena can be reached, which only the Mac's `on-device` words read.\n * For `on-device`, `evictable` says the device may remove the changes before they sync (default\n * `false`).\n */\nexport function documentSyncCopy({\n state,\n device,\n delay = 'unconfirmed',\n keeping = 'device',\n reachable = true,\n evictable = false,\n}: {\n state: DocumentSyncState;\n device: DeviceNoun;\n delay?: SavingDelayCause;\n keeping?: Exclude<OfflineKeeping, 'none'>;\n reachable?: boolean;\n evictable?: boolean;\n}): LabelCopy {\n switch (state) {\n case 'saved':\n return { label: 'Saved', detail: 'Saved to Athena.' };\n case 'saving':\n return { label: 'Saving…', detail: 'Saving to Athena.' };\n case 'on-device': {\n const copy = onDeviceCopy({ device, reachable });\n return evictable\n ? { ...copy, detail: `${copy.detail} ${removableBeforeSync({ device, count: 2 })}` }\n : copy;\n }\n case 'in-memory':\n return {\n label: 'Not saved yet',\n detail: `Your changes are kept only until you close ${openContainer(device)}, and save when Athena is back.`,\n };\n case 'syncing':\n return { label: 'Syncing…', detail: `Sending the changes saved on ${device}.` };\n case 'needs-review':\n return {\n label: 'Review changes',\n detail: 'Some of your changes overlap with changes made in Athena. Choose what to keep.',\n };\n case 'view-only':\n return {\n label: 'View only',\n detail: `You can’t edit this anymore. Your changes stay on ${device}.`,\n };\n case 'delayed':\n return { label: 'Saving delayed', detail: savingDelayedDetail({ delay, keeping, device }) };\n }\n}\n\n/**\n * How long a document's edits may wait unconfirmed on a connection that is up before its saving\n * reads as delayed (`delayed`, `unconfirmed`), and before its room asks Keryx why: the stall window\n * every editor shares (`ACK_STALL_MS` in `@athenaintel/asset-host/local-updates`, which Olympus's\n * `room-sync-store.test.ts` holds equal).\n */\nexport const UNCONFIRMED_EDITS_STALL_MS = 15_000;\n\n/**\n * Whether a document's saving is delayed, and why (`DocumentSyncState` `delayed`): only while Athena\n * answers and the document's room is connected; `repairing` when Keryx refuses the room's writes\n * (quarantined while it is repaired: said at once, before anything waits), `unconfirmed` once its\n * edits have stayed unconfirmed past {@link UNCONFIRMED_EDITS_STALL_MS}; `null` otherwise. Every\n * app's chip asks it after a hold and after edits kept without a connection, and ahead of syncing\n * and saving, so a room that refuses writes never spins and being offline is never a delay.\n */\nexport function savingDelayCause({\n reachable,\n connected,\n writesRefused,\n unconfirmedStalled,\n}: {\n /** Athena answers (the app's reachability, never the socket alone). */\n reachable: boolean;\n /** The document's room is connected. */\n connected: boolean;\n /** Keryx's document status says the room takes no writes for now. */\n writesRefused: boolean;\n /** Local edits have waited unconfirmed past the stall window on this connection. */\n unconfirmedStalled: boolean;\n}): SavingDelayCause | null {\n if (!reachable || !connected) return null;\n if (writesRefused) return 'repairing';\n return unconfirmedStalled ? 'unconfirmed' : null;\n}\n\n/**\n * What the person lost of a document while it was open, when the server checked its room's grant\n * again (Keryx's 4401, after a share changed): `edit`, they may still view it but no longer edit it;\n * `view`, they may no longer open it at all.\n */\nexport type AccessLoss = 'edit' | 'view';\n\n/** What a document says once the person's access changed while it was open. */\nexport interface AccessChangedCopy extends StatusCopy {\n /**\n * The label of the button that saves the person's version as a file of their own, with the\n * changes Athena never took, or `null` when nothing is offered: nothing of theirs waits, or the\n * device no longer serves the document (`view`).\n */\n saveCopy: string | null;\n}\n\n/**\n * What a document says once the person's access to it changed while it was open (its editor turns\n * read-only at once), in Word's own words (Word for Mac's message bar, `strman_a6d4`, and its\n * \"Permissions Have Changed\" notice, `strman_0a3e`). `keptChanges`: changes Athena never took wait\n * on the device, never sent; Word offers to save a copy of the file so nothing typed is lost. A\n * `view` loss offers nothing to save: the device stops serving a document the person may no longer\n * read, and their changes stay where they are kept.\n */\nexport function accessChangedCopy({\n loss,\n keptChanges,\n}: {\n loss: AccessLoss;\n keptChanges: boolean;\n}): AccessChangedCopy {\n if (loss === 'view') {\n return {\n title: 'Permissions Have Changed',\n detail:\n 'The permissions on this file were updated and you no longer have rights to view this file. If you previously made changes to this file, they may not be saved.',\n saveCopy: null,\n };\n }\n if (keptChanges) {\n return {\n title: 'Can’t save',\n detail:\n 'You no longer have the permission to edit this file. To keep your changes, save a copy of the file.',\n saveCopy: 'Save a Copy',\n };\n }\n return {\n title: 'Read Only',\n detail: 'You no longer have the permission to edit this file.',\n saveCopy: null,\n };\n}\n\n/** What a document says while it holds changes an older version of Athena made on the device. */\nexport interface OlderVersionChangesCopy extends StatusCopy {\n /** Saves this device's version as a file of the person's own, those changes included (Word's). */\n saveCopy: string;\n /** Sets this device's version aside, kept on the device to compare, and opens Athena's. */\n useAthenaVersion: string;\n /** Athena's version couldn't be opened: another window of the device has the document open. */\n openElsewhere: string;\n}\n\n/**\n * What a document says while its local copy holds changes an older version of Athena made on this\n * device, below its room's write floor (`older-version`, `@athenaintel/local-copy/room-copy`): such\n * a version deletes what newer ones store, so those changes are never uploaded. Word's way out,\n * as when it can't save a cloud document (\"You can save a copy to prevent losing your work\",\n * `strman`): Save a Copy, and Athena's version, which keeps this device's version on it to compare\n * and copy from until the person discards it. `saveCopy: false` for an editor that offers no Save\n * a Copy of the live document (the phone's page): its kept version downloads instead.\n */\nexport function olderVersionChangesCopy({\n device,\n noun,\n saveCopy = true,\n}: {\n device: DeviceNoun;\n /** What the person calls the document (\"document\", \"spreadsheet\"). */\n noun: string;\n /** Whether the editor offers Save a Copy beside Athena's version. */\n saveCopy?: boolean;\n}): OlderVersionChangesCopy {\n const made = `You changed this ${noun} on ${device} in an older version of Athena, so those changes can’t be uploaded.`;\n return {\n title: 'Changes made in an older version of Athena',\n detail: saveCopy\n ? `${made} To keep them, save a copy, or use Athena’s version: yours stays on ${device} to compare and copy from.`\n : `${made} Use Athena’s version to keep yours on ${device}, where you can compare it, copy from it or download it.`,\n saveCopy: 'Save a Copy',\n useAthenaVersion: 'Use Athena’s version',\n openElsewhere: `This ${noun} is open in another window. Close it there, then try again.`,\n };\n}\n\n/** When something that needs Athena works again (the second half of `NEEDS_CONNECTION`'s line). */\nconst AVAILABLE_AGAIN = 'It’s available again when you’re back online.';\n\n/**\n * The reason on a control that needs Athena (share, run, upload, invite…),\n * shown disabled while Athena can't be reached rather than failing when used.\n */\nexport const NEEDS_CONNECTION: LabelCopy = {\n label: 'Needs a connection',\n detail: `This needs Athena. ${AVAILABLE_AGAIN}`,\n};\n\n/** What a composer was given to attach: a photo (from the phone's library or camera) or any file. */\nexport type AttachmentKind = 'photo' | 'file';\n\n/**\n * What a composer says when a photo or file is picked, pasted or dropped while\n * Athena can't be reached. It isn't attached: only Athena can take the upload.\n * In a chat whose messages wait to be sent meanwhile (`messagesWait`: the chat\n * keeps an outbox), the message itself still goes, so that comes first. Where\n * nothing waits (the Chrome side panel, a launcher that keeps its draft), it\n * says only when attaching works again, as `NEEDS_CONNECTION` does.\n */\nexport function attachmentNeedsConnection({\n kind,\n messagesWait,\n}: {\n kind: AttachmentKind;\n messagesWait: boolean;\n}): string {\n const attaching = `Attaching ${kind === 'photo' ? 'a photo' : 'a file'} needs Athena. ${AVAILABLE_AGAIN}`;\n return messagesWait\n ? `You can still send your message: it goes when Athena is back. ${attaching}`\n : attaching;\n}\n\n/** What a sent message carries besides its text that can't wait for Athena. */\nfunction heldExtras(withQuote: boolean): string {\n return withQuote ? 'an attachment or a quote' : 'an attachment';\n}\n\n/**\n * What a composer says when a message is sent while Athena can't be reached\n * with an attachment that never reached Athena (or, `withQuote`, a quote the\n * chat can't keep waiting). Its text could wait in the chat outbox; the\n * attachment can't, so the draft stays as it is.\n */\nexport function attachedMessageNeedsConnection({\n withQuote = false,\n}: {\n withQuote?: boolean;\n} = {}): string {\n return `Your text can wait and go when Athena is back, but ${heldExtras(withQuote)} can’t. Remove ${\n withQuote ? 'it' : 'the attachment'\n } to send the text.`;\n}\n\n/**\n * What a composer says when a message with an attachment (or, `withQuote`, a\n * quote) is sent while messages written when Athena couldn't be reached still\n * wait to go: those go first, and this one can't wait behind them.\n */\nexport function attachedMessageBehindWaiting({\n withQuote = false,\n}: {\n withQuote?: boolean;\n} = {}): string {\n return `Messages you wrote while Athena couldn’t be reached go first. A message with ${heldExtras(\n withQuote\n )} can’t wait behind them, so send it once they’ve gone.`;\n}\n\n/**\n * The reason on New Presentation while Athena can't be reached, in a workspace\n * whose new presentations start from its design system's template: a\n * presentation made offline starts blank, and only Athena can copy the\n * template, so none is made until it can.\n */\nexport const NEW_PRESENTATION_NEEDS_TEMPLATE: LabelCopy = {\n label: 'Needs a connection',\n detail:\n 'New presentations in this workspace start from its design template, which needs Athena. You can make one when you’re back online.',\n};\n\n/**\n * What a download of a spreadsheet made from an Excel Macro-Enabled Workbook\n * (`.xlsm`) says when it went without the macros because they come from Athena,\n * which can't be reached, and the device hasn't kept them (they travel with the\n * workbook and never run). The file is the workbook without them; downloading\n * it again with a connection keeps them.\n */\nexport function downloadedWithoutMacros({ device }: { device: DeviceNoun }): string {\n return `Downloaded without the spreadsheet’s macros: they come from Athena, which can’t be reached, and ${device} hasn’t kept them. Download it again when you’re back online to keep them.`;\n}\n\n/**\n * Save's question for a spreadsheet whose file is an Excel Macro-Enabled\n * Workbook (`.xlsm`) while its macros come from Athena, which can't be reached,\n * and the device hasn't kept them: the `.xlsm` is never written without them,\n * so the person may save an Excel Workbook (`.xlsx`) beside it, and Save writes\n * the `.xlsm` again once Athena answers.\n */\nexport function macrosNeedConnectionToSave({\n name,\n device,\n}: {\n name: string;\n device: DeviceNoun;\n}): StatusCopy {\n return {\n title: `Athena can’t save the macros in “${name}” right now.`,\n detail: `They come from Athena, which can’t be reached, and ${device} hasn’t kept them. Save it as an Excel Workbook (.xlsx) instead. “${name}” stays as it is, macros included, and Save writes it again when you’re back online.`,\n };\n}\n\n/**\n * What saving a version kept on the device as a new spreadsheet says when the\n * spreadsheet was made from an Excel Macro-Enabled Workbook (`.xlsm`) and\n * Athena can't be reached: the new spreadsheet is made all the same (on the\n * device, and it syncs when Athena is back), but without the macros, which only\n * Athena can keep with a new spreadsheet (they travel with the workbook and\n * never run). The kept version stays on the device, so saving it again with a\n * connection keeps them.\n */\nexport function savedAsNewWithoutMacros({ device }: { device: DeviceNoun }): string {\n return `The new spreadsheet was made without the macros: only Athena can keep them in a new spreadsheet, and it can’t be reached. The kept version stays on ${device}: save it as a new spreadsheet again when you’re back online to keep them.`;\n}\n\n/**\n * What saving a copy of a Word document says when the copy was made on the\n * device while Athena can't be reached, for a document whose original Word file\n * Athena keeps (one imported from Word): the copy is made all the same, from the\n * document as the device holds it, over the original file kept with it, so it\n * keeps that file's parts but writes its body from what the editor shows.\n * Athena's own copy, made from the original file, keeps everything, so saving\n * a copy again with a connection makes that one.\n */\nexport function wordCopyMadeOnDevice({ device }: { device: DeviceNoun }): StatusCopy {\n return {\n title: `Copy made on ${device}`,\n detail: `Athena can’t be reached, so the copy holds the document as it is on ${device}. Anything in the original Word file that Athena doesn’t show may be missing from it: save a copy again when you’re back online for the complete file.`,\n };\n}\n\n/**\n * Whether an item opens without a connection on this device, for lists.\n * `canKeep` says whether opening it online would keep a copy here (the\n * deployment allows device copies and the item's type is one that is kept):\n * only then is the person told to open it once.\n */\nexport function offlineAvailabilityCopy({\n available,\n canKeep,\n device,\n}: {\n available: boolean;\n canKeep: boolean;\n device: DeviceNoun;\n}): LabelCopy {\n if (available) {\n return { label: 'Available offline', detail: `Opens without a connection on ${device}.` };\n }\n return canKeep\n ? {\n label: 'Not available offline',\n detail: `Open it once while online to keep it on ${device}.`,\n }\n : { label: 'Not available offline', detail: 'This opens only with a connection.' };\n}\n\n/**\n * The one-time explainer shown the first time the person goes offline, on a\n * surface that keeps work there (`keeping` `device`). A surface that keeps\n * nothing (`none`: the Chrome side panel, the Office task pane) shows no\n * explainer; its status line already says all that holds.\n */\nexport function firstOfflineExplainer({ device }: { device: DeviceNoun }): StatusCopy & {\n action: string;\n} {\n return {\n title: 'You can keep working offline',\n detail: `Documents you’ve opened recently keep working on ${device}. Your changes sync when you’re back online.`,\n action: 'Got it',\n };\n}\n\n/**\n * How a document's changes could be lost before they reach Athena:\n *\n * - `device`: saved on the device until they reach Athena (no connection, or a review the person\n * has not finished), but the device can remove them before then (a browser that hasn't granted\n * persistent storage, a private window);\n * - `held`: saved on the device and can't be sent (the person can only view the document now, or\n * Athena refused it), and the device can remove them;\n * - `memory`: kept only until the tab or app closes (the device keeps no copy).\n */\nexport type ChangesAtRisk = 'device' | 'held' | 'memory';\n\n/**\n * What an editor says above a document whose changes could be lost before they reach Athena, with\n * the copy it offers of them (Word's \"Upload pending\" and \"Changes not saved\"), by\n * {@link ChangesAtRisk}.\n */\nexport function changesAtRiskCopy({\n risk,\n device,\n}: {\n risk: ChangesAtRisk;\n device: DeviceNoun;\n}): StatusCopy & { download: string; downloadFailed: string } {\n const actions = {\n download: 'Download a copy',\n downloadFailed: 'Couldn’t download a copy. Try again.',\n };\n switch (risk) {\n case 'memory':\n return {\n title: 'Changes not saved',\n detail: `Your changes are kept only until you close ${openContainer(device)}. Download a copy to keep them.`,\n ...actions,\n };\n case 'held':\n return {\n title: 'Changes not saved',\n detail: `Your changes can’t be sent, and they’re saved only on ${device}, which can remove them. Download a copy to keep them.`,\n ...actions,\n };\n case 'device':\n return {\n title: 'Upload pending',\n detail: `Your changes are saved only on ${device} until they reach Athena, and ${device} can remove them before then. Download a copy to keep them.`,\n ...actions,\n };\n }\n}\n\n/**\n * The action that asks the device to keep what it holds until it syncs, where asking shows the\n * person a question of the device's own (Firefox asks whether the site may store data in\n * persistent storage): the app says why first (`changesAtRiskCopy`) and asks only on this press.\n */\nexport function keepOnDeviceAction({ device }: { device: DeviceNoun }): string {\n return `Keep them on ${device}`;\n}\n\n/** A browser whose own way of keeping a site's data longer the words point to. */\nexport type SaferStorageBrowser = 'safari-mac' | 'safari-ios';\n\n/**\n * Where changes made offline in Safari are kept longer: Safari keeps a site added to the Dock or\n * the Home Screen as an app of its own, which it is likelier to let keep its data, and the desktop\n * app keeps them in storage of its own.\n */\nexport function saferStorageHint({ browser }: { browser: SaferStorageBrowser }): string {\n return browser === 'safari-mac'\n ? 'To keep changes made offline safer in Safari, add Athena to the Dock (File ▸ Add to Dock), or use Athena Desktop.'\n : 'To keep changes made offline safer, add Athena to your Home Screen (Share ▸ Add to Home Screen).';\n}\n\n/**\n * What the app says when it finds that changes it kept on the device never reached Athena and the\n * device no longer has them (the browser removed them before they synced), naming how many\n * documents; each document's row says when its changes were made (`lostChangesItemCopy`).\n */\nexport function lostChangesCopy({\n device,\n documents,\n}: {\n device: DeviceNoun;\n documents: number;\n}): StatusCopy & { why: string; open: string; dismiss: string } {\n const which = documents === 1 ? 'a document' : plural(documents, 'document', 'documents');\n return {\n title: 'Changes not saved',\n detail: `Changes you made to ${which} on ${device} never reached Athena, and ${device} no longer has them.`,\n why: 'Browsers can remove what a site keeps when they run short of space, or when the site hasn’t been opened for a while.',\n open: 'Open',\n dismiss: 'Dismiss',\n };\n}\n\n/** One document's row under `lostChangesCopy`: the words before when its changes were made. */\nexport function lostChangesItemCopy({ device }: { device: DeviceNoun }): string {\n return `Changed on ${device}`;\n}\n\n/**\n * The summary heading of the one \"Waiting to sync\" list, from what waits on\n * the device; `null` when nothing does.\n */\nexport function waitingSummary({\n changes = 0,\n messages = 0,\n recordings = 0,\n}: {\n changes?: number;\n messages?: number;\n recordings?: number;\n}): string | null {\n const parts = [\n changes > 0 ? plural(changes, 'change', 'changes') : null,\n messages > 0 ? plural(messages, 'message', 'messages') : null,\n recordings > 0 ? plural(recordings, 'recording', 'recordings') : null,\n ].filter((part): part is string => part !== null);\n return parts.length === 0 ? null : `Waiting to sync: ${parts.join(', ')}`;\n}\n\n/**\n * Where one item in the \"Waiting to sync\" list stands: a change, a message or a\n * recording made while Athena couldn't be reached.\n */\nexport type WaitingItemState =\n /** Saved on the device; it syncs when Athena is back. */\n | 'waiting'\n /** Being sent to Athena now. */\n | 'syncing'\n /**\n * Kept only while this tab or app stays open: it couldn't be saved on the\n * device (the organization keeps nothing on devices, or storage failed).\n */\n | 'in-memory'\n /**\n * Saved on the device in something that isn't open (a document closed before\n * its edits synced, one made offline): it syncs when it is next opened with a\n * connection (opening it offline sends nothing).\n */\n | 'when-opened'\n /** Made in another workspace: it syncs once that workspace is open again, with a connection. */\n | 'other-workspace'\n /** It doesn't go on its own: the person chooses (a message that waited more than a day). */\n | 'needs-you'\n /** Athena didn't take it: the app adds why, and what the person can do about it. */\n | 'not-synced';\n\n/**\n * The state of one item in the \"Waiting to sync\" list, and the line that explains it. For an item\n * saved on the device (`waiting`, `when-opened`), `evictable` says the device may remove it before\n * it syncs (default `false`).\n */\nexport function waitingItemCopy({\n state,\n device,\n evictable = false,\n}: {\n state: WaitingItemState;\n device: DeviceNoun;\n evictable?: boolean;\n}): LabelCopy {\n const removable = evictable ? ` ${removableBeforeSync({ device, count: 1 })}` : '';\n switch (state) {\n case 'waiting':\n return {\n label: 'Waiting to sync',\n detail: `Saved on ${device}. It syncs when Athena is back.${removable}`,\n };\n case 'syncing':\n return { label: 'Syncing…', detail: `Sending what was saved on ${device}.` };\n case 'in-memory':\n return {\n label: 'Not saved yet',\n detail: `Kept only until you close ${openContainer(device)}. It syncs when Athena is back.`,\n };\n case 'when-opened':\n return {\n label: 'Not synced yet',\n detail: `Saved on ${device}. It syncs when you next open it with a connection.${removable}`,\n };\n case 'other-workspace':\n return {\n label: 'Waiting for its workspace',\n detail: 'It syncs once you’re in the workspace it was made in, with a connection.',\n };\n case 'needs-you':\n return { label: 'Waiting for you', detail: 'Open it to choose what happens to it.' };\n case 'not-synced':\n return { label: 'Couldn’t sync', detail: 'Athena didn’t take it.' };\n }\n}\n\n/** The headings of the \"Waiting to sync\" list, one per kind of item. */\nexport const WAITING_SECTION_TITLES = {\n changes: 'Changes',\n messages: 'Messages',\n recordings: 'Recordings',\n} as const;\n\n/**\n * What the person can do with an item Athena didn't take (`not-synced`) in the\n * \"Waiting to sync\" list: send it again, or delete the copy on the device. That\n * copy is the item's only one, so the app asks first (`deleteFromDeviceConfirm`)\n * and never deletes it as a side effect of anything else.\n */\nexport function notSyncedActions({ device }: { device: DeviceNoun }): {\n retry: string;\n remove: string;\n} {\n return { retry: 'Try again', remove: `Delete from ${device}` };\n}\n\n/** One of `notSyncedActions`, or showing where the item is kept on the device. */\nexport type NotSyncedAction = 'retry' | 'reveal' | 'remove';\n\n/**\n * What the person hears when the device couldn't do what they asked for an\n * item Athena didn't take (its files, not Athena, failed).\n */\nexport function notSyncedActionFailed({\n action,\n device,\n}: {\n action: NotSyncedAction;\n device: DeviceNoun;\n}): string {\n switch (action) {\n case 'retry':\n return 'Couldn’t send it again. Try again in a moment.';\n case 'reveal':\n return `Couldn’t show where it’s kept on ${device}.`;\n case 'remove':\n return `Couldn’t delete it from ${device}.`;\n }\n}\n\n/**\n * The question before deleting such an item's copy on the device, naming the\n * item: the destructive choice is never the default.\n */\nexport function deleteFromDeviceConfirm({\n name,\n device,\n}: {\n name: string;\n device: DeviceNoun;\n}): StatusCopy & { confirm: string; cancel: string } {\n return {\n title: `Delete “${name}” from ${device}?`,\n detail: 'Athena didn’t take it, so this is its only copy. Deleting it can’t be undone.',\n confirm: 'Delete',\n cancel: 'Cancel',\n };\n}\n"],"names":[],"mappings":"AA6TO,MAAM,6BAA6B;AAgI1C,MAAM,kBAAkB;AAMjB,MAAM,mBAA8B;AAAA,EACzC,OAAO;AAAA,EACP,QAAQ,sBAAsB,eAAe;AAC/C;AAaO,SAAS,0BAA0B;AAAA,EACxC;AAAA,EACA;AACF,GAGW;AACT,QAAM,YAAY,aAA4C,QAAQ,kBAAkB,eAAe;AACvG,SAAO,eACH,iEAAiE,SAAS,KAC1E;AACN;AAGA,SAAS,WAAW,WAA4B;AAC9C,SAAO,YAAY,6BAA6B;AAClD;AAQO,SAAS,+BAA+B;AAAA,EAC7C,YAAY;AACd,IAEI,IAAY;AACd,SAAO,sDAAsD,WAAW,SAAS,CAAC,kBAChF,YAAY,OAAO,gBACrB;AACF;AAOO,SAAS,6BAA6B;AAAA,EAC3C,YAAY;AACd,IAEI,IAAY;AACd,SAAO,gFAAgF;AAAA,IACrF;AAAA,EAAA,CACD;AACH;"}
|
|
1
|
+
{"version":3,"file":"offline-status.js","sources":["../../../../agent-runtime/src/offline-status.ts"],"sourcesContent":["/**\n * Athena's offline language: the one set of states and words every app uses to\n * say where the person stands when the network, or Athena, is out of reach —\n * Olympus, the desktop app, the phone app, the Chrome extension and the Office\n * add-in.\n *\n * The rule the words follow: say what still works before what doesn't. Work\n * done while Athena can't be reached is kept on the device and syncs when\n * Athena is back, so every message leads with that promise. Nothing here is\n * shown while Athena answers and nothing waits; the \"back\" messages are brief.\n *\n * Pure strings and small functions, no UI library: each app draws them its own\n * way (a banner, a header chip, a tooltip, a sheet). Reachability itself is\n * each app's own (the browser's or OS's online flag AND agora answering its\n * health read); this module only names the result.\n */\n\n/** Where the app stands with Athena. */\nexport type ConnectionState =\n /** Athena answers. Nothing is shown. */\n | 'online'\n /** The device has no network. */\n | 'offline'\n /** The network is up but Athena doesn't answer. */\n | 'unreachable'\n /** Athena answers again and what waited is being sent. */\n | 'reconnecting'\n /** Just back, and everything that waited was sent. Shown briefly. */\n | 'synced';\n\n/** Where one document's edits stand, for the chip in its header. */\nexport type DocumentSyncState =\n /** In Athena. */\n | 'saved'\n /** Being sent to Athena. */\n | 'saving'\n /** Kept on this device while Athena can't be reached; syncs when it is back. */\n | 'on-device'\n /** Kept only while this tab or app stays open (no device storage); syncs when Athena is back. */\n | 'in-memory'\n /** Sending what was kept on this device. */\n | 'syncing'\n /** Some changes overlap with Athena's version: the person chooses. */\n | 'needs-review'\n /** The document can no longer take these edits (access or state changed): kept, not sent. */\n | 'view-only'\n /**\n * Athena answers but isn't taking this document's changes for now: it holds the document while it\n * repairs it, or hasn't confirmed the latest changes for longer than usual (`SavingDelayCause`\n * says which). Kept, and saved once Athena takes them. Never said while Athena can't be reached:\n * that is `on-device` or `in-memory`.\n */\n | 'delayed';\n\n/** Why a document's saving is delayed while Athena answers (`DocumentSyncState` `delayed`). */\nexport type SavingDelayCause =\n /** Athena holds the document while it repairs it, and takes no changes to it until then. */\n | 'repairing'\n /** Athena hasn't confirmed the latest changes for longer than usual. */\n | 'unconfirmed';\n\n/** How a sentence names the device the person is on. */\nexport type DeviceNoun =\n | 'this browser'\n | 'this Mac'\n | 'this computer'\n | 'this phone'\n | 'this tablet'\n | 'this device';\n\n/**\n * What the app really keeps of work done while Athena can't be reached, so the\n * words never promise more: `device` (stored on the device, survives closing),\n * `memory` (kept only while this tab or app stays open: a tenant that turns\n * device copies off, or storage the app can't open), `none` (a surface that\n * keeps no work offline at all, like the Chrome side panel).\n */\nexport type OfflineKeeping = 'device' | 'memory' | 'none';\n\n/** A title and the one line under it (a banner, a sheet, a tooltip's heading). */\nexport interface StatusCopy {\n title: string;\n detail: string;\n}\n\n/** A short label for a chip or a disabled control, and its one-line explanation. */\nexport interface LabelCopy {\n label: string;\n detail: string;\n}\n\nfunction plural(count: number, one: string, many: string): string {\n return `${count} ${count === 1 ? one : many}`;\n}\n\n/** What a tab or an app is called when work lasts only while it stays open. */\nfunction openContainer(device: DeviceNoun): string {\n return device === 'this browser' ? 'this tab' : 'the app';\n}\n\n/** The device noun at the start of a sentence (\"This browser can…\"). */\nfunction deviceAtStart(device: DeviceNoun): string {\n return `${device.charAt(0).toUpperCase()}${device.slice(1)}`;\n}\n\n/**\n * The sentence a promise ends with when the device can remove what it keeps before it syncs\n * (`evictable`: a browser that hasn't granted persistent storage, a private window): \"before then\"\n * after a sentence that says when it syncs, \"before it syncs\" after one that doesn't.\n */\nfunction removableBeforeSync({\n device,\n count,\n before = 'then',\n}: {\n device: DeviceNoun;\n count: number;\n before?: 'then' | 'syncing';\n}): string {\n const what = count === 1 ? 'it' : 'them';\n const when = before === 'then' ? 'then' : count === 1 ? 'it syncs' : 'they sync';\n return `${deviceAtStart(device)} can remove ${what} before ${when}.`;\n}\n\n/** The promise after \"You're offline\" / \"Can't reach Athena\", honest to what is kept. */\nfunction keepingPromise({\n keeping,\n device,\n when,\n evictable,\n}: {\n keeping: OfflineKeeping;\n device: DeviceNoun;\n when: string;\n evictable: boolean;\n}): string {\n switch (keeping) {\n case 'device':\n return evictable\n ? `You can keep working. Changes are kept on ${device} and sync ${when}. ${removableBeforeSync({ device, count: 2 })}`\n : `You can keep working. Changes are saved on ${device} and sync ${when}.`;\n case 'memory':\n return `You can keep working, but changes are kept only until you close ${openContainer(device)}. They sync ${when}.`;\n case 'none':\n return `You’re still signed in. This reconnects ${when}.`;\n }\n}\n\n/**\n * The app-wide status line, or `null` while Athena answers and nothing waits.\n * `waiting` counts changes not in Athena yet: while `reconnecting` they are\n * being sent; while `online` they wait for something else (a copy that sends\n * when it is next opened), and the line stays until they are gone.\n * `keeping` is what the app really keeps offline (default `device`). A surface\n * that keeps nothing (`none`) has nothing to sync, so its way back is only\n * \"Back online\", never \"Syncing…\" or \"All changes synced\".\n * `evictable`: the device may remove what it keeps before it syncs (a browser that hasn't granted\n * persistent storage, a private window); only `keeping` `device` says so (default `false`).\n */\nexport function connectionCopy({\n state,\n device,\n waiting = 0,\n keeping = 'device',\n evictable = false,\n}: {\n state: ConnectionState;\n device: DeviceNoun;\n waiting?: number;\n keeping?: OfflineKeeping;\n evictable?: boolean;\n}): StatusCopy | null {\n const atRisk = evictable && keeping === 'device';\n switch (state) {\n case 'online':\n return waiting > 0\n ? {\n title: 'Not synced yet',\n detail: `${plural(waiting, 'change', 'changes')} on ${device} ${waiting === 1 ? 'hasn’t' : 'haven’t'} synced yet.${\n atRisk ? ` ${removableBeforeSync({ device, count: waiting, before: 'syncing' })}` : ''\n }`,\n }\n : null;\n case 'offline':\n return {\n title: 'You’re offline',\n detail: keepingPromise({\n keeping,\n device,\n when: 'when you’re back online',\n evictable: atRisk,\n }),\n };\n case 'unreachable':\n return {\n title: 'Can’t reach Athena',\n detail: keepingPromise({ keeping, device, when: 'when Athena is back', evictable: atRisk }),\n };\n case 'reconnecting':\n if (keeping === 'none') return { title: 'Back online', detail: '' };\n return {\n title: 'Back online',\n detail:\n waiting > 0 ? `Syncing ${plural(waiting, 'change', 'changes')}…` : 'Syncing…',\n };\n case 'synced':\n return keeping === 'none'\n ? { title: 'Back online', detail: '' }\n : { title: 'All changes synced', detail: '' };\n }\n}\n\n/**\n * The line under \"Saving delayed\": why saving waits, and what is kept meanwhile, never promising\n * more than the app keeps.\n */\nfunction savingDelayedDetail({\n delay,\n keeping,\n device,\n}: {\n delay: SavingDelayCause;\n keeping: Exclude<OfflineKeeping, 'none'>;\n device: DeviceNoun;\n}): string {\n if (delay === 'repairing') {\n return keeping === 'memory'\n ? `You can keep working, but your changes are kept only until you close ${openContainer(device)}. They save once Athena finishes repairing this document.`\n : `You can keep working. Your changes are kept on ${device} and save once Athena finishes repairing this document.`;\n }\n return keeping === 'memory'\n ? `Athena is taking longer than usual to save your latest changes. They’re kept only until you close ${openContainer(device)}, so keep it open.`\n : `Athena is taking longer than usual to save your latest changes. They’re kept on ${device} in the meantime.`;\n}\n\n/**\n * What `on-device` says. The desktop app on a Mac speaks as Word, Excel and PowerPoint for Mac do\n * of a cloud document whose changes wait on the Mac (Office's own title-bar words): \"Upload\n * Pending\", and \"Upload Pending (Offline)\" while Athena can't be reached. Every other app says the\n * changes are saved on its device: a browser has no such words (Word for the web can't edit\n * offline), nor does the phone.\n */\nfunction onDeviceCopy({ device, reachable }: { device: DeviceNoun; reachable: boolean }): LabelCopy {\n if (device === 'this Mac') {\n return {\n label: reachable ? 'Upload Pending' : 'Upload Pending (Offline)',\n detail: 'Upload pending. Your changes sync when Athena is back.',\n };\n }\n return {\n label: `Saved on ${device}`,\n detail: `Saved on ${device}. Your changes sync when Athena is back.`,\n };\n}\n\n/**\n * The chip in a document's header, and the line it explains itself with. For `delayed`, `delay`\n * says why (default `unconfirmed`) and `keeping` whether the changes are kept on the device or only\n * while the tab or app stays open (default `device`); every other state ignores both. `reachable`\n * (default `true`) is whether Athena can be reached, which only the Mac's `on-device` words read.\n * For `on-device`, `evictable` says the device may remove the changes before they sync (default\n * `false`).\n */\nexport function documentSyncCopy({\n state,\n device,\n delay = 'unconfirmed',\n keeping = 'device',\n reachable = true,\n evictable = false,\n}: {\n state: DocumentSyncState;\n device: DeviceNoun;\n delay?: SavingDelayCause;\n keeping?: Exclude<OfflineKeeping, 'none'>;\n reachable?: boolean;\n evictable?: boolean;\n}): LabelCopy {\n switch (state) {\n case 'saved':\n return { label: 'Saved', detail: 'Saved to Athena.' };\n case 'saving':\n return { label: 'Saving…', detail: 'Saving to Athena.' };\n case 'on-device': {\n const copy = onDeviceCopy({ device, reachable });\n return evictable\n ? { ...copy, detail: `${copy.detail} ${removableBeforeSync({ device, count: 2 })}` }\n : copy;\n }\n case 'in-memory':\n return {\n label: 'Not saved yet',\n detail: `Your changes are kept only until you close ${openContainer(device)}, and save when Athena is back.`,\n };\n case 'syncing':\n return { label: 'Syncing…', detail: `Sending the changes saved on ${device}.` };\n case 'needs-review':\n return {\n label: 'Review changes',\n detail: 'Some of your changes overlap with changes made in Athena. Choose what to keep.',\n };\n case 'view-only':\n return {\n label: 'View only',\n detail: `You can’t edit this anymore. Your changes stay on ${device}.`,\n };\n case 'delayed':\n return { label: 'Saving delayed', detail: savingDelayedDetail({ delay, keeping, device }) };\n }\n}\n\n/**\n * How long a document's edits may wait unconfirmed on a connection that is up before its saving\n * reads as delayed (`delayed`, `unconfirmed`), and before its room asks Keryx why: the stall window\n * every editor shares (`ACK_STALL_MS` in `@athenaintel/asset-host/local-updates`, which Olympus's\n * `room-sync-store.test.ts` holds equal).\n */\nexport const UNCONFIRMED_EDITS_STALL_MS = 15_000;\n\n/**\n * Whether a document's saving is delayed, and why (`DocumentSyncState` `delayed`): only while Athena\n * answers and the document's room is connected; `repairing` when Keryx refuses the room's writes\n * (quarantined while it is repaired: said at once, before anything waits), `unconfirmed` once its\n * edits have stayed unconfirmed past {@link UNCONFIRMED_EDITS_STALL_MS}; `null` otherwise. Every\n * app's chip asks it after a hold and after edits kept without a connection, and ahead of syncing\n * and saving, so a room that refuses writes never spins and being offline is never a delay.\n */\nexport function savingDelayCause({\n reachable,\n connected,\n writesRefused,\n unconfirmedStalled,\n}: {\n /** Athena answers (the app's reachability, never the socket alone). */\n reachable: boolean;\n /** The document's room is connected. */\n connected: boolean;\n /** Keryx's document status says the room takes no writes for now. */\n writesRefused: boolean;\n /** Local edits have waited unconfirmed past the stall window on this connection. */\n unconfirmedStalled: boolean;\n}): SavingDelayCause | null {\n if (!reachable || !connected) return null;\n if (writesRefused) return 'repairing';\n return unconfirmedStalled ? 'unconfirmed' : null;\n}\n\n/**\n * How long a chat message sent while Athena answers may go unaccepted before it counts as waiting\n * to sync. Athena accepts a send when it takes it, not when its turn ends: 99% of follow-up messages\n * within 3.4 s of the send, and 99% of a chat's first, which also dials, within 5.7 s (production\n * `chat_ttft`, 30 days to 2026-11-07). A send still unaccepted after this is stuck, not on its way.\n */\nexport const UNACCEPTED_SEND_STALL_MS = 8_000;\n\n/** Where a chat message a chat outbox lists stands, for {@link messageWaitsToSync}. */\nexport interface OutboxMessageStanding {\n /** Athena answers (the app's reachability, never the socket alone). */\n reachable: boolean;\n /**\n * On its way to Athena: sent, or queued to go. `false` while the outbox holds it: typed while\n * Athena couldn't be reached, behind a message that waits, asking after a day, or failed.\n */\n sending: boolean;\n /** Athena received it, before its answer reached the outbox. */\n received?: boolean;\n /** When it was sent (epoch ms); for one typed while Athena couldn't be reached, when it was typed. */\n sentAt: number;\n}\n\n/**\n * When a message on its way starts counting as waiting to sync, should Athena not have accepted it\n * by then ({@link UNACCEPTED_SEND_STALL_MS} after it was sent, while Athena answers); `null` when no\n * time passing changes whether it counts.\n */\nexport function messageStartsWaitingAt({\n reachable,\n sending,\n received = false,\n sentAt,\n}: OutboxMessageStanding): number | null {\n return reachable && sending && !received ? sentAt + UNACCEPTED_SEND_STALL_MS : null;\n}\n\n/**\n * Whether a chat message a chat outbox lists counts as waiting to sync, for the status line's\n * count and the \"Waiting to sync\" list: one the outbox holds, always; one on its way, at once while\n * Athena can't be reached, and while it answers only once it went unaccepted past\n * {@link UNACCEPTED_SEND_STALL_MS}; one Athena received, never. A send that goes as usual, however\n * long its turn runs, shows no status line.\n */\nexport function messageWaitsToSync(standing: OutboxMessageStanding & { now: number }): boolean {\n const startsAt = messageStartsWaitingAt(standing);\n if (startsAt !== null) return standing.now >= startsAt;\n return !(standing.sending && standing.received === true);\n}\n\n/**\n * What the person lost of a document while it was open, when the server checked its room's grant\n * again (Keryx's 4401, after a share changed): `edit`, they may still view it but no longer edit it;\n * `view`, they may no longer open it at all.\n */\nexport type AccessLoss = 'edit' | 'view';\n\n/** What a document says once the person's access changed while it was open. */\nexport interface AccessChangedCopy extends StatusCopy {\n /**\n * The label of the button that saves the person's version as a file of their own, with the\n * changes Athena never took, or `null` when nothing is offered: nothing of theirs waits, or the\n * device no longer serves the document (`view`).\n */\n saveCopy: string | null;\n}\n\n/**\n * What a document says once the person's access to it changed while it was open (its editor turns\n * read-only at once), in Word's own words (Word for Mac's message bar, `strman_a6d4`, and its\n * \"Permissions Have Changed\" notice, `strman_0a3e`). `keptChanges`: changes Athena never took wait\n * on the device, never sent; Word offers to save a copy of the file so nothing typed is lost. A\n * `view` loss offers nothing to save: the device stops serving a document the person may no longer\n * read, and their changes stay where they are kept.\n */\nexport function accessChangedCopy({\n loss,\n keptChanges,\n}: {\n loss: AccessLoss;\n keptChanges: boolean;\n}): AccessChangedCopy {\n if (loss === 'view') {\n return {\n title: 'Permissions Have Changed',\n detail:\n 'The permissions on this file were updated and you no longer have rights to view this file. If you previously made changes to this file, they may not be saved.',\n saveCopy: null,\n };\n }\n if (keptChanges) {\n return {\n title: 'Can’t save',\n detail:\n 'You no longer have the permission to edit this file. To keep your changes, save a copy of the file.',\n saveCopy: 'Save a Copy',\n };\n }\n return {\n title: 'Read Only',\n detail: 'You no longer have the permission to edit this file.',\n saveCopy: null,\n };\n}\n\n/** What a document says while it holds changes an older version of Athena made on the device. */\nexport interface OlderVersionChangesCopy extends StatusCopy {\n /** Saves this device's version as a file of the person's own, those changes included (Word's). */\n saveCopy: string;\n /** Sets this device's version aside, kept on the device to compare, and opens Athena's. */\n useAthenaVersion: string;\n /** Athena's version couldn't be opened: another window of the device has the document open. */\n openElsewhere: string;\n}\n\n/**\n * What a document says while its local copy holds changes an older version of Athena made on this\n * device, below its room's write floor (`older-version`, `@athenaintel/local-copy/room-copy`): such\n * a version deletes what newer ones store, so those changes are never uploaded. Word's way out,\n * as when it can't save a cloud document (\"You can save a copy to prevent losing your work\",\n * `strman`): Save a Copy, and Athena's version, which keeps this device's version on it to compare\n * and copy from until the person discards it. `saveCopy: false` for an editor that offers no Save\n * a Copy of the live document. `keepsAside: false` where the device keeps no version of it aside\n * (copies off, an embed): Athena's version then replaces the changes, which the person confirms\n * first (`olderVersionDiscardCopy`). `atRisk`: the device can lose them before the person chooses\n * (`ChangesAtRisk`), said here so the document shows one strip, never a second \"Changes not saved\".\n */\nexport function olderVersionChangesCopy({\n device,\n noun,\n saveCopy = true,\n keepsAside = true,\n atRisk = null,\n}: {\n device: DeviceNoun;\n /** What the person calls the document (\"document\", \"spreadsheet\"). */\n noun: string;\n /** Whether the editor offers Save a Copy beside Athena's version. */\n saveCopy?: boolean;\n /** Whether Athena's version keeps the device's aside, as a version to compare and copy from. */\n keepsAside?: boolean;\n /** How the device could lose the changes before the person chooses, or `null`. */\n atRisk?: ChangesAtRisk | null;\n}): OlderVersionChangesCopy {\n const made = `You changed this ${noun} on ${device} in an older version of Athena, so those changes can’t be uploaded.`;\n const keep = !keepsAside\n ? `${made} To keep them, save a copy: Athena’s version replaces them on ${device}.`\n : saveCopy\n ? `${made} To keep them, save a copy, or use Athena’s version: yours stays on ${device} to compare and copy from.`\n : `${made} Use Athena’s version to keep yours on ${device}, where you can compare it, copy from it or download it.`;\n const risk =\n atRisk === null\n ? ''\n : atRisk === 'memory'\n ? ` Until you choose, they’re kept only until you close ${openContainer(device)}.`\n : ` Until you choose, they’re saved only on ${device}, which can remove them.`;\n return {\n title: 'Changes made in an older version of Athena',\n detail: `${keep}${risk}`,\n saveCopy: 'Save a Copy',\n useAthenaVersion: 'Use Athena’s version',\n openElsewhere: `This ${noun} is open in another window. Close it there, then try again.`,\n };\n}\n\n/**\n * What the device asks before Athena's version replaces changes an older version of Athena made,\n * where it keeps no version of them aside (`olderVersionChangesCopy`'s `keepsAside: false`): they\n * are deleted then, so a copy saved first is the only way to keep them.\n */\nexport function olderVersionDiscardCopy({ device }: { device: DeviceNoun }): StatusCopy & {\n confirm: string;\n cancel: string;\n} {\n return {\n title: 'Use Athena’s version?',\n detail: `The changes made in an older version of Athena are deleted from ${device} and can’t be recovered. To keep them, save a copy first.`,\n confirm: 'Use Athena’s version',\n cancel: 'Cancel',\n };\n}\n\n/** When something that needs Athena works again (the second half of `NEEDS_CONNECTION`'s line). */\nconst AVAILABLE_AGAIN = 'It’s available again when you’re back online.';\n\n/**\n * The reason on a control that needs Athena (share, run, upload, invite…),\n * shown disabled while Athena can't be reached rather than failing when used.\n */\nexport const NEEDS_CONNECTION: LabelCopy = {\n label: 'Needs a connection',\n detail: `This needs Athena. ${AVAILABLE_AGAIN}`,\n};\n\n/** What a composer was given to attach: a photo (from the phone's library or camera) or any file. */\nexport type AttachmentKind = 'photo' | 'file';\n\n/**\n * What a composer says when a photo or file is picked, pasted or dropped while\n * Athena can't be reached. It isn't attached: only Athena can take the upload.\n * In a chat whose messages wait to be sent meanwhile (`messagesWait`: the chat\n * keeps an outbox), the message itself still goes, so that comes first. Where\n * nothing waits (the Chrome side panel, a launcher that keeps its draft), it\n * says only when attaching works again, as `NEEDS_CONNECTION` does.\n */\nexport function attachmentNeedsConnection({\n kind,\n messagesWait,\n}: {\n kind: AttachmentKind;\n messagesWait: boolean;\n}): string {\n const attaching = `Attaching ${kind === 'photo' ? 'a photo' : 'a file'} needs Athena. ${AVAILABLE_AGAIN}`;\n return messagesWait\n ? `You can still send your message: it goes when Athena is back. ${attaching}`\n : attaching;\n}\n\n/** What a sent message carries besides its text that can't wait for Athena. */\nfunction heldExtras(withQuote: boolean): string {\n return withQuote ? 'an attachment or a quote' : 'an attachment';\n}\n\n/**\n * What a composer says when a message is sent while Athena can't be reached\n * with an attachment that never reached Athena (or, `withQuote`, a quote the\n * chat can't keep waiting). Its text could wait in the chat outbox; the\n * attachment can't, so the draft stays as it is.\n */\nexport function attachedMessageNeedsConnection({\n withQuote = false,\n}: {\n withQuote?: boolean;\n} = {}): string {\n return `Your text can wait and go when Athena is back, but ${heldExtras(withQuote)} can’t. Remove ${\n withQuote ? 'it' : 'the attachment'\n } to send the text.`;\n}\n\n/**\n * What a composer says when a message with an attachment (or, `withQuote`, a\n * quote) is sent while messages written when Athena couldn't be reached still\n * wait to go: those go first, and this one can't wait behind them.\n */\nexport function attachedMessageBehindWaiting({\n withQuote = false,\n}: {\n withQuote?: boolean;\n} = {}): string {\n return `Messages you wrote while Athena couldn’t be reached go first. A message with ${heldExtras(\n withQuote\n )} can’t wait behind them, so send it once they’ve gone.`;\n}\n\n/**\n * The reason on New Presentation while Athena can't be reached, in a workspace\n * whose new presentations start from its design system's template: a\n * presentation made offline starts blank, and only Athena can copy the\n * template, so none is made until it can.\n */\nexport const NEW_PRESENTATION_NEEDS_TEMPLATE: LabelCopy = {\n label: 'Needs a connection',\n detail:\n 'New presentations in this workspace start from its design template, which needs Athena. You can make one when you’re back online.',\n};\n\n/**\n * What a download of a spreadsheet made from an Excel Macro-Enabled Workbook\n * (`.xlsm`) says when it went without the macros because they come from Athena,\n * which can't be reached, and the device hasn't kept them (they travel with the\n * workbook and never run). The file is the workbook without them; downloading\n * it again with a connection keeps them.\n */\nexport function downloadedWithoutMacros({ device }: { device: DeviceNoun }): string {\n return `Downloaded without the spreadsheet’s macros: they come from Athena, which can’t be reached, and ${device} hasn’t kept them. Download it again when you’re back online to keep them.`;\n}\n\n/**\n * Save's question for a spreadsheet whose file is an Excel Macro-Enabled\n * Workbook (`.xlsm`) while its macros come from Athena, which can't be reached,\n * and the device hasn't kept them: the `.xlsm` is never written without them,\n * so the person may save an Excel Workbook (`.xlsx`) beside it, and Save writes\n * the `.xlsm` again once Athena answers.\n */\nexport function macrosNeedConnectionToSave({\n name,\n device,\n}: {\n name: string;\n device: DeviceNoun;\n}): StatusCopy {\n return {\n title: `Athena can’t save the macros in “${name}” right now.`,\n detail: `They come from Athena, which can’t be reached, and ${device} hasn’t kept them. Save it as an Excel Workbook (.xlsx) instead. “${name}” stays as it is, macros included, and Save writes it again when you’re back online.`,\n };\n}\n\n/**\n * What saving a version kept on the device as a new spreadsheet says when the\n * spreadsheet was made from an Excel Macro-Enabled Workbook (`.xlsm`) and\n * Athena can't be reached: the new spreadsheet is made all the same (on the\n * device, and it syncs when Athena is back), but without the macros, which only\n * Athena can keep with a new spreadsheet (they travel with the workbook and\n * never run). The kept version stays on the device, so saving it again with a\n * connection keeps them.\n */\nexport function savedAsNewWithoutMacros({ device }: { device: DeviceNoun }): string {\n return `The new spreadsheet was made without the macros: only Athena can keep them in a new spreadsheet, and it can’t be reached. The kept version stays on ${device}: save it as a new spreadsheet again when you’re back online to keep them.`;\n}\n\n/**\n * What saving a copy of a Word document says when the copy was made on the\n * device while Athena can't be reached, for a document whose original Word file\n * Athena keeps (one imported from Word): the copy is made all the same, from the\n * document as the device holds it, over the original file kept with it, so it\n * keeps that file's parts but writes its body from what the editor shows.\n * Athena's own copy, made from the original file, keeps everything, so saving\n * a copy again with a connection makes that one.\n */\nexport function wordCopyMadeOnDevice({ device }: { device: DeviceNoun }): StatusCopy {\n return {\n title: `Copy made on ${device}`,\n detail: `Athena can’t be reached, so the copy holds the document as it is on ${device}. Anything in the original Word file that Athena doesn’t show may be missing from it: save a copy again when you’re back online for the complete file.`,\n };\n}\n\n/**\n * Whether an item opens without a connection on this device, for lists.\n * `canKeep` says whether opening it online would keep a copy here (the\n * deployment allows device copies and the item's type is one that is kept):\n * only then is the person told to open it once.\n */\nexport function offlineAvailabilityCopy({\n available,\n canKeep,\n device,\n}: {\n available: boolean;\n canKeep: boolean;\n device: DeviceNoun;\n}): LabelCopy {\n if (available) {\n return { label: 'Available offline', detail: `Opens without a connection on ${device}.` };\n }\n return canKeep\n ? {\n label: 'Not available offline',\n detail: `Open it once while online to keep it on ${device}.`,\n }\n : { label: 'Not available offline', detail: 'This opens only with a connection.' };\n}\n\n/**\n * A history Athena keeps in full (a person's dictations), shown while Athena\n * can't be reached: the list holds only what is kept on the device, and the\n * rest comes back once online. `items` names what the list holds, plural.\n */\nexport function historyOnDeviceCopy({\n items,\n device,\n}: {\n items: string;\n device: DeviceNoun;\n}): string {\n return `Showing the ${items} kept on ${device}. Your full history shows when you’re back online.`;\n}\n\n/**\n * The one-time explainer shown the first time the person goes offline, on a\n * surface that keeps work there (`keeping` `device`). A surface that keeps\n * nothing (`none`: the Chrome side panel, the Office task pane) shows no\n * explainer; its status line already says all that holds.\n */\nexport function firstOfflineExplainer({ device }: { device: DeviceNoun }): StatusCopy & {\n action: string;\n} {\n return {\n title: 'You can keep working offline',\n detail: `Documents you’ve opened recently keep working on ${device}. Your changes sync when you’re back online.`,\n action: 'Got it',\n };\n}\n\n/**\n * How a document's changes could be lost before they reach Athena:\n *\n * - `device`: saved on the device until they reach Athena (no connection, or a review the person\n * has not finished), but the device can remove them before then (a browser that hasn't granted\n * persistent storage, a private window);\n * - `held`: saved on the device and can't be sent (the person can only view the document now, or\n * Athena refused it), and the device can remove them;\n * - `memory`: kept only until the tab or app closes (the device keeps no copy).\n */\nexport type ChangesAtRisk = 'device' | 'held' | 'memory';\n\n/**\n * What an editor says above a document whose changes could be lost before they reach Athena, with\n * the copy it offers of them (Word's \"Upload pending\" and \"Changes not saved\"), by\n * {@link ChangesAtRisk}.\n */\nexport function changesAtRiskCopy({\n risk,\n device,\n}: {\n risk: ChangesAtRisk;\n device: DeviceNoun;\n}): StatusCopy & { download: string; downloadFailed: string } {\n const actions = {\n download: 'Download a copy',\n downloadFailed: 'Couldn’t download a copy. Try again.',\n };\n switch (risk) {\n case 'memory':\n return {\n title: 'Changes not saved',\n detail: `Your changes are kept only until you close ${openContainer(device)}. Download a copy to keep them.`,\n ...actions,\n };\n case 'held':\n return {\n title: 'Changes not saved',\n detail: `Your changes can’t be sent, and they’re saved only on ${device}, which can remove them. Download a copy to keep them.`,\n ...actions,\n };\n case 'device':\n return {\n title: 'Upload pending',\n detail: `Your changes are saved only on ${device} until they reach Athena, and ${device} can remove them before then. Download a copy to keep them.`,\n ...actions,\n };\n }\n}\n\n/**\n * The action that asks the device to keep what it holds until it syncs, where asking shows the\n * person a question of the device's own (Firefox asks whether the site may store data in\n * persistent storage): the app says why first (`changesAtRiskCopy`) and asks only on this press.\n */\nexport function keepOnDeviceAction({ device }: { device: DeviceNoun }): string {\n return `Keep them on ${device}`;\n}\n\n/** A browser whose own way of keeping a site's data longer the words point to. */\nexport type SaferStorageBrowser = 'safari-mac' | 'safari-ios';\n\n/**\n * Where changes made offline in Safari are kept longer: Safari keeps a site added to the Dock or\n * the Home Screen as an app of its own, which it is likelier to let keep its data, and the desktop\n * app keeps them in storage of its own.\n */\nexport function saferStorageHint({ browser }: { browser: SaferStorageBrowser }): string {\n return browser === 'safari-mac'\n ? 'To keep changes made offline safer in Safari, add Athena to the Dock (File ▸ Add to Dock), or use Athena Desktop.'\n : 'To keep changes made offline safer, add Athena to your Home Screen (Share ▸ Add to Home Screen).';\n}\n\n/**\n * What the app says when it finds that changes it kept on the device never reached Athena and the\n * device no longer has them (the browser removed them before they synced), naming how many\n * documents; each document's row says when its changes were made (`lostChangesItemCopy`).\n */\nexport function lostChangesCopy({\n device,\n documents,\n}: {\n device: DeviceNoun;\n documents: number;\n}): StatusCopy & { why: string; open: string; dismiss: string } {\n const which = documents === 1 ? 'a document' : plural(documents, 'document', 'documents');\n return {\n title: 'Changes not saved',\n detail: `Changes you made to ${which} on ${device} never reached Athena, and ${device} no longer has them.`,\n why: 'Browsers can remove what a site keeps when they run short of space, or when the site hasn’t been opened for a while.',\n open: 'Open',\n dismiss: 'Dismiss',\n };\n}\n\n/** One document's row under `lostChangesCopy`: the words before when its changes were made. */\nexport function lostChangesItemCopy({ device }: { device: DeviceNoun }): string {\n return `Changed on ${device}`;\n}\n\n/**\n * The summary heading of the one \"Waiting to sync\" list, from what waits on\n * the device; `null` when nothing does.\n */\nexport function waitingSummary({\n changes = 0,\n messages = 0,\n recordings = 0,\n}: {\n changes?: number;\n messages?: number;\n recordings?: number;\n}): string | null {\n const parts = [\n changes > 0 ? plural(changes, 'change', 'changes') : null,\n messages > 0 ? plural(messages, 'message', 'messages') : null,\n recordings > 0 ? plural(recordings, 'recording', 'recordings') : null,\n ].filter((part): part is string => part !== null);\n return parts.length === 0 ? null : `Waiting to sync: ${parts.join(', ')}`;\n}\n\n/**\n * Where one item in the \"Waiting to sync\" list stands: a change, a message or a\n * recording made while Athena couldn't be reached.\n */\nexport type WaitingItemState =\n /** Saved on the device; it syncs when Athena is back. */\n | 'waiting'\n /** Being sent to Athena now. */\n | 'syncing'\n /**\n * Kept only while this tab or app stays open: it couldn't be saved on the\n * device (the organization keeps nothing on devices, or storage failed).\n */\n | 'in-memory'\n /**\n * Saved on the device in something that isn't open (a document closed before\n * its edits synced, one made offline): it syncs when it is next opened with a\n * connection (opening it offline sends nothing).\n */\n | 'when-opened'\n /** Made in another workspace: it syncs once that workspace is open again, with a connection. */\n | 'other-workspace'\n /** It doesn't go on its own: the person chooses (a message that waited more than a day). */\n | 'needs-you'\n /** Athena didn't take it: the app adds why, and what the person can do about it. */\n | 'not-synced';\n\n/**\n * The state of one item in the \"Waiting to sync\" list, and the line that explains it. For an item\n * saved on the device (`waiting`, `when-opened`), `evictable` says the device may remove it before\n * it syncs (default `false`).\n */\nexport function waitingItemCopy({\n state,\n device,\n evictable = false,\n}: {\n state: WaitingItemState;\n device: DeviceNoun;\n evictable?: boolean;\n}): LabelCopy {\n const removable = evictable ? ` ${removableBeforeSync({ device, count: 1 })}` : '';\n switch (state) {\n case 'waiting':\n return {\n label: 'Waiting to sync',\n detail: `Saved on ${device}. It syncs when Athena is back.${removable}`,\n };\n case 'syncing':\n return { label: 'Syncing…', detail: `Sending what was saved on ${device}.` };\n case 'in-memory':\n return {\n label: 'Not saved yet',\n detail: `Kept only until you close ${openContainer(device)}. It syncs when Athena is back.`,\n };\n case 'when-opened':\n return {\n label: 'Not synced yet',\n detail: `Saved on ${device}. It syncs when you next open it with a connection.${removable}`,\n };\n case 'other-workspace':\n return {\n label: 'Waiting for its workspace',\n detail: 'It syncs once you’re in the workspace it was made in, with a connection.',\n };\n case 'needs-you':\n return { label: 'Waiting for you', detail: 'Open it to choose what happens to it.' };\n case 'not-synced':\n return { label: 'Couldn’t sync', detail: 'Athena didn’t take it.' };\n }\n}\n\n/** The headings of the \"Waiting to sync\" list, one per kind of item. */\nexport const WAITING_SECTION_TITLES = {\n changes: 'Changes',\n messages: 'Messages',\n recordings: 'Recordings',\n} as const;\n\n/**\n * What the person can do with an item Athena didn't take (`not-synced`) in the\n * \"Waiting to sync\" list: send it again, or delete the copy on the device. That\n * copy is the item's only one, so the app asks first (`deleteFromDeviceConfirm`)\n * and never deletes it as a side effect of anything else.\n */\nexport function notSyncedActions({ device }: { device: DeviceNoun }): {\n retry: string;\n remove: string;\n} {\n return { retry: 'Try again', remove: `Delete from ${device}` };\n}\n\n/** One of `notSyncedActions`, or showing where the item is kept on the device. */\nexport type NotSyncedAction = 'retry' | 'reveal' | 'remove';\n\n/**\n * What the person hears when the device couldn't do what they asked for an\n * item Athena didn't take (its files, not Athena, failed).\n */\nexport function notSyncedActionFailed({\n action,\n device,\n}: {\n action: NotSyncedAction;\n device: DeviceNoun;\n}): string {\n switch (action) {\n case 'retry':\n return 'Couldn’t send it again. Try again in a moment.';\n case 'reveal':\n return `Couldn’t show where it’s kept on ${device}.`;\n case 'remove':\n return `Couldn’t delete it from ${device}.`;\n }\n}\n\n/**\n * The question before deleting such an item's copy on the device, naming the\n * item: the destructive choice is never the default.\n */\nexport function deleteFromDeviceConfirm({\n name,\n device,\n}: {\n name: string;\n device: DeviceNoun;\n}): StatusCopy & { confirm: string; cancel: string } {\n return {\n title: `Delete “${name}” from ${device}?`,\n detail: 'Athena didn’t take it, so this is its only copy. Deleting it can’t be undone.',\n confirm: 'Delete',\n cancel: 'Cancel',\n };\n}\n"],"names":[],"mappings":"AA6TO,MAAM,6BAA6B;AAqN1C,MAAM,kBAAkB;AAMjB,MAAM,mBAA8B;AAAA,EACzC,OAAO;AAAA,EACP,QAAQ,sBAAsB,eAAe;AAC/C;AAaO,SAAS,0BAA0B;AAAA,EACxC;AAAA,EACA;AACF,GAGW;AACT,QAAM,YAAY,aAA4C,QAAQ,kBAAkB,eAAe;AACvG,SAAO,eACH,iEAAiE,SAAS,KAC1E;AACN;AAGA,SAAS,WAAW,WAA4B;AAC9C,SAAO,YAAY,6BAA6B;AAClD;AAQO,SAAS,+BAA+B;AAAA,EAC7C,YAAY;AACd,IAEI,IAAY;AACd,SAAO,sDAAsD,WAAW,SAAS,CAAC,kBAChF,YAAY,OAAO,gBACrB;AACF;AAOO,SAAS,6BAA6B;AAAA,EAC3C,YAAY;AACd,IAEI,IAAY;AACd,SAAO,gFAAgF;AAAA,IACrF;AAAA,EAAA,CACD;AACH;"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const messageText = require("./message-text.cjs");
|
|
4
|
+
const subagents = require("./subagents.cjs");
|
|
5
|
+
function parseJsonLoose(text) {
|
|
6
|
+
try {
|
|
7
|
+
return JSON.parse(text);
|
|
8
|
+
} catch {
|
|
9
|
+
return text;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function ptcSubcallsFromArtifact(artifact) {
|
|
13
|
+
const nested = subagents.nestedMessagesFromArtifact(artifact);
|
|
14
|
+
if (nested.length === 0) return [];
|
|
15
|
+
const results = /* @__PURE__ */ new Map();
|
|
16
|
+
for (const m of nested) {
|
|
17
|
+
if (m.type === "tool" && m.tool_call_id) results.set(m.tool_call_id, m);
|
|
18
|
+
}
|
|
19
|
+
const subcalls = [];
|
|
20
|
+
for (const m of nested) {
|
|
21
|
+
if (m.type !== "ai" || !m.tool_calls) continue;
|
|
22
|
+
for (const tc of m.tool_calls) {
|
|
23
|
+
if (!tc.id) continue;
|
|
24
|
+
const result = results.get(tc.id);
|
|
25
|
+
const resultText = result ? messageText.getMessageText(result) : "";
|
|
26
|
+
subcalls.push({
|
|
27
|
+
id: tc.id,
|
|
28
|
+
name: tc.name,
|
|
29
|
+
args: tc.args ?? {},
|
|
30
|
+
status: result ? result.status === "error" ? "error" : "completed" : "in_flight",
|
|
31
|
+
// The backend serializes the PTC end event's result payload as JSON
|
|
32
|
+
// into the nested ToolMessage content (`to_langchain_message_dicts`).
|
|
33
|
+
result: resultText ? parseJsonLoose(resultText) : void 0,
|
|
34
|
+
resultText
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return subcalls;
|
|
39
|
+
}
|
|
40
|
+
exports.ptcSubcallsFromArtifact = ptcSubcallsFromArtifact;
|
|
41
|
+
//# sourceMappingURL=ptc-subcalls.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ptc-subcalls.cjs","sources":["../../../../agent-runtime/src/ptc-subcalls.ts"],"sourcesContent":["/**\n * Programmatic-tool-calling (PTC) sub-call parsing — the SDK method calls a\n * sandbox `execute` / interpreter `eval` recorded, promoted by the backend onto\n * the parent ToolMessage's artifact (`promote_artifact_with_ptc_subcalls`\n * shape: one AIMessage carrying every call, then one ToolMessage per settled\n * call). Pure parsing shared by the nested tool cards and the studio\n * follow-along; React selectors over these live with each runtime host.\n */\nimport type { LangChainMessage } from '@assistant-ui/react-langgraph';\nimport { getMessageText } from './message-text';\nimport { isRunningToolPlaceholder } from './running-tool-placeholder';\nimport { nestedMessagesFromArtifact } from './subagents';\nimport { PTC_PARENT_TOOL_NAMES, TASK_TOOL_NAME } from './tool-names';\n\ntype ToolMsg = Extract<LangChainMessage, { type: 'tool' }>;\n\n/**\n * One SDK sub-call recorded under a sandbox `execute` (or interpreter `eval`)\n * tool call — an Athena SDK method call (e.g. `Presentation.create`) the\n * backend's PTC display channel captured and promoted onto the parent\n * ToolMessage's `artifact.subgraph_state.messages`.\n */\nexport interface PtcSubcall {\n id: string;\n name: string;\n args: Record<string, unknown>;\n status: 'in_flight' | 'completed' | 'error';\n /** The settled call's parsed result payload (`undefined` while in flight). */\n result: unknown;\n /** The settled call's result text ('' while in flight). */\n resultText: string;\n}\n\nfunction parseJsonLoose(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\n/** Parse the PTC sub-call list from a parent ToolMessage's promoted artifact. */\nexport function ptcSubcallsFromArtifact(artifact: unknown): PtcSubcall[] {\n const nested = nestedMessagesFromArtifact(artifact);\n if (nested.length === 0) return [];\n const results = new Map<string, ToolMsg>();\n for (const m of nested) {\n if (m.type === 'tool' && m.tool_call_id) results.set(m.tool_call_id, m);\n }\n const subcalls: PtcSubcall[] = [];\n for (const m of nested) {\n if (m.type !== 'ai' || !m.tool_calls) continue;\n for (const tc of m.tool_calls) {\n if (!tc.id) continue;\n const result = results.get(tc.id);\n const resultText = result ? getMessageText(result) : '';\n subcalls.push({\n id: tc.id,\n name: tc.name,\n args: (tc.args as Record<string, unknown> | undefined) ?? {},\n status: result ? (result.status === 'error' ? 'error' : 'completed') : 'in_flight',\n // The backend serializes the PTC end event's result payload as JSON\n // into the nested ToolMessage content (`to_langchain_message_dicts`).\n result: resultText ? parseJsonLoose(resultText) : undefined,\n resultText,\n });\n }\n }\n return subcalls;\n}\n\n/** One completed PTC parent (`execute`, `eval`, or a studio executor) carrying recorded sub-calls. */\nexport interface CompletedPtcParent {\n toolCallId: string;\n /** The parent tool's name, one of `PTC_PARENT_TOOL_NAMES`. */\n toolName: string;\n /**\n * The executor source the call ran (`eval`'s `code` arg), read off the AI\n * message that requested it. The studio SDKs emit no cell-level sub-calls,\n * so the code string is the only carrier of the written spreadsheet cell.\n */\n code: string | undefined;\n /** Shape `computeStudioFollowTarget` expects: `{ artifact, result }`. */\n rawResult: { artifact: unknown; result: unknown };\n}\n\n/** Args of every tool call requested by the AI messages in one transcript, by call id. */\nfunction toolCallArgsById(\n messages: readonly LangChainMessage[]\n): Map<string, Record<string, unknown>> {\n const argsById = new Map<string, Record<string, unknown>>();\n for (const message of messages) {\n if (message.type !== 'ai' || !message.tool_calls) continue;\n for (const toolCall of message.tool_calls) {\n if (!toolCall.id) continue;\n argsById.set(toolCall.id, (toolCall.args as Record<string, unknown> | undefined) ?? {});\n }\n }\n return argsById;\n}\n\nfunction collectCompletedPtcParents(\n messages: readonly LangChainMessage[],\n completed: CompletedPtcParent[]\n): void {\n const argsById = toolCallArgsById(messages);\n for (const message of messages) {\n if (message.type !== 'tool' || !message.tool_call_id || !message.name) continue;\n const nested = nestedMessagesFromArtifact(message.artifact);\n if (nested.length === 0) continue;\n // A subagent's whole transcript is nested under its `task` ToolMessage, so\n // its own execute/eval calls (and their PTC sub-calls) only exist there.\n if (message.name === TASK_TOOL_NAME) {\n collectCompletedPtcParents(nested, completed);\n continue;\n }\n if (!PTC_PARENT_TOOL_NAMES.has(message.name)) continue;\n // The execution's sub-call log can reach its running placeholder before\n // the call returns: completed is the real ToolMessage that replaces it.\n if (isRunningToolPlaceholder(message)) continue;\n const code = argsById.get(message.tool_call_id)?.code;\n completed.push({\n toolCallId: message.tool_call_id,\n toolName: message.name,\n code: typeof code === 'string' ? code : undefined,\n rawResult: { artifact: message.artifact, result: message.content },\n });\n }\n}\n\n/**\n * Every completed `execute`/`eval` ToolMessage carrying recorded PTC\n * sub-calls, from the raw transport messages — including the ones a subagent\n * ran inside a `task` call's nested transcript. Drives the deep-agent's studio\n * follow-along (`DeepAgentPtcStudioFollowObserver`).\n */\nexport function extractCompletedPtcParents(\n messages: readonly LangChainMessage[]\n): CompletedPtcParent[] {\n const completed: CompletedPtcParent[] = [];\n collectCompletedPtcParents(messages, completed);\n return completed;\n}\n"],"names":["nestedMessagesFromArtifact","getMessageText"],"mappings":";;;;AAiCA,SAAS,eAAe,MAAuB;AAC7C,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,wBAAwB,UAAiC;AACvE,QAAM,SAASA,UAAAA,2BAA2B,QAAQ;AAClD,MAAI,OAAO,WAAW,EAAG,QAAO,CAAA;AAChC,QAAM,8BAAc,IAAA;AACpB,aAAW,KAAK,QAAQ;AACtB,QAAI,EAAE,SAAS,UAAU,EAAE,aAAc,SAAQ,IAAI,EAAE,cAAc,CAAC;AAAA,EACxE;AACA,QAAM,WAAyB,CAAA;AAC/B,aAAW,KAAK,QAAQ;AACtB,QAAI,EAAE,SAAS,QAAQ,CAAC,EAAE,WAAY;AACtC,eAAW,MAAM,EAAE,YAAY;AAC7B,UAAI,CAAC,GAAG,GAAI;AACZ,YAAM,SAAS,QAAQ,IAAI,GAAG,EAAE;AAChC,YAAM,aAAa,SAASC,2BAAe,MAAM,IAAI;AACrD,eAAS,KAAK;AAAA,QACZ,IAAI,GAAG;AAAA,QACP,MAAM,GAAG;AAAA,QACT,MAAO,GAAG,QAAgD,CAAA;AAAA,QAC1D,QAAQ,SAAU,OAAO,WAAW,UAAU,UAAU,cAAe;AAAA;AAAA;AAAA,QAGvE,QAAQ,aAAa,eAAe,UAAU,IAAI;AAAA,QAClD;AAAA,MAAA,CACD;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;;"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getMessageText } from "./message-text.js";
|
|
2
|
+
import { nestedMessagesFromArtifact } from "./subagents.js";
|
|
3
|
+
function parseJsonLoose(text) {
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(text);
|
|
6
|
+
} catch {
|
|
7
|
+
return text;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function ptcSubcallsFromArtifact(artifact) {
|
|
11
|
+
const nested = nestedMessagesFromArtifact(artifact);
|
|
12
|
+
if (nested.length === 0) return [];
|
|
13
|
+
const results = /* @__PURE__ */ new Map();
|
|
14
|
+
for (const m of nested) {
|
|
15
|
+
if (m.type === "tool" && m.tool_call_id) results.set(m.tool_call_id, m);
|
|
16
|
+
}
|
|
17
|
+
const subcalls = [];
|
|
18
|
+
for (const m of nested) {
|
|
19
|
+
if (m.type !== "ai" || !m.tool_calls) continue;
|
|
20
|
+
for (const tc of m.tool_calls) {
|
|
21
|
+
if (!tc.id) continue;
|
|
22
|
+
const result = results.get(tc.id);
|
|
23
|
+
const resultText = result ? getMessageText(result) : "";
|
|
24
|
+
subcalls.push({
|
|
25
|
+
id: tc.id,
|
|
26
|
+
name: tc.name,
|
|
27
|
+
args: tc.args ?? {},
|
|
28
|
+
status: result ? result.status === "error" ? "error" : "completed" : "in_flight",
|
|
29
|
+
// The backend serializes the PTC end event's result payload as JSON
|
|
30
|
+
// into the nested ToolMessage content (`to_langchain_message_dicts`).
|
|
31
|
+
result: resultText ? parseJsonLoose(resultText) : void 0,
|
|
32
|
+
resultText
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return subcalls;
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
ptcSubcallsFromArtifact
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=ptc-subcalls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ptc-subcalls.js","sources":["../../../../agent-runtime/src/ptc-subcalls.ts"],"sourcesContent":["/**\n * Programmatic-tool-calling (PTC) sub-call parsing — the SDK method calls a\n * sandbox `execute` / interpreter `eval` recorded, promoted by the backend onto\n * the parent ToolMessage's artifact (`promote_artifact_with_ptc_subcalls`\n * shape: one AIMessage carrying every call, then one ToolMessage per settled\n * call). Pure parsing shared by the nested tool cards and the studio\n * follow-along; React selectors over these live with each runtime host.\n */\nimport type { LangChainMessage } from '@assistant-ui/react-langgraph';\nimport { getMessageText } from './message-text';\nimport { isRunningToolPlaceholder } from './running-tool-placeholder';\nimport { nestedMessagesFromArtifact } from './subagents';\nimport { PTC_PARENT_TOOL_NAMES, TASK_TOOL_NAME } from './tool-names';\n\ntype ToolMsg = Extract<LangChainMessage, { type: 'tool' }>;\n\n/**\n * One SDK sub-call recorded under a sandbox `execute` (or interpreter `eval`)\n * tool call — an Athena SDK method call (e.g. `Presentation.create`) the\n * backend's PTC display channel captured and promoted onto the parent\n * ToolMessage's `artifact.subgraph_state.messages`.\n */\nexport interface PtcSubcall {\n id: string;\n name: string;\n args: Record<string, unknown>;\n status: 'in_flight' | 'completed' | 'error';\n /** The settled call's parsed result payload (`undefined` while in flight). */\n result: unknown;\n /** The settled call's result text ('' while in flight). */\n resultText: string;\n}\n\nfunction parseJsonLoose(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\n/** Parse the PTC sub-call list from a parent ToolMessage's promoted artifact. */\nexport function ptcSubcallsFromArtifact(artifact: unknown): PtcSubcall[] {\n const nested = nestedMessagesFromArtifact(artifact);\n if (nested.length === 0) return [];\n const results = new Map<string, ToolMsg>();\n for (const m of nested) {\n if (m.type === 'tool' && m.tool_call_id) results.set(m.tool_call_id, m);\n }\n const subcalls: PtcSubcall[] = [];\n for (const m of nested) {\n if (m.type !== 'ai' || !m.tool_calls) continue;\n for (const tc of m.tool_calls) {\n if (!tc.id) continue;\n const result = results.get(tc.id);\n const resultText = result ? getMessageText(result) : '';\n subcalls.push({\n id: tc.id,\n name: tc.name,\n args: (tc.args as Record<string, unknown> | undefined) ?? {},\n status: result ? (result.status === 'error' ? 'error' : 'completed') : 'in_flight',\n // The backend serializes the PTC end event's result payload as JSON\n // into the nested ToolMessage content (`to_langchain_message_dicts`).\n result: resultText ? parseJsonLoose(resultText) : undefined,\n resultText,\n });\n }\n }\n return subcalls;\n}\n\n/** One completed PTC parent (`execute`, `eval`, or a studio executor) carrying recorded sub-calls. */\nexport interface CompletedPtcParent {\n toolCallId: string;\n /** The parent tool's name, one of `PTC_PARENT_TOOL_NAMES`. */\n toolName: string;\n /**\n * The executor source the call ran (`eval`'s `code` arg), read off the AI\n * message that requested it. The studio SDKs emit no cell-level sub-calls,\n * so the code string is the only carrier of the written spreadsheet cell.\n */\n code: string | undefined;\n /** Shape `computeStudioFollowTarget` expects: `{ artifact, result }`. */\n rawResult: { artifact: unknown; result: unknown };\n}\n\n/** Args of every tool call requested by the AI messages in one transcript, by call id. */\nfunction toolCallArgsById(\n messages: readonly LangChainMessage[]\n): Map<string, Record<string, unknown>> {\n const argsById = new Map<string, Record<string, unknown>>();\n for (const message of messages) {\n if (message.type !== 'ai' || !message.tool_calls) continue;\n for (const toolCall of message.tool_calls) {\n if (!toolCall.id) continue;\n argsById.set(toolCall.id, (toolCall.args as Record<string, unknown> | undefined) ?? {});\n }\n }\n return argsById;\n}\n\nfunction collectCompletedPtcParents(\n messages: readonly LangChainMessage[],\n completed: CompletedPtcParent[]\n): void {\n const argsById = toolCallArgsById(messages);\n for (const message of messages) {\n if (message.type !== 'tool' || !message.tool_call_id || !message.name) continue;\n const nested = nestedMessagesFromArtifact(message.artifact);\n if (nested.length === 0) continue;\n // A subagent's whole transcript is nested under its `task` ToolMessage, so\n // its own execute/eval calls (and their PTC sub-calls) only exist there.\n if (message.name === TASK_TOOL_NAME) {\n collectCompletedPtcParents(nested, completed);\n continue;\n }\n if (!PTC_PARENT_TOOL_NAMES.has(message.name)) continue;\n // The execution's sub-call log can reach its running placeholder before\n // the call returns: completed is the real ToolMessage that replaces it.\n if (isRunningToolPlaceholder(message)) continue;\n const code = argsById.get(message.tool_call_id)?.code;\n completed.push({\n toolCallId: message.tool_call_id,\n toolName: message.name,\n code: typeof code === 'string' ? code : undefined,\n rawResult: { artifact: message.artifact, result: message.content },\n });\n }\n}\n\n/**\n * Every completed `execute`/`eval` ToolMessage carrying recorded PTC\n * sub-calls, from the raw transport messages — including the ones a subagent\n * ran inside a `task` call's nested transcript. Drives the deep-agent's studio\n * follow-along (`DeepAgentPtcStudioFollowObserver`).\n */\nexport function extractCompletedPtcParents(\n messages: readonly LangChainMessage[]\n): CompletedPtcParent[] {\n const completed: CompletedPtcParent[] = [];\n collectCompletedPtcParents(messages, completed);\n return completed;\n}\n"],"names":[],"mappings":";;AAiCA,SAAS,eAAe,MAAuB;AAC7C,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,wBAAwB,UAAiC;AACvE,QAAM,SAAS,2BAA2B,QAAQ;AAClD,MAAI,OAAO,WAAW,EAAG,QAAO,CAAA;AAChC,QAAM,8BAAc,IAAA;AACpB,aAAW,KAAK,QAAQ;AACtB,QAAI,EAAE,SAAS,UAAU,EAAE,aAAc,SAAQ,IAAI,EAAE,cAAc,CAAC;AAAA,EACxE;AACA,QAAM,WAAyB,CAAA;AAC/B,aAAW,KAAK,QAAQ;AACtB,QAAI,EAAE,SAAS,QAAQ,CAAC,EAAE,WAAY;AACtC,eAAW,MAAM,EAAE,YAAY;AAC7B,UAAI,CAAC,GAAG,GAAI;AACZ,YAAM,SAAS,QAAQ,IAAI,GAAG,EAAE;AAChC,YAAM,aAAa,SAAS,eAAe,MAAM,IAAI;AACrD,eAAS,KAAK;AAAA,QACZ,IAAI,GAAG;AAAA,QACP,MAAM,GAAG;AAAA,QACT,MAAO,GAAG,QAAgD,CAAA;AAAA,QAC1D,QAAQ,SAAU,OAAO,WAAW,UAAU,UAAU,cAAe;AAAA;AAAA;AAAA,QAGvE,QAAQ,aAAa,eAAe,UAAU,IAAI;AAAA,QAClD;AAAA,MAAA,CACD;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;"}
|
|
@@ -43,7 +43,7 @@ function buildQueueEditCommand(options) {
|
|
|
43
43
|
parts: [{ type: "text", text }, ...item.parts.filter((part) => part.type !== "text")],
|
|
44
44
|
...metadata === void 0 ? {} : { metadata: { ...metadata } }
|
|
45
45
|
};
|
|
46
|
-
return
|
|
46
|
+
return { type: "run/send", runId, behavior: lane, message };
|
|
47
47
|
}
|
|
48
48
|
function nonEmpty(metadata) {
|
|
49
49
|
return metadata !== void 0 && Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
@@ -68,7 +68,7 @@ function describeQueueSendFailure(failure) {
|
|
|
68
68
|
return `${failure.fate} (${failure.cause})${message}`;
|
|
69
69
|
}
|
|
70
70
|
function isFailedSendEntryRace(error) {
|
|
71
|
-
return error instanceof Error && error.message.startsWith("statewire: unknown failed");
|
|
71
|
+
return error instanceof Error && (error.message.startsWith("statewire: unknown failed") || error.message.startsWith("outbox: no entry") || /^outbox: .* is in flight$/.test(error.message));
|
|
72
72
|
}
|
|
73
73
|
exports.QUEUE_AUTO_CONTINUE_DELAY_MS = QUEUE_AUTO_CONTINUE_DELAY_MS;
|
|
74
74
|
exports.buildQueueEditCommand = buildQueueEditCommand;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.cjs","sources":["../../../../agent-runtime/src/queue.ts"],"sourcesContent":["/**\n * Derivations for the server-owned statewire queue and steer lanes, shared by\n * every queued-messages tray (Olympus, the React SDK, the Chrome extension).\n *\n * The queue is SERVER-owned: statewire surfaces it on the runs projection.\n * \"Send now\" moves an item into the steer lane (`run/steer` — the host stops\n * the run and dispatches it once the run settles; on a stopped/errored thread\n * the same move dispatches immediately as a stop-/error-continue run) and\n * remove issues `run/dequeue`. While the thread rests stopped/errored,\n * stranded steer-lane entries list ahead of the queue — they dispatch first,\n * as one batch, so they carry Remove but no per-row Send now.\n *\n * Pure helpers only: the host component reads `useStatewireRuns()` and\n * `useDeepAgentThreadStatus()` itself (both mockable per surface) and passes\n * the values in.\n */\n\nimport type { StatewireThread } from '@assistant-ui/react-statewire';\nimport { DEEP_AGENT_COMPOSER_MARKDOWN_KEY } from './composer-markdown';\nimport { ATHENA_RUN_MARKER_CANCELLED, isServerUpdateStopSource } from './messages';\nimport type { DeepAgentThreadStatus } from './thread-status';\n\n/** The text content of a queued entry (non-text parts render as fallbacks). */\nexport function queueEntryText(\n parts: readonly { type: string; text?: string }[],\n): string {\n return parts\n .flatMap((part) =>\n part.type === 'text' && typeof part.text === 'string' ? [part.text] : [],\n )\n .join('\\n\\n');\n}\n\n/**\n * Whether a lane entry is still awaiting its send's settle: the host stamps\n * `meta` on every entry it admits (`_op_meta` — submitter and contextSync\n * snapshot), so a meta-less entry is this client's own optimistic fold. The\n * send is still in flight and can still be refused (billing gate, auth,\n * reconnect), which the tray must not render as an accepted queue position.\n */\nexport function isQueueEntryUnsettled(entry: StatewireThread.RunsQueueEntry): boolean {\n return entry.meta === undefined;\n}\n\n/**\n * The ids of queued entries the user prioritized (⚡ — `run/prioritize`), as\n * the host records them in its durable `prioritizedQueueIds` state. A\n * prioritized entry heads the queue lane and the live run ends at its next\n * model-call boundary to deliver it, so trays render these rows lit and offer\n * \"Remove priority\" instead of \"Prioritize\". Tolerates the key being absent\n * (a thread that never prioritized, a pre-feature host) and ignores anything\n * that is not a string id.\n */\nexport function readPrioritizedQueueIds(raw: unknown): readonly string[] {\n return Array.isArray(raw)\n ? raw.filter((id): id is string => typeof id === 'string')\n : [];\n}\n\nexport interface QueueLaneFlags {\n isRunning: boolean;\n /** A stopped/errored thread can continue with its queued work. */\n isContinuable: boolean;\n}\n\n/** The thread-status split every queue tray keys its affordances on. */\nexport function queueLaneFlags(status: DeepAgentThreadStatus): QueueLaneFlags {\n return {\n isRunning: status === 'running',\n isContinuable: status === 'stopped' || status === 'error',\n };\n}\n\nexport interface StatewireQueueRow {\n item: StatewireThread.RunsQueueEntry;\n lane: 'queue' | 'steer';\n}\n\n/**\n * The rows a queue tray renders, in dispatch order: stranded steer-lane\n * entries first (only while the thread rests continuable — during a run they\n * already render in the message list), then the queue lane.\n */\nexport function buildStatewireQueueRows(options: {\n queue: readonly StatewireThread.RunsQueueEntry[];\n steerQueue: readonly StatewireThread.RunsQueueEntry[];\n isContinuable: boolean;\n}): StatewireQueueRow[] {\n const { queue, steerQueue, isContinuable } = options;\n return [\n ...(isContinuable\n ? steerQueue.map((item) => ({ item, lane: 'steer' as const }))\n : []),\n ...queue.map((item) => ({ item, lane: 'queue' as const })),\n ];\n}\n\n/**\n * Whether a row offers \"Send now\": queue-lane rows only (steer entries already\n * dispatch first), every row while the thread rests continuable, and only the\n * head row while a run is live (later rows would jump the queue order).\n */\nexport function showQueueRowSendNow(options: {\n lane: 'queue' | 'steer';\n index: number;\n isRunning: boolean;\n isContinuable: boolean;\n}): boolean {\n const { lane, index, isRunning, isContinuable } = options;\n return lane === 'queue' && (isContinuable || (isRunning && index === 0));\n}\n\n/**\n * Whether a row offers \"Steer\" (`run/steer-live`): queue-lane rows while a run\n * is live. Steer folds the entry into the RUNNING turn at its next model call\n * — after the in-flight tool chain, never mid-tool — and the run goes on with\n * it in context (ChatGPT's and Codex's Steer, versus Queue). Nothing is\n * cancelled and no second run starts, so every queued row qualifies, not just\n * the head. At rest there is no turn to steer: Send now already dispatches.\n */\nexport function showQueueRowSteer(options: {\n lane: 'queue' | 'steer';\n isRunning: boolean;\n}): boolean {\n return options.lane === 'queue' && options.isRunning;\n}\n\nexport type QueueEditCommand =\n | { type: 'run/steer'; runId: string; message: StatewireThread.UserMessage }\n | { type: 'run/enqueue'; runId: string; message: StatewireThread.UserMessage };\n\n/**\n * Re-send a queued entry under its own id on its own lane with edited text:\n * the host replaces the queued message's content in place, leaving its queue\n * position and lane untouched (a same-id send never dispatches). The built-in\n * queue client has no update command, so this goes straight to the runs\n * protocol. Returns `null` when there is nothing to send — blank or unchanged\n * text, or no live run entry to address.\n */\nexport function buildQueueEditCommand(options: {\n item: StatewireThread.RunsQueueEntry;\n lane: 'queue' | 'steer';\n runId: string | null;\n text: string;\n /**\n * The edited message's metadata, replacing the entry's (the host replaces\n * the queued message whole). Omitted, the entry's metadata is kept, minus a\n * composer markdown that described the old text.\n */\n metadata?: Readonly<Record<string, unknown>> | undefined;\n}): QueueEditCommand | null {\n const { item, lane, runId, text } = options;\n const textChanged: boolean = text !== queueEntryText(item.parts);\n const previous: Readonly<Record<string, unknown>> | undefined = nonEmpty(item.metadata);\n const next: Readonly<Record<string, unknown>> | undefined = nonEmpty(\n options.metadata !== undefined\n ? options.metadata\n : textChanged\n ? withoutComposerMarkdown(item.metadata)\n : item.metadata,\n );\n if (\n !text.trim() ||\n runId === null ||\n (!textChanged && stableJson(next ?? null) === stableJson(previous ?? null))\n ) {\n return null;\n }\n // An entry that had metadata and keeps none sends an empty object: the\n // optimistic lane keeps an entry's metadata when the command carries none,\n // and would go on showing the old composer markdown until the host answers.\n const metadata: Readonly<Record<string, unknown>> | undefined =\n next ?? (previous === undefined ? undefined : {});\n const message: StatewireThread.UserMessage = {\n id: item.id,\n role: 'user',\n parts: [{ type: 'text', text }, ...item.parts.filter((part) => part.type !== 'text')],\n ...(metadata === undefined ? {} : { metadata: { ...metadata } }),\n };\n return lane === 'steer'\n ? { type: 'run/steer', runId, message }\n : { type: 'run/enqueue', runId, message };\n}\n\n/** `metadata` unless it is empty. */\nfunction nonEmpty(\n metadata: Readonly<Record<string, unknown>> | undefined,\n): Readonly<Record<string, unknown>> | undefined {\n return metadata !== undefined && Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\n/** JSON with object keys sorted, so equal metadata compares equal whatever its key order. */\nfunction stableJson(value: unknown): string {\n const sorted = (entry: unknown): unknown =>\n Array.isArray(entry)\n ? entry.map(sorted)\n : typeof entry === 'object' && entry !== null\n ? Object.fromEntries(\n Object.keys(entry)\n .sort()\n .map((key) => [key, sorted((entry as Record<string, unknown>)[key])]),\n )\n : entry;\n return JSON.stringify(sorted(value));\n}\n\n/** Entry metadata without a composer markdown, `undefined` when nothing is left. */\nfunction withoutComposerMarkdown(\n metadata: Readonly<Record<string, unknown>> | undefined,\n): Readonly<Record<string, unknown>> | undefined {\n if (metadata === undefined || !(DEEP_AGENT_COMPOSER_MARKDOWN_KEY in metadata)) return metadata;\n const { [DEEP_AGENT_COMPOSER_MARKDOWN_KEY]: _stale, ...rest } = metadata;\n return Object.keys(rest).length > 0 ? rest : undefined;\n}\n\n/**\n * Grace between observing a stranded settle and auto-promoting the queue\n * head — long enough for the host's own settle bookkeeping (or a status flap\n * during reconnect) to resolve first, short enough to read as \"it just\n * continued\" rather than \"it hung\".\n */\nexport const QUEUE_AUTO_CONTINUE_DELAY_MS = 2_000;\n\n/** Whether the last cancellation marker records a user or client stop. */\nexport function userStopBlocksQueueAutoContinue(options: {\n marker: string | undefined;\n source: string | undefined;\n}): boolean {\n return (\n options.marker === ATHENA_RUN_MARKER_CANCELLED && !isServerUpdateStopSource(options.source)\n );\n}\n\n/** `fate (cause)[: message]` — the detail a failed-send row carries. */\nexport function describeQueueSendFailure(\n failure: StatewireThread.RunsFailedEntry['sendFailure'],\n): string {\n const message =\n 'message' in failure && failure.message !== undefined ? `: ${failure.message}` : '';\n return `${failure.fate} (${failure.cause})${message}`;\n}\n\n/**\n * Whether a `retryFailed` / `discardFailed` throw is the covered drop race:\n * statewire drops a failed entry on its own as soon as a canonical update\n * shows the message landed, and acting on a just-dropped entry throws. Both\n * the session record (\"unknown failed command\") and the adapter's projection\n * (\"unknown failed entry\") use this prefix. Nothing is lost in that race — the\n * message already made it and the row is about to disappear — so a tray\n * swallows it (keeping telemetry) instead of crashing the click handler.\n */\nexport function isFailedSendEntryRace(error: unknown): boolean {\n return error instanceof Error && error.message.startsWith('statewire: unknown failed');\n}\n"],"names":["DEEP_AGENT_COMPOSER_MARKDOWN_KEY","ATHENA_RUN_MARKER_CANCELLED","isServerUpdateStopSource"],"mappings":";;;;AAuBO,SAAS,eACd,OACQ;AACR,SAAO,MACJ;AAAA,IAAQ,CAAC,SACR,KAAK,SAAS,UAAU,OAAO,KAAK,SAAS,WAAW,CAAC,KAAK,IAAI,IAAI,CAAA;AAAA,EAAC,EAExE,KAAK,MAAM;AAChB;AASO,SAAS,sBAAsB,OAAgD;AACpF,SAAO,MAAM,SAAS;AACxB;AAwBO,SAAS,eAAe,QAA+C;AAC5E,SAAO;AAAA,IACL,WAAW,WAAW;AAAA,IACtB,eAAe,WAAW,aAAa,WAAW;AAAA,EAAA;AAEtD;AAYO,SAAS,wBAAwB,SAIhB;AACtB,QAAM,EAAE,OAAO,YAAY,cAAA,IAAkB;AAC7C,SAAO;AAAA,IACL,GAAI,gBACA,WAAW,IAAI,CAAC,UAAU,EAAE,MAAM,MAAM,UAAmB,IAC3D,CAAA;AAAA,IACJ,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,MAAM,MAAM,UAAmB;AAAA,EAAA;AAE7D;AAyBO,SAAS,kBAAkB,SAGtB;AACV,SAAO,QAAQ,SAAS,WAAW,QAAQ;AAC7C;AAcO,SAAS,sBAAsB,SAWV;AAC1B,QAAM,EAAE,MAAM,MAAM,OAAO,SAAS;AACpC,QAAM,cAAuB,SAAS,eAAe,KAAK,KAAK;AAC/D,QAAM,WAA0D,SAAS,KAAK,QAAQ;AACtF,QAAM,OAAsD;AAAA,IAC1D,QAAQ,aAAa,SACjB,QAAQ,WACR,cACE,wBAAwB,KAAK,QAAQ,IACrC,KAAK;AAAA,EAAA;AAEb,MACE,CAAC,KAAK,KAAA,KACN,UAAU,QACT,CAAC,eAAe,WAAW,QAAQ,IAAI,MAAM,WAAW,YAAY,IAAI,GACzE;AACA,WAAO;AAAA,EACT;AAIA,QAAM,WACJ,SAAS,aAAa,SAAY,SAAY,CAAA;AAChD,QAAM,UAAuC;AAAA,IAC3C,IAAI,KAAK;AAAA,IACT,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,QAAQ,QAAQ,GAAG,KAAK,MAAM,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,CAAC;AAAA,IACpF,GAAI,aAAa,SAAY,CAAA,IAAK,EAAE,UAAU,EAAE,GAAG,SAAA,EAAS;AAAA,EAAE;AAEhE,SAAO,SAAS,UACZ,EAAE,MAAM,aAAa,OAAO,QAAA,IAC5B,EAAE,MAAM,eAAe,OAAO,QAAA;AACpC;AAGA,SAAS,SACP,UAC+C;AAC/C,SAAO,aAAa,UAAa,OAAO,KAAK,QAAQ,EAAE,SAAS,IAAI,WAAW;AACjF;AAGA,SAAS,WAAW,OAAwB;AAC1C,QAAM,SAAS,CAAC,UACd,MAAM,QAAQ,KAAK,IACf,MAAM,IAAI,MAAM,IAChB,OAAO,UAAU,YAAY,UAAU,OACrC,OAAO;AAAA,IACL,OAAO,KAAK,KAAK,EACd,KAAA,EACA,IAAI,CAAC,QAAQ,CAAC,KAAK,OAAQ,MAAkC,GAAG,CAAC,CAAC,CAAC;AAAA,EAAA,IAExE;AACR,SAAO,KAAK,UAAU,OAAO,KAAK,CAAC;AACrC;AAGA,SAAS,wBACP,UAC+C;AAC/C,MAAI,aAAa,UAAa,EAAEA,iBAAAA,oCAAoC,UAAW,QAAO;AACtF,QAAM,EAAE,CAACA,iBAAAA,gCAAgC,GAAG,QAAQ,GAAG,SAAS;AAChE,SAAO,OAAO,KAAK,IAAI,EAAE,SAAS,IAAI,OAAO;AAC/C;AAQO,MAAM,+BAA+B;AAGrC,SAAS,gCAAgC,SAGpC;AACV,SACE,QAAQ,WAAWC,SAAAA,+BAA+B,CAACC,SAAAA,yBAAyB,QAAQ,MAAM;AAE9F;AAGO,SAAS,yBACd,SACQ;AACR,QAAM,UACJ,aAAa,WAAW,QAAQ,YAAY,SAAY,KAAK,QAAQ,OAAO,KAAK;AACnF,SAAO,GAAG,QAAQ,IAAI,KAAK,QAAQ,KAAK,IAAI,OAAO;AACrD;AAWO,SAAS,sBAAsB,OAAyB;AAC7D,SAAO,iBAAiB,SAAS,MAAM,QAAQ,WAAW,2BAA2B;AACvF;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"queue.cjs","sources":["../../../../agent-runtime/src/queue.ts"],"sourcesContent":["/**\n * Derivations for the server-owned statewire queue and steer lanes, shared by\n * every queued-messages tray (Olympus, the React SDK, the Chrome extension).\n *\n * The queue is SERVER-owned: statewire surfaces it on the runs projection.\n * \"Send now\" moves an item into the steer lane and stops the live run\n * (`run/send` `preempt` — the run settles and the steer lane dispatches next;\n * on a stopped/errored thread the same move dispatches immediately as a\n * stop-/error-continue run) and remove issues `run/dequeue`. While the thread rests stopped/errored,\n * stranded steer-lane entries list ahead of the queue — they dispatch first,\n * as one batch, so they carry Remove but no per-row Send now.\n *\n * Pure helpers only: the host component reads `useStatewireRuns()` and\n * `useDeepAgentThreadStatus()` itself (both mockable per surface) and passes\n * the values in.\n */\n\nimport type { StatewireThread } from '@assistant-ui/react-statewire';\nimport type { StatewireClient } from 'statewire';\nimport { DEEP_AGENT_COMPOSER_MARKDOWN_KEY } from './composer-markdown';\nimport { ATHENA_RUN_MARKER_CANCELLED, isServerUpdateStopSource } from './messages';\nimport type { DeepAgentThreadStatus } from './thread-status';\n\n/** The text content of a queued entry (non-text parts render as fallbacks). */\nexport function queueEntryText(\n parts: readonly { type: string; text?: string }[],\n): string {\n return parts\n .flatMap((part) =>\n part.type === 'text' && typeof part.text === 'string' ? [part.text] : [],\n )\n .join('\\n\\n');\n}\n\n/**\n * Whether a lane entry is still awaiting its send's settle: the host stamps\n * `meta` on every entry it admits (`_op_meta` — submitter and contextSync\n * snapshot), so a meta-less entry is this client's own optimistic fold. The\n * send is still in flight and can still be refused (billing gate, auth,\n * reconnect), which the tray must not render as an accepted queue position.\n */\nexport function isQueueEntryUnsettled(entry: StatewireThread.RunsQueueEntry): boolean {\n return entry.meta === undefined;\n}\n\n/**\n * The ids of queued entries a backend delivery prioritized, as the host\n * records them in its durable `prioritizedQueueIds` state. A prioritized entry\n * heads the queue lane and the live run ends at its next model-call boundary\n * to deliver it, so trays render these rows lit. Tolerates the key being\n * absent and ignores anything that is not a string id.\n */\nexport function readPrioritizedQueueIds(raw: unknown): readonly string[] {\n return Array.isArray(raw)\n ? raw.filter((id): id is string => typeof id === 'string')\n : [];\n}\n\nexport interface QueueLaneFlags {\n isRunning: boolean;\n /** A stopped/errored thread can continue with its queued work. */\n isContinuable: boolean;\n}\n\n/** The thread-status split every queue tray keys its affordances on. */\nexport function queueLaneFlags(status: DeepAgentThreadStatus): QueueLaneFlags {\n return {\n isRunning: status === 'running',\n isContinuable: status === 'stopped' || status === 'error',\n };\n}\n\nexport interface StatewireQueueRow {\n item: StatewireThread.RunsQueueEntry;\n lane: 'queue' | 'steer';\n}\n\n/**\n * The rows a queue tray renders, in dispatch order: stranded steer-lane\n * entries first (only while the thread rests continuable — during a run they\n * already render in the message list), then the queue lane.\n */\nexport function buildStatewireQueueRows(options: {\n queue: readonly StatewireThread.RunsQueueEntry[];\n steerQueue: readonly StatewireThread.RunsQueueEntry[];\n isContinuable: boolean;\n}): StatewireQueueRow[] {\n const { queue, steerQueue, isContinuable } = options;\n return [\n ...(isContinuable\n ? steerQueue.map((item) => ({ item, lane: 'steer' as const }))\n : []),\n ...queue.map((item) => ({ item, lane: 'queue' as const })),\n ];\n}\n\n/**\n * Whether a row offers \"Send now\": queue-lane rows only (steer entries already\n * dispatch first), every row while the thread rests continuable, and only the\n * head row while a run is live (later rows would jump the queue order).\n */\nexport function showQueueRowSendNow(options: {\n lane: 'queue' | 'steer';\n index: number;\n isRunning: boolean;\n isContinuable: boolean;\n}): boolean {\n const { lane, index, isRunning, isContinuable } = options;\n return lane === 'queue' && (isContinuable || (isRunning && index === 0));\n}\n\n/**\n * Whether a row offers \"Steer\" (`run/send` `steer`): queue-lane rows while a\n * run is live. Steer folds the entry into the RUNNING turn at its next model call\n * — after the in-flight tool chain, never mid-tool — and the run goes on with\n * it in context (ChatGPT's and Codex's Steer, versus Queue). Nothing is\n * cancelled and no second run starts, so every queued row qualifies, not just\n * the head. At rest there is no turn to steer: Send now already dispatches.\n */\nexport function showQueueRowSteer(options: {\n lane: 'queue' | 'steer';\n isRunning: boolean;\n}): boolean {\n return options.lane === 'queue' && options.isRunning;\n}\n\nexport type QueueEditCommand = {\n type: 'run/send';\n runId: string;\n behavior: 'steer' | 'queue';\n message: StatewireThread.UserMessage;\n};\n\n/**\n * Re-send a queued entry under its own id on its own lane with edited text:\n * the host replaces the queued message's content in place, leaving its queue\n * position and lane untouched (a same-id send never dispatches). The built-in\n * queue client has no update command, so this goes straight to the runs\n * protocol. Returns `null` when there is nothing to send — blank or unchanged\n * text, or no live run entry to address.\n */\nexport function buildQueueEditCommand(options: {\n item: StatewireThread.RunsQueueEntry;\n lane: 'queue' | 'steer';\n runId: string | null;\n text: string;\n /**\n * The edited message's metadata, replacing the entry's (the host replaces\n * the queued message whole). Omitted, the entry's metadata is kept, minus a\n * composer markdown that described the old text.\n */\n metadata?: Readonly<Record<string, unknown>> | undefined;\n}): QueueEditCommand | null {\n const { item, lane, runId, text } = options;\n const textChanged: boolean = text !== queueEntryText(item.parts);\n const previous: Readonly<Record<string, unknown>> | undefined = nonEmpty(item.metadata);\n const next: Readonly<Record<string, unknown>> | undefined = nonEmpty(\n options.metadata !== undefined\n ? options.metadata\n : textChanged\n ? withoutComposerMarkdown(item.metadata)\n : item.metadata,\n );\n if (\n !text.trim() ||\n runId === null ||\n (!textChanged && stableJson(next ?? null) === stableJson(previous ?? null))\n ) {\n return null;\n }\n // An entry that had metadata and keeps none sends an empty object: the\n // optimistic lane keeps an entry's metadata when the command carries none,\n // and would go on showing the old composer markdown until the host answers.\n const metadata: Readonly<Record<string, unknown>> | undefined =\n next ?? (previous === undefined ? undefined : {});\n const message: StatewireThread.UserMessage = {\n id: item.id,\n role: 'user',\n parts: [{ type: 'text', text }, ...item.parts.filter((part) => part.type !== 'text')],\n ...(metadata === undefined ? {} : { metadata: { ...metadata } }),\n };\n return { type: 'run/send', runId, behavior: lane, message };\n}\n\n/** `metadata` unless it is empty. */\nfunction nonEmpty(\n metadata: Readonly<Record<string, unknown>> | undefined,\n): Readonly<Record<string, unknown>> | undefined {\n return metadata !== undefined && Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\n/** JSON with object keys sorted, so equal metadata compares equal whatever its key order. */\nfunction stableJson(value: unknown): string {\n const sorted = (entry: unknown): unknown =>\n Array.isArray(entry)\n ? entry.map(sorted)\n : typeof entry === 'object' && entry !== null\n ? Object.fromEntries(\n Object.keys(entry)\n .sort()\n .map((key) => [key, sorted((entry as Record<string, unknown>)[key])]),\n )\n : entry;\n return JSON.stringify(sorted(value));\n}\n\n/** Entry metadata without a composer markdown, `undefined` when nothing is left. */\nfunction withoutComposerMarkdown(\n metadata: Readonly<Record<string, unknown>> | undefined,\n): Readonly<Record<string, unknown>> | undefined {\n if (metadata === undefined || !(DEEP_AGENT_COMPOSER_MARKDOWN_KEY in metadata)) return metadata;\n const { [DEEP_AGENT_COMPOSER_MARKDOWN_KEY]: _stale, ...rest } = metadata;\n return Object.keys(rest).length > 0 ? rest : undefined;\n}\n\n/**\n * Grace between observing a stranded settle and auto-promoting the queue\n * head — long enough for the host's own settle bookkeeping (or a status flap\n * during reconnect) to resolve first, short enough to read as \"it just\n * continued\" rather than \"it hung\".\n */\nexport const QUEUE_AUTO_CONTINUE_DELAY_MS = 2_000;\n\n/** Whether the last cancellation marker records a user or client stop. */\nexport function userStopBlocksQueueAutoContinue(options: {\n marker: string | undefined;\n source: string | undefined;\n}): boolean {\n return (\n options.marker === ATHENA_RUN_MARKER_CANCELLED && !isServerUpdateStopSource(options.source)\n );\n}\n\n/** `fate (cause)[: message]` — the detail a failed-send row carries. */\nexport function describeQueueSendFailure(failure: StatewireClient.SendFailure): string {\n const message =\n 'message' in failure && failure.message !== undefined ? `: ${failure.message}` : '';\n return `${failure.fate} (${failure.cause})${message}`;\n}\n\n/**\n * Whether a `retryFailed` / `discardFailed` throw is the drop race: the held\n * failed send left the outbox (another tab retried or discarded it, or its\n * retry is already in flight) between the render and the click. The lookup\n * (\"unknown failed entry\") and the outbox verbs (\"outbox: no entry …\",\n * \"outbox: … is in flight\") report it. Nothing is lost in that race, so a tray\n * swallows it (keeping telemetry) instead of crashing the click handler.\n */\nexport function isFailedSendEntryRace(error: unknown): boolean {\n return (\n error instanceof Error &&\n (error.message.startsWith('statewire: unknown failed') ||\n error.message.startsWith('outbox: no entry') ||\n /^outbox: .* is in flight$/.test(error.message))\n );\n}\n"],"names":["DEEP_AGENT_COMPOSER_MARKDOWN_KEY","ATHENA_RUN_MARKER_CANCELLED","isServerUpdateStopSource"],"mappings":";;;;AAwBO,SAAS,eACd,OACQ;AACR,SAAO,MACJ;AAAA,IAAQ,CAAC,SACR,KAAK,SAAS,UAAU,OAAO,KAAK,SAAS,WAAW,CAAC,KAAK,IAAI,IAAI,CAAA;AAAA,EAAC,EAExE,KAAK,MAAM;AAChB;AASO,SAAS,sBAAsB,OAAgD;AACpF,SAAO,MAAM,SAAS;AACxB;AAsBO,SAAS,eAAe,QAA+C;AAC5E,SAAO;AAAA,IACL,WAAW,WAAW;AAAA,IACtB,eAAe,WAAW,aAAa,WAAW;AAAA,EAAA;AAEtD;AAYO,SAAS,wBAAwB,SAIhB;AACtB,QAAM,EAAE,OAAO,YAAY,cAAA,IAAkB;AAC7C,SAAO;AAAA,IACL,GAAI,gBACA,WAAW,IAAI,CAAC,UAAU,EAAE,MAAM,MAAM,UAAmB,IAC3D,CAAA;AAAA,IACJ,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,MAAM,MAAM,UAAmB;AAAA,EAAA;AAE7D;AAyBO,SAAS,kBAAkB,SAGtB;AACV,SAAO,QAAQ,SAAS,WAAW,QAAQ;AAC7C;AAiBO,SAAS,sBAAsB,SAWV;AAC1B,QAAM,EAAE,MAAM,MAAM,OAAO,SAAS;AACpC,QAAM,cAAuB,SAAS,eAAe,KAAK,KAAK;AAC/D,QAAM,WAA0D,SAAS,KAAK,QAAQ;AACtF,QAAM,OAAsD;AAAA,IAC1D,QAAQ,aAAa,SACjB,QAAQ,WACR,cACE,wBAAwB,KAAK,QAAQ,IACrC,KAAK;AAAA,EAAA;AAEb,MACE,CAAC,KAAK,KAAA,KACN,UAAU,QACT,CAAC,eAAe,WAAW,QAAQ,IAAI,MAAM,WAAW,YAAY,IAAI,GACzE;AACA,WAAO;AAAA,EACT;AAIA,QAAM,WACJ,SAAS,aAAa,SAAY,SAAY,CAAA;AAChD,QAAM,UAAuC;AAAA,IAC3C,IAAI,KAAK;AAAA,IACT,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,QAAQ,QAAQ,GAAG,KAAK,MAAM,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,CAAC;AAAA,IACpF,GAAI,aAAa,SAAY,CAAA,IAAK,EAAE,UAAU,EAAE,GAAG,SAAA,EAAS;AAAA,EAAE;AAEhE,SAAO,EAAE,MAAM,YAAY,OAAO,UAAU,MAAM,QAAA;AACpD;AAGA,SAAS,SACP,UAC+C;AAC/C,SAAO,aAAa,UAAa,OAAO,KAAK,QAAQ,EAAE,SAAS,IAAI,WAAW;AACjF;AAGA,SAAS,WAAW,OAAwB;AAC1C,QAAM,SAAS,CAAC,UACd,MAAM,QAAQ,KAAK,IACf,MAAM,IAAI,MAAM,IAChB,OAAO,UAAU,YAAY,UAAU,OACrC,OAAO;AAAA,IACL,OAAO,KAAK,KAAK,EACd,KAAA,EACA,IAAI,CAAC,QAAQ,CAAC,KAAK,OAAQ,MAAkC,GAAG,CAAC,CAAC,CAAC;AAAA,EAAA,IAExE;AACR,SAAO,KAAK,UAAU,OAAO,KAAK,CAAC;AACrC;AAGA,SAAS,wBACP,UAC+C;AAC/C,MAAI,aAAa,UAAa,EAAEA,iBAAAA,oCAAoC,UAAW,QAAO;AACtF,QAAM,EAAE,CAACA,iBAAAA,gCAAgC,GAAG,QAAQ,GAAG,SAAS;AAChE,SAAO,OAAO,KAAK,IAAI,EAAE,SAAS,IAAI,OAAO;AAC/C;AAQO,MAAM,+BAA+B;AAGrC,SAAS,gCAAgC,SAGpC;AACV,SACE,QAAQ,WAAWC,SAAAA,+BAA+B,CAACC,SAAAA,yBAAyB,QAAQ,MAAM;AAE9F;AAGO,SAAS,yBAAyB,SAA8C;AACrF,QAAM,UACJ,aAAa,WAAW,QAAQ,YAAY,SAAY,KAAK,QAAQ,OAAO,KAAK;AACnF,SAAO,GAAG,QAAQ,IAAI,KAAK,QAAQ,KAAK,IAAI,OAAO;AACrD;AAUO,SAAS,sBAAsB,OAAyB;AAC7D,SACE,iBAAiB,UAChB,MAAM,QAAQ,WAAW,2BAA2B,KACnD,MAAM,QAAQ,WAAW,kBAAkB,KAC3C,4BAA4B,KAAK,MAAM,OAAO;AAEpD;;;;;;;;;;;"}
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* every queued-messages tray (Olympus, the React SDK, the Chrome extension).
|
|
4
4
|
*
|
|
5
5
|
* The queue is SERVER-owned: statewire surfaces it on the runs projection.
|
|
6
|
-
* "Send now" moves an item into the steer lane
|
|
7
|
-
*
|
|
8
|
-
* the same move dispatches immediately as a
|
|
9
|
-
* remove issues `run/dequeue`. While the thread rests stopped/errored,
|
|
6
|
+
* "Send now" moves an item into the steer lane and stops the live run
|
|
7
|
+
* (`run/send` `preempt` — the run settles and the steer lane dispatches next;
|
|
8
|
+
* on a stopped/errored thread the same move dispatches immediately as a
|
|
9
|
+
* stop-/error-continue run) and remove issues `run/dequeue`. While the thread rests stopped/errored,
|
|
10
10
|
* stranded steer-lane entries list ahead of the queue — they dispatch first,
|
|
11
11
|
* as one batch, so they carry Remove but no per-row Send now.
|
|
12
12
|
*
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* the values in.
|
|
16
16
|
*/
|
|
17
17
|
import type { StatewireThread } from '@assistant-ui/react-statewire';
|
|
18
|
+
import type { StatewireClient } from 'statewire';
|
|
18
19
|
import type { DeepAgentThreadStatus } from './thread-status';
|
|
19
20
|
/** The text content of a queued entry (non-text parts render as fallbacks). */
|
|
20
21
|
export declare function queueEntryText(parts: readonly {
|
|
@@ -30,13 +31,11 @@ export declare function queueEntryText(parts: readonly {
|
|
|
30
31
|
*/
|
|
31
32
|
export declare function isQueueEntryUnsettled(entry: StatewireThread.RunsQueueEntry): boolean;
|
|
32
33
|
/**
|
|
33
|
-
* The ids of queued entries
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* (a thread that never prioritized, a pre-feature host) and ignores anything
|
|
39
|
-
* that is not a string id.
|
|
34
|
+
* The ids of queued entries a backend delivery prioritized, as the host
|
|
35
|
+
* records them in its durable `prioritizedQueueIds` state. A prioritized entry
|
|
36
|
+
* heads the queue lane and the live run ends at its next model-call boundary
|
|
37
|
+
* to deliver it, so trays render these rows lit. Tolerates the key being
|
|
38
|
+
* absent and ignores anything that is not a string id.
|
|
40
39
|
*/
|
|
41
40
|
export declare function readPrioritizedQueueIds(raw: unknown): readonly string[];
|
|
42
41
|
export interface QueueLaneFlags {
|
|
@@ -72,8 +71,8 @@ export declare function showQueueRowSendNow(options: {
|
|
|
72
71
|
isContinuable: boolean;
|
|
73
72
|
}): boolean;
|
|
74
73
|
/**
|
|
75
|
-
* Whether a row offers "Steer" (`run/steer
|
|
76
|
-
* is live. Steer folds the entry into the RUNNING turn at its next model call
|
|
74
|
+
* Whether a row offers "Steer" (`run/send` `steer`): queue-lane rows while a
|
|
75
|
+
* run is live. Steer folds the entry into the RUNNING turn at its next model call
|
|
77
76
|
* — after the in-flight tool chain, never mid-tool — and the run goes on with
|
|
78
77
|
* it in context (ChatGPT's and Codex's Steer, versus Queue). Nothing is
|
|
79
78
|
* cancelled and no second run starts, so every queued row qualifies, not just
|
|
@@ -84,12 +83,9 @@ export declare function showQueueRowSteer(options: {
|
|
|
84
83
|
isRunning: boolean;
|
|
85
84
|
}): boolean;
|
|
86
85
|
export type QueueEditCommand = {
|
|
87
|
-
type: 'run/
|
|
88
|
-
runId: string;
|
|
89
|
-
message: StatewireThread.UserMessage;
|
|
90
|
-
} | {
|
|
91
|
-
type: 'run/enqueue';
|
|
86
|
+
type: 'run/send';
|
|
92
87
|
runId: string;
|
|
88
|
+
behavior: 'steer' | 'queue';
|
|
93
89
|
message: StatewireThread.UserMessage;
|
|
94
90
|
};
|
|
95
91
|
/**
|
|
@@ -125,14 +121,13 @@ export declare function userStopBlocksQueueAutoContinue(options: {
|
|
|
125
121
|
source: string | undefined;
|
|
126
122
|
}): boolean;
|
|
127
123
|
/** `fate (cause)[: message]` — the detail a failed-send row carries. */
|
|
128
|
-
export declare function describeQueueSendFailure(failure:
|
|
124
|
+
export declare function describeQueueSendFailure(failure: StatewireClient.SendFailure): string;
|
|
129
125
|
/**
|
|
130
|
-
* Whether a `retryFailed` / `discardFailed` throw is the
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* message already made it and the row is about to disappear — so a tray
|
|
126
|
+
* Whether a `retryFailed` / `discardFailed` throw is the drop race: the held
|
|
127
|
+
* failed send left the outbox (another tab retried or discarded it, or its
|
|
128
|
+
* retry is already in flight) between the render and the click. The lookup
|
|
129
|
+
* ("unknown failed entry") and the outbox verbs ("outbox: no entry …",
|
|
130
|
+
* "outbox: … is in flight") report it. Nothing is lost in that race, so a tray
|
|
136
131
|
* swallows it (keeping telemetry) instead of crashing the click handler.
|
|
137
132
|
*/
|
|
138
133
|
export declare function isFailedSendEntryRace(error: unknown): boolean;
|
|
@@ -41,7 +41,7 @@ function buildQueueEditCommand(options) {
|
|
|
41
41
|
parts: [{ type: "text", text }, ...item.parts.filter((part) => part.type !== "text")],
|
|
42
42
|
...metadata === void 0 ? {} : { metadata: { ...metadata } }
|
|
43
43
|
};
|
|
44
|
-
return
|
|
44
|
+
return { type: "run/send", runId, behavior: lane, message };
|
|
45
45
|
}
|
|
46
46
|
function nonEmpty(metadata) {
|
|
47
47
|
return metadata !== void 0 && Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
@@ -66,7 +66,7 @@ function describeQueueSendFailure(failure) {
|
|
|
66
66
|
return `${failure.fate} (${failure.cause})${message}`;
|
|
67
67
|
}
|
|
68
68
|
function isFailedSendEntryRace(error) {
|
|
69
|
-
return error instanceof Error && error.message.startsWith("statewire: unknown failed");
|
|
69
|
+
return error instanceof Error && (error.message.startsWith("statewire: unknown failed") || error.message.startsWith("outbox: no entry") || /^outbox: .* is in flight$/.test(error.message));
|
|
70
70
|
}
|
|
71
71
|
export {
|
|
72
72
|
QUEUE_AUTO_CONTINUE_DELAY_MS,
|