@athenaintel/react 0.41.2 → 0.42.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -9
- package/dist/agent-runtime/src/asset-attachment.d.ts +98 -0
- package/dist/agent-runtime/src/athena-asset-drag.d.ts +32 -0
- package/dist/agent-runtime/src/auth-denial.d.ts +29 -0
- package/dist/agent-runtime/src/chat-outbox-attachments.cjs +41 -0
- package/dist/agent-runtime/src/chat-outbox-attachments.cjs.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-attachments.d.ts +38 -0
- package/dist/agent-runtime/src/chat-outbox-attachments.js +41 -0
- package/dist/agent-runtime/src/chat-outbox-attachments.js.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-signals.cjs +63 -0
- package/dist/agent-runtime/src/chat-outbox-signals.cjs.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-signals.d.ts +12 -0
- package/dist/agent-runtime/src/chat-outbox-signals.js +63 -0
- package/dist/agent-runtime/src/chat-outbox-signals.js.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-store.cjs +509 -0
- package/dist/agent-runtime/src/chat-outbox-store.cjs.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-store.d.ts +203 -0
- package/dist/agent-runtime/src/chat-outbox-store.js +509 -0
- package/dist/agent-runtime/src/chat-outbox-store.js.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-thread.cjs +136 -0
- package/dist/agent-runtime/src/chat-outbox-thread.cjs.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-thread.d.ts +118 -0
- package/dist/agent-runtime/src/chat-outbox-thread.js +136 -0
- package/dist/agent-runtime/src/chat-outbox-thread.js.map +1 -0
- package/dist/agent-runtime/src/chat-outbox.cjs +696 -0
- package/dist/agent-runtime/src/chat-outbox.cjs.map +1 -0
- package/dist/agent-runtime/src/chat-outbox.d.ts +285 -0
- package/dist/agent-runtime/src/chat-outbox.js +696 -0
- package/dist/agent-runtime/src/chat-outbox.js.map +1 -0
- package/dist/agent-runtime/src/chat-socket-reachability.d.ts +45 -0
- package/dist/agent-runtime/src/client-tool-bridge.d.ts +152 -0
- package/dist/agent-runtime/src/client-tools.d.ts +133 -0
- package/dist/agent-runtime/src/composer-markdown.cjs +10 -0
- package/dist/agent-runtime/src/composer-markdown.cjs.map +1 -1
- package/dist/agent-runtime/src/composer-markdown.d.ts +108 -0
- package/dist/agent-runtime/src/composer-markdown.js +10 -0
- package/dist/agent-runtime/src/composer-markdown.js.map +1 -1
- package/dist/agent-runtime/src/config-mutations.d.ts +51 -0
- package/dist/agent-runtime/src/conversation-index.d.ts +110 -0
- package/dist/agent-runtime/src/conversation-list.d.ts +343 -0
- package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs +3 -2
- package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
- package/dist/agent-runtime/src/deep-agent-transport-recipe.d.ts +166 -0
- package/dist/agent-runtime/src/deep-agent-transport-recipe.js +3 -2
- package/dist/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
- package/dist/agent-runtime/src/desktop-handoff.d.ts +139 -0
- package/dist/agent-runtime/src/durable-thread-snapshot-cache.cjs +158 -0
- package/dist/agent-runtime/src/durable-thread-snapshot-cache.cjs.map +1 -0
- package/dist/agent-runtime/src/durable-thread-snapshot-cache.d.ts +60 -0
- package/dist/agent-runtime/src/durable-thread-snapshot-cache.js +158 -0
- package/dist/agent-runtime/src/durable-thread-snapshot-cache.js.map +1 -0
- package/dist/agent-runtime/src/edit-command.d.ts +156 -0
- package/dist/agent-runtime/src/errors.d.ts +174 -0
- package/dist/agent-runtime/src/execute-output.d.ts +31 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs +16 -2
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +202 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.js +16 -2
- package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/agent-runtime/src/github-wake-event.d.ts +77 -0
- package/dist/agent-runtime/src/index.d.ts +74 -0
- package/dist/agent-runtime/src/interrupts.cjs +17 -0
- package/dist/agent-runtime/src/interrupts.cjs.map +1 -1
- package/dist/agent-runtime/src/interrupts.d.ts +348 -0
- package/dist/agent-runtime/src/interrupts.js +17 -0
- package/dist/agent-runtime/src/interrupts.js.map +1 -1
- package/dist/agent-runtime/src/lane-follow.d.ts +121 -0
- package/dist/agent-runtime/src/lane-history.cjs +209 -0
- package/dist/agent-runtime/src/lane-history.cjs.map +1 -0
- package/dist/agent-runtime/src/lane-history.d.ts +175 -0
- package/dist/agent-runtime/src/lane-history.js +209 -0
- package/dist/agent-runtime/src/lane-history.js.map +1 -0
- package/dist/agent-runtime/src/lane-images.d.ts +184 -0
- package/dist/agent-runtime/src/message-author.d.ts +43 -0
- package/dist/agent-runtime/src/message-text.cjs +15 -0
- package/dist/agent-runtime/src/message-text.cjs.map +1 -0
- package/dist/agent-runtime/src/message-text.d.ts +47 -0
- package/dist/agent-runtime/src/message-text.js +15 -0
- package/dist/agent-runtime/src/message-text.js.map +1 -0
- package/dist/agent-runtime/src/message-window.cjs +15 -1
- package/dist/agent-runtime/src/message-window.cjs.map +1 -1
- package/dist/agent-runtime/src/message-window.d.ts +159 -0
- package/dist/agent-runtime/src/message-window.js +16 -2
- package/dist/agent-runtime/src/message-window.js.map +1 -1
- package/dist/agent-runtime/src/messages.cjs +88 -4
- package/dist/agent-runtime/src/messages.cjs.map +1 -1
- package/dist/agent-runtime/src/messages.d.ts +603 -0
- package/dist/agent-runtime/src/messages.js +88 -4
- package/dist/agent-runtime/src/messages.js.map +1 -1
- package/dist/agent-runtime/src/model-context.d.ts +22 -0
- package/dist/agent-runtime/src/offline-status.d.ts +157 -0
- package/dist/agent-runtime/src/optimistic-content.d.ts +21 -0
- package/dist/agent-runtime/src/protocol.cjs +12 -4
- package/dist/agent-runtime/src/protocol.cjs.map +1 -1
- package/dist/agent-runtime/src/protocol.d.ts +119 -0
- package/dist/agent-runtime/src/protocol.js +13 -5
- package/dist/agent-runtime/src/protocol.js.map +1 -1
- package/dist/agent-runtime/src/ptc-subcalls.d.ts +51 -0
- package/dist/agent-runtime/src/queue.d.ts +138 -0
- package/dist/agent-runtime/src/quota-safe-local-storage-session.d.ts +154 -0
- package/dist/agent-runtime/src/running-tool-placeholder.cjs +11 -0
- package/dist/agent-runtime/src/running-tool-placeholder.cjs.map +1 -0
- package/dist/agent-runtime/src/running-tool-placeholder.d.ts +25 -0
- package/dist/agent-runtime/src/running-tool-placeholder.js +11 -0
- package/dist/agent-runtime/src/running-tool-placeholder.js.map +1 -0
- package/dist/agent-runtime/src/runtime-messages.d.ts +104 -0
- package/dist/agent-runtime/src/screen-point.d.ts +151 -0
- package/dist/agent-runtime/src/sealed-idb.cjs +112 -0
- package/dist/agent-runtime/src/sealed-idb.cjs.map +1 -0
- package/dist/agent-runtime/src/sealed-idb.d.ts +106 -0
- package/dist/agent-runtime/src/sealed-idb.js +112 -0
- package/dist/agent-runtime/src/sealed-idb.js.map +1 -0
- package/dist/agent-runtime/src/send-recovery.d.ts +40 -0
- package/dist/agent-runtime/src/statewire-attach-observer.d.ts +194 -0
- package/dist/agent-runtime/src/statewire-diagnostics.d.ts +74 -0
- package/dist/agent-runtime/src/statewire-state.d.ts +29 -0
- package/dist/agent-runtime/src/statewire-suspended.cjs.map +1 -1
- package/dist/agent-runtime/src/statewire-suspended.d.ts +27 -0
- package/dist/agent-runtime/src/statewire-suspended.js.map +1 -1
- package/dist/agent-runtime/src/statewire-transport.d.ts +40 -0
- package/dist/agent-runtime/src/streaming-markdown.d.ts +46 -0
- package/dist/agent-runtime/src/subagent-transcripts.cjs +209 -0
- package/dist/agent-runtime/src/subagent-transcripts.cjs.map +1 -0
- package/dist/agent-runtime/src/subagent-transcripts.d.ts +71 -0
- package/dist/agent-runtime/src/subagent-transcripts.js +209 -0
- package/dist/agent-runtime/src/subagent-transcripts.js.map +1 -0
- package/dist/agent-runtime/src/subagents.cjs +253 -0
- package/dist/agent-runtime/src/subagents.cjs.map +1 -0
- package/dist/agent-runtime/src/subagents.d.ts +311 -0
- package/dist/agent-runtime/src/subagents.js +253 -0
- package/dist/agent-runtime/src/subagents.js.map +1 -0
- package/dist/agent-runtime/src/subscription-wake-event.d.ts +111 -0
- package/dist/agent-runtime/src/thread-extras.d.ts +43 -0
- package/dist/agent-runtime/src/thread-handoff.d.ts +364 -0
- package/dist/agent-runtime/src/thread-prewarm-controller.d.ts +76 -0
- package/dist/agent-runtime/src/thread-prewarm.d.ts +118 -0
- package/dist/agent-runtime/src/thread-snapshot-cache.d.ts +99 -0
- package/dist/agent-runtime/src/thread-snapshot-mirror.cjs +329 -0
- package/dist/agent-runtime/src/thread-snapshot-mirror.cjs.map +1 -0
- package/dist/agent-runtime/src/thread-snapshot-mirror.d.ts +101 -0
- package/dist/agent-runtime/src/thread-snapshot-mirror.js +329 -0
- package/dist/agent-runtime/src/thread-snapshot-mirror.js.map +1 -0
- package/dist/agent-runtime/src/thread-status.d.ts +53 -0
- package/dist/agent-runtime/src/tool-metadata.d.ts +146 -0
- package/dist/agent-runtime/src/tool-names.cjs +67 -0
- package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-names.d.ts +60 -0
- package/dist/agent-runtime/src/tool-names.js +68 -1
- package/dist/agent-runtime/src/tool-names.js.map +1 -1
- package/dist/agent-runtime/src/tool-outputs.d.ts +35 -0
- package/dist/agent-runtime/src/tool-result.cjs +1 -0
- package/dist/agent-runtime/src/tool-result.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-result.d.ts +126 -0
- package/dist/agent-runtime/src/tool-result.js +1 -0
- package/dist/agent-runtime/src/tool-result.js.map +1 -1
- package/dist/agent-runtime/src/types.d.ts +159 -0
- package/dist/agent-runtime/src/use-conversation-list.d.ts +76 -0
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs +136 -0
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs.map +1 -0
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.d.ts +64 -0
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js +136 -0
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js.map +1 -0
- package/dist/agent-runtime/src/use-deep-agent-config.d.ts +169 -0
- package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs +13 -0
- package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-edit-submit.d.ts +22 -0
- package/dist/agent-runtime/src/use-deep-agent-edit-submit.js +13 -0
- package/dist/agent-runtime/src/use-deep-agent-edit-submit.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +20 -2
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +168 -0
- package/dist/agent-runtime/src/use-deep-agent-runtime.js +20 -2
- package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs +12 -4
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.d.ts +320 -0
- package/dist/agent-runtime/src/use-deep-agent-thread.js +12 -4
- package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs +999 -0
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -0
- package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +409 -0
- package/dist/agent-runtime/src/use-deep-agent-voice.js +999 -0
- package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -0
- package/dist/agent-runtime/src/use-deep-agent-window-sync.d.ts +102 -0
- package/dist/agent-runtime/src/use-historical-edit-attachments.d.ts +2 -0
- package/dist/agent-runtime/src/use-thread-handoff-flow.d.ts +84 -0
- package/dist/agent-runtime/src/voice-presentation.d.ts +80 -0
- package/dist/agent-runtime/src/voice-turn-grouping.d.ts +28 -0
- package/dist/agent-runtime/src/voice-wire-types.d.ts +15 -0
- package/dist/agent-runtime/src/withdrawn-turns.d.ts +97 -0
- package/dist/chat/AthenaChat.cjs +77 -6
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.js +78 -7
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/StatewireApprovalCard.d.ts +1 -1
- package/dist/chat/StatewireClientToolBridge.d.ts +1 -1
- package/dist/chat/StatewireQueuedMessages.cjs +11 -4
- package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
- package/dist/chat/StatewireQueuedMessages.d.ts +1 -1
- package/dist/chat/StatewireQueuedMessages.js +11 -4
- package/dist/chat/StatewireQueuedMessages.js.map +1 -1
- package/dist/chat/chat-outbox-rows.cjs +223 -0
- package/dist/chat/chat-outbox-rows.cjs.map +1 -0
- package/dist/chat/chat-outbox-rows.d.ts +29 -0
- package/dist/chat/chat-outbox-rows.js +223 -0
- package/dist/chat/chat-outbox-rows.js.map +1 -0
- package/dist/chat/statewire-approval.d.ts +1 -1
- package/dist/chat/statewire-client-tools.d.ts +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.cjs +3 -1
- package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.d.ts +7 -1
- package/dist/chat/super-grouping/SuperGroupingCard.js +3 -1
- package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs +7 -2
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.d.ts +2 -2
- package/dist/chat/super-grouping/SuperGroupingTranscript.js +7 -2
- package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.cjs +19 -11
- package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.d.ts +25 -9
- package/dist/chat/super-grouping/activity-timeline.js +19 -11
- package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
- package/dist/chat/use-statewire-approval-request.cjs +36 -0
- package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
- package/dist/chat/use-statewire-approval-request.d.ts +49 -1
- package/dist/chat/use-statewire-approval-request.js +39 -3
- package/dist/chat/use-statewire-approval-request.js.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.cjs +102 -3
- package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.d.ts +32 -1
- package/dist/chat-ui/composer/tiptap-composer.js +103 -4
- package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
- package/dist/chat-ui/header/conversation-history-panel.d.ts +1 -1
- package/dist/chat-ui/index.d.ts +1 -1
- package/dist/chat-ui/messages/message-components.cjs +15 -0
- package/dist/chat-ui/messages/message-components.cjs.map +1 -1
- package/dist/chat-ui/messages/message-components.js +15 -0
- package/dist/chat-ui/messages/message-components.js.map +1 -1
- package/dist/chat-ui/messages/runtime-message.d.ts +1 -1
- package/dist/chat-ui/messages/statewire-continue-run.d.ts +1 -1
- package/dist/chat-ui/messages/user-edit-composer.cjs +15 -2
- package/dist/chat-ui/messages/user-edit-composer.cjs.map +1 -1
- package/dist/chat-ui/messages/user-edit-composer.d.ts +4 -2
- package/dist/chat-ui/messages/user-edit-composer.js +15 -2
- package/dist/chat-ui/messages/user-edit-composer.js.map +1 -1
- package/dist/chat-ui/messages/wake-marker.d.ts +1 -1
- package/dist/chat-ui/rich-text/chat-text-schema.cjs +1 -0
- package/dist/chat-ui/rich-text/chat-text-schema.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-text-schema.d.ts +3 -0
- package/dist/chat-ui/rich-text/chat-text-schema.js +1 -0
- package/dist/chat-ui/rich-text/chat-text-schema.js.map +1 -1
- package/dist/chat-ui/statewire.cjs +1 -0
- package/dist/chat-ui/statewire.cjs.map +1 -1
- package/dist/chat-ui/statewire.d.ts +2 -2
- package/dist/chat-ui/statewire.js +2 -1
- package/dist/chat-ui/thread/statewire-history-edge.d.ts +1 -1
- package/dist/composer/AttachmentContext.cjs +8 -4
- package/dist/composer/AttachmentContext.cjs.map +1 -1
- package/dist/composer/AttachmentContext.d.ts +7 -0
- package/dist/composer/AttachmentContext.js +8 -4
- package/dist/composer/AttachmentContext.js.map +1 -1
- package/dist/composer/build-composed-message.cjs +34 -0
- package/dist/composer/build-composed-message.cjs.map +1 -1
- package/dist/composer/build-composed-message.d.ts +20 -0
- package/dist/composer/build-composed-message.js +35 -1
- package/dist/composer/build-composed-message.js.map +1 -1
- package/dist/composer/composer-handoff.cjs +39 -2
- package/dist/composer/composer-handoff.cjs.map +1 -1
- package/dist/composer/composer-handoff.d.ts +28 -3
- package/dist/composer/composer-handoff.js +39 -2
- package/dist/composer/composer-handoff.js.map +1 -1
- package/dist/composer/useAttachFiles.cjs +15 -2
- package/dist/composer/useAttachFiles.cjs.map +1 -1
- package/dist/composer/useAttachFiles.d.ts +11 -0
- package/dist/composer/useAttachFiles.js +15 -2
- package/dist/composer/useAttachFiles.js.map +1 -1
- package/dist/composer/useSendMessage.cjs.map +1 -1
- package/dist/composer/useSendMessage.d.ts +4 -3
- package/dist/composer/useSendMessage.js.map +1 -1
- package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
- package/dist/diagnostics/athena-diagnostics.d.ts +3 -1
- package/dist/diagnostics/athena-diagnostics.js.map +1 -1
- package/dist/index.cjs +18 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +15 -6
- package/dist/index.js +19 -1
- package/dist/index.js.map +1 -1
- package/dist/offline/chat-outbox.cjs +57 -0
- package/dist/offline/chat-outbox.cjs.map +1 -0
- package/dist/offline/chat-outbox.d.ts +80 -0
- package/dist/offline/chat-outbox.js +57 -0
- package/dist/offline/chat-outbox.js.map +1 -0
- package/dist/offline/offline-history.cjs +77 -0
- package/dist/offline/offline-history.cjs.map +1 -0
- package/dist/offline/offline-history.d.ts +60 -0
- package/dist/offline/offline-history.js +77 -0
- package/dist/offline/offline-history.js.map +1 -0
- package/dist/provider/AthenaProvider.cjs +206 -9
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.d.ts +22 -1
- package/dist/provider/AthenaProvider.js +207 -10
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/provider/statewire-window-context.d.ts +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/references/src/anchors/file-line-range.d.ts +58 -0
- package/dist/references/src/anchors/format.d.ts +21 -0
- package/dist/references/src/anchors/message-anchors.d.ts +71 -0
- package/dist/references/src/anchors/parse.d.ts +8 -0
- package/dist/references/src/anchors/registry-contract.d.ts +24 -0
- package/dist/references/src/anchors/registry.d.ts +19 -0
- package/dist/references/src/anchors/schemas.d.ts +194 -0
- package/dist/references/src/anchors/serialize.d.ts +8 -0
- package/dist/references/src/anchors/time.d.ts +78 -0
- package/dist/references/src/anchors/types.d.ts +474 -0
- package/dist/references/src/asset-bounds.d.ts +27 -0
- package/dist/references/src/asset-links.d.ts +23 -0
- package/dist/references/src/asset-reference.d.ts +16 -0
- package/dist/references/src/formats/format-catalog.d.ts +79 -0
- package/dist/references/src/formats/markdown/parse-reference-markdown.d.ts +28 -0
- package/dist/references/src/formats/markdown/reference-display-name.d.ts +6 -0
- package/dist/references/src/formats/object/asset-object.d.ts +9 -0
- package/dist/references/src/formats/object/callable-object.d.ts +6 -0
- package/dist/references/src/formats/object/decode-reference-object-payload.d.ts +3 -0
- package/dist/references/src/formats/object/external-url-object.d.ts +9 -0
- package/dist/references/src/formats/object/group-object.d.ts +9 -0
- package/dist/references/src/formats/object/navigation-object.d.ts +9 -0
- package/dist/references/src/formats/object/parse-reference-object.d.ts +11 -0
- package/dist/references/src/formats/object/person-object.d.ts +9 -0
- package/dist/references/src/formats/uri/asset-mention-uri.d.ts +9 -0
- package/dist/references/src/formats/uri/asset-spaces-url.d.ts +9 -0
- package/dist/references/src/formats/uri/callable-mention-uris.d.ts +9 -0
- package/dist/references/src/formats/uri/detect-uri-wire.d.ts +9 -0
- package/dist/references/src/formats/uri/group-mention-uri.d.ts +12 -0
- package/dist/references/src/formats/uri/navigation-spaces-url.d.ts +14 -0
- package/dist/references/src/formats/uri/parse-reference-uri.d.ts +20 -0
- package/dist/references/src/formats/uri/person-mention-uri.d.ts +9 -0
- package/dist/references/src/formats/uri/template-placeholder.d.ts +12 -0
- package/dist/references/src/index.d.ts +47 -0
- package/dist/references/src/legacy/index.d.ts +14 -0
- package/dist/references/src/legacy/pre-reference-asset-url.d.ts +57 -0
- package/dist/references/src/legacy/pre-reference-citation-bridge.d.ts +22 -0
- package/dist/references/src/legacy/pre-reference-citation.d.ts +138 -0
- package/dist/references/src/legacy/pre-reference-external-url.d.ts +31 -0
- package/dist/references/src/legacy/pre-reference-format.d.ts +8 -0
- package/dist/references/src/legacy/pre-reference-mention.d.ts +27 -0
- package/dist/references/src/legacy/pre-reference-object.d.ts +8 -0
- package/dist/references/src/legacy/pre-reference-uri.d.ts +12 -0
- package/dist/references/src/legacy.d.ts +2 -0
- package/dist/references/src/mention-href-patterns.d.ts +19 -0
- package/dist/references/src/mention-node/index.d.ts +5 -0
- package/dist/references/src/mention-node/mention-node.d.ts +31 -0
- package/dist/references/src/mention-node/resolve-node-attrs.d.ts +27 -0
- package/dist/references/src/parse-reference.d.ts +23 -0
- package/dist/references/src/schemas.d.ts +463 -0
- package/dist/references/src/serialize-reference.d.ts +50 -0
- package/dist/references/src/sheet-name.d.ts +10 -0
- package/dist/references/src/tool-option-schemas.d.ts +597 -0
- package/dist/references/src/types.d.ts +125 -0
- package/dist/references/src/version-ref.d.ts +30 -0
- package/dist/runtime/statewire-lifecycle.d.ts +1 -1
- package/dist/runtime/statewire-model-lane.d.ts +1 -1
- package/dist/runtime/statewire-server-lane-context.d.ts +1 -1
- package/dist/runtime/statewire-session-key.cjs +7 -0
- package/dist/runtime/statewire-session-key.cjs.map +1 -1
- package/dist/runtime/statewire-session-key.d.ts +16 -0
- package/dist/runtime/statewire-session-key.js +8 -1
- package/dist/runtime/statewire-session-key.js.map +1 -1
- package/dist/runtime/statewire-session-lane.cjs +48 -0
- package/dist/runtime/statewire-session-lane.cjs.map +1 -0
- package/dist/runtime/statewire-session-lane.d.ts +29 -0
- package/dist/runtime/statewire-session-lane.js +48 -0
- package/dist/runtime/statewire-session-lane.js.map +1 -0
- package/dist/runtime/statewire-thread-config-lane.d.ts +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs +16 -5
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.d.ts +15 -1
- package/dist/runtime/useAthenaStatewireRuntime.js +17 -6
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/threads/api.d.ts +1 -1
- package/dist/threads/conversation-list-fetcher.d.ts +1 -1
- package/dist/threads/index-triggered-refresh.cjs +164 -0
- package/dist/threads/index-triggered-refresh.cjs.map +1 -0
- package/dist/threads/index-triggered-refresh.d.ts +70 -0
- package/dist/threads/index-triggered-refresh.js +164 -0
- package/dist/threads/index-triggered-refresh.js.map +1 -0
- package/dist/threads/offline-session-list.cjs +75 -0
- package/dist/threads/offline-session-list.cjs.map +1 -0
- package/dist/threads/offline-session-list.d.ts +27 -0
- package/dist/threads/offline-session-list.js +75 -0
- package/dist/threads/offline-session-list.js.map +1 -0
- package/dist/threads/pull-request-display.d.ts +1 -1
- package/dist/threads/session-list-model.d.ts +1 -1
- package/dist/threads/session-list-tab-share.cjs +150 -0
- package/dist/threads/session-list-tab-share.cjs.map +1 -0
- package/dist/threads/session-list-tab-share.d.ts +73 -0
- package/dist/threads/session-list-tab-share.js +150 -0
- package/dist/threads/session-list-tab-share.js.map +1 -0
- package/dist/threads/session-row-parts.d.ts +1 -1
- package/dist/threads/sessions-query.d.ts +1 -1
- package/dist/threads/statewire-thread-list.cjs +105 -20
- package/dist/threads/statewire-thread-list.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.d.ts +31 -3
- package/dist/threads/statewire-thread-list.js +107 -22
- package/dist/threads/statewire-thread-list.js.map +1 -1
- package/dist/threads/thread-prefetcher.d.ts +1 -1
- package/dist/threads/use-athena-session-attention.d.ts +1 -1
- package/dist/threads/use-athena-sessions.cjs +32 -22
- package/dist/threads/use-athena-sessions.cjs.map +1 -1
- package/dist/threads/use-athena-sessions.js +33 -23
- package/dist/threads/use-athena-sessions.js.map +1 -1
- package/dist/threads/use-rest-conversation-history.d.ts +1 -1
- package/dist/threads/use-statewire-conversation-history.d.ts +5 -5
- package/dist/tiptap-markdown-table/src/markdown-table-serializer.d.ts +56 -0
- package/dist/tools/NestedPtcMessages.cjs +14 -9
- package/dist/tools/NestedPtcMessages.cjs.map +1 -1
- package/dist/tools/NestedPtcMessages.d.ts +9 -0
- package/dist/tools/NestedPtcMessages.js +6 -1
- package/dist/tools/NestedPtcMessages.js.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/primitives.d.ts +1 -1
- package/dist/tools/subagent-task-tool-ui.cjs +494 -0
- package/dist/tools/subagent-task-tool-ui.cjs.map +1 -0
- package/dist/tools/subagent-task-tool-ui.d.ts +109 -0
- package/dist/tools/subagent-task-tool-ui.js +494 -0
- package/dist/tools/subagent-task-tool-ui.js.map +1 -0
- package/dist/tools/tool-fallback.d.ts +1 -1
- package/dist/tools/tool-icons.d.ts +1 -1
- package/dist/tools/tool-summary.d.ts +1 -1
- package/dist/tools/tool-uis.cjs +4 -0
- package/dist/tools/tool-uis.cjs.map +1 -1
- package/dist/tools/tool-uis.js +4 -0
- package/dist/tools/tool-uis.js.map +1 -1
- package/dist/voice/chat.cjs +6 -0
- package/dist/voice/chat.cjs.map +1 -0
- package/dist/voice/chat.d.ts +2 -0
- package/dist/voice/chat.js +6 -0
- package/dist/voice/chat.js.map +1 -0
- package/dist/voice/livekit-join.cjs +119 -0
- package/dist/voice/livekit-join.cjs.map +1 -0
- package/dist/voice/livekit-join.d.ts +8 -0
- package/dist/voice/livekit-join.js +119 -0
- package/dist/voice/livekit-join.js.map +1 -0
- package/dist/voice/livekit.cjs +32 -0
- package/dist/voice/livekit.cjs.map +1 -0
- package/dist/voice/livekit.d.ts +80 -0
- package/dist/voice/livekit.js +32 -0
- package/dist/voice/livekit.js.map +1 -0
- package/package.json +20 -10
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
6
|
+
const react = require("react");
|
|
7
|
+
const INDEX_REFRESH_DEBOUNCE_MS = 750;
|
|
8
|
+
const INDEX_REFRESH_MAX_WAIT_MS = 3e3;
|
|
9
|
+
const INDEX_REFRESH_HIDDEN_TAB_DELAY_MS = 1500;
|
|
10
|
+
const INDEX_REFRESH_JITTER_MS = 300;
|
|
11
|
+
const INDEX_REFRESH_MAX_ATTEMPTS = 3;
|
|
12
|
+
const INDEX_REFRESH_RETRY_BASE_MS = 1e4;
|
|
13
|
+
const DEFAULT_TIMING = {
|
|
14
|
+
debounceMs: INDEX_REFRESH_DEBOUNCE_MS,
|
|
15
|
+
hiddenTabDelayMs: INDEX_REFRESH_HIDDEN_TAB_DELAY_MS,
|
|
16
|
+
jitterMs: INDEX_REFRESH_JITTER_MS,
|
|
17
|
+
maxWaitMs: INDEX_REFRESH_MAX_WAIT_MS,
|
|
18
|
+
maxAttempts: INDEX_REFRESH_MAX_ATTEMPTS,
|
|
19
|
+
retryBaseMs: INDEX_REFRESH_RETRY_BASE_MS
|
|
20
|
+
};
|
|
21
|
+
class IndexRefreshLedger {
|
|
22
|
+
constructor(timing) {
|
|
23
|
+
__publicField(this, "settled", /* @__PURE__ */ new Set());
|
|
24
|
+
__publicField(this, "inFlight", /* @__PURE__ */ new Set());
|
|
25
|
+
__publicField(this, "failures", /* @__PURE__ */ new Map());
|
|
26
|
+
this.timing = timing;
|
|
27
|
+
}
|
|
28
|
+
/** The keys a refresh should be sent for now. */
|
|
29
|
+
due(keys, now) {
|
|
30
|
+
return keys.filter((key) => {
|
|
31
|
+
if (this.settled.has(key) || this.inFlight.has(key)) return false;
|
|
32
|
+
const failure = this.failures.get(key);
|
|
33
|
+
return failure === void 0 || failure.retryAt <= now;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/** When the earliest of these keys that failed is due again; `null` if none waits. */
|
|
37
|
+
nextRetryAt(keys) {
|
|
38
|
+
let next = null;
|
|
39
|
+
for (const key of keys) {
|
|
40
|
+
if (this.settled.has(key) || this.inFlight.has(key)) continue;
|
|
41
|
+
const failure = this.failures.get(key);
|
|
42
|
+
if (failure && (next === null || failure.retryAt < next)) next = failure.retryAt;
|
|
43
|
+
}
|
|
44
|
+
return next;
|
|
45
|
+
}
|
|
46
|
+
begin(keys) {
|
|
47
|
+
for (const key of keys) this.inFlight.add(key);
|
|
48
|
+
}
|
|
49
|
+
succeed(keys) {
|
|
50
|
+
for (const key of keys) {
|
|
51
|
+
this.inFlight.delete(key);
|
|
52
|
+
this.failures.delete(key);
|
|
53
|
+
this.settled.add(key);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
fail(keys, now) {
|
|
57
|
+
var _a;
|
|
58
|
+
for (const key of keys) {
|
|
59
|
+
this.inFlight.delete(key);
|
|
60
|
+
const attempts = (((_a = this.failures.get(key)) == null ? void 0 : _a.attempts) ?? 0) + 1;
|
|
61
|
+
if (attempts >= this.timing.maxAttempts) {
|
|
62
|
+
this.failures.delete(key);
|
|
63
|
+
this.settled.add(key);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
this.failures.set(key, {
|
|
67
|
+
attempts,
|
|
68
|
+
retryAt: now + this.timing.retryBaseMs * 2 ** (attempts - 1)
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function refreshSucceeded(result) {
|
|
74
|
+
if (result === null || typeof result !== "object") return true;
|
|
75
|
+
const { status, isError } = result;
|
|
76
|
+
return status !== "error" && isError !== true;
|
|
77
|
+
}
|
|
78
|
+
function useIndexTriggeredRefresh({
|
|
79
|
+
pending,
|
|
80
|
+
refresh,
|
|
81
|
+
enabled,
|
|
82
|
+
tabShare,
|
|
83
|
+
shareKey,
|
|
84
|
+
timing
|
|
85
|
+
}) {
|
|
86
|
+
const resolvedTiming = { ...DEFAULT_TIMING, ...timing };
|
|
87
|
+
const timingRef = react.useRef(resolvedTiming);
|
|
88
|
+
timingRef.current = resolvedTiming;
|
|
89
|
+
const ledgerRef = react.useRef(null);
|
|
90
|
+
ledgerRef.current ?? (ledgerRef.current = new IndexRefreshLedger(resolvedTiming));
|
|
91
|
+
const refreshRef = react.useRef(refresh);
|
|
92
|
+
refreshRef.current = refresh;
|
|
93
|
+
const tabShareRef = react.useRef(tabShare);
|
|
94
|
+
tabShareRef.current = tabShare;
|
|
95
|
+
const firstDueAtRef = react.useRef(null);
|
|
96
|
+
const mountedRef = react.useRef(true);
|
|
97
|
+
react.useEffect(() => {
|
|
98
|
+
mountedRef.current = true;
|
|
99
|
+
return () => {
|
|
100
|
+
mountedRef.current = false;
|
|
101
|
+
};
|
|
102
|
+
}, []);
|
|
103
|
+
const [tick, setTick] = react.useState(0);
|
|
104
|
+
const bump = () => {
|
|
105
|
+
if (mountedRef.current) setTick((value) => value + 1);
|
|
106
|
+
};
|
|
107
|
+
const pendingKey = JSON.stringify(pending);
|
|
108
|
+
react.useEffect(() => {
|
|
109
|
+
var _a;
|
|
110
|
+
if (!enabled) return;
|
|
111
|
+
const ledger = ledgerRef.current;
|
|
112
|
+
if (!ledger) return;
|
|
113
|
+
const { debounceMs, maxWaitMs, hiddenTabDelayMs, jitterMs } = timingRef.current;
|
|
114
|
+
const keys = JSON.parse(pendingKey);
|
|
115
|
+
const now = Date.now();
|
|
116
|
+
const due = ledger.due(keys, now);
|
|
117
|
+
if (due.length === 0) {
|
|
118
|
+
firstDueAtRef.current = null;
|
|
119
|
+
const retryAt = ledger.nextRetryAt(keys);
|
|
120
|
+
if (retryAt === null) return;
|
|
121
|
+
const retryId = setTimeout(bump, Math.max(0, retryAt - now));
|
|
122
|
+
return () => clearTimeout(retryId);
|
|
123
|
+
}
|
|
124
|
+
const claimedUntil = shareKey ? ((_a = tabShareRef.current) == null ? void 0 : _a.claimedUntil(shareKey)) ?? null : null;
|
|
125
|
+
if (claimedUntil !== null) {
|
|
126
|
+
const claimId = setTimeout(bump, Math.max(0, claimedUntil - now));
|
|
127
|
+
return () => clearTimeout(claimId);
|
|
128
|
+
}
|
|
129
|
+
firstDueAtRef.current ?? (firstDueAtRef.current = now);
|
|
130
|
+
const isHidden = typeof document !== "undefined" && document.visibilityState === "hidden";
|
|
131
|
+
const stagger = (isHidden ? hiddenTabDelayMs : 0) + Math.random() * jitterMs;
|
|
132
|
+
const delay = Math.max(0, Math.min(debounceMs, firstDueAtRef.current + maxWaitMs - now)) + stagger;
|
|
133
|
+
const flushId = setTimeout(() => {
|
|
134
|
+
var _a2, _b;
|
|
135
|
+
firstDueAtRef.current = null;
|
|
136
|
+
const sending = ledger.due(keys, Date.now());
|
|
137
|
+
if (sending.length === 0) return;
|
|
138
|
+
if (shareKey && ((_a2 = tabShareRef.current) == null ? void 0 : _a2.claimedUntil(shareKey)) != null) {
|
|
139
|
+
bump();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (shareKey) (_b = tabShareRef.current) == null ? void 0 : _b.claim(shareKey);
|
|
143
|
+
ledger.begin(sending);
|
|
144
|
+
void Promise.resolve().then(() => refreshRef.current()).then(
|
|
145
|
+
(result) => {
|
|
146
|
+
if (refreshSucceeded(result)) ledger.succeed(sending);
|
|
147
|
+
else ledger.fail(sending, Date.now());
|
|
148
|
+
},
|
|
149
|
+
() => ledger.fail(sending, Date.now())
|
|
150
|
+
).finally(bump);
|
|
151
|
+
}, delay);
|
|
152
|
+
return () => clearTimeout(flushId);
|
|
153
|
+
}, [enabled, pendingKey, shareKey, tick]);
|
|
154
|
+
}
|
|
155
|
+
exports.INDEX_REFRESH_DEBOUNCE_MS = INDEX_REFRESH_DEBOUNCE_MS;
|
|
156
|
+
exports.INDEX_REFRESH_HIDDEN_TAB_DELAY_MS = INDEX_REFRESH_HIDDEN_TAB_DELAY_MS;
|
|
157
|
+
exports.INDEX_REFRESH_JITTER_MS = INDEX_REFRESH_JITTER_MS;
|
|
158
|
+
exports.INDEX_REFRESH_MAX_ATTEMPTS = INDEX_REFRESH_MAX_ATTEMPTS;
|
|
159
|
+
exports.INDEX_REFRESH_MAX_WAIT_MS = INDEX_REFRESH_MAX_WAIT_MS;
|
|
160
|
+
exports.INDEX_REFRESH_RETRY_BASE_MS = INDEX_REFRESH_RETRY_BASE_MS;
|
|
161
|
+
exports.IndexRefreshLedger = IndexRefreshLedger;
|
|
162
|
+
exports.refreshSucceeded = refreshSucceeded;
|
|
163
|
+
exports.useIndexTriggeredRefresh = useIndexTriggeredRefresh;
|
|
164
|
+
//# sourceMappingURL=index-triggered-refresh.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-triggered-refresh.cjs","sources":["../../src/threads/index-triggered-refresh.ts"],"sourcesContent":["/**\n * The refresh a list runs when the pushed conversation index knows a thread\n * the list does not show yet (a session just started here or in another tab,\n * or one that just came to match a filter). Shared by the sidebar provider\n * and `useAthenaSessions`.\n *\n * - **Coalesced.** One push rarely comes alone (a new session is created,\n * titled and starts running within a second), and every open tab hears\n * each one. Keys that become due are gathered for\n * {@link INDEX_REFRESH_DEBOUNCE_MS} after the last change (at most\n * {@link INDEX_REFRESH_MAX_WAIT_MS} after the first), and nothing is sent\n * while the list is already fetching: that fetch may list the row, and the\n * keys are looked at again once it lands.\n * - **One tab for all.** With a `tabShare`, the tab that is about to refresh\n * claims the list first; the user's other tabs hold their own refresh\n * while the claim stands and take the page it shares\n * (`session-list-tab-share.ts`). A claim that lapses without a page lets\n * them refresh themselves.\n * - **Retried.** A key is settled only by a refresh that SUCCEEDED. A refused\n * one (429, network, a deploy restart) is tried again after\n * {@link INDEX_REFRESH_RETRY_BASE_MS}, doubling, at most\n * {@link INDEX_REFRESH_MAX_ATTEMPTS} times, so a thread the list\n * legitimately never shows (another app, a search) cannot loop.\n */\nimport { useEffect, useRef, useState } from 'react';\nimport type { SessionListTabShare } from './session-list-tab-share';\n\n/** Quiet time gathered after the last change before the refresh is sent. */\nexport const INDEX_REFRESH_DEBOUNCE_MS = 750;\n/** The longest a due key waits for quiet before its refresh is sent anyway. */\nexport const INDEX_REFRESH_MAX_WAIT_MS = 3_000;\n/**\n * Extra wait for a tab nobody is looking at, so the visible tab is usually the\n * one that claims a list and reads it for the others.\n */\nexport const INDEX_REFRESH_HIDDEN_TAB_DELAY_MS = 1_500;\n/** Up to this much random wait on top, so tabs that heard the same push do not flush together. */\nexport const INDEX_REFRESH_JITTER_MS = 300;\n/** Refreshes tried per key before it is given up on. */\nexport const INDEX_REFRESH_MAX_ATTEMPTS = 3;\n/**\n * Wait before the first retry; each later retry waits twice as long. Long enough that a refusal\n * from the per-minute request window has a chance to clear (the list query has already retried\n * on its own by then).\n */\nexport const INDEX_REFRESH_RETRY_BASE_MS = 10_000;\n\nexport interface IndexRefreshTiming {\n debounceMs: number;\n hiddenTabDelayMs: number;\n jitterMs: number;\n maxWaitMs: number;\n maxAttempts: number;\n retryBaseMs: number;\n}\n\nconst DEFAULT_TIMING: IndexRefreshTiming = {\n debounceMs: INDEX_REFRESH_DEBOUNCE_MS,\n hiddenTabDelayMs: INDEX_REFRESH_HIDDEN_TAB_DELAY_MS,\n jitterMs: INDEX_REFRESH_JITTER_MS,\n maxWaitMs: INDEX_REFRESH_MAX_WAIT_MS,\n maxAttempts: INDEX_REFRESH_MAX_ATTEMPTS,\n retryBaseMs: INDEX_REFRESH_RETRY_BASE_MS,\n};\n\n/**\n * What each key has cost so far: settled (a refresh succeeded, or it ran out\n * of attempts), in flight, or failed N times and next due at an instant.\n * Exported for tests.\n */\nexport class IndexRefreshLedger {\n private readonly settled = new Set<string>();\n private readonly inFlight = new Set<string>();\n private readonly failures = new Map<string, { attempts: number; retryAt: number }>();\n\n constructor(private readonly timing: Pick<IndexRefreshTiming, 'maxAttempts' | 'retryBaseMs'>) {}\n\n /** The keys a refresh should be sent for now. */\n due(keys: readonly string[], now: number): string[] {\n return keys.filter((key) => {\n if (this.settled.has(key) || this.inFlight.has(key)) return false;\n const failure = this.failures.get(key);\n return failure === undefined || failure.retryAt <= now;\n });\n }\n\n /** When the earliest of these keys that failed is due again; `null` if none waits. */\n nextRetryAt(keys: readonly string[]): number | null {\n let next: number | null = null;\n for (const key of keys) {\n if (this.settled.has(key) || this.inFlight.has(key)) continue;\n const failure = this.failures.get(key);\n if (failure && (next === null || failure.retryAt < next)) next = failure.retryAt;\n }\n return next;\n }\n\n begin(keys: readonly string[]): void {\n for (const key of keys) this.inFlight.add(key);\n }\n\n succeed(keys: readonly string[]): void {\n for (const key of keys) {\n this.inFlight.delete(key);\n this.failures.delete(key);\n this.settled.add(key);\n }\n }\n\n fail(keys: readonly string[], now: number): void {\n for (const key of keys) {\n this.inFlight.delete(key);\n const attempts = (this.failures.get(key)?.attempts ?? 0) + 1;\n if (attempts >= this.timing.maxAttempts) {\n this.failures.delete(key);\n this.settled.add(key);\n continue;\n }\n this.failures.set(key, {\n attempts,\n retryAt: now + this.timing.retryBaseMs * 2 ** (attempts - 1),\n });\n }\n }\n}\n\n/**\n * Whether a list refresh answered. `useConversationList().refresh` resolves\n * with the query result rather than throwing, so a refused fetch shows as\n * `status: 'error'`. Exported for tests.\n */\nexport function refreshSucceeded(result: unknown): boolean {\n if (result === null || typeof result !== 'object') return true;\n const { status, isError } = result as { status?: unknown; isError?: unknown };\n return status !== 'error' && isError !== true;\n}\n\n/**\n * Run `refresh` for the `pending` keys (the threads, or thread versions, the\n * index knows and the list does not show), coalesced and retried as described\n * above. `enabled` false holds everything (no index yet, the first page not\n * read, or a fetch of the list already in flight); pending keys are looked at\n * again when it turns true.\n */\nexport function useIndexTriggeredRefresh({\n pending,\n refresh,\n enabled,\n tabShare,\n shareKey,\n timing,\n}: {\n pending: readonly string[];\n refresh: () => Promise<unknown>;\n enabled: boolean;\n /** The user's other open tabs, and this list's name among them (its first-page query key). */\n tabShare?: SessionListTabShare;\n shareKey?: string;\n /** Overrides for tests. */\n timing?: Partial<IndexRefreshTiming>;\n}): void {\n const resolvedTiming = { ...DEFAULT_TIMING, ...timing };\n const timingRef = useRef(resolvedTiming);\n timingRef.current = resolvedTiming;\n const ledgerRef = useRef<IndexRefreshLedger | null>(null);\n ledgerRef.current ??= new IndexRefreshLedger(resolvedTiming);\n const refreshRef = useRef(refresh);\n refreshRef.current = refresh;\n const tabShareRef = useRef(tabShare);\n tabShareRef.current = tabShare;\n // When the oldest key now waiting for quiet first became due.\n const firstDueAtRef = useRef<number | null>(null);\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n // Bumped when a refresh settles or a retry falls due, so the keys are looked at again.\n const [tick, setTick] = useState(0);\n const bump = () => {\n if (mountedRef.current) setTick((value) => value + 1);\n };\n\n // A stable key, so a fresh array with the same keys does not restart the wait.\n const pendingKey = JSON.stringify(pending);\n useEffect(() => {\n if (!enabled) return;\n const ledger = ledgerRef.current;\n if (!ledger) return;\n const { debounceMs, maxWaitMs, hiddenTabDelayMs, jitterMs } = timingRef.current;\n const keys = JSON.parse(pendingKey) as string[];\n const now = Date.now();\n const due = ledger.due(keys, now);\n if (due.length === 0) {\n firstDueAtRef.current = null;\n const retryAt = ledger.nextRetryAt(keys);\n if (retryAt === null) return;\n const retryId = setTimeout(bump, Math.max(0, retryAt - now));\n return () => clearTimeout(retryId);\n }\n // Another tab is reading this list: its page will be shared here. Look\n // again once its claim lapses, in case it never arrives.\n const claimedUntil = shareKey ? (tabShareRef.current?.claimedUntil(shareKey) ?? null) : null;\n if (claimedUntil !== null) {\n const claimId = setTimeout(bump, Math.max(0, claimedUntil - now));\n return () => clearTimeout(claimId);\n }\n firstDueAtRef.current ??= now;\n const isHidden = typeof document !== 'undefined' && document.visibilityState === 'hidden';\n const stagger = (isHidden ? hiddenTabDelayMs : 0) + Math.random() * jitterMs;\n const delay =\n Math.max(0, Math.min(debounceMs, firstDueAtRef.current + maxWaitMs - now)) + stagger;\n const flushId = setTimeout(() => {\n firstDueAtRef.current = null;\n const sending = ledger.due(keys, Date.now());\n if (sending.length === 0) return;\n if (shareKey && tabShareRef.current?.claimedUntil(shareKey) != null) {\n bump();\n return;\n }\n if (shareKey) tabShareRef.current?.claim(shareKey);\n ledger.begin(sending);\n void Promise.resolve()\n .then(() => refreshRef.current())\n .then(\n (result) => {\n if (refreshSucceeded(result)) ledger.succeed(sending);\n else ledger.fail(sending, Date.now());\n },\n () => ledger.fail(sending, Date.now()),\n )\n .finally(bump);\n }, delay);\n return () => clearTimeout(flushId);\n // `bump` only sets state; `tick` re-runs this after a settle or a retry falls due.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, pendingKey, shareKey, tick]);\n}\n"],"names":["useRef","useEffect","useState","_a"],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { SessionListTabShare } from './session-list-tab-share';
|
|
2
|
+
/** Quiet time gathered after the last change before the refresh is sent. */
|
|
3
|
+
export declare const INDEX_REFRESH_DEBOUNCE_MS = 750;
|
|
4
|
+
/** The longest a due key waits for quiet before its refresh is sent anyway. */
|
|
5
|
+
export declare const INDEX_REFRESH_MAX_WAIT_MS = 3000;
|
|
6
|
+
/**
|
|
7
|
+
* Extra wait for a tab nobody is looking at, so the visible tab is usually the
|
|
8
|
+
* one that claims a list and reads it for the others.
|
|
9
|
+
*/
|
|
10
|
+
export declare const INDEX_REFRESH_HIDDEN_TAB_DELAY_MS = 1500;
|
|
11
|
+
/** Up to this much random wait on top, so tabs that heard the same push do not flush together. */
|
|
12
|
+
export declare const INDEX_REFRESH_JITTER_MS = 300;
|
|
13
|
+
/** Refreshes tried per key before it is given up on. */
|
|
14
|
+
export declare const INDEX_REFRESH_MAX_ATTEMPTS = 3;
|
|
15
|
+
/**
|
|
16
|
+
* Wait before the first retry; each later retry waits twice as long. Long enough that a refusal
|
|
17
|
+
* from the per-minute request window has a chance to clear (the list query has already retried
|
|
18
|
+
* on its own by then).
|
|
19
|
+
*/
|
|
20
|
+
export declare const INDEX_REFRESH_RETRY_BASE_MS = 10000;
|
|
21
|
+
export interface IndexRefreshTiming {
|
|
22
|
+
debounceMs: number;
|
|
23
|
+
hiddenTabDelayMs: number;
|
|
24
|
+
jitterMs: number;
|
|
25
|
+
maxWaitMs: number;
|
|
26
|
+
maxAttempts: number;
|
|
27
|
+
retryBaseMs: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* What each key has cost so far: settled (a refresh succeeded, or it ran out
|
|
31
|
+
* of attempts), in flight, or failed N times and next due at an instant.
|
|
32
|
+
* Exported for tests.
|
|
33
|
+
*/
|
|
34
|
+
export declare class IndexRefreshLedger {
|
|
35
|
+
private readonly timing;
|
|
36
|
+
private readonly settled;
|
|
37
|
+
private readonly inFlight;
|
|
38
|
+
private readonly failures;
|
|
39
|
+
constructor(timing: Pick<IndexRefreshTiming, 'maxAttempts' | 'retryBaseMs'>);
|
|
40
|
+
/** The keys a refresh should be sent for now. */
|
|
41
|
+
due(keys: readonly string[], now: number): string[];
|
|
42
|
+
/** When the earliest of these keys that failed is due again; `null` if none waits. */
|
|
43
|
+
nextRetryAt(keys: readonly string[]): number | null;
|
|
44
|
+
begin(keys: readonly string[]): void;
|
|
45
|
+
succeed(keys: readonly string[]): void;
|
|
46
|
+
fail(keys: readonly string[], now: number): void;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Whether a list refresh answered. `useConversationList().refresh` resolves
|
|
50
|
+
* with the query result rather than throwing, so a refused fetch shows as
|
|
51
|
+
* `status: 'error'`. Exported for tests.
|
|
52
|
+
*/
|
|
53
|
+
export declare function refreshSucceeded(result: unknown): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Run `refresh` for the `pending` keys (the threads, or thread versions, the
|
|
56
|
+
* index knows and the list does not show), coalesced and retried as described
|
|
57
|
+
* above. `enabled` false holds everything (no index yet, the first page not
|
|
58
|
+
* read, or a fetch of the list already in flight); pending keys are looked at
|
|
59
|
+
* again when it turns true.
|
|
60
|
+
*/
|
|
61
|
+
export declare function useIndexTriggeredRefresh({ pending, refresh, enabled, tabShare, shareKey, timing, }: {
|
|
62
|
+
pending: readonly string[];
|
|
63
|
+
refresh: () => Promise<unknown>;
|
|
64
|
+
enabled: boolean;
|
|
65
|
+
/** The user's other open tabs, and this list's name among them (its first-page query key). */
|
|
66
|
+
tabShare?: SessionListTabShare;
|
|
67
|
+
shareKey?: string;
|
|
68
|
+
/** Overrides for tests. */
|
|
69
|
+
timing?: Partial<IndexRefreshTiming>;
|
|
70
|
+
}): void;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { useRef, useEffect, useState } from "react";
|
|
5
|
+
const INDEX_REFRESH_DEBOUNCE_MS = 750;
|
|
6
|
+
const INDEX_REFRESH_MAX_WAIT_MS = 3e3;
|
|
7
|
+
const INDEX_REFRESH_HIDDEN_TAB_DELAY_MS = 1500;
|
|
8
|
+
const INDEX_REFRESH_JITTER_MS = 300;
|
|
9
|
+
const INDEX_REFRESH_MAX_ATTEMPTS = 3;
|
|
10
|
+
const INDEX_REFRESH_RETRY_BASE_MS = 1e4;
|
|
11
|
+
const DEFAULT_TIMING = {
|
|
12
|
+
debounceMs: INDEX_REFRESH_DEBOUNCE_MS,
|
|
13
|
+
hiddenTabDelayMs: INDEX_REFRESH_HIDDEN_TAB_DELAY_MS,
|
|
14
|
+
jitterMs: INDEX_REFRESH_JITTER_MS,
|
|
15
|
+
maxWaitMs: INDEX_REFRESH_MAX_WAIT_MS,
|
|
16
|
+
maxAttempts: INDEX_REFRESH_MAX_ATTEMPTS,
|
|
17
|
+
retryBaseMs: INDEX_REFRESH_RETRY_BASE_MS
|
|
18
|
+
};
|
|
19
|
+
class IndexRefreshLedger {
|
|
20
|
+
constructor(timing) {
|
|
21
|
+
__publicField(this, "settled", /* @__PURE__ */ new Set());
|
|
22
|
+
__publicField(this, "inFlight", /* @__PURE__ */ new Set());
|
|
23
|
+
__publicField(this, "failures", /* @__PURE__ */ new Map());
|
|
24
|
+
this.timing = timing;
|
|
25
|
+
}
|
|
26
|
+
/** The keys a refresh should be sent for now. */
|
|
27
|
+
due(keys, now) {
|
|
28
|
+
return keys.filter((key) => {
|
|
29
|
+
if (this.settled.has(key) || this.inFlight.has(key)) return false;
|
|
30
|
+
const failure = this.failures.get(key);
|
|
31
|
+
return failure === void 0 || failure.retryAt <= now;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/** When the earliest of these keys that failed is due again; `null` if none waits. */
|
|
35
|
+
nextRetryAt(keys) {
|
|
36
|
+
let next = null;
|
|
37
|
+
for (const key of keys) {
|
|
38
|
+
if (this.settled.has(key) || this.inFlight.has(key)) continue;
|
|
39
|
+
const failure = this.failures.get(key);
|
|
40
|
+
if (failure && (next === null || failure.retryAt < next)) next = failure.retryAt;
|
|
41
|
+
}
|
|
42
|
+
return next;
|
|
43
|
+
}
|
|
44
|
+
begin(keys) {
|
|
45
|
+
for (const key of keys) this.inFlight.add(key);
|
|
46
|
+
}
|
|
47
|
+
succeed(keys) {
|
|
48
|
+
for (const key of keys) {
|
|
49
|
+
this.inFlight.delete(key);
|
|
50
|
+
this.failures.delete(key);
|
|
51
|
+
this.settled.add(key);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
fail(keys, now) {
|
|
55
|
+
var _a;
|
|
56
|
+
for (const key of keys) {
|
|
57
|
+
this.inFlight.delete(key);
|
|
58
|
+
const attempts = (((_a = this.failures.get(key)) == null ? void 0 : _a.attempts) ?? 0) + 1;
|
|
59
|
+
if (attempts >= this.timing.maxAttempts) {
|
|
60
|
+
this.failures.delete(key);
|
|
61
|
+
this.settled.add(key);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
this.failures.set(key, {
|
|
65
|
+
attempts,
|
|
66
|
+
retryAt: now + this.timing.retryBaseMs * 2 ** (attempts - 1)
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function refreshSucceeded(result) {
|
|
72
|
+
if (result === null || typeof result !== "object") return true;
|
|
73
|
+
const { status, isError } = result;
|
|
74
|
+
return status !== "error" && isError !== true;
|
|
75
|
+
}
|
|
76
|
+
function useIndexTriggeredRefresh({
|
|
77
|
+
pending,
|
|
78
|
+
refresh,
|
|
79
|
+
enabled,
|
|
80
|
+
tabShare,
|
|
81
|
+
shareKey,
|
|
82
|
+
timing
|
|
83
|
+
}) {
|
|
84
|
+
const resolvedTiming = { ...DEFAULT_TIMING, ...timing };
|
|
85
|
+
const timingRef = useRef(resolvedTiming);
|
|
86
|
+
timingRef.current = resolvedTiming;
|
|
87
|
+
const ledgerRef = useRef(null);
|
|
88
|
+
ledgerRef.current ?? (ledgerRef.current = new IndexRefreshLedger(resolvedTiming));
|
|
89
|
+
const refreshRef = useRef(refresh);
|
|
90
|
+
refreshRef.current = refresh;
|
|
91
|
+
const tabShareRef = useRef(tabShare);
|
|
92
|
+
tabShareRef.current = tabShare;
|
|
93
|
+
const firstDueAtRef = useRef(null);
|
|
94
|
+
const mountedRef = useRef(true);
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
mountedRef.current = true;
|
|
97
|
+
return () => {
|
|
98
|
+
mountedRef.current = false;
|
|
99
|
+
};
|
|
100
|
+
}, []);
|
|
101
|
+
const [tick, setTick] = useState(0);
|
|
102
|
+
const bump = () => {
|
|
103
|
+
if (mountedRef.current) setTick((value) => value + 1);
|
|
104
|
+
};
|
|
105
|
+
const pendingKey = JSON.stringify(pending);
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
var _a;
|
|
108
|
+
if (!enabled) return;
|
|
109
|
+
const ledger = ledgerRef.current;
|
|
110
|
+
if (!ledger) return;
|
|
111
|
+
const { debounceMs, maxWaitMs, hiddenTabDelayMs, jitterMs } = timingRef.current;
|
|
112
|
+
const keys = JSON.parse(pendingKey);
|
|
113
|
+
const now = Date.now();
|
|
114
|
+
const due = ledger.due(keys, now);
|
|
115
|
+
if (due.length === 0) {
|
|
116
|
+
firstDueAtRef.current = null;
|
|
117
|
+
const retryAt = ledger.nextRetryAt(keys);
|
|
118
|
+
if (retryAt === null) return;
|
|
119
|
+
const retryId = setTimeout(bump, Math.max(0, retryAt - now));
|
|
120
|
+
return () => clearTimeout(retryId);
|
|
121
|
+
}
|
|
122
|
+
const claimedUntil = shareKey ? ((_a = tabShareRef.current) == null ? void 0 : _a.claimedUntil(shareKey)) ?? null : null;
|
|
123
|
+
if (claimedUntil !== null) {
|
|
124
|
+
const claimId = setTimeout(bump, Math.max(0, claimedUntil - now));
|
|
125
|
+
return () => clearTimeout(claimId);
|
|
126
|
+
}
|
|
127
|
+
firstDueAtRef.current ?? (firstDueAtRef.current = now);
|
|
128
|
+
const isHidden = typeof document !== "undefined" && document.visibilityState === "hidden";
|
|
129
|
+
const stagger = (isHidden ? hiddenTabDelayMs : 0) + Math.random() * jitterMs;
|
|
130
|
+
const delay = Math.max(0, Math.min(debounceMs, firstDueAtRef.current + maxWaitMs - now)) + stagger;
|
|
131
|
+
const flushId = setTimeout(() => {
|
|
132
|
+
var _a2, _b;
|
|
133
|
+
firstDueAtRef.current = null;
|
|
134
|
+
const sending = ledger.due(keys, Date.now());
|
|
135
|
+
if (sending.length === 0) return;
|
|
136
|
+
if (shareKey && ((_a2 = tabShareRef.current) == null ? void 0 : _a2.claimedUntil(shareKey)) != null) {
|
|
137
|
+
bump();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (shareKey) (_b = tabShareRef.current) == null ? void 0 : _b.claim(shareKey);
|
|
141
|
+
ledger.begin(sending);
|
|
142
|
+
void Promise.resolve().then(() => refreshRef.current()).then(
|
|
143
|
+
(result) => {
|
|
144
|
+
if (refreshSucceeded(result)) ledger.succeed(sending);
|
|
145
|
+
else ledger.fail(sending, Date.now());
|
|
146
|
+
},
|
|
147
|
+
() => ledger.fail(sending, Date.now())
|
|
148
|
+
).finally(bump);
|
|
149
|
+
}, delay);
|
|
150
|
+
return () => clearTimeout(flushId);
|
|
151
|
+
}, [enabled, pendingKey, shareKey, tick]);
|
|
152
|
+
}
|
|
153
|
+
export {
|
|
154
|
+
INDEX_REFRESH_DEBOUNCE_MS,
|
|
155
|
+
INDEX_REFRESH_HIDDEN_TAB_DELAY_MS,
|
|
156
|
+
INDEX_REFRESH_JITTER_MS,
|
|
157
|
+
INDEX_REFRESH_MAX_ATTEMPTS,
|
|
158
|
+
INDEX_REFRESH_MAX_WAIT_MS,
|
|
159
|
+
INDEX_REFRESH_RETRY_BASE_MS,
|
|
160
|
+
IndexRefreshLedger,
|
|
161
|
+
refreshSucceeded,
|
|
162
|
+
useIndexTriggeredRefresh
|
|
163
|
+
};
|
|
164
|
+
//# sourceMappingURL=index-triggered-refresh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-triggered-refresh.js","sources":["../../src/threads/index-triggered-refresh.ts"],"sourcesContent":["/**\n * The refresh a list runs when the pushed conversation index knows a thread\n * the list does not show yet (a session just started here or in another tab,\n * or one that just came to match a filter). Shared by the sidebar provider\n * and `useAthenaSessions`.\n *\n * - **Coalesced.** One push rarely comes alone (a new session is created,\n * titled and starts running within a second), and every open tab hears\n * each one. Keys that become due are gathered for\n * {@link INDEX_REFRESH_DEBOUNCE_MS} after the last change (at most\n * {@link INDEX_REFRESH_MAX_WAIT_MS} after the first), and nothing is sent\n * while the list is already fetching: that fetch may list the row, and the\n * keys are looked at again once it lands.\n * - **One tab for all.** With a `tabShare`, the tab that is about to refresh\n * claims the list first; the user's other tabs hold their own refresh\n * while the claim stands and take the page it shares\n * (`session-list-tab-share.ts`). A claim that lapses without a page lets\n * them refresh themselves.\n * - **Retried.** A key is settled only by a refresh that SUCCEEDED. A refused\n * one (429, network, a deploy restart) is tried again after\n * {@link INDEX_REFRESH_RETRY_BASE_MS}, doubling, at most\n * {@link INDEX_REFRESH_MAX_ATTEMPTS} times, so a thread the list\n * legitimately never shows (another app, a search) cannot loop.\n */\nimport { useEffect, useRef, useState } from 'react';\nimport type { SessionListTabShare } from './session-list-tab-share';\n\n/** Quiet time gathered after the last change before the refresh is sent. */\nexport const INDEX_REFRESH_DEBOUNCE_MS = 750;\n/** The longest a due key waits for quiet before its refresh is sent anyway. */\nexport const INDEX_REFRESH_MAX_WAIT_MS = 3_000;\n/**\n * Extra wait for a tab nobody is looking at, so the visible tab is usually the\n * one that claims a list and reads it for the others.\n */\nexport const INDEX_REFRESH_HIDDEN_TAB_DELAY_MS = 1_500;\n/** Up to this much random wait on top, so tabs that heard the same push do not flush together. */\nexport const INDEX_REFRESH_JITTER_MS = 300;\n/** Refreshes tried per key before it is given up on. */\nexport const INDEX_REFRESH_MAX_ATTEMPTS = 3;\n/**\n * Wait before the first retry; each later retry waits twice as long. Long enough that a refusal\n * from the per-minute request window has a chance to clear (the list query has already retried\n * on its own by then).\n */\nexport const INDEX_REFRESH_RETRY_BASE_MS = 10_000;\n\nexport interface IndexRefreshTiming {\n debounceMs: number;\n hiddenTabDelayMs: number;\n jitterMs: number;\n maxWaitMs: number;\n maxAttempts: number;\n retryBaseMs: number;\n}\n\nconst DEFAULT_TIMING: IndexRefreshTiming = {\n debounceMs: INDEX_REFRESH_DEBOUNCE_MS,\n hiddenTabDelayMs: INDEX_REFRESH_HIDDEN_TAB_DELAY_MS,\n jitterMs: INDEX_REFRESH_JITTER_MS,\n maxWaitMs: INDEX_REFRESH_MAX_WAIT_MS,\n maxAttempts: INDEX_REFRESH_MAX_ATTEMPTS,\n retryBaseMs: INDEX_REFRESH_RETRY_BASE_MS,\n};\n\n/**\n * What each key has cost so far: settled (a refresh succeeded, or it ran out\n * of attempts), in flight, or failed N times and next due at an instant.\n * Exported for tests.\n */\nexport class IndexRefreshLedger {\n private readonly settled = new Set<string>();\n private readonly inFlight = new Set<string>();\n private readonly failures = new Map<string, { attempts: number; retryAt: number }>();\n\n constructor(private readonly timing: Pick<IndexRefreshTiming, 'maxAttempts' | 'retryBaseMs'>) {}\n\n /** The keys a refresh should be sent for now. */\n due(keys: readonly string[], now: number): string[] {\n return keys.filter((key) => {\n if (this.settled.has(key) || this.inFlight.has(key)) return false;\n const failure = this.failures.get(key);\n return failure === undefined || failure.retryAt <= now;\n });\n }\n\n /** When the earliest of these keys that failed is due again; `null` if none waits. */\n nextRetryAt(keys: readonly string[]): number | null {\n let next: number | null = null;\n for (const key of keys) {\n if (this.settled.has(key) || this.inFlight.has(key)) continue;\n const failure = this.failures.get(key);\n if (failure && (next === null || failure.retryAt < next)) next = failure.retryAt;\n }\n return next;\n }\n\n begin(keys: readonly string[]): void {\n for (const key of keys) this.inFlight.add(key);\n }\n\n succeed(keys: readonly string[]): void {\n for (const key of keys) {\n this.inFlight.delete(key);\n this.failures.delete(key);\n this.settled.add(key);\n }\n }\n\n fail(keys: readonly string[], now: number): void {\n for (const key of keys) {\n this.inFlight.delete(key);\n const attempts = (this.failures.get(key)?.attempts ?? 0) + 1;\n if (attempts >= this.timing.maxAttempts) {\n this.failures.delete(key);\n this.settled.add(key);\n continue;\n }\n this.failures.set(key, {\n attempts,\n retryAt: now + this.timing.retryBaseMs * 2 ** (attempts - 1),\n });\n }\n }\n}\n\n/**\n * Whether a list refresh answered. `useConversationList().refresh` resolves\n * with the query result rather than throwing, so a refused fetch shows as\n * `status: 'error'`. Exported for tests.\n */\nexport function refreshSucceeded(result: unknown): boolean {\n if (result === null || typeof result !== 'object') return true;\n const { status, isError } = result as { status?: unknown; isError?: unknown };\n return status !== 'error' && isError !== true;\n}\n\n/**\n * Run `refresh` for the `pending` keys (the threads, or thread versions, the\n * index knows and the list does not show), coalesced and retried as described\n * above. `enabled` false holds everything (no index yet, the first page not\n * read, or a fetch of the list already in flight); pending keys are looked at\n * again when it turns true.\n */\nexport function useIndexTriggeredRefresh({\n pending,\n refresh,\n enabled,\n tabShare,\n shareKey,\n timing,\n}: {\n pending: readonly string[];\n refresh: () => Promise<unknown>;\n enabled: boolean;\n /** The user's other open tabs, and this list's name among them (its first-page query key). */\n tabShare?: SessionListTabShare;\n shareKey?: string;\n /** Overrides for tests. */\n timing?: Partial<IndexRefreshTiming>;\n}): void {\n const resolvedTiming = { ...DEFAULT_TIMING, ...timing };\n const timingRef = useRef(resolvedTiming);\n timingRef.current = resolvedTiming;\n const ledgerRef = useRef<IndexRefreshLedger | null>(null);\n ledgerRef.current ??= new IndexRefreshLedger(resolvedTiming);\n const refreshRef = useRef(refresh);\n refreshRef.current = refresh;\n const tabShareRef = useRef(tabShare);\n tabShareRef.current = tabShare;\n // When the oldest key now waiting for quiet first became due.\n const firstDueAtRef = useRef<number | null>(null);\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n // Bumped when a refresh settles or a retry falls due, so the keys are looked at again.\n const [tick, setTick] = useState(0);\n const bump = () => {\n if (mountedRef.current) setTick((value) => value + 1);\n };\n\n // A stable key, so a fresh array with the same keys does not restart the wait.\n const pendingKey = JSON.stringify(pending);\n useEffect(() => {\n if (!enabled) return;\n const ledger = ledgerRef.current;\n if (!ledger) return;\n const { debounceMs, maxWaitMs, hiddenTabDelayMs, jitterMs } = timingRef.current;\n const keys = JSON.parse(pendingKey) as string[];\n const now = Date.now();\n const due = ledger.due(keys, now);\n if (due.length === 0) {\n firstDueAtRef.current = null;\n const retryAt = ledger.nextRetryAt(keys);\n if (retryAt === null) return;\n const retryId = setTimeout(bump, Math.max(0, retryAt - now));\n return () => clearTimeout(retryId);\n }\n // Another tab is reading this list: its page will be shared here. Look\n // again once its claim lapses, in case it never arrives.\n const claimedUntil = shareKey ? (tabShareRef.current?.claimedUntil(shareKey) ?? null) : null;\n if (claimedUntil !== null) {\n const claimId = setTimeout(bump, Math.max(0, claimedUntil - now));\n return () => clearTimeout(claimId);\n }\n firstDueAtRef.current ??= now;\n const isHidden = typeof document !== 'undefined' && document.visibilityState === 'hidden';\n const stagger = (isHidden ? hiddenTabDelayMs : 0) + Math.random() * jitterMs;\n const delay =\n Math.max(0, Math.min(debounceMs, firstDueAtRef.current + maxWaitMs - now)) + stagger;\n const flushId = setTimeout(() => {\n firstDueAtRef.current = null;\n const sending = ledger.due(keys, Date.now());\n if (sending.length === 0) return;\n if (shareKey && tabShareRef.current?.claimedUntil(shareKey) != null) {\n bump();\n return;\n }\n if (shareKey) tabShareRef.current?.claim(shareKey);\n ledger.begin(sending);\n void Promise.resolve()\n .then(() => refreshRef.current())\n .then(\n (result) => {\n if (refreshSucceeded(result)) ledger.succeed(sending);\n else ledger.fail(sending, Date.now());\n },\n () => ledger.fail(sending, Date.now()),\n )\n .finally(bump);\n }, delay);\n return () => clearTimeout(flushId);\n // `bump` only sets state; `tick` re-runs this after a settle or a retry falls due.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, pendingKey, shareKey, tick]);\n}\n"],"names":["_a"],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const react = require("react");
|
|
4
|
+
const conversationList = require("../agent-runtime/src/conversation-list.cjs");
|
|
5
|
+
const OFFLINE_SESSION_LIST_KEY = "session-list";
|
|
6
|
+
const MAX_OFFLINE_SESSION_LIST_PAGES = 4;
|
|
7
|
+
const RESTORED_UPDATED_AT = 1;
|
|
8
|
+
function isSessionListFirstPage(queryKey) {
|
|
9
|
+
return queryKey[0] === conversationList.CONVERSATION_LIST_QUERY_KEY_ROOT && queryKey[4] === "first-page";
|
|
10
|
+
}
|
|
11
|
+
function isFirstPageKey(queryKey) {
|
|
12
|
+
return Array.isArray(queryKey) && queryKey.length === 5 && isSessionListFirstPage(queryKey) && typeof queryKey[1] === "string" && typeof queryKey[2] === "string" && typeof queryKey[3] === "number";
|
|
13
|
+
}
|
|
14
|
+
function isConversationRow(row) {
|
|
15
|
+
if (typeof row !== "object" || row === null) return false;
|
|
16
|
+
const { threadId, title, updatedAt } = row;
|
|
17
|
+
return typeof threadId === "string" && typeof title === "string" && typeof updatedAt === "string";
|
|
18
|
+
}
|
|
19
|
+
function isConversationListPage(value) {
|
|
20
|
+
if (typeof value !== "object" || value === null) return false;
|
|
21
|
+
const { items, hasMore, totalCount } = value;
|
|
22
|
+
return Array.isArray(items) && items.every(isConversationRow) && typeof hasMore === "boolean" && (totalCount === null || typeof totalCount === "number");
|
|
23
|
+
}
|
|
24
|
+
function isKeptPage(value) {
|
|
25
|
+
if (typeof value !== "object" || value === null) return false;
|
|
26
|
+
const { queryKey, data } = value;
|
|
27
|
+
return isFirstPageKey(queryKey) && isConversationListPage(data);
|
|
28
|
+
}
|
|
29
|
+
function useOfflineSessionList({
|
|
30
|
+
queryClient,
|
|
31
|
+
offlineList
|
|
32
|
+
}) {
|
|
33
|
+
const mirror = offlineList == null ? void 0 : offlineList.mirror;
|
|
34
|
+
const ownerId = offlineList == null ? void 0 : offlineList.ownerId;
|
|
35
|
+
const boundOwner = react.useRef(null);
|
|
36
|
+
react.useEffect(() => {
|
|
37
|
+
if (!mirror || !ownerId) return;
|
|
38
|
+
if (boundOwner.current !== null && boundOwner.current !== ownerId) {
|
|
39
|
+
void queryClient.cancelQueries({ queryKey: [conversationList.CONVERSATION_LIST_QUERY_KEY_ROOT] });
|
|
40
|
+
queryClient.removeQueries({ queryKey: [conversationList.CONVERSATION_LIST_QUERY_KEY_ROOT] });
|
|
41
|
+
}
|
|
42
|
+
boundOwner.current = ownerId;
|
|
43
|
+
const boundAt = Date.now();
|
|
44
|
+
let stopped = false;
|
|
45
|
+
void mirror.loadList({ ownerId, listKey: OFFLINE_SESSION_LIST_KEY }).then((kept) => {
|
|
46
|
+
if (stopped || !kept || !Array.isArray(kept.value)) return;
|
|
47
|
+
for (const page of kept.value) {
|
|
48
|
+
if (!isKeptPage(page)) continue;
|
|
49
|
+
if (queryClient.getQueryData(page.queryKey) !== void 0) continue;
|
|
50
|
+
queryClient.setQueryData(page.queryKey, page.data, { updatedAt: RESTORED_UPDATED_AT });
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
const write = () => {
|
|
54
|
+
const pages = queryClient.getQueryCache().findAll({ predicate: (query) => isSessionListFirstPage(query.queryKey) }).filter(
|
|
55
|
+
(query) => query.state.status === "success" && query.state.dataUpdatedAt >= boundAt && isConversationListPage(query.state.data)
|
|
56
|
+
).sort((a, b) => b.state.dataUpdatedAt - a.state.dataUpdatedAt).slice(0, MAX_OFFLINE_SESSION_LIST_PAGES).map((query) => ({ queryKey: query.queryKey, data: query.state.data }));
|
|
57
|
+
if (pages.length > 0) mirror.writeList({ ownerId, listKey: OFFLINE_SESSION_LIST_KEY, value: pages });
|
|
58
|
+
};
|
|
59
|
+
const unsubscribe = queryClient.getQueryCache().subscribe((event) => {
|
|
60
|
+
if (event.type !== "updated" || event.action.type !== "success") return;
|
|
61
|
+
if (!isSessionListFirstPage(event.query.queryKey)) return;
|
|
62
|
+
if (event.query.state.dataUpdatedAt === RESTORED_UPDATED_AT) return;
|
|
63
|
+
write();
|
|
64
|
+
});
|
|
65
|
+
return () => {
|
|
66
|
+
stopped = true;
|
|
67
|
+
unsubscribe();
|
|
68
|
+
};
|
|
69
|
+
}, [queryClient, mirror, ownerId]);
|
|
70
|
+
}
|
|
71
|
+
exports.MAX_OFFLINE_SESSION_LIST_PAGES = MAX_OFFLINE_SESSION_LIST_PAGES;
|
|
72
|
+
exports.OFFLINE_SESSION_LIST_KEY = OFFLINE_SESSION_LIST_KEY;
|
|
73
|
+
exports.isSessionListFirstPage = isSessionListFirstPage;
|
|
74
|
+
exports.useOfflineSessionList = useOfflineSessionList;
|
|
75
|
+
//# sourceMappingURL=offline-session-list.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offline-session-list.cjs","sources":["../../src/threads/offline-session-list.ts"],"sourcesContent":["import {\n CONVERSATION_LIST_QUERY_KEY_ROOT,\n type ConversationListPage,\n type ThreadSnapshotMirror,\n} from '@athenaintel/agent-runtime';\nimport type { QueryClient, QueryKey } from '@tanstack/react-query';\nimport { useEffect, useRef } from 'react';\n\n/** Under this name the list's pages are kept, per owner. */\nexport const OFFLINE_SESSION_LIST_KEY = 'session-list';\n/** The first pages kept: one per filter the list was read with, the newest first. */\nexport const MAX_OFFLINE_SESSION_LIST_PAGES = 4;\n/**\n * Restored pages are stamped this old, so they paint at once and are read again on mount whenever\n * Athena can be reached (and never replace a page already read in this provider).\n */\nconst RESTORED_UPDATED_AT = 1;\n\ninterface KeptPage {\n queryKey: QueryKey;\n data: ConversationListPage;\n}\n\n/** A conversation list's live first page (`conversationListQueryKeys.firstPage`). */\nexport function isSessionListFirstPage(queryKey: QueryKey): boolean {\n return queryKey[0] === CONVERSATION_LIST_QUERY_KEY_ROOT && queryKey[4] === 'first-page';\n}\n\n/** Exactly `conversationListQueryKeys.firstPage(scopeKey, filterKey, pageSize)`. */\nfunction isFirstPageKey(queryKey: unknown): queryKey is QueryKey {\n return (\n Array.isArray(queryKey) &&\n queryKey.length === 5 &&\n isSessionListFirstPage(queryKey) &&\n typeof queryKey[1] === 'string' &&\n typeof queryKey[2] === 'string' &&\n typeof queryKey[3] === 'number'\n );\n}\n\nfunction isConversationRow(row: unknown): boolean {\n if (typeof row !== 'object' || row === null) return false;\n const { threadId, title, updatedAt } = row as Record<string, unknown>;\n return typeof threadId === 'string' && typeof title === 'string' && typeof updatedAt === 'string';\n}\n\n/** A page the list can render: its rows carry the fields every row reads. */\nfunction isConversationListPage(value: unknown): value is ConversationListPage {\n if (typeof value !== 'object' || value === null) return false;\n const { items, hasMore, totalCount } = value as Record<string, unknown>;\n return (\n Array.isArray(items) &&\n items.every(isConversationRow) &&\n typeof hasMore === 'boolean' &&\n (totalCount === null || typeof totalCount === 'number')\n );\n}\n\nfunction isKeptPage(value: unknown): value is KeptPage {\n if (typeof value !== 'object' || value === null) return false;\n const { queryKey, data } = value as Record<string, unknown>;\n return isFirstPageKey(queryKey) && isConversationListPage(data);\n}\n\n/**\n * The session list's first pages, kept on this device sealed under the host's key\n * (`offlineList`'s mirror, `AthenaProvider`'s `offlineHistory`): restored into the list's own query\n * client before it is read, so the list paints at once and reads while Athena can't be reached,\n * and written back (debounced by the mirror) each time a first page is read. Without `offlineList`,\n * nothing.\n *\n * Owner-bound. A list kept for one owner is never restored for another, and a change of owner\n * drops every page of the list's cache before the new owner's are restored (in API-key mode two\n * people read the same list keys); only pages read since the owner was bound are kept for them. A\n * restored page that is not a list page the rows can render is left out.\n */\nexport function useOfflineSessionList({\n queryClient,\n offlineList,\n}: {\n queryClient: QueryClient;\n offlineList: { mirror: ThreadSnapshotMirror; ownerId: string } | undefined;\n}): void {\n const mirror = offlineList?.mirror;\n const ownerId = offlineList?.ownerId;\n const boundOwner = useRef<string | null>(null);\n useEffect(() => {\n if (!mirror || !ownerId) return;\n if (boundOwner.current !== null && boundOwner.current !== ownerId) {\n void queryClient.cancelQueries({ queryKey: [CONVERSATION_LIST_QUERY_KEY_ROOT] });\n queryClient.removeQueries({ queryKey: [CONVERSATION_LIST_QUERY_KEY_ROOT] });\n }\n boundOwner.current = ownerId;\n const boundAt = Date.now();\n let stopped = false;\n void mirror.loadList({ ownerId, listKey: OFFLINE_SESSION_LIST_KEY }).then((kept) => {\n if (stopped || !kept || !Array.isArray(kept.value)) return;\n for (const page of kept.value) {\n if (!isKeptPage(page)) continue;\n if (queryClient.getQueryData(page.queryKey) !== undefined) continue;\n queryClient.setQueryData(page.queryKey, page.data, { updatedAt: RESTORED_UPDATED_AT });\n }\n });\n const write = (): void => {\n const pages: KeptPage[] = queryClient\n .getQueryCache()\n .findAll({ predicate: (query) => isSessionListFirstPage(query.queryKey) })\n .filter(\n (query) =>\n query.state.status === 'success' &&\n query.state.dataUpdatedAt >= boundAt &&\n isConversationListPage(query.state.data),\n )\n .sort((a, b) => b.state.dataUpdatedAt - a.state.dataUpdatedAt)\n .slice(0, MAX_OFFLINE_SESSION_LIST_PAGES)\n .map((query) => ({ queryKey: query.queryKey, data: query.state.data as ConversationListPage }));\n if (pages.length > 0) mirror.writeList({ ownerId, listKey: OFFLINE_SESSION_LIST_KEY, value: pages });\n };\n const unsubscribe = queryClient.getQueryCache().subscribe((event) => {\n if (event.type !== 'updated' || event.action.type !== 'success') return;\n if (!isSessionListFirstPage(event.query.queryKey)) return;\n // A page restored from the device is not news to write back.\n if (event.query.state.dataUpdatedAt === RESTORED_UPDATED_AT) return;\n write();\n });\n return () => {\n stopped = true;\n unsubscribe();\n };\n }, [queryClient, mirror, ownerId]);\n}\n"],"names":["CONVERSATION_LIST_QUERY_KEY_ROOT","useRef","useEffect"],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ThreadSnapshotMirror } from '../agent-runtime/src/index';
|
|
2
|
+
import type { QueryClient, QueryKey } from '@tanstack/react-query';
|
|
3
|
+
/** Under this name the list's pages are kept, per owner. */
|
|
4
|
+
export declare const OFFLINE_SESSION_LIST_KEY = "session-list";
|
|
5
|
+
/** The first pages kept: one per filter the list was read with, the newest first. */
|
|
6
|
+
export declare const MAX_OFFLINE_SESSION_LIST_PAGES = 4;
|
|
7
|
+
/** A conversation list's live first page (`conversationListQueryKeys.firstPage`). */
|
|
8
|
+
export declare function isSessionListFirstPage(queryKey: QueryKey): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* The session list's first pages, kept on this device sealed under the host's key
|
|
11
|
+
* (`offlineList`'s mirror, `AthenaProvider`'s `offlineHistory`): restored into the list's own query
|
|
12
|
+
* client before it is read, so the list paints at once and reads while Athena can't be reached,
|
|
13
|
+
* and written back (debounced by the mirror) each time a first page is read. Without `offlineList`,
|
|
14
|
+
* nothing.
|
|
15
|
+
*
|
|
16
|
+
* Owner-bound. A list kept for one owner is never restored for another, and a change of owner
|
|
17
|
+
* drops every page of the list's cache before the new owner's are restored (in API-key mode two
|
|
18
|
+
* people read the same list keys); only pages read since the owner was bound are kept for them. A
|
|
19
|
+
* restored page that is not a list page the rows can render is left out.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useOfflineSessionList({ queryClient, offlineList, }: {
|
|
22
|
+
queryClient: QueryClient;
|
|
23
|
+
offlineList: {
|
|
24
|
+
mirror: ThreadSnapshotMirror;
|
|
25
|
+
ownerId: string;
|
|
26
|
+
} | undefined;
|
|
27
|
+
}): void;
|