@athenaintel/react 0.22.3 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +394 -4
- package/dist/chat/AthenaChat.cjs +389 -240
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.d.ts +26 -8
- package/dist/chat/AthenaChat.js +394 -245
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/StatewireApprovalCard.cjs +2 -1
- package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
- package/dist/chat/StatewireApprovalCard.js +2 -1
- package/dist/chat/StatewireApprovalCard.js.map +1 -1
- package/dist/chat/StatewireClientToolBridge.cjs +1 -0
- package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
- package/dist/chat/StatewireClientToolBridge.js +1 -0
- package/dist/chat/StatewireClientToolBridge.js.map +1 -1
- package/dist/chat/StatewireQueuedMessages.cjs +1 -0
- package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
- package/dist/chat/StatewireQueuedMessages.js +1 -0
- package/dist/chat/StatewireQueuedMessages.js.map +1 -1
- package/dist/chat/WaitingOnYouBanner.cjs +100 -0
- package/dist/chat/WaitingOnYouBanner.cjs.map +1 -0
- package/dist/chat/WaitingOnYouBanner.d.ts +29 -0
- package/dist/chat/WaitingOnYouBanner.js +100 -0
- package/dist/chat/WaitingOnYouBanner.js.map +1 -0
- package/dist/chat/athena-chat-welcome.cjs +148 -0
- package/dist/chat/athena-chat-welcome.cjs.map +1 -0
- package/dist/chat/athena-chat-welcome.d.ts +54 -0
- package/dist/chat/athena-chat-welcome.js +148 -0
- package/dist/chat/athena-chat-welcome.js.map +1 -0
- package/dist/chat/athena-composer-controls.cjs +76 -0
- package/dist/chat/athena-composer-controls.cjs.map +1 -0
- package/dist/chat/athena-composer-controls.d.ts +21 -0
- package/dist/chat/athena-composer-controls.js +76 -0
- package/dist/chat/athena-composer-controls.js.map +1 -0
- package/dist/chat/composer-keyboard-hint.cjs +61 -0
- package/dist/chat/composer-keyboard-hint.cjs.map +1 -0
- package/dist/chat/composer-keyboard-hint.d.ts +33 -0
- package/dist/chat/composer-keyboard-hint.js +61 -0
- package/dist/chat/composer-keyboard-hint.js.map +1 -0
- package/dist/chat/message-time.cjs +64 -0
- package/dist/chat/message-time.cjs.map +1 -0
- package/dist/chat/message-time.d.ts +45 -0
- package/dist/chat/message-time.js +64 -0
- package/dist/chat/message-time.js.map +1 -0
- package/dist/chat/run-activity.cjs +38 -7
- package/dist/chat/run-activity.cjs.map +1 -1
- package/dist/chat/run-activity.d.ts +14 -3
- package/dist/chat/run-activity.js +39 -8
- package/dist/chat/run-activity.js.map +1 -1
- package/dist/chat/statewire-client-tools.cjs +2 -1
- package/dist/chat/statewire-client-tools.cjs.map +1 -1
- package/dist/chat/statewire-client-tools.js +2 -1
- package/dist/chat/statewire-client-tools.js.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.cjs +2 -1
- package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.js +2 -1
- package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
- package/dist/chat/thread-scroll-to-bottom.cjs +24 -0
- package/dist/chat/thread-scroll-to-bottom.cjs.map +1 -0
- package/dist/chat/thread-scroll-to-bottom.d.ts +11 -0
- package/dist/chat/thread-scroll-to-bottom.js +24 -0
- package/dist/chat/thread-scroll-to-bottom.js.map +1 -0
- package/dist/chat/tiptap-text.cjs +26 -99
- package/dist/chat/tiptap-text.cjs.map +1 -1
- package/dist/chat/tiptap-text.d.ts +13 -0
- package/dist/chat/tiptap-text.js +26 -99
- package/dist/chat/tiptap-text.js.map +1 -1
- package/dist/chat/use-athena-run-live.cjs +2 -1
- package/dist/chat/use-athena-run-live.cjs.map +1 -1
- package/dist/chat/use-athena-run-live.js +2 -1
- package/dist/chat/use-athena-run-live.js.map +1 -1
- package/dist/chat/use-statewire-approval-request.cjs +1 -0
- package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
- package/dist/chat/use-statewire-approval-request.js +1 -0
- package/dist/chat/use-statewire-approval-request.js.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.cjs +39 -4
- package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.d.ts +21 -0
- package/dist/chat-ui/composer/tiptap-composer.js +39 -4
- package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
- package/dist/chat-ui/index.cjs +15 -1
- package/dist/chat-ui/index.cjs.map +1 -1
- package/dist/chat-ui/index.d.ts +6 -3
- package/dist/chat-ui/index.js +16 -2
- package/dist/chat-ui/index.js.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.cjs +31 -4
- package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.js +31 -4
- package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
- package/dist/chat-ui/messages/message-components.cjs +19 -1
- package/dist/chat-ui/messages/message-components.cjs.map +1 -1
- package/dist/chat-ui/messages/message-components.d.ts +13 -0
- package/dist/chat-ui/messages/message-components.js +19 -1
- package/dist/chat-ui/messages/message-components.js.map +1 -1
- package/dist/chat-ui/messages/runtime-message.cjs +2 -1
- package/dist/chat-ui/messages/runtime-message.cjs.map +1 -1
- package/dist/chat-ui/messages/runtime-message.js +2 -1
- package/dist/chat-ui/messages/runtime-message.js.map +1 -1
- package/dist/chat-ui/messages/statewire-continue-run.cjs +1 -0
- package/dist/chat-ui/messages/statewire-continue-run.cjs.map +1 -1
- package/dist/chat-ui/messages/statewire-continue-run.js +1 -0
- package/dist/chat-ui/messages/statewire-continue-run.js.map +1 -1
- package/dist/chat-ui/messages/user-edit-composer.cjs +3 -1
- package/dist/chat-ui/messages/user-edit-composer.cjs.map +1 -1
- package/dist/chat-ui/messages/user-edit-composer.js +3 -1
- package/dist/chat-ui/messages/user-edit-composer.js.map +1 -1
- package/dist/chat-ui/messages/wake-marker.cjs +84 -0
- package/dist/chat-ui/messages/wake-marker.cjs.map +1 -0
- package/dist/chat-ui/messages/wake-marker.d.ts +16 -0
- package/dist/chat-ui/messages/wake-marker.js +84 -0
- package/dist/chat-ui/messages/wake-marker.js.map +1 -0
- package/dist/chat-ui/rich-text/chat-blocks.cjs +177 -0
- package/dist/chat-ui/rich-text/chat-blocks.cjs.map +1 -0
- package/dist/chat-ui/rich-text/chat-blocks.d.ts +58 -0
- package/dist/chat-ui/rich-text/chat-blocks.js +177 -0
- package/dist/chat-ui/rich-text/chat-blocks.js.map +1 -0
- package/dist/chat-ui/rich-text/chat-link.cjs +69 -0
- package/dist/chat-ui/rich-text/chat-link.cjs.map +1 -0
- package/dist/chat-ui/rich-text/chat-link.d.ts +24 -0
- package/dist/chat-ui/rich-text/chat-link.js +69 -0
- package/dist/chat-ui/rich-text/chat-link.js.map +1 -0
- package/dist/chat-ui/rich-text/chat-message-body.cjs +144 -18
- package/dist/chat-ui/rich-text/chat-message-body.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-message-body.d.ts +10 -1
- package/dist/chat-ui/rich-text/chat-message-body.js +149 -23
- package/dist/chat-ui/rich-text/chat-message-body.js.map +1 -1
- package/dist/chat-ui/rich-text/chat-node-views.cjs +84 -4
- package/dist/chat-ui/rich-text/chat-node-views.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-node-views.d.ts +12 -1
- package/dist/chat-ui/rich-text/chat-node-views.js +85 -5
- package/dist/chat-ui/rich-text/chat-node-views.js.map +1 -1
- package/dist/chat-ui/rich-text/chat-text-schema.cjs +21 -3
- package/dist/chat-ui/rich-text/chat-text-schema.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-text-schema.d.ts +17 -2
- package/dist/chat-ui/rich-text/chat-text-schema.js +21 -3
- package/dist/chat-ui/rich-text/chat-text-schema.js.map +1 -1
- package/dist/chat-ui/rich-text/citation-anchors.cjs +139 -0
- package/dist/chat-ui/rich-text/citation-anchors.cjs.map +1 -0
- package/dist/chat-ui/rich-text/citation-anchors.d.ts +74 -0
- package/dist/chat-ui/rich-text/citation-anchors.js +139 -0
- package/dist/chat-ui/rich-text/citation-anchors.js.map +1 -0
- package/dist/chat-ui/statewire.cjs +8 -1
- package/dist/chat-ui/statewire.cjs.map +1 -1
- package/dist/chat-ui/statewire.d.ts +2 -0
- package/dist/chat-ui/statewire.js +8 -1
- package/dist/chat-ui/statewire.js.map +1 -1
- package/dist/chat-ui/thread/chat-composer-dock.cjs +27 -6
- package/dist/chat-ui/thread/chat-composer-dock.cjs.map +1 -1
- package/dist/chat-ui/thread/chat-composer-dock.d.ts +21 -1
- package/dist/chat-ui/thread/chat-composer-dock.js +28 -7
- package/dist/chat-ui/thread/chat-composer-dock.js.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.cjs +12 -13
- package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.d.ts +11 -10
- package/dist/chat-ui/thread/statewire-history-edge.js +13 -14
- package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
- package/dist/chat-ui/thread/thread-loading-overlay.cjs +31 -0
- package/dist/chat-ui/thread/thread-loading-overlay.cjs.map +1 -0
- package/dist/chat-ui/thread/thread-loading-overlay.d.ts +14 -0
- package/dist/chat-ui/thread/thread-loading-overlay.js +31 -0
- package/dist/chat-ui/thread/thread-loading-overlay.js.map +1 -0
- package/dist/composer/ComposerDropZone.cjs +8 -1
- package/dist/composer/ComposerDropZone.cjs.map +1 -1
- package/dist/composer/ComposerDropZone.d.ts +6 -0
- package/dist/composer/ComposerDropZone.js +9 -2
- package/dist/composer/ComposerDropZone.js.map +1 -1
- package/dist/diagnostics/errors.cjs +20 -0
- package/dist/diagnostics/errors.cjs.map +1 -1
- package/dist/diagnostics/errors.d.ts +20 -0
- package/dist/diagnostics/errors.js +20 -0
- package/dist/diagnostics/errors.js.map +1 -1
- package/dist/index.cjs +47 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +26 -7
- package/dist/index.js +51 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/use-prefers-reduced-motion.cjs +29 -0
- package/dist/lib/use-prefers-reduced-motion.cjs.map +1 -0
- package/dist/lib/use-prefers-reduced-motion.d.ts +6 -0
- package/dist/lib/use-prefers-reduced-motion.js +29 -0
- package/dist/lib/use-prefers-reduced-motion.js.map +1 -0
- package/dist/packages/agent-runtime/src/conversation-index.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/conversation-index.js.map +1 -1
- package/dist/packages/agent-runtime/src/conversation-list.cjs +59 -0
- package/dist/packages/agent-runtime/src/conversation-list.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/conversation-list.js +60 -1
- package/dist/packages/agent-runtime/src/conversation-list.js.map +1 -1
- package/dist/packages/agent-runtime/src/deep-agent-transport-recipe.cjs +5 -3
- package/dist/packages/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/deep-agent-transport-recipe.js +5 -3
- package/dist/packages/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
- package/dist/packages/agent-runtime/src/edit-command.cjs +21 -17
- package/dist/packages/agent-runtime/src/edit-command.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/edit-command.js +22 -18
- package/dist/packages/agent-runtime/src/edit-command.js.map +1 -1
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.cjs +9 -11
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.js +9 -11
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/packages/agent-runtime/src/github-wake-event.cjs +86 -0
- package/dist/packages/agent-runtime/src/github-wake-event.cjs.map +1 -0
- package/dist/packages/agent-runtime/src/github-wake-event.js +86 -0
- package/dist/packages/agent-runtime/src/github-wake-event.js.map +1 -0
- package/dist/packages/agent-runtime/src/message-window.cjs +150 -42
- package/dist/packages/agent-runtime/src/message-window.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/message-window.js +151 -43
- package/dist/packages/agent-runtime/src/message-window.js.map +1 -1
- package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.cjs +13 -9
- package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.js +13 -9
- package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
- package/dist/packages/agent-runtime/src/statewire-suspended.cjs +1 -3
- package/dist/packages/agent-runtime/src/statewire-suspended.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/statewire-suspended.js +1 -3
- package/dist/packages/agent-runtime/src/statewire-suspended.js.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-edit-submit.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-edit-submit.js.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-thread.cjs +61 -30
- package/dist/packages/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-thread.js +59 -28
- package/dist/packages/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-window-sync.cjs +56 -36
- package/dist/packages/agent-runtime/src/use-deep-agent-window-sync.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-window-sync.js +59 -39
- package/dist/packages/agent-runtime/src/use-deep-agent-window-sync.js.map +1 -1
- package/dist/packages/react/package.json.cjs +1 -1
- package/dist/packages/react/package.json.js +1 -1
- package/dist/provider/AthenaContext.cjs.map +1 -1
- package/dist/provider/AthenaContext.d.ts +3 -0
- package/dist/provider/AthenaContext.js.map +1 -1
- package/dist/provider/AthenaProvider.cjs +93 -45
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.d.ts +6 -1
- package/dist/provider/AthenaProvider.js +97 -49
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/runtime/statewire-lifecycle.cjs +2 -1
- package/dist/runtime/statewire-lifecycle.cjs.map +1 -1
- package/dist/runtime/statewire-lifecycle.js +2 -1
- package/dist/runtime/statewire-lifecycle.js.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs +3 -2
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.d.ts +8 -12
- package/dist/runtime/useAthenaStatewireRuntime.js +3 -2
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/search/useAthenaRepoSearch.cjs +94 -0
- package/dist/search/useAthenaRepoSearch.cjs.map +1 -0
- package/dist/search/useAthenaRepoSearch.d.ts +95 -0
- package/dist/search/useAthenaRepoSearch.js +94 -0
- package/dist/search/useAthenaRepoSearch.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/threads/SessionList.cjs +486 -0
- package/dist/threads/SessionList.cjs.map +1 -0
- package/dist/threads/SessionList.d.ts +60 -0
- package/dist/threads/SessionList.js +486 -0
- package/dist/threads/SessionList.js.map +1 -0
- package/dist/threads/api.cjs +112 -4
- package/dist/threads/api.cjs.map +1 -1
- package/dist/threads/api.d.ts +128 -1
- package/dist/threads/api.js +113 -5
- package/dist/threads/api.js.map +1 -1
- package/dist/threads/conversation-list-fetcher.cjs +27 -3
- package/dist/threads/conversation-list-fetcher.cjs.map +1 -1
- package/dist/threads/conversation-list-fetcher.d.ts +16 -3
- package/dist/threads/conversation-list-fetcher.js +27 -3
- package/dist/threads/conversation-list-fetcher.js.map +1 -1
- package/dist/threads/index.d.ts +5 -1
- package/dist/threads/session-list-model.cjs +130 -0
- package/dist/threads/session-list-model.cjs.map +1 -0
- package/dist/threads/session-list-model.d.ts +62 -0
- package/dist/threads/session-list-model.js +130 -0
- package/dist/threads/session-list-model.js.map +1 -0
- package/dist/threads/statewire-thread-list.cjs +220 -38
- package/dist/threads/statewire-thread-list.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.d.ts +152 -2
- package/dist/threads/statewire-thread-list.js +222 -40
- package/dist/threads/statewire-thread-list.js.map +1 -1
- package/dist/threads/thread-prefetcher.cjs +63 -0
- package/dist/threads/thread-prefetcher.cjs.map +1 -0
- package/dist/threads/thread-prefetcher.d.ts +54 -0
- package/dist/threads/thread-prefetcher.js +63 -0
- package/dist/threads/thread-prefetcher.js.map +1 -0
- package/dist/threads/use-athena-session-attention.cjs +22 -0
- package/dist/threads/use-athena-session-attention.cjs.map +1 -0
- package/dist/threads/use-athena-session-attention.d.ts +24 -0
- package/dist/threads/use-athena-session-attention.js +22 -0
- package/dist/threads/use-athena-session-attention.js.map +1 -0
- package/dist/threads/use-rest-conversation-history.cjs +25 -2
- package/dist/threads/use-rest-conversation-history.cjs.map +1 -1
- package/dist/threads/use-rest-conversation-history.d.ts +8 -1
- package/dist/threads/use-rest-conversation-history.js +25 -2
- package/dist/threads/use-rest-conversation-history.js.map +1 -1
- package/dist/threads/use-statewire-conversation-history.cjs +40 -16
- package/dist/threads/use-statewire-conversation-history.cjs.map +1 -1
- package/dist/threads/use-statewire-conversation-history.d.ts +13 -0
- package/dist/threads/use-statewire-conversation-history.js +40 -16
- package/dist/threads/use-statewire-conversation-history.js.map +1 -1
- package/dist/threads/use-thread-archive.cjs +128 -0
- package/dist/threads/use-thread-archive.cjs.map +1 -0
- package/dist/threads/use-thread-archive.d.ts +26 -0
- package/dist/threads/use-thread-archive.js +128 -0
- package/dist/threads/use-thread-archive.js.map +1 -0
- package/dist/threads/use-thread-favorite.cjs +53 -0
- package/dist/threads/use-thread-favorite.cjs.map +1 -0
- package/dist/threads/use-thread-favorite.d.ts +49 -0
- package/dist/threads/use-thread-favorite.js +53 -0
- package/dist/threads/use-thread-favorite.js.map +1 -0
- package/dist/threads/use-thread-field-override.cjs +184 -0
- package/dist/threads/use-thread-field-override.cjs.map +1 -0
- package/dist/threads/use-thread-field-override.d.ts +55 -0
- package/dist/threads/use-thread-field-override.js +184 -0
- package/dist/threads/use-thread-field-override.js.map +1 -0
- package/dist/threads/use-thread-rename.cjs +53 -0
- package/dist/threads/use-thread-rename.cjs.map +1 -0
- package/dist/threads/use-thread-rename.d.ts +48 -0
- package/dist/threads/use-thread-rename.js +53 -0
- package/dist/threads/use-thread-rename.js.map +1 -0
- package/dist/tools/index.cjs +5 -1
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.js +7 -3
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/misc-tool-uis.cjs +2 -1
- package/dist/tools/misc-tool-uis.cjs.map +1 -1
- package/dist/tools/misc-tool-uis.js +2 -1
- package/dist/tools/misc-tool-uis.js.map +1 -1
- package/dist/tools/primitives.cjs +25 -2
- package/dist/tools/primitives.cjs.map +1 -1
- package/dist/tools/primitives.d.ts +9 -2
- package/dist/tools/primitives.js +26 -3
- package/dist/tools/primitives.js.map +1 -1
- package/dist/tools/tool-appearance.cjs +11 -0
- package/dist/tools/tool-appearance.cjs.map +1 -0
- package/dist/tools/tool-appearance.d.ts +29 -0
- package/dist/tools/tool-appearance.js +11 -0
- package/dist/tools/tool-appearance.js.map +1 -0
- package/dist/tools/tool-fallback.cjs +211 -13
- package/dist/tools/tool-fallback.cjs.map +1 -1
- package/dist/tools/tool-fallback.d.ts +31 -4
- package/dist/tools/tool-fallback.js +214 -16
- package/dist/tools/tool-fallback.js.map +1 -1
- package/dist/tools/use-elapsed-seconds.cjs +24 -0
- package/dist/tools/use-elapsed-seconds.cjs.map +1 -0
- package/dist/tools/use-elapsed-seconds.d.ts +10 -0
- package/dist/tools/use-elapsed-seconds.js +24 -0
- package/dist/tools/use-elapsed-seconds.js.map +1 -0
- package/dist/tools/voice-update-tool-ui.cjs +2 -1
- package/dist/tools/voice-update-tool-ui.cjs.map +1 -1
- package/dist/tools/voice-update-tool-ui.js +2 -1
- package/dist/tools/voice-update-tool-ui.js.map +1 -1
- package/package.json +1 -1
- package/src/chat-ui/tailwind-preset.js +14 -1
package/dist/threads/api.cjs
CHANGED
|
@@ -41,7 +41,8 @@ async function listThreads(backendUrl, auth, opts = {}) {
|
|
|
41
41
|
exclude_triggered: opts.exclude_triggered ?? false,
|
|
42
42
|
...opts.app_id ? { app_id: opts.app_id } : {},
|
|
43
43
|
...opts.start_channel ? { start_channel: opts.start_channel } : {},
|
|
44
|
-
...opts.search ? { search: opts.search } : {}
|
|
44
|
+
...opts.search ? { search: opts.search } : {},
|
|
45
|
+
...opts.include_pull_requests ? { include_pull_requests: true } : {}
|
|
45
46
|
})
|
|
46
47
|
});
|
|
47
48
|
if (!res.ok) {
|
|
@@ -108,6 +109,93 @@ async function setThreadReadState(backendUrl, auth, opts) {
|
|
|
108
109
|
}
|
|
109
110
|
return res.json();
|
|
110
111
|
}
|
|
112
|
+
function classifyThreadRouteRejection(status, body, threadId) {
|
|
113
|
+
let detail = body || void 0;
|
|
114
|
+
try {
|
|
115
|
+
const parsed = JSON.parse(body);
|
|
116
|
+
if (parsed && typeof parsed === "object") {
|
|
117
|
+
const record = parsed;
|
|
118
|
+
detail = record.detail ?? record.message ?? parsed;
|
|
119
|
+
}
|
|
120
|
+
} catch {
|
|
121
|
+
}
|
|
122
|
+
const routeMissing = status === 405 || status === 404 && !mentionsThread(body, threadId);
|
|
123
|
+
return { routeMissing, detail };
|
|
124
|
+
}
|
|
125
|
+
function mentionsThread(body, threadId) {
|
|
126
|
+
if (!threadId) return false;
|
|
127
|
+
const escaped = threadId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
128
|
+
return new RegExp(`(^|[^A-Za-z0-9_-])${escaped}($|[^A-Za-z0-9_-])`).test(body);
|
|
129
|
+
}
|
|
130
|
+
function isThreadRouteUnavailableError(error, code) {
|
|
131
|
+
return errors.isAthenaSdkError(error) && error.code === code && error.context.route_missing === true;
|
|
132
|
+
}
|
|
133
|
+
async function setThreadFavorite(backendUrl, auth, opts) {
|
|
134
|
+
const base = getAthenaApiBaseUrl(backendUrl);
|
|
135
|
+
const res = await fetch(`${base}/api/conversations/threads/favorite`, {
|
|
136
|
+
method: "POST",
|
|
137
|
+
headers: { "Content-Type": "application/json", ...getAuthHeaders(auth) },
|
|
138
|
+
body: JSON.stringify({
|
|
139
|
+
thread_id: opts.threadId,
|
|
140
|
+
is_favorited: opts.isFavorited
|
|
141
|
+
})
|
|
142
|
+
});
|
|
143
|
+
if (!res.ok) {
|
|
144
|
+
const refused = res.status === 401 || res.status === 403;
|
|
145
|
+
const { routeMissing, detail } = classifyThreadRouteRejection(
|
|
146
|
+
res.status,
|
|
147
|
+
await getResponseErrorBody(res),
|
|
148
|
+
opts.threadId
|
|
149
|
+
);
|
|
150
|
+
throw new errors.AthenaSdkError({
|
|
151
|
+
code: refused ? "auth_rejected" : "thread_favorite_failed",
|
|
152
|
+
message: `Failed to set thread favorite: ${res.status}`,
|
|
153
|
+
status: res.status,
|
|
154
|
+
detail,
|
|
155
|
+
hint: refused ? "The credential cannot view this thread." : routeMissing ? "The backend has no favorite route yet (older agora); the pin stays read-only until it deploys." : res.status === 404 ? "The thread no longer exists on the server (archived or deleted elsewhere); refresh the list." : "Check backendUrl points at the Agora API base.",
|
|
156
|
+
context: { thread_id: opts.threadId, auth_mode: getAuthMode(auth), route_missing: routeMissing }
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return res.json();
|
|
160
|
+
}
|
|
161
|
+
function isThreadFavoriteUnavailableError(error) {
|
|
162
|
+
return isThreadRouteUnavailableError(error, "thread_favorite_failed");
|
|
163
|
+
}
|
|
164
|
+
const THREAD_TITLE_MAX_LENGTH = 200;
|
|
165
|
+
async function renameThread(backendUrl, auth, opts) {
|
|
166
|
+
const base = getAthenaApiBaseUrl(backendUrl);
|
|
167
|
+
const res = await fetch(`${base}/api/conversations/threads/rename`, {
|
|
168
|
+
method: "POST",
|
|
169
|
+
headers: { "Content-Type": "application/json", ...getAuthHeaders(auth) },
|
|
170
|
+
body: JSON.stringify({
|
|
171
|
+
thread_id: opts.threadId,
|
|
172
|
+
title: opts.title
|
|
173
|
+
})
|
|
174
|
+
});
|
|
175
|
+
if (!res.ok) {
|
|
176
|
+
const refused = res.status === 401 || res.status === 403;
|
|
177
|
+
const { routeMissing, detail } = classifyThreadRouteRejection(
|
|
178
|
+
res.status,
|
|
179
|
+
await getResponseErrorBody(res),
|
|
180
|
+
opts.threadId
|
|
181
|
+
);
|
|
182
|
+
throw new errors.AthenaSdkError({
|
|
183
|
+
code: refused ? "auth_rejected" : "thread_rename_failed",
|
|
184
|
+
message: `Failed to rename thread: ${res.status}`,
|
|
185
|
+
status: res.status,
|
|
186
|
+
detail,
|
|
187
|
+
hint: refused ? "The credential cannot edit this thread (a viewer can pin a shared session, not retitle it)." : routeMissing ? "The backend has no rename route yet (older agora); sessions cannot be renamed from here until it deploys." : res.status === 404 ? "The thread no longer exists on the server (archived or deleted elsewhere); refresh the list." : res.status === 422 ? `The title must be 1–${THREAD_TITLE_MAX_LENGTH} characters after trimming.` : "Check backendUrl points at the Agora API base.",
|
|
188
|
+
context: { thread_id: opts.threadId, auth_mode: getAuthMode(auth), route_missing: routeMissing }
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return res.json();
|
|
192
|
+
}
|
|
193
|
+
function isThreadRenameUnavailableError(error) {
|
|
194
|
+
return isThreadRouteUnavailableError(error, "thread_rename_failed");
|
|
195
|
+
}
|
|
196
|
+
function isThreadArchiveUnavailableError(error) {
|
|
197
|
+
return isThreadRouteUnavailableError(error, "thread_archive_failed");
|
|
198
|
+
}
|
|
111
199
|
async function createThread(backendUrl, auth, opts = {}) {
|
|
112
200
|
const base = getAthenaApiBaseUrl(backendUrl);
|
|
113
201
|
const res = await fetch(`${base}/api/unstable/threads/`, {
|
|
@@ -151,7 +239,7 @@ function getAuthMode(auth) {
|
|
|
151
239
|
function getResponseErrorBody(response) {
|
|
152
240
|
return response.text().catch(() => "");
|
|
153
241
|
}
|
|
154
|
-
async function getThreadState(backendUrl, auth, threadId) {
|
|
242
|
+
async function getThreadState(backendUrl, auth, threadId, opts = {}) {
|
|
155
243
|
var _a, _b, _c, _d;
|
|
156
244
|
const base = getAthenaApiBaseUrl(backendUrl);
|
|
157
245
|
const authMode = getAuthMode(auth);
|
|
@@ -165,9 +253,10 @@ async function getThreadState(backendUrl, auth, threadId) {
|
|
|
165
253
|
res = await fetch(endpoint, {
|
|
166
254
|
method: "POST",
|
|
167
255
|
headers: { "Content-Type": "application/json", ...getAuthHeaders(auth) },
|
|
256
|
+
signal: opts.signal ?? null,
|
|
168
257
|
body: JSON.stringify({
|
|
169
258
|
thread_id: threadId,
|
|
170
|
-
skip_cache: true
|
|
259
|
+
skip_cache: opts.skipCache ?? true
|
|
171
260
|
})
|
|
172
261
|
});
|
|
173
262
|
} catch (error) {
|
|
@@ -225,13 +314,32 @@ async function archiveThread(backendUrl, auth, threadId) {
|
|
|
225
314
|
body: JSON.stringify({ thread_id: threadId })
|
|
226
315
|
});
|
|
227
316
|
if (!res.ok) {
|
|
228
|
-
|
|
317
|
+
const refused = res.status === 401 || res.status === 403;
|
|
318
|
+
const { routeMissing, detail } = classifyThreadRouteRejection(
|
|
319
|
+
res.status,
|
|
320
|
+
await getResponseErrorBody(res),
|
|
321
|
+
threadId
|
|
322
|
+
);
|
|
323
|
+
throw new errors.AthenaSdkError({
|
|
324
|
+
code: refused ? "auth_rejected" : "thread_archive_failed",
|
|
325
|
+
message: `Failed to archive thread: ${res.status}`,
|
|
326
|
+
status: res.status,
|
|
327
|
+
detail,
|
|
328
|
+
hint: refused ? "The credential cannot access this thread." : routeMissing ? "The backend has no archive route (no checkpointer, or an older agora)." : res.status === 404 ? "The thread no longer exists on the server (archived or deleted elsewhere); refresh the list." : "Check backendUrl points at the Agora API base.",
|
|
329
|
+
context: { thread_id: threadId, auth_mode: getAuthMode(auth), route_missing: routeMissing }
|
|
330
|
+
});
|
|
229
331
|
}
|
|
230
332
|
}
|
|
333
|
+
exports.THREAD_TITLE_MAX_LENGTH = THREAD_TITLE_MAX_LENGTH;
|
|
231
334
|
exports.archiveThread = archiveThread;
|
|
232
335
|
exports.createThread = createThread;
|
|
233
336
|
exports.fetchAccountIdentity = fetchAccountIdentity;
|
|
234
337
|
exports.getThreadState = getThreadState;
|
|
338
|
+
exports.isThreadArchiveUnavailableError = isThreadArchiveUnavailableError;
|
|
339
|
+
exports.isThreadFavoriteUnavailableError = isThreadFavoriteUnavailableError;
|
|
340
|
+
exports.isThreadRenameUnavailableError = isThreadRenameUnavailableError;
|
|
235
341
|
exports.listThreads = listThreads;
|
|
342
|
+
exports.renameThread = renameThread;
|
|
343
|
+
exports.setThreadFavorite = setThreadFavorite;
|
|
236
344
|
exports.setThreadReadState = setThreadReadState;
|
|
237
345
|
//# sourceMappingURL=api.cjs.map
|
package/dist/threads/api.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.cjs","sources":["../../src/threads/api.ts"],"sourcesContent":["/**\n * Athena thread API client.\n * Calls existing REST endpoints for thread CRUD.\n */\n\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport { AthenaSdkError } from '../diagnostics/errors';\n\nexport interface ThreadSummary {\n thread_id: string;\n title: string;\n created_at: string;\n updated_at: string;\n last_message: string | null;\n message_count: number;\n state: string | null;\n start_channel?: string | null;\n last_channel?: string | null;\n /** Client app that created the session (SESSION_APP_ID_GUIDE). */\n app_id?: string | null;\n /** Trigger marker for automated/background sessions. */\n trigger_type?: string | null;\n /** Whether the calling user has seen this thread since it last changed. */\n is_unread?: boolean;\n}\n\n/**\n * True for fetch cancellations (unmount/remount aborts, StrictMode double\n * effects). These are lifecycle noise, not failures: emitting them as\n * `*.error` diagnostics floods the console with\n * \"signal is aborted without reason\" for requests the caller itself aborted.\n */\nfunction isAbortError(error: unknown): boolean {\n return (\n (error instanceof DOMException && error.name === 'AbortError') ||\n (error instanceof Error && error.name === 'AbortError')\n );\n}\n\nexport interface ThreadListResponse {\n threads: ThreadSummary[];\n /** Server lookahead result. Older servers may omit this field. */\n has_more?: boolean;\n}\n\nexport interface ThreadCreateResponse {\n thread_id: string;\n}\n\ninterface AuthConfig {\n apiKey?: string;\n token?: string | null;\n}\n\nfunction getAuthHeaders(auth: AuthConfig): Record<string, string> {\n if (auth.token) {\n return { Authorization: `Bearer ${auth.token}` };\n }\n if (auth.apiKey) {\n return { 'X-API-KEY': auth.apiKey };\n }\n return {};\n}\n\n/**\n * Resolves the Athena API base URL from backendUrl.\n * Thread endpoints live under `/api/conversations/threads/*` and `/api/unstable/threads/`.\n * If backendUrl points at a nested Athena endpoint, trim it back to the API base first.\n */\nfunction getAthenaApiBaseUrl(backendUrl: string): string {\n const stripped = backendUrl.replace(/\\/api\\/assistant-ui\\/?$/, '');\n // If the suffix wasn't found, assume the URL already points to the API base\n if (stripped === backendUrl) {\n return backendUrl.replace(/\\/$/, '');\n }\n return stripped;\n}\n\nexport async function listThreads(\n backendUrl: string,\n auth: AuthConfig,\n opts: {\n limit?: number;\n offset?: number;\n exclude_triggered?: boolean;\n app_id?: string;\n start_channel?: string;\n search?: string;\n signal?: AbortSignal;\n } = {},\n): Promise<ThreadListResponse> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const endSpan = athenaDiagnostics.span('threads.list', 'threads.list.start', {\n auth_mode: getAuthMode(auth),\n app_id: opts.app_id,\n });\n try {\n const res = await fetch(`${base}/api/conversations/threads/list`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getAuthHeaders(auth) },\n signal: opts.signal ?? null,\n body: JSON.stringify({\n limit: opts.limit ?? 50,\n offset: opts.offset ?? 0,\n // Default to the full recent-conversations set unless a caller\n // explicitly asks to hide triggered/background sessions.\n exclude_triggered: opts.exclude_triggered ?? false,\n ...(opts.app_id ? { app_id: opts.app_id } : {}),\n ...(opts.start_channel ? { start_channel: opts.start_channel } : {}),\n ...(opts.search ? { search: opts.search } : {}),\n }),\n });\n if (!res.ok) {\n throw new AthenaSdkError({\n code: res.status === 401 || res.status === 403 ? 'auth_rejected' : 'threads_list_failed',\n message: `Failed to list threads: ${res.status}`,\n status: res.status,\n hint:\n res.status === 401 || res.status === 403\n ? 'The credential was refused. Check the token/API key and that the user belongs to the workspace.'\n : 'Check backendUrl points at the Agora API base.',\n context: { auth_mode: getAuthMode(auth) },\n });\n }\n const data = (await res.json()) as ThreadListResponse;\n endSpan('threads.list.done', { data: { count: data.threads?.length ?? 0 } });\n return data;\n } catch (error) {\n // Cancellation is lifecycle noise (unmount/remount aborts): log it as an\n // informational abort, not an error — passing `error` would force the\n // span end to error level and spam the console.\n if (isAbortError(error)) {\n endSpan('threads.list.aborted', { data: { reason: 'request aborted' } });\n } else {\n endSpan('threads.list.error', { error });\n }\n throw error;\n }\n}\n\n/** The `(workspace, user)` pair the credential resolves to on the backend. */\nexport interface AccountIdentity {\n userId: string;\n /** `null` for a user with no current workspace. */\n workspaceId: string | null;\n}\n\n/**\n * Resolve the credential's agora identity. The conversation index is one\n * statewire instance per `(workspace, user)`, and neither half is knowable\n * from the credential alone: the SDK's auth context carries an identity\n * provider user id, not agora's, and never a workspace.\n */\nexport async function fetchAccountIdentity(\n backendUrl: string,\n auth: AuthConfig,\n opts: { signal?: AbortSignal } = {},\n): Promise<AccountIdentity> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const res = await fetch(`${base}/api/v0/me`, {\n headers: getAuthHeaders(auth),\n signal: opts.signal ?? null,\n });\n if (!res.ok) {\n throw new AthenaSdkError({\n code: res.status === 401 || res.status === 403 ? 'auth_rejected' : 'threads_list_failed',\n message: `Failed to resolve account identity: ${res.status}`,\n status: res.status,\n hint:\n res.status === 401 || res.status === 403\n ? 'The credential was refused. Check the token/API key and that the user belongs to the workspace.'\n : 'Check backendUrl points at the Agora API base.',\n context: { auth_mode: getAuthMode(auth) },\n });\n }\n const body = (await res.json()) as { user_id?: unknown; workspace_id?: unknown };\n if (typeof body.user_id !== 'string' || body.user_id.length === 0) {\n throw new AthenaSdkError({\n code: 'threads_list_failed',\n message: 'Account identity lookup returned no user id.',\n context: { auth_mode: getAuthMode(auth) },\n });\n }\n return {\n userId: body.user_id,\n workspaceId: typeof body.workspace_id === 'string' ? body.workspace_id : null,\n };\n}\n\nexport interface ThreadReadStateResponse {\n thread_id: string;\n is_unread: boolean;\n}\n\n/** Store the calling user's read receipt for a thread. */\nexport async function setThreadReadState(\n backendUrl: string,\n auth: AuthConfig,\n opts: { threadId: string; isUnread: boolean },\n): Promise<ThreadReadStateResponse> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const res = await fetch(`${base}/api/conversations/threads/read-state`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getAuthHeaders(auth) },\n body: JSON.stringify({\n thread_id: opts.threadId,\n is_unread: opts.isUnread,\n }),\n });\n if (!res.ok) {\n throw new Error(`[AthenaSDK] Failed to set thread read state: ${res.status}`);\n }\n return res.json();\n}\n\nexport async function createThread(\n backendUrl: string,\n auth: AuthConfig,\n opts: { systemPrompt?: string; enabledTools?: string[]; appId?: string } = {},\n): Promise<ThreadCreateResponse> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const res = await fetch(`${base}/api/unstable/threads/`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getAuthHeaders(auth) },\n body: JSON.stringify({\n config: {\n system_prompt: opts.systemPrompt ?? '',\n enabled_tools: opts.enabledTools,\n ...(opts.appId ? { app_id: opts.appId } : {}),\n },\n }),\n });\n if (!res.ok) {\n throw new Error(`[AthenaSDK] Failed to create thread: ${res.status}`);\n }\n return res.json();\n}\n\nexport interface ThreadStateResponse {\n thread_id: string;\n messages: unknown[];\n status?: string;\n [key: string]: unknown;\n}\n\ninterface ConversationThreadResponse {\n thread?: {\n thread_id?: string;\n state?: string | null;\n channel_values?: Record<string, unknown> | null;\n messages?: unknown[] | null;\n } | null;\n thread_found?: boolean;\n}\n\n/**\n * Deserialize a LangChain serialized message.\n * The API returns messages in `{lc, type: \"constructor\", id, kwargs}` format.\n * We need the plain format: `{type: \"human\", content: \"...\", id: \"...\"}`.\n */\nfunction deserializeMessage(msg: unknown): unknown {\n if (\n msg &&\n typeof msg === 'object' &&\n 'lc' in msg &&\n 'kwargs' in msg &&\n (msg as Record<string, unknown>).type === 'constructor'\n ) {\n const kwargs = (msg as { kwargs: Record<string, unknown> }).kwargs;\n\n // Recursively deserialize nested content without mutating the original\n const deserializedToolCalls = Array.isArray(kwargs.tool_calls)\n ? kwargs.tool_calls.map((tc: unknown) => {\n if (tc && typeof tc === 'object' && 'lc' in tc && 'kwargs' in tc) {\n return (tc as { kwargs: unknown }).kwargs;\n }\n return tc;\n })\n : kwargs.tool_calls;\n\n return { ...kwargs, tool_calls: deserializedToolCalls };\n }\n return msg;\n}\n\n/** Return a non-sensitive auth label for request diagnostics. */\nfunction getAuthMode(auth: AuthConfig): 'bearer' | 'api-key' | 'none' {\n if (auth.token) {\n return 'bearer';\n }\n if (auth.apiKey) {\n return 'api-key';\n }\n return 'none';\n}\n\n/** Safely read a response body for error messages without masking the root failure. */\nfunction getResponseErrorBody(response: Response): Promise<string> {\n return response.text().catch(() => '');\n}\n\n/**\n * Fetch persisted thread state from the conversations API.\n *\n * This endpoint is the same source used by Athena's conversation sidebar and\n * supports API-key auth plus BYO SSO session tokens sent as Bearer tokens.\n */\nexport async function getThreadState(\n backendUrl: string,\n auth: AuthConfig,\n threadId: string,\n): Promise<ThreadStateResponse> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const authMode = getAuthMode(auth);\n const endpoint = `${base}/api/conversations/threads/get`;\n\n const endSpan = athenaDiagnostics.span('threads.history', 'threads.history.start', {\n thread_id: threadId,\n auth_mode: authMode,\n });\n\n let res: Response;\n try {\n res = await fetch(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getAuthHeaders(auth) },\n body: JSON.stringify({\n thread_id: threadId,\n skip_cache: true,\n }),\n });\n } catch (error) {\n if (isAbortError(error)) {\n endSpan('threads.history.aborted', {\n data: { thread_id: threadId, reason: 'request aborted' },\n });\n } else {\n endSpan('threads.history.error', { error, data: { thread_id: threadId } });\n }\n throw error;\n }\n if (!res.ok) {\n const body = await getResponseErrorBody(res);\n const error = new AthenaSdkError({\n code: res.status === 401 || res.status === 403 ? 'auth_rejected' : 'thread_load_failed',\n message: `Failed to get thread state: ${res.status} (${authMode})${\n body ? `: ${body.slice(0, 300)}` : ''\n }`,\n status: res.status,\n hint: 'A brand-new thread may not be persisted yet; anything else means the credential or backendUrl is wrong.',\n context: { thread_id: threadId, auth_mode: authMode },\n });\n endSpan('threads.history.error', { error, data: { thread_id: threadId } });\n throw error;\n }\n const data = (await res.json()) as ConversationThreadResponse;\n const channelMessages = data.thread?.channel_values?.messages;\n endSpan('threads.history.done', {\n data: {\n thread_id: threadId,\n found: data.thread_found !== false,\n message_count: Array.isArray(channelMessages)\n ? channelMessages.length\n : (data.thread?.messages?.length ?? 0),\n },\n });\n const thread = data.thread;\n\n if (data.thread_found === false || !thread) {\n return {\n thread_id: threadId,\n messages: [],\n };\n }\n\n const channelValues = thread.channel_values ?? {};\n const rawMessages = Array.isArray(channelValues.messages)\n ? channelValues.messages\n : Array.isArray(thread.messages)\n ? thread.messages\n : [];\n\n return {\n ...channelValues,\n thread_id: thread.thread_id ?? threadId,\n messages: rawMessages.map(deserializeMessage),\n ...(thread.state ? { status: thread.state } : {}),\n };\n}\n\nexport async function archiveThread(\n backendUrl: string,\n auth: AuthConfig,\n threadId: string,\n): Promise<void> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const res = await fetch(`${base}/api/conversations/threads/archive`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getAuthHeaders(auth) },\n body: JSON.stringify({ thread_id: threadId }),\n });\n if (!res.ok) {\n throw new Error(`[AthenaSDK] Failed to archive thread: ${res.status}`);\n }\n}\n"],"names":["athenaDiagnostics","AthenaSdkError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api.cjs","sources":["../../src/threads/api.ts"],"sourcesContent":["/**\n * Athena thread API client.\n * Calls existing REST endpoints for thread CRUD.\n */\n\nimport type {\n ConversationAttention,\n ConversationAttentionSource,\n} from '@athenaintel/agent-runtime';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport { AthenaSdkError, type AthenaSdkErrorCode, isAthenaSdkError } from '../diagnostics/errors';\n\n/**\n * Live GitHub state of a pull request the thread opened, read by the server\n * when the list renders (agora `agent_pr_threads` is the only stored link).\n */\nexport interface ThreadPullRequest {\n /** `owner/repo` the pull request lives in. */\n repo_full_name: string;\n number: number;\n url: string;\n title: string;\n state: 'OPEN' | 'CLOSED' | 'MERGED';\n is_draft: boolean;\n /** GitHub's review decision (APPROVED, CHANGES_REQUESTED, REVIEW_REQUIRED) or null. */\n review_decision: string | null;\n /** Combined state of the checks on the head commit. */\n checks_state: 'SUCCESS' | 'FAILURE' | 'PENDING' | 'NONE';\n /** ISO 8601 timestamp of the pull request's last update on GitHub. */\n updated_at: string;\n}\n\n/** The last event that woke a resting thread (a GitHub webhook, a schedule, a handoff). */\nexport interface ThreadWake {\n source: string | null;\n reason: string | null;\n /** ISO 8601 timestamp of the wake. */\n at: string | null;\n}\n\nexport interface ThreadSummary {\n thread_id: string;\n title: string;\n created_at: string;\n updated_at: string;\n last_message: string | null;\n message_count: number;\n state: string | null;\n start_channel?: string | null;\n last_channel?: string | null;\n /** Client app that created the session (SESSION_APP_ID_GUIDE). */\n app_id?: string | null;\n /** Trigger marker for automated/background sessions. */\n trigger_type?: string | null;\n /** Whether the calling user has seen this thread since it last changed. */\n is_unread?: boolean;\n /**\n * Canonical status_v2 planes (`idle | active | needs_input | error` and\n * `scheduled | queued | running | needs_input | completed | failed |\n * canceled`); older servers omit them.\n */\n session_status?: string | null;\n run_status?: string | null;\n /**\n * The viewer's attention state, the one-line next action (≤ 80 chars) and\n * the signal that produced them, derived server-side; older servers omit them.\n */\n attention?: ConversationAttention | null;\n next_action?: string | null;\n attention_source?: ConversationAttentionSource | null;\n /** Whether the calling user favorited (pinned) the thread; older servers omit it. */\n is_favorited?: boolean;\n /** The last wake of a resting thread; older servers omit it. */\n last_wake?: ThreadWake | null;\n /**\n * Pull requests the thread opened with their live GitHub state. `[]` when\n * it opened none, `null` when the state could not be read right now;\n * older servers omit the field.\n */\n pull_requests?: ThreadPullRequest[] | null;\n}\n\n/**\n * True for fetch cancellations (unmount/remount aborts, StrictMode double\n * effects). These are lifecycle noise, not failures: emitting them as\n * `*.error` diagnostics floods the console with\n * \"signal is aborted without reason\" for requests the caller itself aborted.\n */\nfunction isAbortError(error: unknown): boolean {\n return (\n (error instanceof DOMException && error.name === 'AbortError') ||\n (error instanceof Error && error.name === 'AbortError')\n );\n}\n\nexport interface ThreadListResponse {\n threads: ThreadSummary[];\n /** Server lookahead result. Older servers may omit this field. */\n has_more?: boolean;\n}\n\nexport interface ThreadCreateResponse {\n thread_id: string;\n}\n\ninterface AuthConfig {\n apiKey?: string;\n token?: string | null;\n}\n\nfunction getAuthHeaders(auth: AuthConfig): Record<string, string> {\n if (auth.token) {\n return { Authorization: `Bearer ${auth.token}` };\n }\n if (auth.apiKey) {\n return { 'X-API-KEY': auth.apiKey };\n }\n return {};\n}\n\n/**\n * Resolves the Athena API base URL from backendUrl.\n * Thread endpoints live under `/api/conversations/threads/*` and `/api/unstable/threads/`.\n * If backendUrl points at a nested Athena endpoint, trim it back to the API base first.\n */\nfunction getAthenaApiBaseUrl(backendUrl: string): string {\n const stripped = backendUrl.replace(/\\/api\\/assistant-ui\\/?$/, '');\n // If the suffix wasn't found, assume the URL already points to the API base\n if (stripped === backendUrl) {\n return backendUrl.replace(/\\/$/, '');\n }\n return stripped;\n}\n\nexport async function listThreads(\n backendUrl: string,\n auth: AuthConfig,\n opts: {\n limit?: number;\n offset?: number;\n exclude_triggered?: boolean;\n app_id?: string;\n start_channel?: string;\n search?: string;\n /** Ask the server for live GitHub state on `pull_requests` (off by default: it costs a lookup). */\n include_pull_requests?: boolean;\n signal?: AbortSignal;\n } = {},\n): Promise<ThreadListResponse> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const endSpan = athenaDiagnostics.span('threads.list', 'threads.list.start', {\n auth_mode: getAuthMode(auth),\n app_id: opts.app_id,\n });\n try {\n const res = await fetch(`${base}/api/conversations/threads/list`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getAuthHeaders(auth) },\n signal: opts.signal ?? null,\n body: JSON.stringify({\n limit: opts.limit ?? 50,\n offset: opts.offset ?? 0,\n // Default to the full recent-conversations set unless a caller\n // explicitly asks to hide triggered/background sessions.\n exclude_triggered: opts.exclude_triggered ?? false,\n ...(opts.app_id ? { app_id: opts.app_id } : {}),\n ...(opts.start_channel ? { start_channel: opts.start_channel } : {}),\n ...(opts.search ? { search: opts.search } : {}),\n ...(opts.include_pull_requests ? { include_pull_requests: true } : {}),\n }),\n });\n if (!res.ok) {\n throw new AthenaSdkError({\n code: res.status === 401 || res.status === 403 ? 'auth_rejected' : 'threads_list_failed',\n message: `Failed to list threads: ${res.status}`,\n status: res.status,\n hint:\n res.status === 401 || res.status === 403\n ? 'The credential was refused. Check the token/API key and that the user belongs to the workspace.'\n : 'Check backendUrl points at the Agora API base.',\n context: { auth_mode: getAuthMode(auth) },\n });\n }\n const data = (await res.json()) as ThreadListResponse;\n endSpan('threads.list.done', { data: { count: data.threads?.length ?? 0 } });\n return data;\n } catch (error) {\n // Cancellation is lifecycle noise (unmount/remount aborts): log it as an\n // informational abort, not an error — passing `error` would force the\n // span end to error level and spam the console.\n if (isAbortError(error)) {\n endSpan('threads.list.aborted', { data: { reason: 'request aborted' } });\n } else {\n endSpan('threads.list.error', { error });\n }\n throw error;\n }\n}\n\n/** The `(workspace, user)` pair the credential resolves to on the backend. */\nexport interface AccountIdentity {\n userId: string;\n /** `null` for a user with no current workspace. */\n workspaceId: string | null;\n}\n\n/**\n * Resolve the credential's agora identity. The conversation index is one\n * statewire instance per `(workspace, user)`, and neither half is knowable\n * from the credential alone: the SDK's auth context carries an identity\n * provider user id, not agora's, and never a workspace.\n */\nexport async function fetchAccountIdentity(\n backendUrl: string,\n auth: AuthConfig,\n opts: { signal?: AbortSignal } = {},\n): Promise<AccountIdentity> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const res = await fetch(`${base}/api/v0/me`, {\n headers: getAuthHeaders(auth),\n signal: opts.signal ?? null,\n });\n if (!res.ok) {\n throw new AthenaSdkError({\n code: res.status === 401 || res.status === 403 ? 'auth_rejected' : 'threads_list_failed',\n message: `Failed to resolve account identity: ${res.status}`,\n status: res.status,\n hint:\n res.status === 401 || res.status === 403\n ? 'The credential was refused. Check the token/API key and that the user belongs to the workspace.'\n : 'Check backendUrl points at the Agora API base.',\n context: { auth_mode: getAuthMode(auth) },\n });\n }\n const body = (await res.json()) as { user_id?: unknown; workspace_id?: unknown };\n if (typeof body.user_id !== 'string' || body.user_id.length === 0) {\n throw new AthenaSdkError({\n code: 'threads_list_failed',\n message: 'Account identity lookup returned no user id.',\n context: { auth_mode: getAuthMode(auth) },\n });\n }\n return {\n userId: body.user_id,\n workspaceId: typeof body.workspace_id === 'string' ? body.workspace_id : null,\n };\n}\n\nexport interface ThreadReadStateResponse {\n thread_id: string;\n is_unread: boolean;\n}\n\n/** Store the calling user's read receipt for a thread. */\nexport async function setThreadReadState(\n backendUrl: string,\n auth: AuthConfig,\n opts: { threadId: string; isUnread: boolean },\n): Promise<ThreadReadStateResponse> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const res = await fetch(`${base}/api/conversations/threads/read-state`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getAuthHeaders(auth) },\n body: JSON.stringify({\n thread_id: opts.threadId,\n is_unread: opts.isUnread,\n }),\n });\n if (!res.ok) {\n throw new Error(`[AthenaSDK] Failed to set thread read state: ${res.status}`);\n }\n return res.json();\n}\n\nexport interface ThreadFavoriteResponse {\n thread_id: string;\n /** The server's state after the write. */\n is_favorited: boolean;\n}\n\n/**\n * Classify a 4xx from one of the per-thread write routes (`favorite`,\n * `rename`, `archive`). A 404 there is ambiguous: FastAPI answers\n * `{\"detail\":\"Not Found\"}` for a route an older agora does not have, the\n * archive route answers `\"Endpoint not available\"` on an agora without the\n * checkpointer — and each route answers 404 for a thread that no longer\n * exists (`\"Thread <id> not found\"`, `\"Conversation with langchain thread id\n * <id> not found\"`). The routes' own not-found answers name the thread, so a\n * body that does not is the ROUTE missing, and only that withdraws the\n * feature; a stale row must not disable the action for every other row.\n */\nfunction classifyThreadRouteRejection(\n status: number,\n body: string,\n threadId: string,\n): { routeMissing: boolean; detail: unknown } {\n let detail: unknown = body || undefined;\n try {\n const parsed: unknown = JSON.parse(body);\n if (parsed && typeof parsed === 'object') {\n const record = parsed as { detail?: unknown; message?: unknown };\n detail = record.detail ?? record.message ?? parsed;\n }\n } catch {\n // A non-JSON body (a proxy page) is kept as text.\n }\n const routeMissing = status === 405 || (status === 404 && !mentionsThread(body, threadId));\n return { routeMissing, detail };\n}\n\n/**\n * Whether an error body names the thread as a whole token (the routes embed\n * the id between spaces: `Thread <id> not found`); a substring match would\n * let a short id match a letter inside `\"detail\"`.\n */\nfunction mentionsThread(body: string, threadId: string): boolean {\n if (!threadId) return false;\n const escaped = threadId.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return new RegExp(`(^|[^A-Za-z0-9_-])${escaped}($|[^A-Za-z0-9_-])`).test(body);\n}\n\n/** True when a per-thread write was rejected because the backend has no such route. */\nfunction isThreadRouteUnavailableError(error: unknown, code: AthenaSdkErrorCode): boolean {\n return isAthenaSdkError(error) && error.code === code && error.context.route_missing === true;\n}\n\n/**\n * Pin (favorite) or unpin a thread for the calling user. The response is the\n * server's truth after the write. Rejections: 401 / 403 when the caller\n * cannot view the thread (`auth_rejected`), otherwise `thread_favorite_failed`\n * with the HTTP status — 404 / 405 from an agora that predates the route,\n * which `isThreadFavoriteUnavailableError` recognizes so callers can fall\n * back to a read-only pin.\n */\nexport async function setThreadFavorite(\n backendUrl: string,\n auth: AuthConfig,\n opts: { threadId: string; isFavorited: boolean },\n): Promise<ThreadFavoriteResponse> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const res = await fetch(`${base}/api/conversations/threads/favorite`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getAuthHeaders(auth) },\n body: JSON.stringify({\n thread_id: opts.threadId,\n is_favorited: opts.isFavorited,\n }),\n });\n if (!res.ok) {\n const refused = res.status === 401 || res.status === 403;\n const { routeMissing, detail } = classifyThreadRouteRejection(\n res.status,\n await getResponseErrorBody(res),\n opts.threadId,\n );\n throw new AthenaSdkError({\n code: refused ? 'auth_rejected' : 'thread_favorite_failed',\n message: `Failed to set thread favorite: ${res.status}`,\n status: res.status,\n detail,\n hint: refused\n ? 'The credential cannot view this thread.'\n : routeMissing\n ? 'The backend has no favorite route yet (older agora); the pin stays read-only until it deploys.'\n : res.status === 404\n ? 'The thread no longer exists on the server (archived or deleted elsewhere); refresh the list.'\n : 'Check backendUrl points at the Agora API base.',\n context: { thread_id: opts.threadId, auth_mode: getAuthMode(auth), route_missing: routeMissing },\n });\n }\n return res.json();\n}\n\n/**\n * True when `setThreadFavorite` failed because the backend has no favorite\n * route (a 405, or a 404 whose body does not name the thread — see\n * `classifyThreadRouteRejection`); a 404 for a thread that is gone is a\n * per-row failure and leaves the toggle available.\n */\nexport function isThreadFavoriteUnavailableError(error: unknown): boolean {\n return isThreadRouteUnavailableError(error, 'thread_favorite_failed');\n}\n\nexport interface ThreadRenameResponse {\n thread_id: string;\n /** The stored title after the write (trimmed by the server). */\n title: string;\n}\n\n/** The longest title the rename route accepts; the server answers 422 past it. */\nexport const THREAD_TITLE_MAX_LENGTH = 200;\n\n/**\n * Rename a thread for every viewer (`POST /api/conversations/threads/rename`).\n * The server trims the title and stores 1–200 characters; the response is the\n * row's title after the write. Rejections: 401 / 403 when the caller cannot\n * edit the thread (`auth_rejected` — a viewer can pin a shared session but not\n * retitle it), otherwise `thread_rename_failed` with the HTTP status — 404 /\n * 405 from an agora that predates the route, which\n * `isThreadRenameUnavailableError` recognizes so callers can drop the action.\n */\nexport async function renameThread(\n backendUrl: string,\n auth: AuthConfig,\n opts: { threadId: string; title: string },\n): Promise<ThreadRenameResponse> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const res = await fetch(`${base}/api/conversations/threads/rename`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getAuthHeaders(auth) },\n body: JSON.stringify({\n thread_id: opts.threadId,\n title: opts.title,\n }),\n });\n if (!res.ok) {\n const refused = res.status === 401 || res.status === 403;\n const { routeMissing, detail } = classifyThreadRouteRejection(\n res.status,\n await getResponseErrorBody(res),\n opts.threadId,\n );\n throw new AthenaSdkError({\n code: refused ? 'auth_rejected' : 'thread_rename_failed',\n message: `Failed to rename thread: ${res.status}`,\n status: res.status,\n detail,\n hint: refused\n ? 'The credential cannot edit this thread (a viewer can pin a shared session, not retitle it).'\n : routeMissing\n ? 'The backend has no rename route yet (older agora); sessions cannot be renamed from here until it deploys.'\n : res.status === 404\n ? 'The thread no longer exists on the server (archived or deleted elsewhere); refresh the list.'\n : res.status === 422\n ? `The title must be 1–${THREAD_TITLE_MAX_LENGTH} characters after trimming.`\n : 'Check backendUrl points at the Agora API base.',\n context: { thread_id: opts.threadId, auth_mode: getAuthMode(auth), route_missing: routeMissing },\n });\n }\n return res.json();\n}\n\n/**\n * True when `renameThread` failed because the backend has no rename route\n * (a 405, or a 404 whose body does not name the thread); a 404 for a thread\n * that is gone is a per-row failure and leaves the action offered.\n */\nexport function isThreadRenameUnavailableError(error: unknown): boolean {\n return isThreadRouteUnavailableError(error, 'thread_rename_failed');\n}\n\n/**\n * True when `archiveThread` failed because the backend offers no archive\n * route: a 405, FastAPI's bare 404 on an agora without the route, or the\n * route's own `\"Endpoint not available\"` 404 on an agora without the\n * checkpointer. The route's `\"Thread <id> not found\"` 404 for a stale row is\n * a per-row failure and leaves the action offered on every other row.\n */\nexport function isThreadArchiveUnavailableError(error: unknown): boolean {\n return isThreadRouteUnavailableError(error, 'thread_archive_failed');\n}\n\nexport async function createThread(\n backendUrl: string,\n auth: AuthConfig,\n opts: { systemPrompt?: string; enabledTools?: string[]; appId?: string } = {},\n): Promise<ThreadCreateResponse> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const res = await fetch(`${base}/api/unstable/threads/`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getAuthHeaders(auth) },\n body: JSON.stringify({\n config: {\n system_prompt: opts.systemPrompt ?? '',\n enabled_tools: opts.enabledTools,\n ...(opts.appId ? { app_id: opts.appId } : {}),\n },\n }),\n });\n if (!res.ok) {\n throw new Error(`[AthenaSDK] Failed to create thread: ${res.status}`);\n }\n return res.json();\n}\n\nexport interface ThreadStateResponse {\n thread_id: string;\n messages: unknown[];\n status?: string;\n [key: string]: unknown;\n}\n\ninterface ConversationThreadResponse {\n thread?: {\n thread_id?: string;\n state?: string | null;\n channel_values?: Record<string, unknown> | null;\n messages?: unknown[] | null;\n } | null;\n thread_found?: boolean;\n}\n\n/**\n * Deserialize a LangChain serialized message.\n * The API returns messages in `{lc, type: \"constructor\", id, kwargs}` format.\n * We need the plain format: `{type: \"human\", content: \"...\", id: \"...\"}`.\n */\nfunction deserializeMessage(msg: unknown): unknown {\n if (\n msg &&\n typeof msg === 'object' &&\n 'lc' in msg &&\n 'kwargs' in msg &&\n (msg as Record<string, unknown>).type === 'constructor'\n ) {\n const kwargs = (msg as { kwargs: Record<string, unknown> }).kwargs;\n\n // Recursively deserialize nested content without mutating the original\n const deserializedToolCalls = Array.isArray(kwargs.tool_calls)\n ? kwargs.tool_calls.map((tc: unknown) => {\n if (tc && typeof tc === 'object' && 'lc' in tc && 'kwargs' in tc) {\n return (tc as { kwargs: unknown }).kwargs;\n }\n return tc;\n })\n : kwargs.tool_calls;\n\n return { ...kwargs, tool_calls: deserializedToolCalls };\n }\n return msg;\n}\n\n/** Return a non-sensitive auth label for request diagnostics. */\nfunction getAuthMode(auth: AuthConfig): 'bearer' | 'api-key' | 'none' {\n if (auth.token) {\n return 'bearer';\n }\n if (auth.apiKey) {\n return 'api-key';\n }\n return 'none';\n}\n\n/** Safely read a response body for error messages without masking the root failure. */\nfunction getResponseErrorBody(response: Response): Promise<string> {\n return response.text().catch(() => '');\n}\n\n/**\n * Fetch persisted thread state from the conversations API.\n *\n * This endpoint is the same source used by Athena's conversation sidebar and\n * supports API-key auth plus BYO SSO session tokens sent as Bearer tokens.\n */\nexport async function getThreadState(\n backendUrl: string,\n auth: AuthConfig,\n threadId: string,\n opts: {\n /**\n * Bypass the server's Redis thread cache and read the checkpoint (default\n * `true`, the history load's contract). A warm-up read that only seeds a\n * first paint passes `false`: the cached copy is cheaper and the attach\n * snapshot replaces it anyway.\n */\n skipCache?: boolean;\n signal?: AbortSignal;\n } = {},\n): Promise<ThreadStateResponse> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const authMode = getAuthMode(auth);\n const endpoint = `${base}/api/conversations/threads/get`;\n\n const endSpan = athenaDiagnostics.span('threads.history', 'threads.history.start', {\n thread_id: threadId,\n auth_mode: authMode,\n });\n\n let res: Response;\n try {\n res = await fetch(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getAuthHeaders(auth) },\n signal: opts.signal ?? null,\n body: JSON.stringify({\n thread_id: threadId,\n skip_cache: opts.skipCache ?? true,\n }),\n });\n } catch (error) {\n if (isAbortError(error)) {\n endSpan('threads.history.aborted', {\n data: { thread_id: threadId, reason: 'request aborted' },\n });\n } else {\n endSpan('threads.history.error', { error, data: { thread_id: threadId } });\n }\n throw error;\n }\n if (!res.ok) {\n const body = await getResponseErrorBody(res);\n const error = new AthenaSdkError({\n code: res.status === 401 || res.status === 403 ? 'auth_rejected' : 'thread_load_failed',\n message: `Failed to get thread state: ${res.status} (${authMode})${\n body ? `: ${body.slice(0, 300)}` : ''\n }`,\n status: res.status,\n hint: 'A brand-new thread may not be persisted yet; anything else means the credential or backendUrl is wrong.',\n context: { thread_id: threadId, auth_mode: authMode },\n });\n endSpan('threads.history.error', { error, data: { thread_id: threadId } });\n throw error;\n }\n const data = (await res.json()) as ConversationThreadResponse;\n const channelMessages = data.thread?.channel_values?.messages;\n endSpan('threads.history.done', {\n data: {\n thread_id: threadId,\n found: data.thread_found !== false,\n message_count: Array.isArray(channelMessages)\n ? channelMessages.length\n : (data.thread?.messages?.length ?? 0),\n },\n });\n const thread = data.thread;\n\n if (data.thread_found === false || !thread) {\n return {\n thread_id: threadId,\n messages: [],\n };\n }\n\n const channelValues = thread.channel_values ?? {};\n const rawMessages = Array.isArray(channelValues.messages)\n ? channelValues.messages\n : Array.isArray(thread.messages)\n ? thread.messages\n : [];\n\n return {\n ...channelValues,\n thread_id: thread.thread_id ?? threadId,\n messages: rawMessages.map(deserializeMessage),\n ...(thread.state ? { status: thread.state } : {}),\n };\n}\n\n/**\n * Archive a thread (`POST /api/conversations/threads/archive`): it leaves\n * every list but keeps its state. Rejections: 401 / 403 when the caller\n * cannot access the thread (`auth_rejected`), otherwise\n * `thread_archive_failed` with the HTTP status — 404 / 405 when the backend\n * has no archive route, which `isThreadArchiveUnavailableError` recognizes.\n */\nexport async function archiveThread(\n backendUrl: string,\n auth: AuthConfig,\n threadId: string,\n): Promise<void> {\n const base = getAthenaApiBaseUrl(backendUrl);\n const res = await fetch(`${base}/api/conversations/threads/archive`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getAuthHeaders(auth) },\n body: JSON.stringify({ thread_id: threadId }),\n });\n if (!res.ok) {\n const refused = res.status === 401 || res.status === 403;\n const { routeMissing, detail } = classifyThreadRouteRejection(\n res.status,\n await getResponseErrorBody(res),\n threadId,\n );\n throw new AthenaSdkError({\n code: refused ? 'auth_rejected' : 'thread_archive_failed',\n message: `Failed to archive thread: ${res.status}`,\n status: res.status,\n detail,\n hint: refused\n ? 'The credential cannot access this thread.'\n : routeMissing\n ? 'The backend has no archive route (no checkpointer, or an older agora).'\n : res.status === 404\n ? 'The thread no longer exists on the server (archived or deleted elsewhere); refresh the list.'\n : 'Check backendUrl points at the Agora API base.',\n context: { thread_id: threadId, auth_mode: getAuthMode(auth), route_missing: routeMissing },\n });\n }\n}\n"],"names":["athenaDiagnostics","AthenaSdkError","isAthenaSdkError"],"mappings":"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"}
|
package/dist/threads/api.d.ts
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
* Athena thread API client.
|
|
3
3
|
* Calls existing REST endpoints for thread CRUD.
|
|
4
4
|
*/
|
|
5
|
+
import type { ConversationAttention, ConversationAttentionSource } from '@athenaintel/agent-runtime';
|
|
6
|
+
/**
|
|
7
|
+
* Live GitHub state of a pull request the thread opened, read by the server
|
|
8
|
+
* when the list renders (agora `agent_pr_threads` is the only stored link).
|
|
9
|
+
*/
|
|
10
|
+
export interface ThreadPullRequest {
|
|
11
|
+
/** `owner/repo` the pull request lives in. */
|
|
12
|
+
repo_full_name: string;
|
|
13
|
+
number: number;
|
|
14
|
+
url: string;
|
|
15
|
+
title: string;
|
|
16
|
+
state: 'OPEN' | 'CLOSED' | 'MERGED';
|
|
17
|
+
is_draft: boolean;
|
|
18
|
+
/** GitHub's review decision (APPROVED, CHANGES_REQUESTED, REVIEW_REQUIRED) or null. */
|
|
19
|
+
review_decision: string | null;
|
|
20
|
+
/** Combined state of the checks on the head commit. */
|
|
21
|
+
checks_state: 'SUCCESS' | 'FAILURE' | 'PENDING' | 'NONE';
|
|
22
|
+
/** ISO 8601 timestamp of the pull request's last update on GitHub. */
|
|
23
|
+
updated_at: string;
|
|
24
|
+
}
|
|
25
|
+
/** The last event that woke a resting thread (a GitHub webhook, a schedule, a handoff). */
|
|
26
|
+
export interface ThreadWake {
|
|
27
|
+
source: string | null;
|
|
28
|
+
reason: string | null;
|
|
29
|
+
/** ISO 8601 timestamp of the wake. */
|
|
30
|
+
at: string | null;
|
|
31
|
+
}
|
|
5
32
|
export interface ThreadSummary {
|
|
6
33
|
thread_id: string;
|
|
7
34
|
title: string;
|
|
@@ -18,6 +45,30 @@ export interface ThreadSummary {
|
|
|
18
45
|
trigger_type?: string | null;
|
|
19
46
|
/** Whether the calling user has seen this thread since it last changed. */
|
|
20
47
|
is_unread?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Canonical status_v2 planes (`idle | active | needs_input | error` and
|
|
50
|
+
* `scheduled | queued | running | needs_input | completed | failed |
|
|
51
|
+
* canceled`); older servers omit them.
|
|
52
|
+
*/
|
|
53
|
+
session_status?: string | null;
|
|
54
|
+
run_status?: string | null;
|
|
55
|
+
/**
|
|
56
|
+
* The viewer's attention state, the one-line next action (≤ 80 chars) and
|
|
57
|
+
* the signal that produced them, derived server-side; older servers omit them.
|
|
58
|
+
*/
|
|
59
|
+
attention?: ConversationAttention | null;
|
|
60
|
+
next_action?: string | null;
|
|
61
|
+
attention_source?: ConversationAttentionSource | null;
|
|
62
|
+
/** Whether the calling user favorited (pinned) the thread; older servers omit it. */
|
|
63
|
+
is_favorited?: boolean;
|
|
64
|
+
/** The last wake of a resting thread; older servers omit it. */
|
|
65
|
+
last_wake?: ThreadWake | null;
|
|
66
|
+
/**
|
|
67
|
+
* Pull requests the thread opened with their live GitHub state. `[]` when
|
|
68
|
+
* it opened none, `null` when the state could not be read right now;
|
|
69
|
+
* older servers omit the field.
|
|
70
|
+
*/
|
|
71
|
+
pull_requests?: ThreadPullRequest[] | null;
|
|
21
72
|
}
|
|
22
73
|
export interface ThreadListResponse {
|
|
23
74
|
threads: ThreadSummary[];
|
|
@@ -38,6 +89,8 @@ export declare function listThreads(backendUrl: string, auth: AuthConfig, opts?:
|
|
|
38
89
|
app_id?: string;
|
|
39
90
|
start_channel?: string;
|
|
40
91
|
search?: string;
|
|
92
|
+
/** Ask the server for live GitHub state on `pull_requests` (off by default: it costs a lookup). */
|
|
93
|
+
include_pull_requests?: boolean;
|
|
41
94
|
signal?: AbortSignal;
|
|
42
95
|
}): Promise<ThreadListResponse>;
|
|
43
96
|
/** The `(workspace, user)` pair the credential resolves to on the backend. */
|
|
@@ -64,6 +117,64 @@ export declare function setThreadReadState(backendUrl: string, auth: AuthConfig,
|
|
|
64
117
|
threadId: string;
|
|
65
118
|
isUnread: boolean;
|
|
66
119
|
}): Promise<ThreadReadStateResponse>;
|
|
120
|
+
export interface ThreadFavoriteResponse {
|
|
121
|
+
thread_id: string;
|
|
122
|
+
/** The server's state after the write. */
|
|
123
|
+
is_favorited: boolean;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Pin (favorite) or unpin a thread for the calling user. The response is the
|
|
127
|
+
* server's truth after the write. Rejections: 401 / 403 when the caller
|
|
128
|
+
* cannot view the thread (`auth_rejected`), otherwise `thread_favorite_failed`
|
|
129
|
+
* with the HTTP status — 404 / 405 from an agora that predates the route,
|
|
130
|
+
* which `isThreadFavoriteUnavailableError` recognizes so callers can fall
|
|
131
|
+
* back to a read-only pin.
|
|
132
|
+
*/
|
|
133
|
+
export declare function setThreadFavorite(backendUrl: string, auth: AuthConfig, opts: {
|
|
134
|
+
threadId: string;
|
|
135
|
+
isFavorited: boolean;
|
|
136
|
+
}): Promise<ThreadFavoriteResponse>;
|
|
137
|
+
/**
|
|
138
|
+
* True when `setThreadFavorite` failed because the backend has no favorite
|
|
139
|
+
* route (a 405, or a 404 whose body does not name the thread — see
|
|
140
|
+
* `classifyThreadRouteRejection`); a 404 for a thread that is gone is a
|
|
141
|
+
* per-row failure and leaves the toggle available.
|
|
142
|
+
*/
|
|
143
|
+
export declare function isThreadFavoriteUnavailableError(error: unknown): boolean;
|
|
144
|
+
export interface ThreadRenameResponse {
|
|
145
|
+
thread_id: string;
|
|
146
|
+
/** The stored title after the write (trimmed by the server). */
|
|
147
|
+
title: string;
|
|
148
|
+
}
|
|
149
|
+
/** The longest title the rename route accepts; the server answers 422 past it. */
|
|
150
|
+
export declare const THREAD_TITLE_MAX_LENGTH = 200;
|
|
151
|
+
/**
|
|
152
|
+
* Rename a thread for every viewer (`POST /api/conversations/threads/rename`).
|
|
153
|
+
* The server trims the title and stores 1–200 characters; the response is the
|
|
154
|
+
* row's title after the write. Rejections: 401 / 403 when the caller cannot
|
|
155
|
+
* edit the thread (`auth_rejected` — a viewer can pin a shared session but not
|
|
156
|
+
* retitle it), otherwise `thread_rename_failed` with the HTTP status — 404 /
|
|
157
|
+
* 405 from an agora that predates the route, which
|
|
158
|
+
* `isThreadRenameUnavailableError` recognizes so callers can drop the action.
|
|
159
|
+
*/
|
|
160
|
+
export declare function renameThread(backendUrl: string, auth: AuthConfig, opts: {
|
|
161
|
+
threadId: string;
|
|
162
|
+
title: string;
|
|
163
|
+
}): Promise<ThreadRenameResponse>;
|
|
164
|
+
/**
|
|
165
|
+
* True when `renameThread` failed because the backend has no rename route
|
|
166
|
+
* (a 405, or a 404 whose body does not name the thread); a 404 for a thread
|
|
167
|
+
* that is gone is a per-row failure and leaves the action offered.
|
|
168
|
+
*/
|
|
169
|
+
export declare function isThreadRenameUnavailableError(error: unknown): boolean;
|
|
170
|
+
/**
|
|
171
|
+
* True when `archiveThread` failed because the backend offers no archive
|
|
172
|
+
* route: a 405, FastAPI's bare 404 on an agora without the route, or the
|
|
173
|
+
* route's own `"Endpoint not available"` 404 on an agora without the
|
|
174
|
+
* checkpointer. The route's `"Thread <id> not found"` 404 for a stale row is
|
|
175
|
+
* a per-row failure and leaves the action offered on every other row.
|
|
176
|
+
*/
|
|
177
|
+
export declare function isThreadArchiveUnavailableError(error: unknown): boolean;
|
|
67
178
|
export declare function createThread(backendUrl: string, auth: AuthConfig, opts?: {
|
|
68
179
|
systemPrompt?: string;
|
|
69
180
|
enabledTools?: string[];
|
|
@@ -81,6 +192,22 @@ export interface ThreadStateResponse {
|
|
|
81
192
|
* This endpoint is the same source used by Athena's conversation sidebar and
|
|
82
193
|
* supports API-key auth plus BYO SSO session tokens sent as Bearer tokens.
|
|
83
194
|
*/
|
|
84
|
-
export declare function getThreadState(backendUrl: string, auth: AuthConfig, threadId: string
|
|
195
|
+
export declare function getThreadState(backendUrl: string, auth: AuthConfig, threadId: string, opts?: {
|
|
196
|
+
/**
|
|
197
|
+
* Bypass the server's Redis thread cache and read the checkpoint (default
|
|
198
|
+
* `true`, the history load's contract). A warm-up read that only seeds a
|
|
199
|
+
* first paint passes `false`: the cached copy is cheaper and the attach
|
|
200
|
+
* snapshot replaces it anyway.
|
|
201
|
+
*/
|
|
202
|
+
skipCache?: boolean;
|
|
203
|
+
signal?: AbortSignal;
|
|
204
|
+
}): Promise<ThreadStateResponse>;
|
|
205
|
+
/**
|
|
206
|
+
* Archive a thread (`POST /api/conversations/threads/archive`): it leaves
|
|
207
|
+
* every list but keeps its state. Rejections: 401 / 403 when the caller
|
|
208
|
+
* cannot access the thread (`auth_rejected`), otherwise
|
|
209
|
+
* `thread_archive_failed` with the HTTP status — 404 / 405 when the backend
|
|
210
|
+
* has no archive route, which `isThreadArchiveUnavailableError` recognizes.
|
|
211
|
+
*/
|
|
85
212
|
export declare function archiveThread(backendUrl: string, auth: AuthConfig, threadId: string): Promise<void>;
|
|
86
213
|
export {};
|
package/dist/threads/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { athenaDiagnostics } from "../diagnostics/athena-diagnostics.js";
|
|
2
|
-
import { AthenaSdkError } from "../diagnostics/errors.js";
|
|
2
|
+
import { AthenaSdkError, isAthenaSdkError } from "../diagnostics/errors.js";
|
|
3
3
|
function isAbortError(error) {
|
|
4
4
|
return error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
|
|
5
5
|
}
|
|
@@ -39,7 +39,8 @@ async function listThreads(backendUrl, auth, opts = {}) {
|
|
|
39
39
|
exclude_triggered: opts.exclude_triggered ?? false,
|
|
40
40
|
...opts.app_id ? { app_id: opts.app_id } : {},
|
|
41
41
|
...opts.start_channel ? { start_channel: opts.start_channel } : {},
|
|
42
|
-
...opts.search ? { search: opts.search } : {}
|
|
42
|
+
...opts.search ? { search: opts.search } : {},
|
|
43
|
+
...opts.include_pull_requests ? { include_pull_requests: true } : {}
|
|
43
44
|
})
|
|
44
45
|
});
|
|
45
46
|
if (!res.ok) {
|
|
@@ -106,6 +107,93 @@ async function setThreadReadState(backendUrl, auth, opts) {
|
|
|
106
107
|
}
|
|
107
108
|
return res.json();
|
|
108
109
|
}
|
|
110
|
+
function classifyThreadRouteRejection(status, body, threadId) {
|
|
111
|
+
let detail = body || void 0;
|
|
112
|
+
try {
|
|
113
|
+
const parsed = JSON.parse(body);
|
|
114
|
+
if (parsed && typeof parsed === "object") {
|
|
115
|
+
const record = parsed;
|
|
116
|
+
detail = record.detail ?? record.message ?? parsed;
|
|
117
|
+
}
|
|
118
|
+
} catch {
|
|
119
|
+
}
|
|
120
|
+
const routeMissing = status === 405 || status === 404 && !mentionsThread(body, threadId);
|
|
121
|
+
return { routeMissing, detail };
|
|
122
|
+
}
|
|
123
|
+
function mentionsThread(body, threadId) {
|
|
124
|
+
if (!threadId) return false;
|
|
125
|
+
const escaped = threadId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
126
|
+
return new RegExp(`(^|[^A-Za-z0-9_-])${escaped}($|[^A-Za-z0-9_-])`).test(body);
|
|
127
|
+
}
|
|
128
|
+
function isThreadRouteUnavailableError(error, code) {
|
|
129
|
+
return isAthenaSdkError(error) && error.code === code && error.context.route_missing === true;
|
|
130
|
+
}
|
|
131
|
+
async function setThreadFavorite(backendUrl, auth, opts) {
|
|
132
|
+
const base = getAthenaApiBaseUrl(backendUrl);
|
|
133
|
+
const res = await fetch(`${base}/api/conversations/threads/favorite`, {
|
|
134
|
+
method: "POST",
|
|
135
|
+
headers: { "Content-Type": "application/json", ...getAuthHeaders(auth) },
|
|
136
|
+
body: JSON.stringify({
|
|
137
|
+
thread_id: opts.threadId,
|
|
138
|
+
is_favorited: opts.isFavorited
|
|
139
|
+
})
|
|
140
|
+
});
|
|
141
|
+
if (!res.ok) {
|
|
142
|
+
const refused = res.status === 401 || res.status === 403;
|
|
143
|
+
const { routeMissing, detail } = classifyThreadRouteRejection(
|
|
144
|
+
res.status,
|
|
145
|
+
await getResponseErrorBody(res),
|
|
146
|
+
opts.threadId
|
|
147
|
+
);
|
|
148
|
+
throw new AthenaSdkError({
|
|
149
|
+
code: refused ? "auth_rejected" : "thread_favorite_failed",
|
|
150
|
+
message: `Failed to set thread favorite: ${res.status}`,
|
|
151
|
+
status: res.status,
|
|
152
|
+
detail,
|
|
153
|
+
hint: refused ? "The credential cannot view this thread." : routeMissing ? "The backend has no favorite route yet (older agora); the pin stays read-only until it deploys." : res.status === 404 ? "The thread no longer exists on the server (archived or deleted elsewhere); refresh the list." : "Check backendUrl points at the Agora API base.",
|
|
154
|
+
context: { thread_id: opts.threadId, auth_mode: getAuthMode(auth), route_missing: routeMissing }
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return res.json();
|
|
158
|
+
}
|
|
159
|
+
function isThreadFavoriteUnavailableError(error) {
|
|
160
|
+
return isThreadRouteUnavailableError(error, "thread_favorite_failed");
|
|
161
|
+
}
|
|
162
|
+
const THREAD_TITLE_MAX_LENGTH = 200;
|
|
163
|
+
async function renameThread(backendUrl, auth, opts) {
|
|
164
|
+
const base = getAthenaApiBaseUrl(backendUrl);
|
|
165
|
+
const res = await fetch(`${base}/api/conversations/threads/rename`, {
|
|
166
|
+
method: "POST",
|
|
167
|
+
headers: { "Content-Type": "application/json", ...getAuthHeaders(auth) },
|
|
168
|
+
body: JSON.stringify({
|
|
169
|
+
thread_id: opts.threadId,
|
|
170
|
+
title: opts.title
|
|
171
|
+
})
|
|
172
|
+
});
|
|
173
|
+
if (!res.ok) {
|
|
174
|
+
const refused = res.status === 401 || res.status === 403;
|
|
175
|
+
const { routeMissing, detail } = classifyThreadRouteRejection(
|
|
176
|
+
res.status,
|
|
177
|
+
await getResponseErrorBody(res),
|
|
178
|
+
opts.threadId
|
|
179
|
+
);
|
|
180
|
+
throw new AthenaSdkError({
|
|
181
|
+
code: refused ? "auth_rejected" : "thread_rename_failed",
|
|
182
|
+
message: `Failed to rename thread: ${res.status}`,
|
|
183
|
+
status: res.status,
|
|
184
|
+
detail,
|
|
185
|
+
hint: refused ? "The credential cannot edit this thread (a viewer can pin a shared session, not retitle it)." : routeMissing ? "The backend has no rename route yet (older agora); sessions cannot be renamed from here until it deploys." : res.status === 404 ? "The thread no longer exists on the server (archived or deleted elsewhere); refresh the list." : res.status === 422 ? `The title must be 1–${THREAD_TITLE_MAX_LENGTH} characters after trimming.` : "Check backendUrl points at the Agora API base.",
|
|
186
|
+
context: { thread_id: opts.threadId, auth_mode: getAuthMode(auth), route_missing: routeMissing }
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return res.json();
|
|
190
|
+
}
|
|
191
|
+
function isThreadRenameUnavailableError(error) {
|
|
192
|
+
return isThreadRouteUnavailableError(error, "thread_rename_failed");
|
|
193
|
+
}
|
|
194
|
+
function isThreadArchiveUnavailableError(error) {
|
|
195
|
+
return isThreadRouteUnavailableError(error, "thread_archive_failed");
|
|
196
|
+
}
|
|
109
197
|
async function createThread(backendUrl, auth, opts = {}) {
|
|
110
198
|
const base = getAthenaApiBaseUrl(backendUrl);
|
|
111
199
|
const res = await fetch(`${base}/api/unstable/threads/`, {
|
|
@@ -149,7 +237,7 @@ function getAuthMode(auth) {
|
|
|
149
237
|
function getResponseErrorBody(response) {
|
|
150
238
|
return response.text().catch(() => "");
|
|
151
239
|
}
|
|
152
|
-
async function getThreadState(backendUrl, auth, threadId) {
|
|
240
|
+
async function getThreadState(backendUrl, auth, threadId, opts = {}) {
|
|
153
241
|
var _a, _b, _c, _d;
|
|
154
242
|
const base = getAthenaApiBaseUrl(backendUrl);
|
|
155
243
|
const authMode = getAuthMode(auth);
|
|
@@ -163,9 +251,10 @@ async function getThreadState(backendUrl, auth, threadId) {
|
|
|
163
251
|
res = await fetch(endpoint, {
|
|
164
252
|
method: "POST",
|
|
165
253
|
headers: { "Content-Type": "application/json", ...getAuthHeaders(auth) },
|
|
254
|
+
signal: opts.signal ?? null,
|
|
166
255
|
body: JSON.stringify({
|
|
167
256
|
thread_id: threadId,
|
|
168
|
-
skip_cache: true
|
|
257
|
+
skip_cache: opts.skipCache ?? true
|
|
169
258
|
})
|
|
170
259
|
});
|
|
171
260
|
} catch (error) {
|
|
@@ -223,15 +312,34 @@ async function archiveThread(backendUrl, auth, threadId) {
|
|
|
223
312
|
body: JSON.stringify({ thread_id: threadId })
|
|
224
313
|
});
|
|
225
314
|
if (!res.ok) {
|
|
226
|
-
|
|
315
|
+
const refused = res.status === 401 || res.status === 403;
|
|
316
|
+
const { routeMissing, detail } = classifyThreadRouteRejection(
|
|
317
|
+
res.status,
|
|
318
|
+
await getResponseErrorBody(res),
|
|
319
|
+
threadId
|
|
320
|
+
);
|
|
321
|
+
throw new AthenaSdkError({
|
|
322
|
+
code: refused ? "auth_rejected" : "thread_archive_failed",
|
|
323
|
+
message: `Failed to archive thread: ${res.status}`,
|
|
324
|
+
status: res.status,
|
|
325
|
+
detail,
|
|
326
|
+
hint: refused ? "The credential cannot access this thread." : routeMissing ? "The backend has no archive route (no checkpointer, or an older agora)." : res.status === 404 ? "The thread no longer exists on the server (archived or deleted elsewhere); refresh the list." : "Check backendUrl points at the Agora API base.",
|
|
327
|
+
context: { thread_id: threadId, auth_mode: getAuthMode(auth), route_missing: routeMissing }
|
|
328
|
+
});
|
|
227
329
|
}
|
|
228
330
|
}
|
|
229
331
|
export {
|
|
332
|
+
THREAD_TITLE_MAX_LENGTH,
|
|
230
333
|
archiveThread,
|
|
231
334
|
createThread,
|
|
232
335
|
fetchAccountIdentity,
|
|
233
336
|
getThreadState,
|
|
337
|
+
isThreadArchiveUnavailableError,
|
|
338
|
+
isThreadFavoriteUnavailableError,
|
|
339
|
+
isThreadRenameUnavailableError,
|
|
234
340
|
listThreads,
|
|
341
|
+
renameThread,
|
|
342
|
+
setThreadFavorite,
|
|
235
343
|
setThreadReadState
|
|
236
344
|
};
|
|
237
345
|
//# sourceMappingURL=api.js.map
|