@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 @@
|
|
|
1
|
+
{"version":3,"file":"thread-snapshot-mirror.cjs","sources":["../../../../agent-runtime/src/thread-snapshot-mirror.ts"],"sourcesContent":["import {\n type IdbDatabase,\n idbGlobals,\n lazySealedDatabase,\n openJson,\n requestToPromise,\n sealJson,\n sha256Hex,\n transactionDone,\n} from \"./sealed-idb\";\nimport type { DeepAgentStreamValues } from \"./types\";\n\n/**\n * A durable, encrypted mirror of the thread snapshot cache (`thread-snapshot-cache.ts`) in the\n * browser's IndexedDB, so a reload paints a recently visited thread from its last-known messages,\n * and a thread can be read while the transport cannot connect at all.\n *\n * - **Sealed.** Each record is AES-GCM-256 with a fresh IV under the host's key for its owner\n * (`getKey`: Olympus a non-extractable key in its own keystore, Midas a key main keeps with the\n * OS keychain). The owner and the thread are hashed for the index and bound to the record as\n * additional data, so the database names no one and a record moved to another owner or thread\n * fails to open (and is dropped). No key, no mirror: every write and read is then a no-op.\n * - **Bounded.** Writes are debounced per thread and never taken mid-stream (a state with a live\n * run is replaced by its resting successor within seconds), transcripts longer than\n * `maxMessages` are not kept (an older, shorter record is removed rather than left to seed),\n * and an owner keeps its `maxPerOwner` most recent threads.\n * - **Never in the way.** Every failure degrades to \"no mirror\": a blocked or missing IndexedDB\n * (private browsing, quota, SSR) must never break the wire path.\n * - **Versioned.** A record a newer build wrote is never read, overwritten or pruned by this one;\n * only removing the person's records altogether (an identity change, a sign-out) removes it.\n */\n\nexport const THREAD_SNAPSHOT_MIRROR_DATABASE = \"athena-thread-snapshots:v2\";\n/** The sealed record's format; older builds leave a newer one alone. */\nexport const THREAD_SNAPSHOT_MIRROR_FORMAT = 1;\n/** Threads mirrored per owner; the least recently captured beyond this is pruned after each write. */\nexport const MAX_MIRRORED_SNAPSHOTS_PER_OWNER = 30;\n/** Transcripts longer than this are not mirrored — sealing them would cost more than the seed saves. */\nexport const MAX_MIRRORED_SNAPSHOT_MESSAGES = 150;\n/** Trailing debounce per thread: a streaming thread remembers a state per token. */\nexport const SNAPSHOT_MIRROR_DEBOUNCE_MS = 1_500;\n\nconst DATABASE_VERSION = 1;\nconst SNAPSHOTS_STORE = \"snapshots\";\nconst LISTS_STORE = \"lists\";\nconst BY_OWNER = \"byOwner\";\nconst BY_OWNER_AT = \"byOwnerAt\";\n\nexport interface MirroredThreadSnapshot {\n threadId: string;\n state: DeepAgentStreamValues;\n /** Capture time (epoch ms). */\n at: number;\n}\n\nexport interface MirroredList {\n value: unknown;\n /** When it was written (epoch ms). */\n at: number;\n}\n\nexport interface ThreadSnapshotMirror {\n /** The owner's mirrored snapshots, oldest first. Resolves `[]` on any fault. */\n load(ownerId: string): Promise<MirroredThreadSnapshot[]>;\n /** Mirror a remembered state (debounced per thread; mid-stream states are skipped). */\n write(input: { ownerId: string; threadId: string; state: DeepAgentStreamValues; at: number }): void;\n remove(input: { ownerId: string; threadId: string }): void;\n /** A session list's page as the host last read it, for reading it offline. */\n writeList(input: { ownerId: string; listKey: string; value: unknown }): void;\n loadList(input: { ownerId: string; listKey: string }): Promise<MirroredList | null>;\n /** Drop every record of one owner (an identity change). */\n clearOwner(ownerId: string): Promise<void>;\n /** Drop every record (a sign-out, a workspace switch). */\n clearAll(): Promise<void>;\n /** Write debounced records now (tests, page hide). */\n flush(): Promise<void>;\n}\n\n/**\n * What a key is asked for: reading what is already kept (`read`) or keeping something new\n * (`write`). A host may let what it kept be read where it would keep nothing new, e.g. while its\n * deployment's policy for device copies is not known yet.\n */\nexport type ThreadSnapshotKeyPurpose = \"read\" | \"write\";\n\nexport interface ThreadSnapshotMirrorOptions {\n /** The owner's AES-GCM key, or `null` when the host keeps no mirror for it (no key, policy off). */\n getKey: (ownerId: string, purpose: ThreadSnapshotKeyPurpose) => Promise<CryptoKey | null>;\n /** An `IDBFactory` (the browser's `indexedDB` by default; a fake one in tests). */\n factory?: object;\n databaseName?: string;\n debounceMs?: number;\n maxPerOwner?: number;\n maxMessages?: number;\n}\n\ninterface SnapshotRecord {\n key: string;\n owner: string;\n at: number;\n format: number;\n sealed: Uint8Array;\n}\n\ninterface ListRecord {\n key: string;\n owner: string;\n at: number;\n format: number;\n sealed: Uint8Array;\n}\n\nfunction upgradeMirrorDatabase(db: IdbDatabase): void {\n if (!db.objectStoreNames.contains(SNAPSHOTS_STORE)) {\n const store = db.createObjectStore(SNAPSHOTS_STORE, { keyPath: \"key\" });\n store.createIndex(BY_OWNER, \"owner\", { unique: false });\n store.createIndex(BY_OWNER_AT, [\"owner\", \"at\"], { unique: false });\n }\n if (!db.objectStoreNames.contains(LISTS_STORE)) {\n const lists = db.createObjectStore(LISTS_STORE, { keyPath: \"key\" });\n lists.createIndex(BY_OWNER, \"owner\", { unique: false });\n }\n}\n\n/**\n * Whether a remembered state is a resting transcript: no run in flight (its own or an out-of-band\n * one) and its messages present. Only such a state is kept, and read while Athena can't be reached;\n * a mid-stream state is a partial transcript.\n */\nexport function isRestingThreadSnapshot(state: DeepAgentStreamValues): boolean {\n const run = state.runs?.[0];\n if (run && run.status === \"running\") return false;\n if (state.outOfBandRunActive === true) return false;\n return Array.isArray(state.messages);\n}\n\n/**\n * What the mirror does with a remembered state: `persist` a resting transcript within the size\n * bound; `skip` a mid-stream state (it arrives per token and its resting successor follows within\n * seconds — the last resting record stays); `invalidate` when the transcript has outgrown the\n * mirror — a stale, shorter record would otherwise seed the next reload until the hello.\n */\nexport function classifyThreadSnapshotForMirror(\n state: DeepAgentStreamValues,\n maxMessages: number = MAX_MIRRORED_SNAPSHOT_MESSAGES,\n): \"persist\" | \"skip\" | \"invalidate\" {\n if (!isRestingThreadSnapshot(state)) return \"skip\";\n return (state.messages?.length ?? 0) <= maxMessages ? \"persist\" : \"invalidate\";\n}\n\n/** A record this build may replace or delete: none, or one in a format it writes itself. */\nfunction isOwnFormat(record: unknown): boolean {\n if (typeof record !== \"object\" || record === null) return true;\n const format = (record as { format?: unknown }).format;\n return typeof format !== \"number\" || format <= THREAD_SNAPSHOT_MIRROR_FORMAT;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nexport function createThreadSnapshotMirror({\n getKey,\n factory = idbGlobals.indexedDB,\n databaseName = THREAD_SNAPSHOT_MIRROR_DATABASE,\n debounceMs = SNAPSHOT_MIRROR_DEBOUNCE_MS,\n maxPerOwner = MAX_MIRRORED_SNAPSHOTS_PER_OWNER,\n maxMessages = MAX_MIRRORED_SNAPSHOT_MESSAGES,\n}: ThreadSnapshotMirrorOptions): ThreadSnapshotMirror {\n const database = lazySealedDatabase({\n factory,\n name: databaseName,\n version: DATABASE_VERSION,\n upgrade: upgradeMirrorDatabase,\n });\n const keyOf = async (ownerId: string, purpose: ThreadSnapshotKeyPurpose): Promise<CryptoKey | null> => {\n try {\n return await getKey(ownerId, purpose);\n } catch {\n return null;\n }\n };\n const aadOf = (kind: string, owner: string, key: string): string =>\n `athena-thread-snapshot|${THREAD_SNAPSHOT_MIRROR_FORMAT}|${kind}|${owner}|${key}`;\n\n const pending = new Map<\n string,\n { input: { ownerId: string; threadId: string; state: DeepAgentStreamValues; at: number }; timer: ReturnType<typeof setTimeout> }\n >();\n const pendingLists = new Map<\n string,\n { input: { ownerId: string; listKey: string; value: unknown }; timer: ReturnType<typeof setTimeout> }\n >();\n // Writes are serialized so a flush never races a clear.\n let queue: Promise<void> = Promise.resolve();\n const enqueue = (task: () => Promise<void>): Promise<void> => {\n queue = queue.then(task, task).catch(() => {});\n return queue;\n };\n\n const pruneOwner = async (db: IdbDatabase, owner: string): Promise<void> => {\n const KeyRange = idbGlobals.IDBKeyRange;\n if (!KeyRange) return;\n const tx = db.transaction(SNAPSHOTS_STORE, \"readwrite\");\n const store = tx.objectStore(SNAPSHOTS_STORE);\n const index = store.index(BY_OWNER_AT);\n // Key cursor, newest first: bookkeeping never loads the sealed payloads of the records it keeps.\n const range = KeyRange.bound([owner, Number.NEGATIVE_INFINITY], [owner, Number.POSITIVE_INFINITY]);\n const beyond: unknown[] = [];\n await new Promise<void>((resolve, reject) => {\n let kept = 0;\n const request = index.openKeyCursor(range, \"prev\");\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n resolve();\n return;\n }\n kept += 1;\n if (kept > maxPerOwner) beyond.push(cursor.primaryKey);\n cursor.continue();\n };\n request.onerror = () => reject(request.error ?? new Error(\"IndexedDB cursor failed\"));\n });\n // A newer build's record is left to that build's own bound.\n for (const key of beyond) {\n if (isOwnFormat(await requestToPromise(store.get(key)))) store.delete(key);\n }\n await transactionDone(tx);\n };\n\n const put = (input: { ownerId: string; threadId: string; state: DeepAgentStreamValues; at: number }) =>\n enqueue(async () => {\n const db = await database();\n if (!db) return;\n const cryptoKey = await keyOf(input.ownerId, \"write\");\n if (!cryptoKey) return;\n const owner = await sha256Hex(input.ownerId);\n const key = await sha256Hex(`${input.ownerId}|${input.threadId}`);\n const sealed = await sealJson({\n key: cryptoKey,\n value: { threadId: input.threadId, state: input.state },\n aad: aadOf(\"snapshot\", owner, key),\n });\n const tx = db.transaction(SNAPSHOTS_STORE, \"readwrite\");\n const store = tx.objectStore(SNAPSHOTS_STORE);\n // A newer build's record of the thread stays as that build wrote it.\n if (isOwnFormat(await requestToPromise(store.get(key)))) {\n store.put({\n key,\n owner,\n at: input.at,\n format: THREAD_SNAPSHOT_MIRROR_FORMAT,\n sealed,\n } satisfies SnapshotRecord);\n }\n await transactionDone(tx);\n await pruneOwner(db, owner);\n });\n\n const deleteSnapshot = (input: { ownerId: string; threadId: string }) =>\n enqueue(async () => {\n const db = await database();\n if (!db) return;\n const key = await sha256Hex(`${input.ownerId}|${input.threadId}`);\n const tx = db.transaction(SNAPSHOTS_STORE, \"readwrite\");\n const store = tx.objectStore(SNAPSHOTS_STORE);\n if (isOwnFormat(await requestToPromise(store.get(key)))) store.delete(key);\n await transactionDone(tx);\n });\n\n const pendingKey = (ownerId: string, threadId: string) => `${ownerId}\\u0000${threadId}`;\n\n const flushPending = (key: string): Promise<void> => {\n const entry = pending.get(key);\n if (!entry) return Promise.resolve();\n pending.delete(key);\n clearTimeout(entry.timer);\n return put(entry.input);\n };\n\n const putList = (input: { ownerId: string; listKey: string; value: unknown }) =>\n enqueue(async () => {\n const db = await database();\n if (!db) return;\n const cryptoKey = await keyOf(input.ownerId, \"write\");\n if (!cryptoKey) return;\n const owner = await sha256Hex(input.ownerId);\n const key = await sha256Hex(`${input.ownerId}|list|${input.listKey}`);\n const sealed = await sealJson({ key: cryptoKey, value: input.value, aad: aadOf(\"list\", owner, key) });\n const tx = db.transaction(LISTS_STORE, \"readwrite\");\n const store = tx.objectStore(LISTS_STORE);\n if (isOwnFormat(await requestToPromise(store.get(key)))) {\n store.put({\n key,\n owner,\n at: Date.now(),\n format: THREAD_SNAPSHOT_MIRROR_FORMAT,\n sealed,\n } satisfies ListRecord);\n }\n await transactionDone(tx);\n });\n\n const flushList = (key: string): Promise<void> => {\n const entry = pendingLists.get(key);\n if (!entry) return Promise.resolve();\n pendingLists.delete(key);\n clearTimeout(entry.timer);\n return putList(entry.input);\n };\n\n const dropPendingOf = (ownerId: string | null): void => {\n for (const [key, entry] of pending) {\n if (ownerId === null || entry.input.ownerId === ownerId) {\n clearTimeout(entry.timer);\n pending.delete(key);\n }\n }\n for (const [key, entry] of pendingLists) {\n if (ownerId === null || entry.input.ownerId === ownerId) {\n clearTimeout(entry.timer);\n pendingLists.delete(key);\n }\n }\n };\n\n return {\n async load(ownerId) {\n try {\n const db = await database();\n if (!db) return [];\n const cryptoKey = await keyOf(ownerId, \"read\");\n if (!cryptoKey) return [];\n const owner = await sha256Hex(ownerId);\n const records = (await requestToPromise(\n db.transaction(SNAPSHOTS_STORE, \"readonly\").objectStore(SNAPSHOTS_STORE).index(BY_OWNER).getAll(owner),\n )) as SnapshotRecord[];\n const loaded: MirroredThreadSnapshot[] = [];\n const unreadable: string[] = [];\n for (const record of records) {\n if (!record || record.format > THREAD_SNAPSHOT_MIRROR_FORMAT) continue;\n try {\n const value = await openJson({\n key: cryptoKey,\n sealed: record.sealed,\n aad: aadOf(\"snapshot\", owner, record.key),\n });\n if (\n isRecord(value) &&\n typeof value.threadId === \"string\" &&\n isRecord(value.state) &&\n typeof record.at === \"number\"\n ) {\n loaded.push({ threadId: value.threadId, state: value.state as DeepAgentStreamValues, at: record.at });\n }\n } catch {\n unreadable.push(record.key);\n }\n }\n if (unreadable.length > 0) {\n void enqueue(async () => {\n const tx = db.transaction(SNAPSHOTS_STORE, \"readwrite\");\n for (const key of unreadable) tx.objectStore(SNAPSHOTS_STORE).delete(key);\n await transactionDone(tx);\n });\n }\n return loaded.sort((a, b) => a.at - b.at);\n } catch {\n return [];\n }\n },\n write(input) {\n const key = pendingKey(input.ownerId, input.threadId);\n const verdict = classifyThreadSnapshotForMirror(input.state, maxMessages);\n if (verdict === \"invalidate\") {\n const existing = pending.get(key);\n if (existing) clearTimeout(existing.timer);\n pending.delete(key);\n void deleteSnapshot(input);\n return;\n }\n if (verdict === \"skip\") return;\n const existing = pending.get(key);\n if (existing) clearTimeout(existing.timer);\n pending.set(key, {\n input,\n timer: setTimeout(() => {\n void flushPending(key);\n }, debounceMs),\n });\n },\n remove(input) {\n const key = pendingKey(input.ownerId, input.threadId);\n const existing = pending.get(key);\n if (existing) clearTimeout(existing.timer);\n pending.delete(key);\n void deleteSnapshot(input);\n },\n writeList(input) {\n const key = pendingKey(input.ownerId, `list:${input.listKey}`);\n const existing = pendingLists.get(key);\n if (existing) clearTimeout(existing.timer);\n pendingLists.set(key, {\n input,\n timer: setTimeout(() => {\n void flushList(key);\n }, debounceMs),\n });\n },\n async loadList({ ownerId, listKey }) {\n try {\n const db = await database();\n if (!db) return null;\n const cryptoKey = await keyOf(ownerId, \"read\");\n if (!cryptoKey) return null;\n const owner = await sha256Hex(ownerId);\n const key = await sha256Hex(`${ownerId}|list|${listKey}`);\n const record = (await requestToPromise(\n db.transaction(LISTS_STORE, \"readonly\").objectStore(LISTS_STORE).get(key),\n )) as ListRecord | undefined;\n if (!record || record.format > THREAD_SNAPSHOT_MIRROR_FORMAT || record.owner !== owner) return null;\n try {\n const value = await openJson({ key: cryptoKey, sealed: record.sealed, aad: aadOf(\"list\", owner, key) });\n return { value, at: record.at };\n } catch {\n return null;\n }\n } catch {\n return null;\n }\n },\n clearOwner(ownerId) {\n dropPendingOf(ownerId);\n return enqueue(async () => {\n const db = await database();\n if (!db) return;\n const owner = await sha256Hex(ownerId);\n const tx = db.transaction([SNAPSHOTS_STORE, LISTS_STORE], \"readwrite\");\n for (const storeName of [SNAPSHOTS_STORE, LISTS_STORE]) {\n const store = tx.objectStore(storeName);\n const keys = await requestToPromise(store.index(BY_OWNER).getAllKeys(owner));\n for (const key of keys) store.delete(key);\n }\n await transactionDone(tx);\n });\n },\n clearAll() {\n dropPendingOf(null);\n return enqueue(async () => {\n const db = await database();\n if (!db) return;\n const tx = db.transaction([SNAPSHOTS_STORE, LISTS_STORE], \"readwrite\");\n tx.objectStore(SNAPSHOTS_STORE).clear();\n tx.objectStore(LISTS_STORE).clear();\n await transactionDone(tx);\n });\n },\n async flush() {\n await Promise.all([...pending.keys()].map(flushPending));\n await Promise.all([...pendingLists.keys()].map(flushList));\n await queue;\n },\n };\n}\n"],"names":["idbGlobals","lazySealedDatabase","requestToPromise","transactionDone","sha256Hex","sealJson","openJson","existing"],"mappings":";;;AAgCO,MAAM,kCAAkC;AAExC,MAAM,gCAAgC;AAEtC,MAAM,mCAAmC;AAEzC,MAAM,iCAAiC;AAEvC,MAAM,8BAA8B;AAE3C,MAAM,mBAAmB;AACzB,MAAM,kBAAkB;AACxB,MAAM,cAAc;AACpB,MAAM,WAAW;AACjB,MAAM,cAAc;AAkEpB,SAAS,sBAAsB,IAAuB;AACpD,MAAI,CAAC,GAAG,iBAAiB,SAAS,eAAe,GAAG;AAClD,UAAM,QAAQ,GAAG,kBAAkB,iBAAiB,EAAE,SAAS,OAAO;AACtE,UAAM,YAAY,UAAU,SAAS,EAAE,QAAQ,OAAO;AACtD,UAAM,YAAY,aAAa,CAAC,SAAS,IAAI,GAAG,EAAE,QAAQ,OAAO;AAAA,EACnE;AACA,MAAI,CAAC,GAAG,iBAAiB,SAAS,WAAW,GAAG;AAC9C,UAAM,QAAQ,GAAG,kBAAkB,aAAa,EAAE,SAAS,OAAO;AAClE,UAAM,YAAY,UAAU,SAAS,EAAE,QAAQ,OAAO;AAAA,EACxD;AACF;AAOO,SAAS,wBAAwB,OAAuC;;AAC7E,QAAM,OAAM,WAAM,SAAN,mBAAa;AACzB,MAAI,OAAO,IAAI,WAAW,UAAW,QAAO;AAC5C,MAAI,MAAM,uBAAuB,KAAM,QAAO;AAC9C,SAAO,MAAM,QAAQ,MAAM,QAAQ;AACrC;AAQO,SAAS,gCACd,OACA,cAAsB,gCACa;;AACnC,MAAI,CAAC,wBAAwB,KAAK,EAAG,QAAO;AAC5C,YAAQ,WAAM,aAAN,mBAAgB,WAAU,MAAM,cAAc,YAAY;AACpE;AAGA,SAAS,YAAY,QAA0B;AAC7C,MAAI,OAAO,WAAW,YAAY,WAAW,KAAM,QAAO;AAC1D,QAAM,SAAU,OAAgC;AAChD,SAAO,OAAO,WAAW,YAAY,UAAU;AACjD;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEO,SAAS,2BAA2B;AAAA,EACzC;AAAA,EACA,UAAUA,UAAAA,WAAW;AAAA,EACrB,eAAe;AAAA,EACf,aAAa;AAAA,EACb,cAAc;AAAA,EACd,cAAc;AAChB,GAAsD;AACpD,QAAM,WAAWC,UAAAA,mBAAmB;AAAA,IAClC;AAAA,IACA,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,EAAA,CACV;AACD,QAAM,QAAQ,OAAO,SAAiB,YAAiE;AACrG,QAAI;AACF,aAAO,MAAM,OAAO,SAAS,OAAO;AAAA,IACtC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,QAAQ,CAAC,MAAc,OAAe,QAC1C,0BAA0B,6BAA6B,IAAI,IAAI,IAAI,KAAK,IAAI,GAAG;AAEjF,QAAM,8BAAc,IAAA;AAIpB,QAAM,mCAAmB,IAAA;AAKzB,MAAI,QAAuB,QAAQ,QAAA;AACnC,QAAM,UAAU,CAAC,SAA6C;AAC5D,YAAQ,MAAM,KAAK,MAAM,IAAI,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAC7C,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,OAAO,IAAiB,UAAiC;AAC1E,UAAM,WAAWD,UAAAA,WAAW;AAC5B,QAAI,CAAC,SAAU;AACf,UAAM,KAAK,GAAG,YAAY,iBAAiB,WAAW;AACtD,UAAM,QAAQ,GAAG,YAAY,eAAe;AAC5C,UAAM,QAAQ,MAAM,MAAM,WAAW;AAErC,UAAM,QAAQ,SAAS,MAAM,CAAC,OAAO,OAAO,iBAAiB,GAAG,CAAC,OAAO,OAAO,iBAAiB,CAAC;AACjG,UAAM,SAAoB,CAAA;AAC1B,UAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,UAAI,OAAO;AACX,YAAM,UAAU,MAAM,cAAc,OAAO,MAAM;AACjD,cAAQ,YAAY,MAAM;AACxB,cAAM,SAAS,QAAQ;AACvB,YAAI,CAAC,QAAQ;AACX,kBAAA;AACA;AAAA,QACF;AACA,gBAAQ;AACR,YAAI,OAAO,YAAa,QAAO,KAAK,OAAO,UAAU;AACrD,eAAO,SAAA;AAAA,MACT;AACA,cAAQ,UAAU,MAAM,OAAO,QAAQ,SAAS,IAAI,MAAM,yBAAyB,CAAC;AAAA,IACtF,CAAC;AAED,eAAW,OAAO,QAAQ;AACxB,UAAI,YAAY,MAAME,2BAAiB,MAAM,IAAI,GAAG,CAAC,CAAC,EAAG,OAAM,OAAO,GAAG;AAAA,IAC3E;AACA,UAAMC,UAAAA,gBAAgB,EAAE;AAAA,EAC1B;AAEA,QAAM,MAAM,CAAC,UACX,QAAQ,YAAY;AAClB,UAAM,KAAK,MAAM,SAAA;AACjB,QAAI,CAAC,GAAI;AACT,UAAM,YAAY,MAAM,MAAM,MAAM,SAAS,OAAO;AACpD,QAAI,CAAC,UAAW;AAChB,UAAM,QAAQ,MAAMC,oBAAU,MAAM,OAAO;AAC3C,UAAM,MAAM,MAAMA,UAAAA,UAAU,GAAG,MAAM,OAAO,IAAI,MAAM,QAAQ,EAAE;AAChE,UAAM,SAAS,MAAMC,mBAAS;AAAA,MAC5B,KAAK;AAAA,MACL,OAAO,EAAE,UAAU,MAAM,UAAU,OAAO,MAAM,MAAA;AAAA,MAChD,KAAK,MAAM,YAAY,OAAO,GAAG;AAAA,IAAA,CAClC;AACD,UAAM,KAAK,GAAG,YAAY,iBAAiB,WAAW;AACtD,UAAM,QAAQ,GAAG,YAAY,eAAe;AAE5C,QAAI,YAAY,MAAMH,2BAAiB,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG;AACvD,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA,IAAI,MAAM;AAAA,QACV,QAAQ;AAAA,QACR;AAAA,MAAA,CACwB;AAAA,IAC5B;AACA,UAAMC,UAAAA,gBAAgB,EAAE;AACxB,UAAM,WAAW,IAAI,KAAK;AAAA,EAC5B,CAAC;AAEH,QAAM,iBAAiB,CAAC,UACtB,QAAQ,YAAY;AAClB,UAAM,KAAK,MAAM,SAAA;AACjB,QAAI,CAAC,GAAI;AACT,UAAM,MAAM,MAAMC,UAAAA,UAAU,GAAG,MAAM,OAAO,IAAI,MAAM,QAAQ,EAAE;AAChE,UAAM,KAAK,GAAG,YAAY,iBAAiB,WAAW;AACtD,UAAM,QAAQ,GAAG,YAAY,eAAe;AAC5C,QAAI,YAAY,MAAMF,2BAAiB,MAAM,IAAI,GAAG,CAAC,CAAC,EAAG,OAAM,OAAO,GAAG;AACzE,UAAMC,UAAAA,gBAAgB,EAAE;AAAA,EAC1B,CAAC;AAEH,QAAM,aAAa,CAAC,SAAiB,aAAqB,GAAG,OAAO,KAAS,QAAQ;AAErF,QAAM,eAAe,CAAC,QAA+B;AACnD,UAAM,QAAQ,QAAQ,IAAI,GAAG;AAC7B,QAAI,CAAC,MAAO,QAAO,QAAQ,QAAA;AAC3B,YAAQ,OAAO,GAAG;AAClB,iBAAa,MAAM,KAAK;AACxB,WAAO,IAAI,MAAM,KAAK;AAAA,EACxB;AAEA,QAAM,UAAU,CAAC,UACf,QAAQ,YAAY;AAClB,UAAM,KAAK,MAAM,SAAA;AACjB,QAAI,CAAC,GAAI;AACT,UAAM,YAAY,MAAM,MAAM,MAAM,SAAS,OAAO;AACpD,QAAI,CAAC,UAAW;AAChB,UAAM,QAAQ,MAAMC,oBAAU,MAAM,OAAO;AAC3C,UAAM,MAAM,MAAMA,UAAAA,UAAU,GAAG,MAAM,OAAO,SAAS,MAAM,OAAO,EAAE;AACpE,UAAM,SAAS,MAAMC,UAAAA,SAAS,EAAE,KAAK,WAAW,OAAO,MAAM,OAAO,KAAK,MAAM,QAAQ,OAAO,GAAG,GAAG;AACpG,UAAM,KAAK,GAAG,YAAY,aAAa,WAAW;AAClD,UAAM,QAAQ,GAAG,YAAY,WAAW;AACxC,QAAI,YAAY,MAAMH,2BAAiB,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG;AACvD,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA,IAAI,KAAK,IAAA;AAAA,QACT,QAAQ;AAAA,QACR;AAAA,MAAA,CACoB;AAAA,IACxB;AACA,UAAMC,UAAAA,gBAAgB,EAAE;AAAA,EAC1B,CAAC;AAEH,QAAM,YAAY,CAAC,QAA+B;AAChD,UAAM,QAAQ,aAAa,IAAI,GAAG;AAClC,QAAI,CAAC,MAAO,QAAO,QAAQ,QAAA;AAC3B,iBAAa,OAAO,GAAG;AACvB,iBAAa,MAAM,KAAK;AACxB,WAAO,QAAQ,MAAM,KAAK;AAAA,EAC5B;AAEA,QAAM,gBAAgB,CAAC,YAAiC;AACtD,eAAW,CAAC,KAAK,KAAK,KAAK,SAAS;AAClC,UAAI,YAAY,QAAQ,MAAM,MAAM,YAAY,SAAS;AACvD,qBAAa,MAAM,KAAK;AACxB,gBAAQ,OAAO,GAAG;AAAA,MACpB;AAAA,IACF;AACA,eAAW,CAAC,KAAK,KAAK,KAAK,cAAc;AACvC,UAAI,YAAY,QAAQ,MAAM,MAAM,YAAY,SAAS;AACvD,qBAAa,MAAM,KAAK;AACxB,qBAAa,OAAO,GAAG;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,KAAK,SAAS;AAClB,UAAI;AACF,cAAM,KAAK,MAAM,SAAA;AACjB,YAAI,CAAC,GAAI,QAAO,CAAA;AAChB,cAAM,YAAY,MAAM,MAAM,SAAS,MAAM;AAC7C,YAAI,CAAC,UAAW,QAAO,CAAA;AACvB,cAAM,QAAQ,MAAMC,UAAAA,UAAU,OAAO;AACrC,cAAM,UAAW,MAAMF,UAAAA;AAAAA,UACrB,GAAG,YAAY,iBAAiB,UAAU,EAAE,YAAY,eAAe,EAAE,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,QAAA;AAEvG,cAAM,SAAmC,CAAA;AACzC,cAAM,aAAuB,CAAA;AAC7B,mBAAW,UAAU,SAAS;AAC5B,cAAI,CAAC,UAAU,OAAO,SAAS,8BAA+B;AAC9D,cAAI;AACF,kBAAM,QAAQ,MAAMI,mBAAS;AAAA,cAC3B,KAAK;AAAA,cACL,QAAQ,OAAO;AAAA,cACf,KAAK,MAAM,YAAY,OAAO,OAAO,GAAG;AAAA,YAAA,CACzC;AACD,gBACE,SAAS,KAAK,KACd,OAAO,MAAM,aAAa,YAC1B,SAAS,MAAM,KAAK,KACpB,OAAO,OAAO,OAAO,UACrB;AACA,qBAAO,KAAK,EAAE,UAAU,MAAM,UAAU,OAAO,MAAM,OAAgC,IAAI,OAAO,GAAA,CAAI;AAAA,YACtG;AAAA,UACF,QAAQ;AACN,uBAAW,KAAK,OAAO,GAAG;AAAA,UAC5B;AAAA,QACF;AACA,YAAI,WAAW,SAAS,GAAG;AACzB,eAAK,QAAQ,YAAY;AACvB,kBAAM,KAAK,GAAG,YAAY,iBAAiB,WAAW;AACtD,uBAAW,OAAO,WAAY,IAAG,YAAY,eAAe,EAAE,OAAO,GAAG;AACxE,kBAAMH,UAAAA,gBAAgB,EAAE;AAAA,UAC1B,CAAC;AAAA,QACH;AACA,eAAO,OAAO,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,EAAE;AAAA,MAC1C,QAAQ;AACN,eAAO,CAAA;AAAA,MACT;AAAA,IACF;AAAA,IACA,MAAM,OAAO;AACX,YAAM,MAAM,WAAW,MAAM,SAAS,MAAM,QAAQ;AACpD,YAAM,UAAU,gCAAgC,MAAM,OAAO,WAAW;AACxE,UAAI,YAAY,cAAc;AAC5B,cAAMI,YAAW,QAAQ,IAAI,GAAG;AAChC,YAAIA,UAAU,cAAaA,UAAS,KAAK;AACzC,gBAAQ,OAAO,GAAG;AAClB,aAAK,eAAe,KAAK;AACzB;AAAA,MACF;AACA,UAAI,YAAY,OAAQ;AACxB,YAAM,WAAW,QAAQ,IAAI,GAAG;AAChC,UAAI,SAAU,cAAa,SAAS,KAAK;AACzC,cAAQ,IAAI,KAAK;AAAA,QACf;AAAA,QACA,OAAO,WAAW,MAAM;AACtB,eAAK,aAAa,GAAG;AAAA,QACvB,GAAG,UAAU;AAAA,MAAA,CACd;AAAA,IACH;AAAA,IACA,OAAO,OAAO;AACZ,YAAM,MAAM,WAAW,MAAM,SAAS,MAAM,QAAQ;AACpD,YAAM,WAAW,QAAQ,IAAI,GAAG;AAChC,UAAI,SAAU,cAAa,SAAS,KAAK;AACzC,cAAQ,OAAO,GAAG;AAClB,WAAK,eAAe,KAAK;AAAA,IAC3B;AAAA,IACA,UAAU,OAAO;AACf,YAAM,MAAM,WAAW,MAAM,SAAS,QAAQ,MAAM,OAAO,EAAE;AAC7D,YAAM,WAAW,aAAa,IAAI,GAAG;AACrC,UAAI,SAAU,cAAa,SAAS,KAAK;AACzC,mBAAa,IAAI,KAAK;AAAA,QACpB;AAAA,QACA,OAAO,WAAW,MAAM;AACtB,eAAK,UAAU,GAAG;AAAA,QACpB,GAAG,UAAU;AAAA,MAAA,CACd;AAAA,IACH;AAAA,IACA,MAAM,SAAS,EAAE,SAAS,WAAW;AACnC,UAAI;AACF,cAAM,KAAK,MAAM,SAAA;AACjB,YAAI,CAAC,GAAI,QAAO;AAChB,cAAM,YAAY,MAAM,MAAM,SAAS,MAAM;AAC7C,YAAI,CAAC,UAAW,QAAO;AACvB,cAAM,QAAQ,MAAMH,UAAAA,UAAU,OAAO;AACrC,cAAM,MAAM,MAAMA,oBAAU,GAAG,OAAO,SAAS,OAAO,EAAE;AACxD,cAAM,SAAU,MAAMF,UAAAA;AAAAA,UACpB,GAAG,YAAY,aAAa,UAAU,EAAE,YAAY,WAAW,EAAE,IAAI,GAAG;AAAA,QAAA;AAE1E,YAAI,CAAC,UAAU,OAAO,SAAS,iCAAiC,OAAO,UAAU,MAAO,QAAO;AAC/F,YAAI;AACF,gBAAM,QAAQ,MAAMI,UAAAA,SAAS,EAAE,KAAK,WAAW,QAAQ,OAAO,QAAQ,KAAK,MAAM,QAAQ,OAAO,GAAG,GAAG;AACtG,iBAAO,EAAE,OAAO,IAAI,OAAO,GAAA;AAAA,QAC7B,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,WAAW,SAAS;AAClB,oBAAc,OAAO;AACrB,aAAO,QAAQ,YAAY;AACzB,cAAM,KAAK,MAAM,SAAA;AACjB,YAAI,CAAC,GAAI;AACT,cAAM,QAAQ,MAAMF,UAAAA,UAAU,OAAO;AACrC,cAAM,KAAK,GAAG,YAAY,CAAC,iBAAiB,WAAW,GAAG,WAAW;AACrE,mBAAW,aAAa,CAAC,iBAAiB,WAAW,GAAG;AACtD,gBAAM,QAAQ,GAAG,YAAY,SAAS;AACtC,gBAAM,OAAO,MAAMF,UAAAA,iBAAiB,MAAM,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AAC3E,qBAAW,OAAO,KAAM,OAAM,OAAO,GAAG;AAAA,QAC1C;AACA,cAAMC,UAAAA,gBAAgB,EAAE;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,IACA,WAAW;AACT,oBAAc,IAAI;AAClB,aAAO,QAAQ,YAAY;AACzB,cAAM,KAAK,MAAM,SAAA;AACjB,YAAI,CAAC,GAAI;AACT,cAAM,KAAK,GAAG,YAAY,CAAC,iBAAiB,WAAW,GAAG,WAAW;AACrE,WAAG,YAAY,eAAe,EAAE,MAAA;AAChC,WAAG,YAAY,WAAW,EAAE,MAAA;AAC5B,cAAMA,UAAAA,gBAAgB,EAAE;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,IACA,MAAM,QAAQ;AACZ,YAAM,QAAQ,IAAI,CAAC,GAAG,QAAQ,MAAM,EAAE,IAAI,YAAY,CAAC;AACvD,YAAM,QAAQ,IAAI,CAAC,GAAG,aAAa,MAAM,EAAE,IAAI,SAAS,CAAC;AACzD,YAAM;AAAA,IACR;AAAA,EAAA;AAEJ;;;;;;;;;"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { DeepAgentStreamValues } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* A durable, encrypted mirror of the thread snapshot cache (`thread-snapshot-cache.ts`) in the
|
|
4
|
+
* browser's IndexedDB, so a reload paints a recently visited thread from its last-known messages,
|
|
5
|
+
* and a thread can be read while the transport cannot connect at all.
|
|
6
|
+
*
|
|
7
|
+
* - **Sealed.** Each record is AES-GCM-256 with a fresh IV under the host's key for its owner
|
|
8
|
+
* (`getKey`: Olympus a non-extractable key in its own keystore, Midas a key main keeps with the
|
|
9
|
+
* OS keychain). The owner and the thread are hashed for the index and bound to the record as
|
|
10
|
+
* additional data, so the database names no one and a record moved to another owner or thread
|
|
11
|
+
* fails to open (and is dropped). No key, no mirror: every write and read is then a no-op.
|
|
12
|
+
* - **Bounded.** Writes are debounced per thread and never taken mid-stream (a state with a live
|
|
13
|
+
* run is replaced by its resting successor within seconds), transcripts longer than
|
|
14
|
+
* `maxMessages` are not kept (an older, shorter record is removed rather than left to seed),
|
|
15
|
+
* and an owner keeps its `maxPerOwner` most recent threads.
|
|
16
|
+
* - **Never in the way.** Every failure degrades to "no mirror": a blocked or missing IndexedDB
|
|
17
|
+
* (private browsing, quota, SSR) must never break the wire path.
|
|
18
|
+
* - **Versioned.** A record a newer build wrote is never read, overwritten or pruned by this one;
|
|
19
|
+
* only removing the person's records altogether (an identity change, a sign-out) removes it.
|
|
20
|
+
*/
|
|
21
|
+
export declare const THREAD_SNAPSHOT_MIRROR_DATABASE = "athena-thread-snapshots:v2";
|
|
22
|
+
/** The sealed record's format; older builds leave a newer one alone. */
|
|
23
|
+
export declare const THREAD_SNAPSHOT_MIRROR_FORMAT = 1;
|
|
24
|
+
/** Threads mirrored per owner; the least recently captured beyond this is pruned after each write. */
|
|
25
|
+
export declare const MAX_MIRRORED_SNAPSHOTS_PER_OWNER = 30;
|
|
26
|
+
/** Transcripts longer than this are not mirrored — sealing them would cost more than the seed saves. */
|
|
27
|
+
export declare const MAX_MIRRORED_SNAPSHOT_MESSAGES = 150;
|
|
28
|
+
/** Trailing debounce per thread: a streaming thread remembers a state per token. */
|
|
29
|
+
export declare const SNAPSHOT_MIRROR_DEBOUNCE_MS = 1500;
|
|
30
|
+
export interface MirroredThreadSnapshot {
|
|
31
|
+
threadId: string;
|
|
32
|
+
state: DeepAgentStreamValues;
|
|
33
|
+
/** Capture time (epoch ms). */
|
|
34
|
+
at: number;
|
|
35
|
+
}
|
|
36
|
+
export interface MirroredList {
|
|
37
|
+
value: unknown;
|
|
38
|
+
/** When it was written (epoch ms). */
|
|
39
|
+
at: number;
|
|
40
|
+
}
|
|
41
|
+
export interface ThreadSnapshotMirror {
|
|
42
|
+
/** The owner's mirrored snapshots, oldest first. Resolves `[]` on any fault. */
|
|
43
|
+
load(ownerId: string): Promise<MirroredThreadSnapshot[]>;
|
|
44
|
+
/** Mirror a remembered state (debounced per thread; mid-stream states are skipped). */
|
|
45
|
+
write(input: {
|
|
46
|
+
ownerId: string;
|
|
47
|
+
threadId: string;
|
|
48
|
+
state: DeepAgentStreamValues;
|
|
49
|
+
at: number;
|
|
50
|
+
}): void;
|
|
51
|
+
remove(input: {
|
|
52
|
+
ownerId: string;
|
|
53
|
+
threadId: string;
|
|
54
|
+
}): void;
|
|
55
|
+
/** A session list's page as the host last read it, for reading it offline. */
|
|
56
|
+
writeList(input: {
|
|
57
|
+
ownerId: string;
|
|
58
|
+
listKey: string;
|
|
59
|
+
value: unknown;
|
|
60
|
+
}): void;
|
|
61
|
+
loadList(input: {
|
|
62
|
+
ownerId: string;
|
|
63
|
+
listKey: string;
|
|
64
|
+
}): Promise<MirroredList | null>;
|
|
65
|
+
/** Drop every record of one owner (an identity change). */
|
|
66
|
+
clearOwner(ownerId: string): Promise<void>;
|
|
67
|
+
/** Drop every record (a sign-out, a workspace switch). */
|
|
68
|
+
clearAll(): Promise<void>;
|
|
69
|
+
/** Write debounced records now (tests, page hide). */
|
|
70
|
+
flush(): Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* What a key is asked for: reading what is already kept (`read`) or keeping something new
|
|
74
|
+
* (`write`). A host may let what it kept be read where it would keep nothing new, e.g. while its
|
|
75
|
+
* deployment's policy for device copies is not known yet.
|
|
76
|
+
*/
|
|
77
|
+
export type ThreadSnapshotKeyPurpose = "read" | "write";
|
|
78
|
+
export interface ThreadSnapshotMirrorOptions {
|
|
79
|
+
/** The owner's AES-GCM key, or `null` when the host keeps no mirror for it (no key, policy off). */
|
|
80
|
+
getKey: (ownerId: string, purpose: ThreadSnapshotKeyPurpose) => Promise<CryptoKey | null>;
|
|
81
|
+
/** An `IDBFactory` (the browser's `indexedDB` by default; a fake one in tests). */
|
|
82
|
+
factory?: object;
|
|
83
|
+
databaseName?: string;
|
|
84
|
+
debounceMs?: number;
|
|
85
|
+
maxPerOwner?: number;
|
|
86
|
+
maxMessages?: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Whether a remembered state is a resting transcript: no run in flight (its own or an out-of-band
|
|
90
|
+
* one) and its messages present. Only such a state is kept, and read while Athena can't be reached;
|
|
91
|
+
* a mid-stream state is a partial transcript.
|
|
92
|
+
*/
|
|
93
|
+
export declare function isRestingThreadSnapshot(state: DeepAgentStreamValues): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* What the mirror does with a remembered state: `persist` a resting transcript within the size
|
|
96
|
+
* bound; `skip` a mid-stream state (it arrives per token and its resting successor follows within
|
|
97
|
+
* seconds — the last resting record stays); `invalidate` when the transcript has outgrown the
|
|
98
|
+
* mirror — a stale, shorter record would otherwise seed the next reload until the hello.
|
|
99
|
+
*/
|
|
100
|
+
export declare function classifyThreadSnapshotForMirror(state: DeepAgentStreamValues, maxMessages?: number): "persist" | "skip" | "invalidate";
|
|
101
|
+
export declare function createThreadSnapshotMirror({ getKey, factory, databaseName, debounceMs, maxPerOwner, maxMessages, }: ThreadSnapshotMirrorOptions): ThreadSnapshotMirror;
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { sha256Hex, requestToPromise, openJson, transactionDone, idbGlobals, lazySealedDatabase, sealJson } from "./sealed-idb.js";
|
|
2
|
+
const THREAD_SNAPSHOT_MIRROR_DATABASE = "athena-thread-snapshots:v2";
|
|
3
|
+
const THREAD_SNAPSHOT_MIRROR_FORMAT = 1;
|
|
4
|
+
const MAX_MIRRORED_SNAPSHOTS_PER_OWNER = 30;
|
|
5
|
+
const MAX_MIRRORED_SNAPSHOT_MESSAGES = 150;
|
|
6
|
+
const SNAPSHOT_MIRROR_DEBOUNCE_MS = 1500;
|
|
7
|
+
const DATABASE_VERSION = 1;
|
|
8
|
+
const SNAPSHOTS_STORE = "snapshots";
|
|
9
|
+
const LISTS_STORE = "lists";
|
|
10
|
+
const BY_OWNER = "byOwner";
|
|
11
|
+
const BY_OWNER_AT = "byOwnerAt";
|
|
12
|
+
function upgradeMirrorDatabase(db) {
|
|
13
|
+
if (!db.objectStoreNames.contains(SNAPSHOTS_STORE)) {
|
|
14
|
+
const store = db.createObjectStore(SNAPSHOTS_STORE, { keyPath: "key" });
|
|
15
|
+
store.createIndex(BY_OWNER, "owner", { unique: false });
|
|
16
|
+
store.createIndex(BY_OWNER_AT, ["owner", "at"], { unique: false });
|
|
17
|
+
}
|
|
18
|
+
if (!db.objectStoreNames.contains(LISTS_STORE)) {
|
|
19
|
+
const lists = db.createObjectStore(LISTS_STORE, { keyPath: "key" });
|
|
20
|
+
lists.createIndex(BY_OWNER, "owner", { unique: false });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function isRestingThreadSnapshot(state) {
|
|
24
|
+
var _a;
|
|
25
|
+
const run = (_a = state.runs) == null ? void 0 : _a[0];
|
|
26
|
+
if (run && run.status === "running") return false;
|
|
27
|
+
if (state.outOfBandRunActive === true) return false;
|
|
28
|
+
return Array.isArray(state.messages);
|
|
29
|
+
}
|
|
30
|
+
function classifyThreadSnapshotForMirror(state, maxMessages = MAX_MIRRORED_SNAPSHOT_MESSAGES) {
|
|
31
|
+
var _a;
|
|
32
|
+
if (!isRestingThreadSnapshot(state)) return "skip";
|
|
33
|
+
return (((_a = state.messages) == null ? void 0 : _a.length) ?? 0) <= maxMessages ? "persist" : "invalidate";
|
|
34
|
+
}
|
|
35
|
+
function isOwnFormat(record) {
|
|
36
|
+
if (typeof record !== "object" || record === null) return true;
|
|
37
|
+
const format = record.format;
|
|
38
|
+
return typeof format !== "number" || format <= THREAD_SNAPSHOT_MIRROR_FORMAT;
|
|
39
|
+
}
|
|
40
|
+
function isRecord(value) {
|
|
41
|
+
return typeof value === "object" && value !== null;
|
|
42
|
+
}
|
|
43
|
+
function createThreadSnapshotMirror({
|
|
44
|
+
getKey,
|
|
45
|
+
factory = idbGlobals.indexedDB,
|
|
46
|
+
databaseName = THREAD_SNAPSHOT_MIRROR_DATABASE,
|
|
47
|
+
debounceMs = SNAPSHOT_MIRROR_DEBOUNCE_MS,
|
|
48
|
+
maxPerOwner = MAX_MIRRORED_SNAPSHOTS_PER_OWNER,
|
|
49
|
+
maxMessages = MAX_MIRRORED_SNAPSHOT_MESSAGES
|
|
50
|
+
}) {
|
|
51
|
+
const database = lazySealedDatabase({
|
|
52
|
+
factory,
|
|
53
|
+
name: databaseName,
|
|
54
|
+
version: DATABASE_VERSION,
|
|
55
|
+
upgrade: upgradeMirrorDatabase
|
|
56
|
+
});
|
|
57
|
+
const keyOf = async (ownerId, purpose) => {
|
|
58
|
+
try {
|
|
59
|
+
return await getKey(ownerId, purpose);
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const aadOf = (kind, owner, key) => `athena-thread-snapshot|${THREAD_SNAPSHOT_MIRROR_FORMAT}|${kind}|${owner}|${key}`;
|
|
65
|
+
const pending = /* @__PURE__ */ new Map();
|
|
66
|
+
const pendingLists = /* @__PURE__ */ new Map();
|
|
67
|
+
let queue = Promise.resolve();
|
|
68
|
+
const enqueue = (task) => {
|
|
69
|
+
queue = queue.then(task, task).catch(() => {
|
|
70
|
+
});
|
|
71
|
+
return queue;
|
|
72
|
+
};
|
|
73
|
+
const pruneOwner = async (db, owner) => {
|
|
74
|
+
const KeyRange = idbGlobals.IDBKeyRange;
|
|
75
|
+
if (!KeyRange) return;
|
|
76
|
+
const tx = db.transaction(SNAPSHOTS_STORE, "readwrite");
|
|
77
|
+
const store = tx.objectStore(SNAPSHOTS_STORE);
|
|
78
|
+
const index = store.index(BY_OWNER_AT);
|
|
79
|
+
const range = KeyRange.bound([owner, Number.NEGATIVE_INFINITY], [owner, Number.POSITIVE_INFINITY]);
|
|
80
|
+
const beyond = [];
|
|
81
|
+
await new Promise((resolve, reject) => {
|
|
82
|
+
let kept = 0;
|
|
83
|
+
const request = index.openKeyCursor(range, "prev");
|
|
84
|
+
request.onsuccess = () => {
|
|
85
|
+
const cursor = request.result;
|
|
86
|
+
if (!cursor) {
|
|
87
|
+
resolve();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
kept += 1;
|
|
91
|
+
if (kept > maxPerOwner) beyond.push(cursor.primaryKey);
|
|
92
|
+
cursor.continue();
|
|
93
|
+
};
|
|
94
|
+
request.onerror = () => reject(request.error ?? new Error("IndexedDB cursor failed"));
|
|
95
|
+
});
|
|
96
|
+
for (const key of beyond) {
|
|
97
|
+
if (isOwnFormat(await requestToPromise(store.get(key)))) store.delete(key);
|
|
98
|
+
}
|
|
99
|
+
await transactionDone(tx);
|
|
100
|
+
};
|
|
101
|
+
const put = (input) => enqueue(async () => {
|
|
102
|
+
const db = await database();
|
|
103
|
+
if (!db) return;
|
|
104
|
+
const cryptoKey = await keyOf(input.ownerId, "write");
|
|
105
|
+
if (!cryptoKey) return;
|
|
106
|
+
const owner = await sha256Hex(input.ownerId);
|
|
107
|
+
const key = await sha256Hex(`${input.ownerId}|${input.threadId}`);
|
|
108
|
+
const sealed = await sealJson({
|
|
109
|
+
key: cryptoKey,
|
|
110
|
+
value: { threadId: input.threadId, state: input.state },
|
|
111
|
+
aad: aadOf("snapshot", owner, key)
|
|
112
|
+
});
|
|
113
|
+
const tx = db.transaction(SNAPSHOTS_STORE, "readwrite");
|
|
114
|
+
const store = tx.objectStore(SNAPSHOTS_STORE);
|
|
115
|
+
if (isOwnFormat(await requestToPromise(store.get(key)))) {
|
|
116
|
+
store.put({
|
|
117
|
+
key,
|
|
118
|
+
owner,
|
|
119
|
+
at: input.at,
|
|
120
|
+
format: THREAD_SNAPSHOT_MIRROR_FORMAT,
|
|
121
|
+
sealed
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
await transactionDone(tx);
|
|
125
|
+
await pruneOwner(db, owner);
|
|
126
|
+
});
|
|
127
|
+
const deleteSnapshot = (input) => enqueue(async () => {
|
|
128
|
+
const db = await database();
|
|
129
|
+
if (!db) return;
|
|
130
|
+
const key = await sha256Hex(`${input.ownerId}|${input.threadId}`);
|
|
131
|
+
const tx = db.transaction(SNAPSHOTS_STORE, "readwrite");
|
|
132
|
+
const store = tx.objectStore(SNAPSHOTS_STORE);
|
|
133
|
+
if (isOwnFormat(await requestToPromise(store.get(key)))) store.delete(key);
|
|
134
|
+
await transactionDone(tx);
|
|
135
|
+
});
|
|
136
|
+
const pendingKey = (ownerId, threadId) => `${ownerId}\0${threadId}`;
|
|
137
|
+
const flushPending = (key) => {
|
|
138
|
+
const entry = pending.get(key);
|
|
139
|
+
if (!entry) return Promise.resolve();
|
|
140
|
+
pending.delete(key);
|
|
141
|
+
clearTimeout(entry.timer);
|
|
142
|
+
return put(entry.input);
|
|
143
|
+
};
|
|
144
|
+
const putList = (input) => enqueue(async () => {
|
|
145
|
+
const db = await database();
|
|
146
|
+
if (!db) return;
|
|
147
|
+
const cryptoKey = await keyOf(input.ownerId, "write");
|
|
148
|
+
if (!cryptoKey) return;
|
|
149
|
+
const owner = await sha256Hex(input.ownerId);
|
|
150
|
+
const key = await sha256Hex(`${input.ownerId}|list|${input.listKey}`);
|
|
151
|
+
const sealed = await sealJson({ key: cryptoKey, value: input.value, aad: aadOf("list", owner, key) });
|
|
152
|
+
const tx = db.transaction(LISTS_STORE, "readwrite");
|
|
153
|
+
const store = tx.objectStore(LISTS_STORE);
|
|
154
|
+
if (isOwnFormat(await requestToPromise(store.get(key)))) {
|
|
155
|
+
store.put({
|
|
156
|
+
key,
|
|
157
|
+
owner,
|
|
158
|
+
at: Date.now(),
|
|
159
|
+
format: THREAD_SNAPSHOT_MIRROR_FORMAT,
|
|
160
|
+
sealed
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
await transactionDone(tx);
|
|
164
|
+
});
|
|
165
|
+
const flushList = (key) => {
|
|
166
|
+
const entry = pendingLists.get(key);
|
|
167
|
+
if (!entry) return Promise.resolve();
|
|
168
|
+
pendingLists.delete(key);
|
|
169
|
+
clearTimeout(entry.timer);
|
|
170
|
+
return putList(entry.input);
|
|
171
|
+
};
|
|
172
|
+
const dropPendingOf = (ownerId) => {
|
|
173
|
+
for (const [key, entry] of pending) {
|
|
174
|
+
if (ownerId === null || entry.input.ownerId === ownerId) {
|
|
175
|
+
clearTimeout(entry.timer);
|
|
176
|
+
pending.delete(key);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
for (const [key, entry] of pendingLists) {
|
|
180
|
+
if (ownerId === null || entry.input.ownerId === ownerId) {
|
|
181
|
+
clearTimeout(entry.timer);
|
|
182
|
+
pendingLists.delete(key);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
return {
|
|
187
|
+
async load(ownerId) {
|
|
188
|
+
try {
|
|
189
|
+
const db = await database();
|
|
190
|
+
if (!db) return [];
|
|
191
|
+
const cryptoKey = await keyOf(ownerId, "read");
|
|
192
|
+
if (!cryptoKey) return [];
|
|
193
|
+
const owner = await sha256Hex(ownerId);
|
|
194
|
+
const records = await requestToPromise(
|
|
195
|
+
db.transaction(SNAPSHOTS_STORE, "readonly").objectStore(SNAPSHOTS_STORE).index(BY_OWNER).getAll(owner)
|
|
196
|
+
);
|
|
197
|
+
const loaded = [];
|
|
198
|
+
const unreadable = [];
|
|
199
|
+
for (const record of records) {
|
|
200
|
+
if (!record || record.format > THREAD_SNAPSHOT_MIRROR_FORMAT) continue;
|
|
201
|
+
try {
|
|
202
|
+
const value = await openJson({
|
|
203
|
+
key: cryptoKey,
|
|
204
|
+
sealed: record.sealed,
|
|
205
|
+
aad: aadOf("snapshot", owner, record.key)
|
|
206
|
+
});
|
|
207
|
+
if (isRecord(value) && typeof value.threadId === "string" && isRecord(value.state) && typeof record.at === "number") {
|
|
208
|
+
loaded.push({ threadId: value.threadId, state: value.state, at: record.at });
|
|
209
|
+
}
|
|
210
|
+
} catch {
|
|
211
|
+
unreadable.push(record.key);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (unreadable.length > 0) {
|
|
215
|
+
void enqueue(async () => {
|
|
216
|
+
const tx = db.transaction(SNAPSHOTS_STORE, "readwrite");
|
|
217
|
+
for (const key of unreadable) tx.objectStore(SNAPSHOTS_STORE).delete(key);
|
|
218
|
+
await transactionDone(tx);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return loaded.sort((a, b) => a.at - b.at);
|
|
222
|
+
} catch {
|
|
223
|
+
return [];
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
write(input) {
|
|
227
|
+
const key = pendingKey(input.ownerId, input.threadId);
|
|
228
|
+
const verdict = classifyThreadSnapshotForMirror(input.state, maxMessages);
|
|
229
|
+
if (verdict === "invalidate") {
|
|
230
|
+
const existing2 = pending.get(key);
|
|
231
|
+
if (existing2) clearTimeout(existing2.timer);
|
|
232
|
+
pending.delete(key);
|
|
233
|
+
void deleteSnapshot(input);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (verdict === "skip") return;
|
|
237
|
+
const existing = pending.get(key);
|
|
238
|
+
if (existing) clearTimeout(existing.timer);
|
|
239
|
+
pending.set(key, {
|
|
240
|
+
input,
|
|
241
|
+
timer: setTimeout(() => {
|
|
242
|
+
void flushPending(key);
|
|
243
|
+
}, debounceMs)
|
|
244
|
+
});
|
|
245
|
+
},
|
|
246
|
+
remove(input) {
|
|
247
|
+
const key = pendingKey(input.ownerId, input.threadId);
|
|
248
|
+
const existing = pending.get(key);
|
|
249
|
+
if (existing) clearTimeout(existing.timer);
|
|
250
|
+
pending.delete(key);
|
|
251
|
+
void deleteSnapshot(input);
|
|
252
|
+
},
|
|
253
|
+
writeList(input) {
|
|
254
|
+
const key = pendingKey(input.ownerId, `list:${input.listKey}`);
|
|
255
|
+
const existing = pendingLists.get(key);
|
|
256
|
+
if (existing) clearTimeout(existing.timer);
|
|
257
|
+
pendingLists.set(key, {
|
|
258
|
+
input,
|
|
259
|
+
timer: setTimeout(() => {
|
|
260
|
+
void flushList(key);
|
|
261
|
+
}, debounceMs)
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
async loadList({ ownerId, listKey }) {
|
|
265
|
+
try {
|
|
266
|
+
const db = await database();
|
|
267
|
+
if (!db) return null;
|
|
268
|
+
const cryptoKey = await keyOf(ownerId, "read");
|
|
269
|
+
if (!cryptoKey) return null;
|
|
270
|
+
const owner = await sha256Hex(ownerId);
|
|
271
|
+
const key = await sha256Hex(`${ownerId}|list|${listKey}`);
|
|
272
|
+
const record = await requestToPromise(
|
|
273
|
+
db.transaction(LISTS_STORE, "readonly").objectStore(LISTS_STORE).get(key)
|
|
274
|
+
);
|
|
275
|
+
if (!record || record.format > THREAD_SNAPSHOT_MIRROR_FORMAT || record.owner !== owner) return null;
|
|
276
|
+
try {
|
|
277
|
+
const value = await openJson({ key: cryptoKey, sealed: record.sealed, aad: aadOf("list", owner, key) });
|
|
278
|
+
return { value, at: record.at };
|
|
279
|
+
} catch {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
} catch {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
clearOwner(ownerId) {
|
|
287
|
+
dropPendingOf(ownerId);
|
|
288
|
+
return enqueue(async () => {
|
|
289
|
+
const db = await database();
|
|
290
|
+
if (!db) return;
|
|
291
|
+
const owner = await sha256Hex(ownerId);
|
|
292
|
+
const tx = db.transaction([SNAPSHOTS_STORE, LISTS_STORE], "readwrite");
|
|
293
|
+
for (const storeName of [SNAPSHOTS_STORE, LISTS_STORE]) {
|
|
294
|
+
const store = tx.objectStore(storeName);
|
|
295
|
+
const keys = await requestToPromise(store.index(BY_OWNER).getAllKeys(owner));
|
|
296
|
+
for (const key of keys) store.delete(key);
|
|
297
|
+
}
|
|
298
|
+
await transactionDone(tx);
|
|
299
|
+
});
|
|
300
|
+
},
|
|
301
|
+
clearAll() {
|
|
302
|
+
dropPendingOf(null);
|
|
303
|
+
return enqueue(async () => {
|
|
304
|
+
const db = await database();
|
|
305
|
+
if (!db) return;
|
|
306
|
+
const tx = db.transaction([SNAPSHOTS_STORE, LISTS_STORE], "readwrite");
|
|
307
|
+
tx.objectStore(SNAPSHOTS_STORE).clear();
|
|
308
|
+
tx.objectStore(LISTS_STORE).clear();
|
|
309
|
+
await transactionDone(tx);
|
|
310
|
+
});
|
|
311
|
+
},
|
|
312
|
+
async flush() {
|
|
313
|
+
await Promise.all([...pending.keys()].map(flushPending));
|
|
314
|
+
await Promise.all([...pendingLists.keys()].map(flushList));
|
|
315
|
+
await queue;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
export {
|
|
320
|
+
MAX_MIRRORED_SNAPSHOTS_PER_OWNER,
|
|
321
|
+
MAX_MIRRORED_SNAPSHOT_MESSAGES,
|
|
322
|
+
SNAPSHOT_MIRROR_DEBOUNCE_MS,
|
|
323
|
+
THREAD_SNAPSHOT_MIRROR_DATABASE,
|
|
324
|
+
THREAD_SNAPSHOT_MIRROR_FORMAT,
|
|
325
|
+
classifyThreadSnapshotForMirror,
|
|
326
|
+
createThreadSnapshotMirror,
|
|
327
|
+
isRestingThreadSnapshot
|
|
328
|
+
};
|
|
329
|
+
//# sourceMappingURL=thread-snapshot-mirror.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-snapshot-mirror.js","sources":["../../../../agent-runtime/src/thread-snapshot-mirror.ts"],"sourcesContent":["import {\n type IdbDatabase,\n idbGlobals,\n lazySealedDatabase,\n openJson,\n requestToPromise,\n sealJson,\n sha256Hex,\n transactionDone,\n} from \"./sealed-idb\";\nimport type { DeepAgentStreamValues } from \"./types\";\n\n/**\n * A durable, encrypted mirror of the thread snapshot cache (`thread-snapshot-cache.ts`) in the\n * browser's IndexedDB, so a reload paints a recently visited thread from its last-known messages,\n * and a thread can be read while the transport cannot connect at all.\n *\n * - **Sealed.** Each record is AES-GCM-256 with a fresh IV under the host's key for its owner\n * (`getKey`: Olympus a non-extractable key in its own keystore, Midas a key main keeps with the\n * OS keychain). The owner and the thread are hashed for the index and bound to the record as\n * additional data, so the database names no one and a record moved to another owner or thread\n * fails to open (and is dropped). No key, no mirror: every write and read is then a no-op.\n * - **Bounded.** Writes are debounced per thread and never taken mid-stream (a state with a live\n * run is replaced by its resting successor within seconds), transcripts longer than\n * `maxMessages` are not kept (an older, shorter record is removed rather than left to seed),\n * and an owner keeps its `maxPerOwner` most recent threads.\n * - **Never in the way.** Every failure degrades to \"no mirror\": a blocked or missing IndexedDB\n * (private browsing, quota, SSR) must never break the wire path.\n * - **Versioned.** A record a newer build wrote is never read, overwritten or pruned by this one;\n * only removing the person's records altogether (an identity change, a sign-out) removes it.\n */\n\nexport const THREAD_SNAPSHOT_MIRROR_DATABASE = \"athena-thread-snapshots:v2\";\n/** The sealed record's format; older builds leave a newer one alone. */\nexport const THREAD_SNAPSHOT_MIRROR_FORMAT = 1;\n/** Threads mirrored per owner; the least recently captured beyond this is pruned after each write. */\nexport const MAX_MIRRORED_SNAPSHOTS_PER_OWNER = 30;\n/** Transcripts longer than this are not mirrored — sealing them would cost more than the seed saves. */\nexport const MAX_MIRRORED_SNAPSHOT_MESSAGES = 150;\n/** Trailing debounce per thread: a streaming thread remembers a state per token. */\nexport const SNAPSHOT_MIRROR_DEBOUNCE_MS = 1_500;\n\nconst DATABASE_VERSION = 1;\nconst SNAPSHOTS_STORE = \"snapshots\";\nconst LISTS_STORE = \"lists\";\nconst BY_OWNER = \"byOwner\";\nconst BY_OWNER_AT = \"byOwnerAt\";\n\nexport interface MirroredThreadSnapshot {\n threadId: string;\n state: DeepAgentStreamValues;\n /** Capture time (epoch ms). */\n at: number;\n}\n\nexport interface MirroredList {\n value: unknown;\n /** When it was written (epoch ms). */\n at: number;\n}\n\nexport interface ThreadSnapshotMirror {\n /** The owner's mirrored snapshots, oldest first. Resolves `[]` on any fault. */\n load(ownerId: string): Promise<MirroredThreadSnapshot[]>;\n /** Mirror a remembered state (debounced per thread; mid-stream states are skipped). */\n write(input: { ownerId: string; threadId: string; state: DeepAgentStreamValues; at: number }): void;\n remove(input: { ownerId: string; threadId: string }): void;\n /** A session list's page as the host last read it, for reading it offline. */\n writeList(input: { ownerId: string; listKey: string; value: unknown }): void;\n loadList(input: { ownerId: string; listKey: string }): Promise<MirroredList | null>;\n /** Drop every record of one owner (an identity change). */\n clearOwner(ownerId: string): Promise<void>;\n /** Drop every record (a sign-out, a workspace switch). */\n clearAll(): Promise<void>;\n /** Write debounced records now (tests, page hide). */\n flush(): Promise<void>;\n}\n\n/**\n * What a key is asked for: reading what is already kept (`read`) or keeping something new\n * (`write`). A host may let what it kept be read where it would keep nothing new, e.g. while its\n * deployment's policy for device copies is not known yet.\n */\nexport type ThreadSnapshotKeyPurpose = \"read\" | \"write\";\n\nexport interface ThreadSnapshotMirrorOptions {\n /** The owner's AES-GCM key, or `null` when the host keeps no mirror for it (no key, policy off). */\n getKey: (ownerId: string, purpose: ThreadSnapshotKeyPurpose) => Promise<CryptoKey | null>;\n /** An `IDBFactory` (the browser's `indexedDB` by default; a fake one in tests). */\n factory?: object;\n databaseName?: string;\n debounceMs?: number;\n maxPerOwner?: number;\n maxMessages?: number;\n}\n\ninterface SnapshotRecord {\n key: string;\n owner: string;\n at: number;\n format: number;\n sealed: Uint8Array;\n}\n\ninterface ListRecord {\n key: string;\n owner: string;\n at: number;\n format: number;\n sealed: Uint8Array;\n}\n\nfunction upgradeMirrorDatabase(db: IdbDatabase): void {\n if (!db.objectStoreNames.contains(SNAPSHOTS_STORE)) {\n const store = db.createObjectStore(SNAPSHOTS_STORE, { keyPath: \"key\" });\n store.createIndex(BY_OWNER, \"owner\", { unique: false });\n store.createIndex(BY_OWNER_AT, [\"owner\", \"at\"], { unique: false });\n }\n if (!db.objectStoreNames.contains(LISTS_STORE)) {\n const lists = db.createObjectStore(LISTS_STORE, { keyPath: \"key\" });\n lists.createIndex(BY_OWNER, \"owner\", { unique: false });\n }\n}\n\n/**\n * Whether a remembered state is a resting transcript: no run in flight (its own or an out-of-band\n * one) and its messages present. Only such a state is kept, and read while Athena can't be reached;\n * a mid-stream state is a partial transcript.\n */\nexport function isRestingThreadSnapshot(state: DeepAgentStreamValues): boolean {\n const run = state.runs?.[0];\n if (run && run.status === \"running\") return false;\n if (state.outOfBandRunActive === true) return false;\n return Array.isArray(state.messages);\n}\n\n/**\n * What the mirror does with a remembered state: `persist` a resting transcript within the size\n * bound; `skip` a mid-stream state (it arrives per token and its resting successor follows within\n * seconds — the last resting record stays); `invalidate` when the transcript has outgrown the\n * mirror — a stale, shorter record would otherwise seed the next reload until the hello.\n */\nexport function classifyThreadSnapshotForMirror(\n state: DeepAgentStreamValues,\n maxMessages: number = MAX_MIRRORED_SNAPSHOT_MESSAGES,\n): \"persist\" | \"skip\" | \"invalidate\" {\n if (!isRestingThreadSnapshot(state)) return \"skip\";\n return (state.messages?.length ?? 0) <= maxMessages ? \"persist\" : \"invalidate\";\n}\n\n/** A record this build may replace or delete: none, or one in a format it writes itself. */\nfunction isOwnFormat(record: unknown): boolean {\n if (typeof record !== \"object\" || record === null) return true;\n const format = (record as { format?: unknown }).format;\n return typeof format !== \"number\" || format <= THREAD_SNAPSHOT_MIRROR_FORMAT;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nexport function createThreadSnapshotMirror({\n getKey,\n factory = idbGlobals.indexedDB,\n databaseName = THREAD_SNAPSHOT_MIRROR_DATABASE,\n debounceMs = SNAPSHOT_MIRROR_DEBOUNCE_MS,\n maxPerOwner = MAX_MIRRORED_SNAPSHOTS_PER_OWNER,\n maxMessages = MAX_MIRRORED_SNAPSHOT_MESSAGES,\n}: ThreadSnapshotMirrorOptions): ThreadSnapshotMirror {\n const database = lazySealedDatabase({\n factory,\n name: databaseName,\n version: DATABASE_VERSION,\n upgrade: upgradeMirrorDatabase,\n });\n const keyOf = async (ownerId: string, purpose: ThreadSnapshotKeyPurpose): Promise<CryptoKey | null> => {\n try {\n return await getKey(ownerId, purpose);\n } catch {\n return null;\n }\n };\n const aadOf = (kind: string, owner: string, key: string): string =>\n `athena-thread-snapshot|${THREAD_SNAPSHOT_MIRROR_FORMAT}|${kind}|${owner}|${key}`;\n\n const pending = new Map<\n string,\n { input: { ownerId: string; threadId: string; state: DeepAgentStreamValues; at: number }; timer: ReturnType<typeof setTimeout> }\n >();\n const pendingLists = new Map<\n string,\n { input: { ownerId: string; listKey: string; value: unknown }; timer: ReturnType<typeof setTimeout> }\n >();\n // Writes are serialized so a flush never races a clear.\n let queue: Promise<void> = Promise.resolve();\n const enqueue = (task: () => Promise<void>): Promise<void> => {\n queue = queue.then(task, task).catch(() => {});\n return queue;\n };\n\n const pruneOwner = async (db: IdbDatabase, owner: string): Promise<void> => {\n const KeyRange = idbGlobals.IDBKeyRange;\n if (!KeyRange) return;\n const tx = db.transaction(SNAPSHOTS_STORE, \"readwrite\");\n const store = tx.objectStore(SNAPSHOTS_STORE);\n const index = store.index(BY_OWNER_AT);\n // Key cursor, newest first: bookkeeping never loads the sealed payloads of the records it keeps.\n const range = KeyRange.bound([owner, Number.NEGATIVE_INFINITY], [owner, Number.POSITIVE_INFINITY]);\n const beyond: unknown[] = [];\n await new Promise<void>((resolve, reject) => {\n let kept = 0;\n const request = index.openKeyCursor(range, \"prev\");\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n resolve();\n return;\n }\n kept += 1;\n if (kept > maxPerOwner) beyond.push(cursor.primaryKey);\n cursor.continue();\n };\n request.onerror = () => reject(request.error ?? new Error(\"IndexedDB cursor failed\"));\n });\n // A newer build's record is left to that build's own bound.\n for (const key of beyond) {\n if (isOwnFormat(await requestToPromise(store.get(key)))) store.delete(key);\n }\n await transactionDone(tx);\n };\n\n const put = (input: { ownerId: string; threadId: string; state: DeepAgentStreamValues; at: number }) =>\n enqueue(async () => {\n const db = await database();\n if (!db) return;\n const cryptoKey = await keyOf(input.ownerId, \"write\");\n if (!cryptoKey) return;\n const owner = await sha256Hex(input.ownerId);\n const key = await sha256Hex(`${input.ownerId}|${input.threadId}`);\n const sealed = await sealJson({\n key: cryptoKey,\n value: { threadId: input.threadId, state: input.state },\n aad: aadOf(\"snapshot\", owner, key),\n });\n const tx = db.transaction(SNAPSHOTS_STORE, \"readwrite\");\n const store = tx.objectStore(SNAPSHOTS_STORE);\n // A newer build's record of the thread stays as that build wrote it.\n if (isOwnFormat(await requestToPromise(store.get(key)))) {\n store.put({\n key,\n owner,\n at: input.at,\n format: THREAD_SNAPSHOT_MIRROR_FORMAT,\n sealed,\n } satisfies SnapshotRecord);\n }\n await transactionDone(tx);\n await pruneOwner(db, owner);\n });\n\n const deleteSnapshot = (input: { ownerId: string; threadId: string }) =>\n enqueue(async () => {\n const db = await database();\n if (!db) return;\n const key = await sha256Hex(`${input.ownerId}|${input.threadId}`);\n const tx = db.transaction(SNAPSHOTS_STORE, \"readwrite\");\n const store = tx.objectStore(SNAPSHOTS_STORE);\n if (isOwnFormat(await requestToPromise(store.get(key)))) store.delete(key);\n await transactionDone(tx);\n });\n\n const pendingKey = (ownerId: string, threadId: string) => `${ownerId}\\u0000${threadId}`;\n\n const flushPending = (key: string): Promise<void> => {\n const entry = pending.get(key);\n if (!entry) return Promise.resolve();\n pending.delete(key);\n clearTimeout(entry.timer);\n return put(entry.input);\n };\n\n const putList = (input: { ownerId: string; listKey: string; value: unknown }) =>\n enqueue(async () => {\n const db = await database();\n if (!db) return;\n const cryptoKey = await keyOf(input.ownerId, \"write\");\n if (!cryptoKey) return;\n const owner = await sha256Hex(input.ownerId);\n const key = await sha256Hex(`${input.ownerId}|list|${input.listKey}`);\n const sealed = await sealJson({ key: cryptoKey, value: input.value, aad: aadOf(\"list\", owner, key) });\n const tx = db.transaction(LISTS_STORE, \"readwrite\");\n const store = tx.objectStore(LISTS_STORE);\n if (isOwnFormat(await requestToPromise(store.get(key)))) {\n store.put({\n key,\n owner,\n at: Date.now(),\n format: THREAD_SNAPSHOT_MIRROR_FORMAT,\n sealed,\n } satisfies ListRecord);\n }\n await transactionDone(tx);\n });\n\n const flushList = (key: string): Promise<void> => {\n const entry = pendingLists.get(key);\n if (!entry) return Promise.resolve();\n pendingLists.delete(key);\n clearTimeout(entry.timer);\n return putList(entry.input);\n };\n\n const dropPendingOf = (ownerId: string | null): void => {\n for (const [key, entry] of pending) {\n if (ownerId === null || entry.input.ownerId === ownerId) {\n clearTimeout(entry.timer);\n pending.delete(key);\n }\n }\n for (const [key, entry] of pendingLists) {\n if (ownerId === null || entry.input.ownerId === ownerId) {\n clearTimeout(entry.timer);\n pendingLists.delete(key);\n }\n }\n };\n\n return {\n async load(ownerId) {\n try {\n const db = await database();\n if (!db) return [];\n const cryptoKey = await keyOf(ownerId, \"read\");\n if (!cryptoKey) return [];\n const owner = await sha256Hex(ownerId);\n const records = (await requestToPromise(\n db.transaction(SNAPSHOTS_STORE, \"readonly\").objectStore(SNAPSHOTS_STORE).index(BY_OWNER).getAll(owner),\n )) as SnapshotRecord[];\n const loaded: MirroredThreadSnapshot[] = [];\n const unreadable: string[] = [];\n for (const record of records) {\n if (!record || record.format > THREAD_SNAPSHOT_MIRROR_FORMAT) continue;\n try {\n const value = await openJson({\n key: cryptoKey,\n sealed: record.sealed,\n aad: aadOf(\"snapshot\", owner, record.key),\n });\n if (\n isRecord(value) &&\n typeof value.threadId === \"string\" &&\n isRecord(value.state) &&\n typeof record.at === \"number\"\n ) {\n loaded.push({ threadId: value.threadId, state: value.state as DeepAgentStreamValues, at: record.at });\n }\n } catch {\n unreadable.push(record.key);\n }\n }\n if (unreadable.length > 0) {\n void enqueue(async () => {\n const tx = db.transaction(SNAPSHOTS_STORE, \"readwrite\");\n for (const key of unreadable) tx.objectStore(SNAPSHOTS_STORE).delete(key);\n await transactionDone(tx);\n });\n }\n return loaded.sort((a, b) => a.at - b.at);\n } catch {\n return [];\n }\n },\n write(input) {\n const key = pendingKey(input.ownerId, input.threadId);\n const verdict = classifyThreadSnapshotForMirror(input.state, maxMessages);\n if (verdict === \"invalidate\") {\n const existing = pending.get(key);\n if (existing) clearTimeout(existing.timer);\n pending.delete(key);\n void deleteSnapshot(input);\n return;\n }\n if (verdict === \"skip\") return;\n const existing = pending.get(key);\n if (existing) clearTimeout(existing.timer);\n pending.set(key, {\n input,\n timer: setTimeout(() => {\n void flushPending(key);\n }, debounceMs),\n });\n },\n remove(input) {\n const key = pendingKey(input.ownerId, input.threadId);\n const existing = pending.get(key);\n if (existing) clearTimeout(existing.timer);\n pending.delete(key);\n void deleteSnapshot(input);\n },\n writeList(input) {\n const key = pendingKey(input.ownerId, `list:${input.listKey}`);\n const existing = pendingLists.get(key);\n if (existing) clearTimeout(existing.timer);\n pendingLists.set(key, {\n input,\n timer: setTimeout(() => {\n void flushList(key);\n }, debounceMs),\n });\n },\n async loadList({ ownerId, listKey }) {\n try {\n const db = await database();\n if (!db) return null;\n const cryptoKey = await keyOf(ownerId, \"read\");\n if (!cryptoKey) return null;\n const owner = await sha256Hex(ownerId);\n const key = await sha256Hex(`${ownerId}|list|${listKey}`);\n const record = (await requestToPromise(\n db.transaction(LISTS_STORE, \"readonly\").objectStore(LISTS_STORE).get(key),\n )) as ListRecord | undefined;\n if (!record || record.format > THREAD_SNAPSHOT_MIRROR_FORMAT || record.owner !== owner) return null;\n try {\n const value = await openJson({ key: cryptoKey, sealed: record.sealed, aad: aadOf(\"list\", owner, key) });\n return { value, at: record.at };\n } catch {\n return null;\n }\n } catch {\n return null;\n }\n },\n clearOwner(ownerId) {\n dropPendingOf(ownerId);\n return enqueue(async () => {\n const db = await database();\n if (!db) return;\n const owner = await sha256Hex(ownerId);\n const tx = db.transaction([SNAPSHOTS_STORE, LISTS_STORE], \"readwrite\");\n for (const storeName of [SNAPSHOTS_STORE, LISTS_STORE]) {\n const store = tx.objectStore(storeName);\n const keys = await requestToPromise(store.index(BY_OWNER).getAllKeys(owner));\n for (const key of keys) store.delete(key);\n }\n await transactionDone(tx);\n });\n },\n clearAll() {\n dropPendingOf(null);\n return enqueue(async () => {\n const db = await database();\n if (!db) return;\n const tx = db.transaction([SNAPSHOTS_STORE, LISTS_STORE], \"readwrite\");\n tx.objectStore(SNAPSHOTS_STORE).clear();\n tx.objectStore(LISTS_STORE).clear();\n await transactionDone(tx);\n });\n },\n async flush() {\n await Promise.all([...pending.keys()].map(flushPending));\n await Promise.all([...pendingLists.keys()].map(flushList));\n await queue;\n },\n };\n}\n"],"names":["existing"],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { StatewireThread } from '@assistant-ui/react-statewire';
|
|
2
|
+
import type { DeepAgentConnectionState } from './types';
|
|
3
|
+
export type DeepAgentThreadStatus = StatewireThread.ThreadStatus;
|
|
4
|
+
/**
|
|
5
|
+
* Runtime-scoped thread status, as the library presents it: `"loading"` /
|
|
6
|
+
* `"ready"` / the run's status replicated by the host, with a mid-run
|
|
7
|
+
* connection loss presented as `"evicted"` (server-update pod drain) or
|
|
8
|
+
* `"disconnected"` instead of `"running"`. Throws outside a statewire aui
|
|
9
|
+
* provider, matching react-statewire 0.13's removed `useStatewireThreadStatus`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useDeepAgentThreadStatus(): DeepAgentThreadStatus;
|
|
12
|
+
/** The two presented statuses that hide a live run behind a channel problem. */
|
|
13
|
+
export type DeepAgentStaleRunReason = Extract<DeepAgentThreadStatus, 'disconnected' | 'evicted'>;
|
|
14
|
+
/** A first connection attempt can present an optimistic run without a stale warning. */
|
|
15
|
+
export declare function resolveStaleRunReason({ status, connection, }: {
|
|
16
|
+
status: DeepAgentThreadStatus;
|
|
17
|
+
connection?: DeepAgentConnectionState | null;
|
|
18
|
+
}): DeepAgentStaleRunReason | null;
|
|
19
|
+
/**
|
|
20
|
+
* Whether the thread has a live run to present — the composer's Running bar
|
|
21
|
+
* and its Stop/Queue slot.
|
|
22
|
+
*
|
|
23
|
+
* The library derives `thread.isRunning` from the PRESENTED status, so a run
|
|
24
|
+
* that is live on the host but sits behind a channel that has not connected
|
|
25
|
+
* yet reads as not running. Behind a first dial that is exactly the run the
|
|
26
|
+
* client just seeded — switching back to a thread that was running when you
|
|
27
|
+
* left, or a brand-new chat's optimistic first send — and nothing is stale:
|
|
28
|
+
* the channel is still attaching. Hiding the run for that round-trip flashes
|
|
29
|
+
* Ready and a Send button before Running comes back. A run behind a reconnect
|
|
30
|
+
* or an eviction is presented by the stale treatment (`resolveStaleRunReason`),
|
|
31
|
+
* never as live.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveRunLive({ status, connection, }: {
|
|
34
|
+
status: DeepAgentThreadStatus;
|
|
35
|
+
connection?: DeepAgentConnectionState | null;
|
|
36
|
+
}): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* `thread.isRunning` for a `useAuiState` selector, folded through
|
|
39
|
+
* `resolveRunLive` when the thread is a statewire thread. A thread without a
|
|
40
|
+
* statewire status (another runtime, a test stub) keeps the library's answer.
|
|
41
|
+
*/
|
|
42
|
+
export declare function readRunLive(thread: {
|
|
43
|
+
isRunning: boolean;
|
|
44
|
+
extras?: unknown;
|
|
45
|
+
}, connection: DeepAgentConnectionState | null): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* The active thread's channel, for `readRunLive`'s first-dial verdict. Each
|
|
48
|
+
* host provides it from its own lifecycle state (`AthenaProvider`, the
|
|
49
|
+
* Chrome extension's lifecycle provider); `null` means "no channel known",
|
|
50
|
+
* which folds a `disconnected` status as stale.
|
|
51
|
+
*/
|
|
52
|
+
export declare const DeepAgentConnectionContext: import("react").Context<DeepAgentConnectionState | null>;
|
|
53
|
+
export declare function useDeepAgentConnection(): DeepAgentConnectionState | null;
|