@flamingo-stack/openframe-frontend-core 0.0.204 → 0.0.205
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/dist/{chunk-4CWSZPXH.cjs → chunk-24KCAECR.cjs} +9 -9
- package/dist/{chunk-4CWSZPXH.cjs.map → chunk-24KCAECR.cjs.map} +1 -1
- package/dist/chunk-27APPAJN.cjs +24 -0
- package/dist/chunk-27APPAJN.cjs.map +1 -0
- package/dist/{chunk-UC43NICZ.cjs → chunk-664KA5FI.cjs} +2 -35
- package/dist/chunk-664KA5FI.cjs.map +1 -0
- package/dist/chunk-6RZYJICV.cjs +24 -0
- package/dist/chunk-6RZYJICV.cjs.map +1 -0
- package/dist/chunk-7L4DWM7P.js +24 -0
- package/dist/chunk-7L4DWM7P.js.map +1 -0
- package/dist/chunk-BZFW3FOF.cjs +21 -0
- package/dist/chunk-BZFW3FOF.cjs.map +1 -0
- package/dist/{chunk-N57KWHDB.js → chunk-CIPO6DXK.js} +5 -5
- package/dist/chunk-EL5YVPD5.js +21 -0
- package/dist/chunk-EL5YVPD5.js.map +1 -0
- package/dist/{chunk-ARQ4XP64.cjs → chunk-FDCFI7YT.cjs} +40080 -31492
- package/dist/chunk-FDCFI7YT.cjs.map +1 -0
- package/dist/chunk-G7UE6RKV.cjs +121 -0
- package/dist/chunk-G7UE6RKV.cjs.map +1 -0
- package/dist/{chunk-25LVV26X.cjs → chunk-JUZGUQMX.cjs} +178 -50
- package/dist/chunk-JUZGUQMX.cjs.map +1 -0
- package/dist/{chunk-SZPJ5R5B.js → chunk-KSOOKNBG.js} +1 -34
- package/dist/chunk-KSOOKNBG.js.map +1 -0
- package/dist/{chunk-RMB5DVED.cjs → chunk-KUZGEA7U.cjs} +83 -66
- package/dist/chunk-KUZGEA7U.cjs.map +1 -0
- package/dist/chunk-LXC6P2EO.js +63 -0
- package/dist/chunk-LXC6P2EO.js.map +1 -0
- package/dist/chunk-MJNXIEV2.js +24 -0
- package/dist/chunk-MJNXIEV2.js.map +1 -0
- package/dist/{chunk-CPXLQ57U.js → chunk-MVGGXOFA.js} +37 -20
- package/dist/chunk-MVGGXOFA.js.map +1 -0
- package/dist/{chunk-LY34ORX6.js → chunk-O55ZUAX7.js} +39920 -31332
- package/dist/chunk-O55ZUAX7.js.map +1 -0
- package/dist/chunk-OHPI2HRK.js +47 -0
- package/dist/chunk-OHPI2HRK.js.map +1 -0
- package/dist/chunk-PLJLE4A4.js +121 -0
- package/dist/chunk-PLJLE4A4.js.map +1 -0
- package/dist/{chunk-XGL5FKIK.js → chunk-SCN5WFIZ.js} +148 -20
- package/dist/chunk-SCN5WFIZ.js.map +1 -0
- package/dist/chunk-WBR7H6E3.cjs +47 -0
- package/dist/chunk-WBR7H6E3.cjs.map +1 -0
- package/dist/chunk-XL4V2PYG.cjs +63 -0
- package/dist/chunk-XL4V2PYG.cjs.map +1 -0
- package/dist/components/announcement-bar.d.ts.map +1 -1
- package/dist/components/chat/chat-attachment-bar.d.ts +66 -0
- package/dist/components/chat/chat-attachment-bar.d.ts.map +1 -0
- package/dist/components/chat/chat-container.d.ts +21 -1
- package/dist/components/chat/chat-container.d.ts.map +1 -1
- package/dist/components/chat/chat-input.d.ts.map +1 -1
- package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
- package/dist/components/chat/chat-message-list.d.ts.map +1 -1
- package/dist/components/chat/chat-panel-context.d.ts +9 -0
- package/dist/components/chat/chat-panel-context.d.ts.map +1 -0
- package/dist/components/chat/chat-ticket-list.d.ts +1 -1
- package/dist/components/chat/chat-ticket-list.d.ts.map +1 -1
- package/dist/components/chat/embeddable-chat.d.ts +42 -0
- package/dist/components/chat/embeddable-chat.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/admin-content-card.d.ts +34 -0
- package/dist/components/chat/entity-cards/admin-content-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/block-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/blog-card.d.ts +30 -0
- package/dist/components/chat/entity-cards/blog-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/blog-image-placeholder.d.ts +26 -0
- package/dist/components/chat/entity-cards/blog-image-placeholder.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/campaign-card-admin.d.ts +33 -0
- package/dist/components/chat/entity-cards/campaign-card-admin.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/case-study-card.d.ts +20 -0
- package/dist/components/chat/entity-cards/case-study-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/chat-ticket-item.d.ts.map +1 -0
- package/dist/components/chat/{chat-video-entity-card.d.ts → entity-cards/chat-video-entity-card.d.ts} +1 -1
- package/dist/components/chat/entity-cards/chat-video-entity-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/customer-interview-card.d.ts +19 -0
- package/dist/components/chat/entity-cards/customer-interview-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/data-room-doc-card.d.ts +47 -0
- package/dist/components/chat/entity-cards/data-room-doc-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/dispatch.d.ts +119 -0
- package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/entity-author-card.d.ts +87 -0
- package/dist/components/chat/entity-cards/entity-author-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/generic-entity-card.d.ts +42 -0
- package/dist/components/chat/entity-cards/generic-entity-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/github-activity-card.d.ts +37 -0
- package/dist/components/chat/entity-cards/github-activity-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/hubspot-ticket-card.d.ts +28 -0
- package/dist/components/chat/entity-cards/hubspot-ticket-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/index.d.ts +32 -0
- package/dist/components/chat/entity-cards/index.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/investor-update-card.d.ts +19 -0
- package/dist/components/chat/entity-cards/investor-update-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/onboarding-guide-card.d.ts +20 -0
- package/dist/components/chat/entity-cards/onboarding-guide-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/product-release-card-defaults.d.ts +21 -0
- package/dist/components/chat/entity-cards/product-release-card-defaults.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/product-release-card.d.ts +12 -0
- package/dist/components/chat/entity-cards/product-release-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/program-card-defaults.d.ts +32 -0
- package/dist/components/chat/entity-cards/program-card-defaults.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/program-card.d.ts +37 -0
- package/dist/components/chat/entity-cards/program-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/roadmap-card.d.ts +28 -0
- package/dist/components/chat/entity-cards/roadmap-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/roadmap-vote-button.d.ts +12 -0
- package/dist/components/chat/entity-cards/roadmap-vote-button.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/slack-message-card.d.ts +28 -0
- package/dist/components/chat/entity-cards/slack-message-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/task-type-icon.d.ts +6 -0
- package/dist/components/chat/entity-cards/task-type-icon.d.ts.map +1 -0
- package/dist/components/chat/hooks/index.d.ts +10 -0
- package/dist/components/chat/hooks/index.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-chat-attachment-image-gallery.d.ts +5 -0
- package/dist/components/chat/hooks/use-chat-attachment-image-gallery.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-chat-attachments.d.ts +33 -0
- package/dist/components/chat/hooks/use-chat-attachments.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-chat-card-item.d.ts +7 -0
- package/dist/components/chat/hooks/use-chat-card-item.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-chat-identity.d.ts +44 -0
- package/dist/components/chat/hooks/use-chat-identity.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-chat.d.ts +30 -0
- package/dist/components/chat/hooks/use-chat.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-close-on-navigation.d.ts +2 -0
- package/dist/components/chat/hooks/use-close-on-navigation.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-embedded-chat.d.ts +174 -0
- package/dist/components/chat/hooks/use-embedded-chat.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-proxied-image-url.d.ts +18 -0
- package/dist/components/chat/hooks/use-proxied-image-url.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-slash-commands.d.ts +32 -0
- package/dist/components/chat/hooks/use-slash-commands.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-sse.d.ts +57 -0
- package/dist/components/chat/hooks/use-sse.d.ts.map +1 -0
- package/dist/components/chat/index.cjs +393 -0
- package/dist/components/chat/index.cjs.map +1 -0
- package/dist/components/chat/index.d.ts +5 -3
- package/dist/components/chat/index.d.ts.map +1 -1
- package/dist/components/chat/index.js +393 -0
- package/dist/components/chat/index.js.map +1 -0
- package/dist/components/chat/nav-link-anchor-via-runtime.d.ts +33 -0
- package/dist/components/chat/nav-link-anchor-via-runtime.d.ts.map +1 -0
- package/dist/components/chat/source-action-button.d.ts +39 -0
- package/dist/components/chat/source-action-button.d.ts.map +1 -0
- package/dist/components/chat/types/chat.types.d.ts +36 -0
- package/dist/components/chat/types/chat.types.d.ts.map +1 -1
- package/dist/components/chat/types/component.types.d.ts +56 -11
- package/dist/components/chat/types/component.types.d.ts.map +1 -1
- package/dist/components/chat/types/entities/blog.d.ts +14 -0
- package/dist/components/chat/types/entities/blog.d.ts.map +1 -0
- package/dist/components/chat/types/entities/case-study.d.ts +10 -0
- package/dist/components/chat/types/entities/case-study.d.ts.map +1 -0
- package/dist/components/chat/types/entities/content-ref.d.ts +23 -0
- package/dist/components/chat/types/entities/content-ref.d.ts.map +1 -0
- package/dist/components/chat/types/entities/customer-interview.d.ts +10 -0
- package/dist/components/chat/types/entities/customer-interview.d.ts.map +1 -0
- package/dist/components/chat/types/entities/data-room-doc.d.ts +37 -0
- package/dist/components/chat/types/entities/data-room-doc.d.ts.map +1 -0
- package/dist/components/chat/types/entities/github-activity.d.ts +29 -0
- package/dist/components/chat/types/entities/github-activity.d.ts.map +1 -0
- package/dist/components/chat/types/entities/hubspot-ticket.d.ts +39 -0
- package/dist/components/chat/types/entities/hubspot-ticket.d.ts.map +1 -0
- package/dist/components/chat/types/entities/index.d.ts +28 -0
- package/dist/components/chat/types/entities/index.d.ts.map +1 -0
- package/dist/components/chat/types/entities/investor-update.d.ts +83 -0
- package/dist/components/chat/types/entities/investor-update.d.ts.map +1 -0
- package/dist/components/chat/types/entities/onboarding-guide.d.ts +79 -0
- package/dist/components/chat/types/entities/onboarding-guide.d.ts.map +1 -0
- package/dist/components/chat/types/entities/program-types.d.ts +303 -0
- package/dist/components/chat/types/entities/program-types.d.ts.map +1 -0
- package/dist/components/chat/types/entities/roadmap-item.d.ts +41 -0
- package/dist/components/chat/types/entities/roadmap-item.d.ts.map +1 -0
- package/dist/components/chat/types/entities/slack-message.d.ts +28 -0
- package/dist/components/chat/types/entities/slack-message.d.ts.map +1 -0
- package/dist/components/chat/types/index.d.ts +1 -0
- package/dist/components/chat/types/index.d.ts.map +1 -1
- package/dist/components/chat/utils/agent-status-message.d.ts +18 -0
- package/dist/components/chat/utils/agent-status-message.d.ts.map +1 -0
- package/dist/components/chat/utils/auto-continuation-directive.d.ts +38 -0
- package/dist/components/chat/utils/auto-continuation-directive.d.ts.map +1 -0
- package/dist/components/chat/utils/chat-attachment-markdown.d.ts +114 -0
- package/dist/components/chat/utils/chat-attachment-markdown.d.ts.map +1 -0
- package/dist/components/chat/utils/chat-authed-fetch.d.ts +13 -0
- package/dist/components/chat/utils/chat-authed-fetch.d.ts.map +1 -0
- package/dist/components/chat/utils/chat-nav-resolution.d.ts +72 -0
- package/dist/components/chat/utils/chat-nav-resolution.d.ts.map +1 -0
- package/dist/components/chat/utils/chat-proxy-auth-storage.d.ts +43 -0
- package/dist/components/chat/utils/chat-proxy-auth-storage.d.ts.map +1 -0
- package/dist/components/chat/utils/chip-action-class.d.ts +16 -0
- package/dist/components/chat/utils/chip-action-class.d.ts.map +1 -0
- package/dist/components/chat/utils/chip-styles.d.ts +32 -0
- package/dist/components/chat/utils/chip-styles.d.ts.map +1 -0
- package/dist/components/chat/utils/clickup-task-type-utils.d.ts +38 -0
- package/dist/components/chat/utils/clickup-task-type-utils.d.ts.map +1 -0
- package/dist/components/chat/utils/compact-card-classes.d.ts +50 -0
- package/dist/components/chat/utils/compact-card-classes.d.ts.map +1 -0
- package/dist/components/chat/utils/decide-new-tab.d.ts +39 -0
- package/dist/components/chat/utils/decide-new-tab.d.ts.map +1 -0
- package/dist/components/chat/utils/external-app-urls.d.ts +14 -0
- package/dist/components/chat/utils/external-app-urls.d.ts.map +1 -0
- package/dist/components/chat/utils/flatten-assistant-content.d.ts +25 -0
- package/dist/components/chat/utils/flatten-assistant-content.d.ts.map +1 -0
- package/dist/components/chat/utils/icon-registry.d.ts +67 -0
- package/dist/components/chat/utils/icon-registry.d.ts.map +1 -0
- package/dist/components/chat/utils/index.d.ts +21 -0
- package/dist/components/chat/utils/index.d.ts.map +1 -1
- package/dist/components/chat/utils/is-cross-origin-url.d.ts +22 -0
- package/dist/components/chat/utils/is-cross-origin-url.d.ts.map +1 -0
- package/dist/components/chat/utils/nav-anchor-props.d.ts +54 -0
- package/dist/components/chat/utils/nav-anchor-props.d.ts.map +1 -0
- package/dist/components/chat/utils/nav-click-handler.d.ts +51 -0
- package/dist/components/chat/utils/nav-click-handler.d.ts.map +1 -0
- package/dist/components/chat/utils/scroll-anchor.d.ts +30 -0
- package/dist/components/chat/utils/scroll-anchor.d.ts.map +1 -0
- package/dist/components/chat/utils/slash-dispatch-utils.d.ts +109 -0
- package/dist/components/chat/utils/slash-dispatch-utils.d.ts.map +1 -0
- package/dist/components/chat/utils/source-icons.d.ts +8 -0
- package/dist/components/chat/utils/source-icons.d.ts.map +1 -0
- package/dist/components/chat/utils/source-row-cta.d.ts +111 -0
- package/dist/components/chat/utils/source-row-cta.d.ts.map +1 -0
- package/dist/components/features/figma-prototype-viewer.d.ts.map +1 -1
- package/dist/components/features/index.cjs +12 -6
- package/dist/components/features/index.cjs.map +1 -1
- package/dist/components/features/index.js +11 -5
- package/dist/components/features/video.d.ts.map +1 -1
- package/dist/components/icons/index.cjs +3 -3
- package/dist/components/icons/index.js +2 -2
- package/dist/components/index.cjs +274 -8
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +273 -7
- package/dist/components/interactive-wrapper.d.ts +3 -3
- package/dist/components/navigation/index.cjs +12 -6
- package/dist/components/navigation/index.cjs.map +1 -1
- package/dist/components/navigation/index.js +11 -5
- package/dist/components/resizable.d.ts +1 -1
- package/dist/components/shared/product-release/product-release-card-skeleton.d.ts +1 -1
- package/dist/components/shared/product-release/product-release-card-skeleton.d.ts.map +1 -1
- package/dist/components/shared/product-release/product-release-card.d.ts +19 -12
- package/dist/components/shared/product-release/product-release-card.d.ts.map +1 -1
- package/dist/components/shared/product-release/release-detail-page.d.ts +2 -4
- package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
- package/dist/components/ui/button/button.d.ts +13 -0
- package/dist/components/ui/button/button.d.ts.map +1 -1
- package/dist/components/ui/dashboard-info-card.d.ts.map +1 -1
- package/dist/components/ui/entity-image.d.ts.map +1 -1
- package/dist/components/ui/file-manager/index.cjs +71 -70
- package/dist/components/ui/file-manager/index.cjs.map +1 -1
- package/dist/components/ui/file-manager/index.js +6 -5
- package/dist/components/ui/file-manager/index.js.map +1 -1
- package/dist/components/ui/hover-dropdown.d.ts +66 -0
- package/dist/components/ui/hover-dropdown.d.ts.map +1 -0
- package/dist/components/ui/index.cjs +276 -6
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +278 -8
- package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -1
- package/dist/components/ui/square-avatar.d.ts.map +1 -1
- package/dist/contexts/chat-runtime-context.d.ts +109 -0
- package/dist/contexts/chat-runtime-context.d.ts.map +1 -0
- package/dist/contexts/endpoints-runtime-context.d.ts +28 -0
- package/dist/contexts/endpoints-runtime-context.d.ts.map +1 -0
- package/dist/contexts/index.cjs +30 -0
- package/dist/contexts/index.cjs.map +1 -0
- package/dist/contexts/index.d.ts +26 -0
- package/dist/contexts/index.d.ts.map +1 -0
- package/dist/contexts/index.js +30 -0
- package/dist/contexts/index.js.map +1 -0
- package/dist/contexts/use-outer-or-default.d.ts +29 -0
- package/dist/contexts/use-outer-or-default.d.ts.map +1 -0
- package/dist/embed-shims/index.cjs +51 -0
- package/dist/embed-shims/index.cjs.map +1 -0
- package/dist/embed-shims/index.d.ts +31 -0
- package/dist/embed-shims/index.d.ts.map +1 -0
- package/dist/embed-shims/index.js +51 -0
- package/dist/embed-shims/index.js.map +1 -0
- package/dist/embed-shims/next-dynamic.cjs +12 -0
- package/dist/embed-shims/next-dynamic.cjs.map +1 -0
- package/dist/embed-shims/next-dynamic.d.ts +47 -0
- package/dist/embed-shims/next-dynamic.d.ts.map +1 -0
- package/dist/embed-shims/next-dynamic.js +12 -0
- package/dist/embed-shims/next-dynamic.js.map +1 -0
- package/dist/embed-shims/next-image.cjs +12 -0
- package/dist/embed-shims/next-image.cjs.map +1 -0
- package/dist/embed-shims/next-image.d.ts +28 -0
- package/dist/embed-shims/next-image.d.ts.map +1 -0
- package/dist/embed-shims/next-image.js +12 -0
- package/dist/embed-shims/next-image.js.map +1 -0
- package/dist/embed-shims/next-link.cjs +14 -0
- package/dist/embed-shims/next-link.cjs.map +1 -0
- package/dist/embed-shims/next-link.d.ts +22 -0
- package/dist/embed-shims/next-link.d.ts.map +1 -0
- package/dist/embed-shims/next-link.js +14 -0
- package/dist/embed-shims/next-link.js.map +1 -0
- package/dist/embed-shims/next-navigation.cjs +30 -0
- package/dist/embed-shims/next-navigation.cjs.map +1 -0
- package/dist/embed-shims/next-navigation.d.ts +46 -0
- package/dist/embed-shims/next-navigation.d.ts.map +1 -0
- package/dist/embed-shims/next-navigation.js +30 -0
- package/dist/embed-shims/next-navigation.js.map +1 -0
- package/dist/hooks/index.cjs +10 -4
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +9 -3
- package/dist/hooks/use-access-code-integration.d.ts +48 -0
- package/dist/hooks/use-access-code-integration.d.ts.map +1 -0
- package/dist/hooks/use-contact-submission.d.ts.map +1 -1
- package/dist/hooks/use-og-placeholder.d.ts +31 -0
- package/dist/hooks/use-og-placeholder.d.ts.map +1 -0
- package/dist/hooks/use-toast.d.ts +1 -1
- package/dist/index.cjs +367 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +378 -18
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/access-code-client.d.ts +21 -37
- package/dist/utils/access-code-client.d.ts.map +1 -1
- package/dist/utils/cn.d.ts +0 -27
- package/dist/utils/cn.d.ts.map +1 -1
- package/dist/utils/color-analysis.d.ts +33 -0
- package/dist/utils/color-analysis.d.ts.map +1 -0
- package/dist/utils/date-formatters.d.ts +16 -5
- package/dist/utils/date-formatters.d.ts.map +1 -1
- package/dist/utils/fetch-priority.d.ts +3 -0
- package/dist/utils/fetch-priority.d.ts.map +1 -0
- package/dist/utils/format.d.ts +192 -1
- package/dist/utils/format.d.ts.map +1 -1
- package/dist/utils/image-proxy.d.ts +67 -2
- package/dist/utils/image-proxy.d.ts.map +1 -1
- package/dist/utils/index.cjs +1274 -155
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +19 -3
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1200 -157
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/local-storage-adapter.d.ts +46 -0
- package/dist/utils/local-storage-adapter.d.ts.map +1 -0
- package/dist/utils/source-icons.d.ts +78 -0
- package/dist/utils/source-icons.d.ts.map +1 -0
- package/package.json +29 -2
- package/src/components/announcement-bar.tsx +26 -4
- package/src/components/categories-cart.tsx +1 -1
- package/src/components/chat/chat-attachment-bar.tsx +323 -0
- package/src/components/chat/chat-container.tsx +39 -5
- package/src/components/chat/chat-input.tsx +7 -1
- package/src/components/chat/chat-message-enhanced.tsx +32 -22
- package/src/components/chat/chat-message-list.tsx +53 -4
- package/src/components/chat/chat-panel-context.tsx +37 -0
- package/src/components/chat/chat-ticket-list.tsx +1 -1
- package/src/components/chat/embeddable-chat.tsx +1106 -0
- package/src/components/chat/entity-cards/admin-content-card.tsx +155 -0
- package/src/components/chat/entity-cards/blog-card.tsx +259 -0
- package/src/components/chat/entity-cards/blog-image-placeholder.tsx +52 -0
- package/src/components/chat/entity-cards/campaign-card-admin.tsx +113 -0
- package/src/components/chat/entity-cards/case-study-card.tsx +192 -0
- package/src/components/chat/{chat-ticket-item.tsx → entity-cards/chat-ticket-item.tsx} +2 -2
- package/src/components/chat/{chat-video-entity-card.tsx → entity-cards/chat-video-entity-card.tsx} +2 -2
- package/src/components/chat/entity-cards/customer-interview-card.tsx +211 -0
- package/src/components/chat/entity-cards/data-room-doc-card.tsx +120 -0
- package/src/components/chat/entity-cards/dispatch.tsx +1093 -0
- package/src/components/chat/entity-cards/entity-author-card.tsx +193 -0
- package/src/components/chat/entity-cards/generic-entity-card.tsx +144 -0
- package/src/components/chat/entity-cards/github-activity-card.tsx +305 -0
- package/src/components/chat/entity-cards/hubspot-ticket-card.tsx +205 -0
- package/src/components/chat/entity-cards/index.ts +125 -0
- package/src/components/chat/entity-cards/investor-update-card.tsx +150 -0
- package/src/components/chat/entity-cards/onboarding-guide-card.tsx +326 -0
- package/src/components/chat/entity-cards/product-release-card-defaults.ts +57 -0
- package/src/components/chat/entity-cards/product-release-card.tsx +19 -0
- package/src/components/chat/entity-cards/program-card-defaults.ts +62 -0
- package/src/components/chat/entity-cards/program-card.tsx +451 -0
- package/src/components/chat/entity-cards/roadmap-card.tsx +356 -0
- package/src/components/chat/entity-cards/roadmap-vote-button.tsx +54 -0
- package/src/components/chat/entity-cards/slack-message-card.tsx +182 -0
- package/src/components/chat/entity-cards/task-type-icon.tsx +60 -0
- package/src/components/chat/hooks/index.ts +22 -0
- package/src/components/chat/hooks/use-chat-attachment-image-gallery.tsx +114 -0
- package/src/components/chat/hooks/use-chat-attachments.ts +429 -0
- package/src/components/chat/hooks/use-chat-card-item.ts +102 -0
- package/src/components/chat/hooks/use-chat-identity.ts +139 -0
- package/src/components/chat/hooks/use-chat.ts +501 -0
- package/src/components/chat/hooks/use-close-on-navigation.ts +87 -0
- package/src/components/chat/hooks/use-embedded-chat.ts +1023 -0
- package/src/components/chat/hooks/use-proxied-image-url.ts +31 -0
- package/src/components/chat/hooks/use-slash-commands.ts +106 -0
- package/src/components/chat/hooks/use-sse.ts +143 -0
- package/src/components/chat/index.ts +30 -4
- package/src/components/chat/nav-link-anchor-via-runtime.tsx +72 -0
- package/src/components/chat/source-action-button.tsx +120 -0
- package/src/components/chat/types/chat.types.ts +61 -0
- package/src/components/chat/types/component.types.ts +57 -11
- package/src/components/chat/types/entities/blog.ts +27 -0
- package/src/components/chat/types/entities/case-study.ts +14 -0
- package/src/components/chat/types/entities/content-ref.ts +23 -0
- package/src/components/chat/types/entities/customer-interview.ts +15 -0
- package/src/components/chat/types/entities/data-room-doc.ts +37 -0
- package/src/components/chat/types/entities/github-activity.ts +36 -0
- package/src/components/chat/types/entities/hubspot-ticket.ts +39 -0
- package/src/components/chat/types/entities/index.ts +28 -0
- package/src/components/chat/types/entities/investor-update.ts +100 -0
- package/src/components/chat/types/entities/onboarding-guide.ts +101 -0
- package/src/components/chat/types/entities/program-types.ts +433 -0
- package/src/components/chat/types/entities/roadmap-item.ts +42 -0
- package/src/components/chat/types/entities/slack-message.ts +28 -0
- package/src/components/chat/types/index.ts +1 -0
- package/src/components/chat/utils/agent-status-message.ts +52 -0
- package/src/components/chat/utils/auto-continuation-directive.ts +70 -0
- package/src/components/chat/utils/chat-attachment-markdown.ts +190 -0
- package/src/components/chat/utils/chat-authed-fetch.ts +73 -0
- package/src/components/chat/utils/chat-nav-resolution.ts +151 -0
- package/src/components/chat/utils/chat-proxy-auth-storage.ts +148 -0
- package/src/components/chat/utils/chip-action-class.ts +19 -0
- package/src/components/chat/utils/chip-styles.ts +51 -0
- package/src/components/chat/utils/clickup-task-type-utils.ts +59 -0
- package/src/components/chat/utils/compact-card-classes.ts +97 -0
- package/src/components/chat/utils/decide-new-tab.ts +57 -0
- package/src/components/chat/utils/external-app-urls.ts +19 -0
- package/src/components/chat/utils/flatten-assistant-content.ts +35 -0
- package/src/components/chat/utils/icon-registry.ts +297 -0
- package/src/components/chat/utils/index.ts +133 -0
- package/src/components/chat/utils/is-cross-origin-url.ts +28 -0
- package/src/components/chat/utils/nav-anchor-props.ts +78 -0
- package/src/components/chat/utils/nav-click-handler.ts +81 -0
- package/src/components/chat/utils/scroll-anchor.ts +35 -0
- package/src/components/chat/utils/slash-dispatch-utils.ts +183 -0
- package/src/components/chat/utils/source-icons.ts +14 -0
- package/src/components/chat/utils/source-row-cta.ts +215 -0
- package/src/components/empty-state.tsx +1 -1
- package/src/components/features/board/ticket-card.tsx +1 -1
- package/src/components/features/figma-prototype-viewer.tsx +2 -1
- package/src/components/features/media-gallery-manager.tsx +1 -1
- package/src/components/features/parallax-image-showcase.tsx +1 -1
- package/src/components/features/release-media-manager.tsx +1 -1
- package/src/components/features/seo-editor-preview.tsx +1 -1
- package/src/components/features/video.tsx +54 -3
- package/src/components/footer-waitlist-button.tsx +1 -1
- package/src/components/navigation/header.tsx +1 -1
- package/src/components/shared/onboarding/onboarding-step-card.tsx +1 -1
- package/src/components/shared/product-release/product-release-card-skeleton.tsx +8 -44
- package/src/components/shared/product-release/product-release-card.tsx +31 -116
- package/src/components/shared/product-release/release-detail-page.tsx +12 -16
- package/src/components/ui/actions-menu.tsx +1 -1
- package/src/components/ui/button/button.tsx +41 -11
- package/src/components/ui/button/split-button.tsx +1 -1
- package/src/components/ui/dashboard-info-card.tsx +2 -3
- package/src/components/ui/data-table/data-table-row.tsx +1 -1
- package/src/components/ui/entity-image.tsx +2 -8
- package/src/components/ui/hover-dropdown.tsx +258 -0
- package/src/components/ui/image-gallery-modal.tsx +1 -1
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/markdown-editor.tsx +1 -1
- package/src/components/ui/more-actions-menu.tsx +1 -1
- package/src/components/ui/organization-card.tsx +1 -1
- package/src/components/ui/simple-markdown-renderer.tsx +53 -5
- package/src/components/ui/square-avatar.tsx +3 -12
- package/src/components/ui/tab-navigation.tsx +1 -1
- package/src/components/ui/table/table-row.tsx +1 -1
- package/src/components/unified-filter-logic.tsx +1 -1
- package/src/components/unified-pagination.tsx +1 -1
- package/src/components/user-summary-stub.tsx +1 -1
- package/src/components/vendor-display-button.tsx +1 -1
- package/src/components/vendor-icon.tsx +1 -1
- package/src/contexts/chat-runtime-context.tsx +163 -0
- package/src/contexts/endpoints-runtime-context.tsx +68 -0
- package/src/contexts/index.ts +38 -0
- package/src/contexts/use-outer-or-default.ts +42 -0
- package/src/embed-shims/index.ts +42 -0
- package/src/embed-shims/next-dynamic.tsx +70 -0
- package/src/embed-shims/next-image.tsx +114 -0
- package/src/embed-shims/next-link.tsx +91 -0
- package/src/embed-shims/next-navigation.tsx +201 -0
- package/src/hooks/index.ts +9 -0
- package/src/hooks/state/use-api-params.ts +1 -1
- package/src/hooks/state/use-query-params.ts +1 -1
- package/src/hooks/use-access-code-integration.ts +107 -0
- package/src/hooks/use-contact-submission.ts +7 -3
- package/src/hooks/use-og-placeholder.ts +45 -0
- package/src/stories/OnboardingStepCard.stories.tsx +140 -0
- package/src/styles/chat-animations.css +65 -0
- package/src/styles/index.css +1 -0
- package/src/utils/access-code-client.ts +32 -75
- package/src/utils/cn.ts +0 -65
- package/src/utils/color-analysis.ts +205 -0
- package/src/utils/date-formatters.ts +54 -11
- package/src/utils/fetch-priority.ts +41 -0
- package/src/utils/format.ts +525 -1
- package/src/utils/image-proxy.ts +127 -7
- package/src/utils/index.ts +145 -5
- package/src/utils/local-storage-adapter.ts +105 -0
- package/src/utils/source-icons.ts +219 -0
- package/dist/chunk-25LVV26X.cjs.map +0 -1
- package/dist/chunk-ARQ4XP64.cjs.map +0 -1
- package/dist/chunk-CPXLQ57U.js.map +0 -1
- package/dist/chunk-LY34ORX6.js.map +0 -1
- package/dist/chunk-RMB5DVED.cjs.map +0 -1
- package/dist/chunk-SZPJ5R5B.js.map +0 -1
- package/dist/chunk-UC43NICZ.cjs.map +0 -1
- package/dist/chunk-XGL5FKIK.js.map +0 -1
- package/dist/components/chat/block-card.d.ts.map +0 -1
- package/dist/components/chat/chat-ticket-item.d.ts.map +0 -1
- package/dist/components/chat/chat-video-entity-card.d.ts.map +0 -1
- package/dist/utils/dynamic-icons.d.ts +0 -26
- package/dist/utils/dynamic-icons.d.ts.map +0 -1
- package/dist/utils/format-relative-time.d.ts +0 -21
- package/dist/utils/format-relative-time.d.ts.map +0 -1
- package/src/utils/.dynamic-icons.md +0 -30
- package/src/utils/.format-relative-time.md +0 -36
- package/src/utils/dynamic-icons.tsx +0 -120
- package/src/utils/format-relative-time.ts +0 -52
- /package/dist/{chunk-N57KWHDB.js.map → chunk-CIPO6DXK.js.map} +0 -0
- /package/dist/components/chat/{block-card.d.ts → entity-cards/block-card.d.ts} +0 -0
- /package/dist/components/chat/{chat-ticket-item.d.ts → entity-cards/chat-ticket-item.d.ts} +0 -0
- /package/src/components/chat/{block-card.tsx → entity-cards/block-card.tsx} +0 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Chat-identity capability hook.
|
|
5
|
+
*
|
|
6
|
+
* Surfaces the `{authTier, source, attachmentsEnabled}` bag for the
|
|
7
|
+
* CURRENT chat session so client code can gate UI elements (today: the
|
|
8
|
+
* `+` attachment button) on chat-side identity tiers WITHOUT sending a
|
|
9
|
+
* chat message first.
|
|
10
|
+
*
|
|
11
|
+
* Server-side parity: the route at `/api/chat/identity` runs the same
|
|
12
|
+
* 3-tier `requireChatAuth` chain the chat itself uses.
|
|
13
|
+
* `attachmentsEnabled` is computed server-side as
|
|
14
|
+
* `authTier !== 'anon' AND isSelfScopedSource(source)` — single
|
|
15
|
+
* source of truth, consumers don't combine the fields themselves.
|
|
16
|
+
*
|
|
17
|
+
* Implementation: plain `useEffect` + `useState` (NOT `useQuery`).
|
|
18
|
+
* Rationale:
|
|
19
|
+
* - Single consumer (`ChatAttachmentAddButton`), so react-query's
|
|
20
|
+
* dedup / cross-component cache benefit is zero.
|
|
21
|
+
* - The hook needs to re-fetch every time bearer-proxy creds change
|
|
22
|
+
* in localStorage. With react-query, this required a contrived
|
|
23
|
+
* `queryKey` that re-evaluated `getChatProxyAuth()` on every
|
|
24
|
+
* render — a layout-shift trap when HMR replaced the module
|
|
25
|
+
* mid-session (cache preserved across module reload but the
|
|
26
|
+
* queryKey computation lagged). Plain `useEffect` with the
|
|
27
|
+
* proxy email as a dep refetches reliably.
|
|
28
|
+
* - `chatAuthedFetch` carries the bearer-act-as headers so
|
|
29
|
+
* `/whoami`-authenticated admins resolve as `bearer-act-as` and
|
|
30
|
+
* get `attachmentsEnabled: true`.
|
|
31
|
+
*
|
|
32
|
+
* Endpoint URL: read from `useRequiredChatRuntime().endpoints.chatIdentityUrl`
|
|
33
|
+
* so embedded apps with their own reverse-proxy topology can override.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import { useEffect, useState } from 'react'
|
|
37
|
+
import { useRequiredChatRuntime } from '../../../contexts/chat-runtime-context'
|
|
38
|
+
import { chatAuthedFetch } from '../utils/chat-authed-fetch'
|
|
39
|
+
import { getChatProxyAuth } from '../utils/chat-proxy-auth-storage'
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Wire-shape for the `/api/chat/identity` route response. Mirrors
|
|
43
|
+
* the hub's `ChatIdentityResponse` (in `app/api/chat/identity/route.ts`)
|
|
44
|
+
* — kept in sync there. Lib-side declaration so the chat panel can
|
|
45
|
+
* compile without depending on hub-internal types.
|
|
46
|
+
*/
|
|
47
|
+
export interface ChatIdentityResponse {
|
|
48
|
+
authTier: 'session' | 'bearer-act-as' | 'anon'
|
|
49
|
+
source: string | null
|
|
50
|
+
attachmentsEnabled: boolean
|
|
51
|
+
/** Server-resolved display identity. `null` for anon. Read by the
|
|
52
|
+
* chat panel for the greeting first-name — embedders DON'T pass
|
|
53
|
+
* user info into the runtime; server is the single source of truth
|
|
54
|
+
* so the displayed name always matches the auth tier.
|
|
55
|
+
*
|
|
56
|
+
* All sub-fields are optional and may be `null`. Consumers MUST
|
|
57
|
+
* treat missing values as "use empty string and skip the affected
|
|
58
|
+
* UI line" — never substitute a placeholder. */
|
|
59
|
+
user: {
|
|
60
|
+
name: string | null
|
|
61
|
+
email: string | null
|
|
62
|
+
/** Optional first name supplied by the identity webservice.
|
|
63
|
+
* When set, the chat greeting renders `Hey ${firstName}, I'm Mingo`.
|
|
64
|
+
* When absent (null/undefined/empty), the greeting falls back to
|
|
65
|
+
* the no-name variant `Hey, I'm Mingo`. The chat panel does NOT
|
|
66
|
+
* derive `firstName` from `name.split(' ')[0]` anymore — this is
|
|
67
|
+
* the dedicated authoritative source from the identity webservice. */
|
|
68
|
+
firstName?: string | null
|
|
69
|
+
/** Optional last name. Currently unused by chat UI; surfaced for
|
|
70
|
+
* embedders that want to display the full name elsewhere. */
|
|
71
|
+
lastName?: string | null
|
|
72
|
+
/** Optional avatar URL. Validated as https:// server-side. */
|
|
73
|
+
avatarUrl?: string | null
|
|
74
|
+
} | null
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Shape returned by the hook. NEVER throws — loading + error fall
|
|
78
|
+
* back to anon defaults so consumers can always render synchronously. */
|
|
79
|
+
export interface ChatIdentitySurface extends ChatIdentityResponse {
|
|
80
|
+
/** True while the query is in-flight on first mount; consumers that
|
|
81
|
+
* show a skeleton spinner can read this. */
|
|
82
|
+
isLoading: boolean
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const ANON_DEFAULTS: ChatIdentityResponse = {
|
|
86
|
+
authTier: 'anon',
|
|
87
|
+
source: null,
|
|
88
|
+
attachmentsEnabled: false,
|
|
89
|
+
user: null,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function useChatIdentity(): ChatIdentitySurface {
|
|
93
|
+
const runtime = useRequiredChatRuntime()
|
|
94
|
+
const url = runtime.endpoints.chatIdentityUrl
|
|
95
|
+
// `getChatProxyAuth()` reads localStorage every render. If the user
|
|
96
|
+
// pastes bearer creds mid-session (via the `/debug` creds bar),
|
|
97
|
+
// their email arrives here and the effect's dep changes → refetch.
|
|
98
|
+
const proxyEmail = getChatProxyAuth()?.email ?? null
|
|
99
|
+
|
|
100
|
+
const [data, setData] = useState<ChatIdentityResponse>(ANON_DEFAULTS)
|
|
101
|
+
const [isLoading, setIsLoading] = useState(true)
|
|
102
|
+
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
let cancelled = false
|
|
105
|
+
const ctrl = new AbortController()
|
|
106
|
+
|
|
107
|
+
setIsLoading(true)
|
|
108
|
+
chatAuthedFetch(url, { signal: ctrl.signal })
|
|
109
|
+
.then(async (resp) => {
|
|
110
|
+
if (!resp.ok) return ANON_DEFAULTS
|
|
111
|
+
return (await resp.json()) as ChatIdentityResponse
|
|
112
|
+
})
|
|
113
|
+
.then((next) => {
|
|
114
|
+
if (cancelled) return
|
|
115
|
+
setData(next)
|
|
116
|
+
setIsLoading(false)
|
|
117
|
+
})
|
|
118
|
+
.catch((err) => {
|
|
119
|
+
// AbortError on unmount is expected; everything else falls
|
|
120
|
+
// back to anon defaults so the UI stays consistent.
|
|
121
|
+
if (cancelled) return
|
|
122
|
+
if ((err as Error).name !== 'AbortError') {
|
|
123
|
+
console.warn('[useChatIdentity] fetch failed, falling back to anon:', err)
|
|
124
|
+
}
|
|
125
|
+
setData(ANON_DEFAULTS)
|
|
126
|
+
setIsLoading(false)
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
return () => {
|
|
130
|
+
cancelled = true
|
|
131
|
+
ctrl.abort()
|
|
132
|
+
}
|
|
133
|
+
// `proxyEmail` in deps → refetch the moment the user pastes creds
|
|
134
|
+
// (or rotates them) and triggers a re-render. `url` is stable for
|
|
135
|
+
// the chat session but listed for completeness.
|
|
136
|
+
}, [url, proxyEmail])
|
|
137
|
+
|
|
138
|
+
return { ...data, isLoading }
|
|
139
|
+
}
|
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState, useCallback, useEffect, useRef } from 'react'
|
|
4
|
+
import { useSSE, type StreamFn, type StreamFnExtraOptions } from './use-sse'
|
|
5
|
+
import type {
|
|
6
|
+
Message,
|
|
7
|
+
MessageSegment,
|
|
8
|
+
ToolExecutionData,
|
|
9
|
+
} from '../types/message.types'
|
|
10
|
+
import { buildChatRefKey } from '../types/chat.types'
|
|
11
|
+
import type { ChatRef } from '../chat-ref.types'
|
|
12
|
+
|
|
13
|
+
export type { Message } from '../types/message.types'
|
|
14
|
+
export type { StreamFnExtraOptions } from './use-sse'
|
|
15
|
+
|
|
16
|
+
interface UseChatOptions {
|
|
17
|
+
useMock?: boolean
|
|
18
|
+
debugMode?: boolean
|
|
19
|
+
assistantName?: string
|
|
20
|
+
assistantAvatar?: string
|
|
21
|
+
/** Custom stream function — bypasses mock/SSE service when provided */
|
|
22
|
+
streamFn?: StreamFn
|
|
23
|
+
/** Initial messages (e.g., restored from localStorage). Evaluated once on mount. */
|
|
24
|
+
initialMessages?: Message[]
|
|
25
|
+
/** Called whenever the messages array changes — use for persistence. */
|
|
26
|
+
onMessagesChange?: (messages: Message[]) => void
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isToolSegment(
|
|
30
|
+
segment: MessageSegment,
|
|
31
|
+
): segment is { type: 'tool_execution'; data: ToolExecutionData } {
|
|
32
|
+
return segment.type === 'tool_execution'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function useChat({
|
|
36
|
+
useMock = true,
|
|
37
|
+
debugMode = false,
|
|
38
|
+
assistantName = 'Fae',
|
|
39
|
+
assistantAvatar,
|
|
40
|
+
streamFn,
|
|
41
|
+
initialMessages,
|
|
42
|
+
onMessagesChange,
|
|
43
|
+
}: UseChatOptions = {}) {
|
|
44
|
+
const [messages, setMessages] = useState<Message[]>(() => initialMessages ?? [])
|
|
45
|
+
const [isTyping, setIsTyping] = useState(false)
|
|
46
|
+
const currentAssistantSegmentsRef = useRef<MessageSegment[]>([])
|
|
47
|
+
|
|
48
|
+
// Notify the host whenever messages change so it can persist them.
|
|
49
|
+
const onMessagesChangeRef = useRef(onMessagesChange)
|
|
50
|
+
onMessagesChangeRef.current = onMessagesChange
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
onMessagesChangeRef.current?.(messages)
|
|
53
|
+
}, [messages])
|
|
54
|
+
|
|
55
|
+
const {
|
|
56
|
+
streamMessage,
|
|
57
|
+
isStreaming,
|
|
58
|
+
error: sseError,
|
|
59
|
+
abort,
|
|
60
|
+
reset,
|
|
61
|
+
} = useSSE({
|
|
62
|
+
useMock,
|
|
63
|
+
debugMode,
|
|
64
|
+
streamFn,
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const addMessage = useCallback((message: Message) => {
|
|
68
|
+
setMessages((prev) => [...prev, message])
|
|
69
|
+
}, [])
|
|
70
|
+
|
|
71
|
+
const updateLastAssistantMessage = useCallback((segments: MessageSegment[]) => {
|
|
72
|
+
setMessages((prev) => {
|
|
73
|
+
const newMessages = [...prev]
|
|
74
|
+
const lastMessage = newMessages[newMessages.length - 1]
|
|
75
|
+
if (lastMessage && lastMessage.role === 'assistant') {
|
|
76
|
+
newMessages[newMessages.length - 1] = {
|
|
77
|
+
...lastMessage,
|
|
78
|
+
content: segments.length > 0 ? segments : '',
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return newMessages
|
|
82
|
+
})
|
|
83
|
+
}, [])
|
|
84
|
+
|
|
85
|
+
const sendMessage = useCallback(
|
|
86
|
+
async (
|
|
87
|
+
text: string,
|
|
88
|
+
extra?: StreamFnExtraOptions,
|
|
89
|
+
/** When `hidden=true` the user message is added to the conversation
|
|
90
|
+
* history (so the LLM sees it as context) but NOT rendered in the
|
|
91
|
+
* UI. Used by the host to fire post-approval auto-continuation
|
|
92
|
+
* turns without polluting the visible thread with synthetic
|
|
93
|
+
* prompts like "(continue per protocol)". The assistant response
|
|
94
|
+
* IS rendered normally. */
|
|
95
|
+
options?: { hidden?: boolean },
|
|
96
|
+
) => {
|
|
97
|
+
const userMessage: Message = {
|
|
98
|
+
id: `user-${Date.now()}`,
|
|
99
|
+
role: 'user',
|
|
100
|
+
name: 'You',
|
|
101
|
+
content: text,
|
|
102
|
+
timestamp: new Date(),
|
|
103
|
+
...(options?.hidden ? { hidden: true } : {}),
|
|
104
|
+
}
|
|
105
|
+
addMessage(userMessage)
|
|
106
|
+
|
|
107
|
+
setIsTyping(true)
|
|
108
|
+
currentAssistantSegmentsRef.current = []
|
|
109
|
+
|
|
110
|
+
const assistantMessage: Message = {
|
|
111
|
+
id: `assistant-${Date.now()}`,
|
|
112
|
+
role: 'assistant',
|
|
113
|
+
name: assistantName,
|
|
114
|
+
content: [],
|
|
115
|
+
timestamp: new Date(),
|
|
116
|
+
avatar: assistantAvatar,
|
|
117
|
+
}
|
|
118
|
+
addMessage(assistantMessage)
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
let receivedFirstTextChunk = false
|
|
122
|
+
let currentTextSegment = ''
|
|
123
|
+
|
|
124
|
+
for await (const segment of streamMessage(text, extra)) {
|
|
125
|
+
// Flip isTyping=false ONLY when the first TEXT segment arrives — NOT
|
|
126
|
+
// on a leading thinking-delta. Reason: <ThinkingDisplay> computes
|
|
127
|
+
// `isStreaming = (index === segments.length - 1 && isTyping)` and
|
|
128
|
+
// switches its label "Thinking" → "Thought" + drops PulseDots when
|
|
129
|
+
// isStreaming is false. If we flipped isTyping on the first thinking
|
|
130
|
+
// delta, the very first thinking chunk would render as "Thought"
|
|
131
|
+
// even while the model is still actively thinking. Holding isTyping
|
|
132
|
+
// true until real text starts keeps the live "Thinking…" UX correct.
|
|
133
|
+
if (!receivedFirstTextChunk && segment.type === 'text') {
|
|
134
|
+
setIsTyping(false)
|
|
135
|
+
receivedFirstTextChunk = true
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (segment.type === 'text') {
|
|
139
|
+
currentTextSegment += segment.text
|
|
140
|
+
const updatedSegments = [...currentAssistantSegmentsRef.current]
|
|
141
|
+
|
|
142
|
+
if (
|
|
143
|
+
updatedSegments.length > 0 &&
|
|
144
|
+
updatedSegments[updatedSegments.length - 1].type === 'text'
|
|
145
|
+
) {
|
|
146
|
+
updatedSegments[updatedSegments.length - 1] = {
|
|
147
|
+
type: 'text',
|
|
148
|
+
text: currentTextSegment,
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
updatedSegments.push({ type: 'text', text: currentTextSegment })
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
currentAssistantSegmentsRef.current = updatedSegments
|
|
155
|
+
updateLastAssistantMessage(updatedSegments)
|
|
156
|
+
} else if (segment.type === 'thinking') {
|
|
157
|
+
// Adaptive-thinking content from the model. Stash as a single
|
|
158
|
+
// 'thinking' segment at the front of the message; if the segment
|
|
159
|
+
// already exists (server flushed thinking in chunks via the
|
|
160
|
+
// leading-frame loop), replace its text. Order matters: thinking
|
|
161
|
+
// ALWAYS precedes the answer text so the OSS-lib renders the
|
|
162
|
+
// ThinkingDisplay card above the answer body.
|
|
163
|
+
const updatedSegments = [...currentAssistantSegmentsRef.current]
|
|
164
|
+
const existingThinkingIdx = updatedSegments.findIndex(
|
|
165
|
+
(s) => s.type === 'thinking',
|
|
166
|
+
)
|
|
167
|
+
if (existingThinkingIdx !== -1) {
|
|
168
|
+
updatedSegments[existingThinkingIdx] = {
|
|
169
|
+
type: 'thinking',
|
|
170
|
+
text: segment.text,
|
|
171
|
+
}
|
|
172
|
+
} else {
|
|
173
|
+
// Insert at the FRONT so it renders before any text accumulated.
|
|
174
|
+
updatedSegments.unshift({ type: 'thinking', text: segment.text })
|
|
175
|
+
}
|
|
176
|
+
currentAssistantSegmentsRef.current = updatedSegments
|
|
177
|
+
updateLastAssistantMessage(updatedSegments)
|
|
178
|
+
} else if ((segment as any).type === 'approval_request') {
|
|
179
|
+
// Tool proposal from the server. The streamFn pre-wired
|
|
180
|
+
// `onApprove`/`onReject` so they POST to
|
|
181
|
+
// `/api/chat/agent/confirm-tool` with the same proxy auth the
|
|
182
|
+
// chat stream used. Here we (1) flip the card's `status` from
|
|
183
|
+
// pending → approved/rejected after the network round-trip,
|
|
184
|
+
// and (2) append a follow-up TEXT segment so the user sees a
|
|
185
|
+
// concrete confirmation of what happened.
|
|
186
|
+
if (currentTextSegment) {
|
|
187
|
+
const updated = [...currentAssistantSegmentsRef.current]
|
|
188
|
+
if (updated.length > 0 && updated[updated.length - 1].type === 'text') {
|
|
189
|
+
updated[updated.length - 1] = { type: 'text', text: currentTextSegment }
|
|
190
|
+
} else {
|
|
191
|
+
updated.push({ type: 'text', text: currentTextSegment })
|
|
192
|
+
}
|
|
193
|
+
currentAssistantSegmentsRef.current = updated
|
|
194
|
+
currentTextSegment = ''
|
|
195
|
+
}
|
|
196
|
+
const seg = segment as any
|
|
197
|
+
const proposalId: string = seg.data?.requestId
|
|
198
|
+
// Locate the assistant message that hosts this approval
|
|
199
|
+
// segment and apply a transform — INDEPENDENT of
|
|
200
|
+
// `currentAssistantSegmentsRef`, which the SSE `finally`
|
|
201
|
+
// resets to `[]` the moment the stream ends. If we mutated
|
|
202
|
+
// the ref then re-rendered `updateLastAssistantMessage([])`
|
|
203
|
+
// (the empty ref's snapshot), we'd wipe the assistant
|
|
204
|
+
// message's content the instant the user clicks Approve.
|
|
205
|
+
const updateApprovalMessage = (
|
|
206
|
+
transform: (segments: MessageSegment[]) => MessageSegment[],
|
|
207
|
+
) => {
|
|
208
|
+
setMessages((prev) => {
|
|
209
|
+
for (let i = prev.length - 1; i >= 0; i--) {
|
|
210
|
+
const m = prev[i]
|
|
211
|
+
if (m.role !== 'assistant') continue
|
|
212
|
+
if (!Array.isArray(m.content)) continue
|
|
213
|
+
const segments = m.content as MessageSegment[]
|
|
214
|
+
const hasMatch = segments.some(
|
|
215
|
+
(s) =>
|
|
216
|
+
(s as any).type === 'approval_request' &&
|
|
217
|
+
(s as any).data?.requestId === proposalId,
|
|
218
|
+
)
|
|
219
|
+
if (!hasMatch) continue
|
|
220
|
+
const next = [...prev]
|
|
221
|
+
next[i] = { ...m, content: transform(segments) }
|
|
222
|
+
return next
|
|
223
|
+
}
|
|
224
|
+
return prev
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
// Server-driven post-approve flow: wrappedApprove/Reject just
|
|
228
|
+
// fire a new chat turn with `approvalAction` set. The streamFn
|
|
229
|
+
// routes that turn to `/api/chat/agent/confirm-tool` which
|
|
230
|
+
// returns SSE — its `decision_resolved` leading frame lands
|
|
231
|
+
// back as a `type: 'decision_resolved'` segment in this same
|
|
232
|
+
// loop, where the handler below matches it back to this
|
|
233
|
+
// approval card via `requestId` and applies status flip +
|
|
234
|
+
// receipt append. NO client-side orchestration.
|
|
235
|
+
const wrappedApprove = async (reqId?: string) => {
|
|
236
|
+
if (!reqId) return
|
|
237
|
+
await sendMessage(
|
|
238
|
+
'',
|
|
239
|
+
{ approvalAction: { proposalId: reqId, action: 'approve' } },
|
|
240
|
+
{ hidden: true },
|
|
241
|
+
)
|
|
242
|
+
}
|
|
243
|
+
const wrappedReject = async (reqId?: string) => {
|
|
244
|
+
if (!reqId) return
|
|
245
|
+
await sendMessage(
|
|
246
|
+
'',
|
|
247
|
+
{ approvalAction: { proposalId: reqId, action: 'reject' } },
|
|
248
|
+
{ hidden: true },
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
currentAssistantSegmentsRef.current.push({
|
|
252
|
+
...seg,
|
|
253
|
+
onApprove: wrappedApprove,
|
|
254
|
+
onReject: wrappedReject,
|
|
255
|
+
})
|
|
256
|
+
updateLastAssistantMessage([...currentAssistantSegmentsRef.current])
|
|
257
|
+
} else if ((segment as any).type === 'decision_resolved') {
|
|
258
|
+
// Server-driven decision frame from /api/chat/agent/confirm-tool.
|
|
259
|
+
//
|
|
260
|
+
// Two side-effects:
|
|
261
|
+
//
|
|
262
|
+
// 1. SOURCE message (the one carrying the approval card):
|
|
263
|
+
// flip the matched approval_request segment's status to
|
|
264
|
+
// 'approved'/'rejected'.
|
|
265
|
+
//
|
|
266
|
+
// 2. CURRENT (new) assistant message: prepend the receipt
|
|
267
|
+
// ("✅ Approved — ticket created: <card>" etc.) into
|
|
268
|
+
// `currentTextSegment`. Subsequent auto-continuation
|
|
269
|
+
// text deltas extend the same segment.
|
|
270
|
+
//
|
|
271
|
+
// For reject, no auto-continuation text follows — the new
|
|
272
|
+
// turn carries only the receipt.
|
|
273
|
+
const decision = segment as unknown as {
|
|
274
|
+
type: 'decision_resolved'
|
|
275
|
+
proposalId?: string
|
|
276
|
+
action: 'approved' | 'rejected'
|
|
277
|
+
ok: boolean
|
|
278
|
+
toolName?: string
|
|
279
|
+
result?: { ticket_id?: string; status?: string | null }
|
|
280
|
+
marker?: string
|
|
281
|
+
/** Full ChatRef payload from the server's `decision_resolved`
|
|
282
|
+
* frame — `card.ref` in the wire format. Carries enough
|
|
283
|
+
* metadata for inline card render. */
|
|
284
|
+
cardRef?: {
|
|
285
|
+
type?: string
|
|
286
|
+
id?: string
|
|
287
|
+
title?: string
|
|
288
|
+
url?: string | null
|
|
289
|
+
metadata?: Record<string, string | null | undefined>
|
|
290
|
+
[key: string]: unknown
|
|
291
|
+
}
|
|
292
|
+
/** Server-rendered receipt copy. Computed by the per-source
|
|
293
|
+
* `strategy.tools.receiptRenderer(...)`. */
|
|
294
|
+
receiptText?: string
|
|
295
|
+
/** True when the server WILL stream an auto-continuation
|
|
296
|
+
* Sonnet turn after this frame. */
|
|
297
|
+
willAutoContinue?: boolean
|
|
298
|
+
}
|
|
299
|
+
if (!decision.proposalId) continue
|
|
300
|
+
// Step 1 — flip the source card's status.
|
|
301
|
+
setMessages((prev) => {
|
|
302
|
+
for (let i = prev.length - 1; i >= 0; i--) {
|
|
303
|
+
const m = prev[i]
|
|
304
|
+
if (m.role !== 'assistant') continue
|
|
305
|
+
if (!Array.isArray(m.content)) continue
|
|
306
|
+
const segments = m.content as MessageSegment[]
|
|
307
|
+
const hasMatch = segments.some(
|
|
308
|
+
(s) =>
|
|
309
|
+
(s as any).type === 'approval_request' &&
|
|
310
|
+
(s as any).data?.requestId === decision.proposalId,
|
|
311
|
+
)
|
|
312
|
+
if (!hasMatch) continue
|
|
313
|
+
const flipped = segments.map((s) =>
|
|
314
|
+
(s as any).type === 'approval_request' &&
|
|
315
|
+
(s as any).data?.requestId === decision.proposalId
|
|
316
|
+
? ({ ...(s as any), status: decision.action } as MessageSegment)
|
|
317
|
+
: s,
|
|
318
|
+
)
|
|
319
|
+
const next = [...prev]
|
|
320
|
+
next[i] = { ...m, content: flipped }
|
|
321
|
+
return next
|
|
322
|
+
}
|
|
323
|
+
return prev
|
|
324
|
+
})
|
|
325
|
+
// Step 2 — receipt text into the CURRENT message.
|
|
326
|
+
// SERVER-RENDERED. The per-source strategy
|
|
327
|
+
// (`strategy.tools.receiptRenderer(...)`) computed the copy
|
|
328
|
+
// and shipped it on the SSE frame as `receiptText`. The
|
|
329
|
+
// chat-shell is source-agnostic — it just appends the string.
|
|
330
|
+
const receipt = decision.receiptText ?? null
|
|
331
|
+
if (receipt === null) {
|
|
332
|
+
// No server-provided copy → don't fabricate a fallback.
|
|
333
|
+
continue
|
|
334
|
+
}
|
|
335
|
+
currentTextSegment = receipt + '\n\n'
|
|
336
|
+
const updatedSegments = [...currentAssistantSegmentsRef.current]
|
|
337
|
+
if (
|
|
338
|
+
updatedSegments.length > 0 &&
|
|
339
|
+
updatedSegments[updatedSegments.length - 1].type === 'text'
|
|
340
|
+
) {
|
|
341
|
+
updatedSegments[updatedSegments.length - 1] = {
|
|
342
|
+
type: 'text',
|
|
343
|
+
text: currentTextSegment,
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
updatedSegments.push({ type: 'text', text: currentTextSegment })
|
|
347
|
+
}
|
|
348
|
+
currentAssistantSegmentsRef.current = updatedSegments
|
|
349
|
+
// SERVER-DRIVEN CARDREF ATTACHMENT — stamp the ref onto THIS
|
|
350
|
+
// assistant message so the `[card://<type>:<id>]` marker
|
|
351
|
+
// resolves via `message.chatRefs` independent of per-turn
|
|
352
|
+
// refsMap indexing.
|
|
353
|
+
const refForMessage =
|
|
354
|
+
decision.cardRef &&
|
|
355
|
+
typeof decision.cardRef.type === 'string' &&
|
|
356
|
+
typeof decision.cardRef.id === 'string'
|
|
357
|
+
? decision.cardRef
|
|
358
|
+
: null
|
|
359
|
+
if (refForMessage) {
|
|
360
|
+
const refKey = buildChatRefKey(
|
|
361
|
+
refForMessage.type as string,
|
|
362
|
+
refForMessage.id as string,
|
|
363
|
+
)
|
|
364
|
+
setMessages((prev) => {
|
|
365
|
+
const next = [...prev]
|
|
366
|
+
const lastIdx = next.length - 1
|
|
367
|
+
const lastMsg = next[lastIdx]
|
|
368
|
+
if (!lastMsg || lastMsg.role !== 'assistant') return prev
|
|
369
|
+
next[lastIdx] = {
|
|
370
|
+
...lastMsg,
|
|
371
|
+
content: updatedSegments.length > 0 ? updatedSegments : '',
|
|
372
|
+
chatRefs: {
|
|
373
|
+
...(lastMsg.chatRefs ?? {}),
|
|
374
|
+
[refKey]: refForMessage as unknown as ChatRef,
|
|
375
|
+
},
|
|
376
|
+
}
|
|
377
|
+
return next
|
|
378
|
+
})
|
|
379
|
+
} else {
|
|
380
|
+
updateLastAssistantMessage(updatedSegments)
|
|
381
|
+
}
|
|
382
|
+
} else if (segment.type === 'tool_execution') {
|
|
383
|
+
if (currentTextSegment) {
|
|
384
|
+
const updatedSegments = [...currentAssistantSegmentsRef.current]
|
|
385
|
+
|
|
386
|
+
if (
|
|
387
|
+
updatedSegments.length > 0 &&
|
|
388
|
+
updatedSegments[updatedSegments.length - 1].type === 'text'
|
|
389
|
+
) {
|
|
390
|
+
updatedSegments[updatedSegments.length - 1] = {
|
|
391
|
+
type: 'text',
|
|
392
|
+
text: currentTextSegment,
|
|
393
|
+
}
|
|
394
|
+
} else {
|
|
395
|
+
updatedSegments.push({ type: 'text', text: currentTextSegment })
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
currentAssistantSegmentsRef.current = updatedSegments
|
|
399
|
+
currentTextSegment = ''
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const existingToolIndex = currentAssistantSegmentsRef.current.findIndex(
|
|
403
|
+
(s): s is { type: 'tool_execution'; data: ToolExecutionData } =>
|
|
404
|
+
isToolSegment(s) &&
|
|
405
|
+
s.data.type === 'EXECUTING_TOOL' &&
|
|
406
|
+
s.data.integratedToolType === segment.data.integratedToolType &&
|
|
407
|
+
s.data.toolFunction === segment.data.toolFunction,
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
if (existingToolIndex !== -1 && segment.data.type === 'EXECUTED_TOOL') {
|
|
411
|
+
const existingTool = currentAssistantSegmentsRef.current[existingToolIndex] as {
|
|
412
|
+
type: 'tool_execution'
|
|
413
|
+
data: ToolExecutionData
|
|
414
|
+
}
|
|
415
|
+
currentAssistantSegmentsRef.current[existingToolIndex] = {
|
|
416
|
+
...segment,
|
|
417
|
+
data: {
|
|
418
|
+
...segment.data,
|
|
419
|
+
parameters: segment.data.parameters || existingTool.data.parameters,
|
|
420
|
+
},
|
|
421
|
+
}
|
|
422
|
+
} else {
|
|
423
|
+
currentAssistantSegmentsRef.current.push(segment)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
updateLastAssistantMessage([...currentAssistantSegmentsRef.current])
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
} catch (err) {
|
|
430
|
+
const errorMessage: Message = {
|
|
431
|
+
id: `error-${Date.now()}`,
|
|
432
|
+
role: 'error',
|
|
433
|
+
content:
|
|
434
|
+
err instanceof Error
|
|
435
|
+
? err.message
|
|
436
|
+
: 'An error occurred while processing your request.',
|
|
437
|
+
timestamp: new Date(),
|
|
438
|
+
}
|
|
439
|
+
setMessages((prev) => [...prev.slice(0, -1), errorMessage])
|
|
440
|
+
} finally {
|
|
441
|
+
setIsTyping(false)
|
|
442
|
+
// Reject-path on confirm-tool emits ONLY a `decision_resolved`
|
|
443
|
+
// leading frame and closes — no text segments stream in, so the
|
|
444
|
+
// placeholder assistant message added by addMessage above would
|
|
445
|
+
// render as a blank bubble. Remove the trailing assistant message
|
|
446
|
+
// if it still has no segments.
|
|
447
|
+
const trailingIsEmpty =
|
|
448
|
+
Array.isArray(currentAssistantSegmentsRef.current) &&
|
|
449
|
+
currentAssistantSegmentsRef.current.length === 0
|
|
450
|
+
if (trailingIsEmpty) {
|
|
451
|
+
setMessages((prev) => {
|
|
452
|
+
if (prev.length === 0) return prev
|
|
453
|
+
const last = prev[prev.length - 1]
|
|
454
|
+
if (last.role !== 'assistant') return prev
|
|
455
|
+
if (Array.isArray(last.content) && last.content.length > 0) return prev
|
|
456
|
+
if (typeof last.content === 'string' && last.content.length > 0) return prev
|
|
457
|
+
return prev.slice(0, -1)
|
|
458
|
+
})
|
|
459
|
+
}
|
|
460
|
+
currentAssistantSegmentsRef.current = []
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
[streamMessage, addMessage, updateLastAssistantMessage, assistantName, assistantAvatar],
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
const handleQuickAction = useCallback(
|
|
467
|
+
(actionText: string) => {
|
|
468
|
+
sendMessage(actionText)
|
|
469
|
+
},
|
|
470
|
+
[sendMessage],
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
const clearMessages = useCallback(() => {
|
|
474
|
+
setMessages([])
|
|
475
|
+
setIsTyping(false)
|
|
476
|
+
reset()
|
|
477
|
+
}, [reset])
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Abort the in-flight streamed message. The fetch's AbortSignal terminates
|
|
481
|
+
* the upstream Anthropic request (so billing stops); the `for await` loop
|
|
482
|
+
* inside `sendMessage` exits via `useSSE`'s AbortError handling, leaving
|
|
483
|
+
* the partial assistant response visible to the user.
|
|
484
|
+
*/
|
|
485
|
+
const stopMessage = useCallback(() => {
|
|
486
|
+
abort()
|
|
487
|
+
setIsTyping(false)
|
|
488
|
+
}, [abort])
|
|
489
|
+
|
|
490
|
+
return {
|
|
491
|
+
messages,
|
|
492
|
+
isTyping,
|
|
493
|
+
isStreaming,
|
|
494
|
+
error: sseError,
|
|
495
|
+
sendMessage,
|
|
496
|
+
stopMessage,
|
|
497
|
+
handleQuickAction,
|
|
498
|
+
clearMessages,
|
|
499
|
+
hasMessages: messages.length > 0,
|
|
500
|
+
}
|
|
501
|
+
}
|