@flamingo-stack/openframe-frontend-core 0.0.222 → 0.0.223
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-AIKPR6BE.js → chunk-4VHWSAQR.js} +6069 -5235
- package/dist/chunk-4VHWSAQR.js.map +1 -0
- package/dist/{chunk-GMNE7P7V.cjs → chunk-4WBVMIKQ.cjs} +26 -26
- package/dist/{chunk-GMNE7P7V.cjs.map → chunk-4WBVMIKQ.cjs.map} +1 -1
- package/dist/{chunk-QYRV6MKX.js → chunk-53EA4QPZ.js} +13 -7
- package/dist/chunk-53EA4QPZ.js.map +1 -0
- package/dist/{chunk-4JOWZLEL.cjs → chunk-7TKYFZ3L.cjs} +7 -7
- package/dist/{chunk-4JOWZLEL.cjs.map → chunk-7TKYFZ3L.cjs.map} +1 -1
- package/dist/{chunk-IZA5WF44.cjs → chunk-ABBU7QOM.cjs} +12 -12
- package/dist/{chunk-IZA5WF44.cjs.map → chunk-ABBU7QOM.cjs.map} +1 -1
- package/dist/{chunk-KM4KK2A6.cjs → chunk-ENDUMC7Z.cjs} +2558 -1724
- package/dist/chunk-ENDUMC7Z.cjs.map +1 -0
- package/dist/{chunk-CCSEXVI4.js → chunk-GYYGA24C.js} +2 -2
- package/dist/{chunk-RMOHKAHA.js → chunk-ISWWP2BH.js} +3 -3
- package/dist/{chunk-QNYH3WUU.cjs → chunk-JUWPBMQM.cjs} +13 -7
- package/dist/chunk-JUWPBMQM.cjs.map +1 -0
- package/dist/{chunk-A2SFHYVF.cjs → chunk-KXLTWANQ.cjs} +10 -10
- package/dist/{chunk-A2SFHYVF.cjs.map → chunk-KXLTWANQ.cjs.map} +1 -1
- package/dist/{chunk-ND24XSVT.js → chunk-TA6Z2AKD.js} +3 -3
- package/dist/chunk-TA6Z2AKD.js.map +1 -0
- package/dist/{chunk-HRIAZQ5D.js → chunk-WOKB6RJ7.js} +3 -3
- package/dist/components/chat/chat-archive-page.d.ts.map +1 -1
- package/dist/components/chat/chat-composer.d.ts.map +1 -1
- package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
- package/dist/components/chat/chat-message-skeleton.d.ts +19 -4
- package/dist/components/chat/chat-message-skeleton.d.ts.map +1 -1
- package/dist/components/chat/chat-panel-header-mobile.d.ts +24 -0
- package/dist/components/chat/chat-panel-header-mobile.d.ts.map +1 -0
- package/dist/components/chat/chat-panel-header.d.ts +6 -0
- package/dist/components/chat/chat-panel-header.d.ts.map +1 -1
- package/dist/components/chat/chat-quick-action-row.d.ts +31 -0
- package/dist/components/chat/chat-quick-action-row.d.ts.map +1 -0
- package/dist/components/chat/embeddable-chat.d.ts +27 -0
- package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
- package/dist/components/chat/entity-cards/dispatch.d.ts +14 -0
- package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
- package/dist/components/chat/entity-cards/github-activity-card.d.ts +10 -1
- package/dist/components/chat/entity-cards/github-activity-card.d.ts.map +1 -1
- package/dist/components/chat/guide-welcome.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +9 -0
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-slash-commands.d.ts +26 -0
- package/dist/components/chat/hooks/use-slash-commands.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +12 -1
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-unified-chat.d.ts +12 -0
- package/dist/components/chat/hooks/use-unified-chat.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +9 -3
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.js +8 -2
- package/dist/components/chat/mingo-chat-history.d.ts +10 -0
- package/dist/components/chat/mingo-chat-history.d.ts.map +1 -1
- package/dist/components/chat/mingo-info-card.d.ts +63 -0
- package/dist/components/chat/mingo-info-card.d.ts.map +1 -0
- package/dist/components/chat/mingo-welcome.d.ts +14 -1
- package/dist/components/chat/mingo-welcome.d.ts.map +1 -1
- package/dist/components/chat/types/chat.types.d.ts +6 -0
- package/dist/components/chat/types/chat.types.d.ts.map +1 -1
- package/dist/components/chat/types/unified-chat-state.types.d.ts +30 -0
- package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
- package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +4 -4
- package/dist/components/contact/index.js +3 -3
- package/dist/components/features/index.cjs +3 -3
- package/dist/components/features/index.js +2 -2
- package/dist/components/index.cjs +110 -104
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +36 -30
- package/dist/components/index.js.map +1 -1
- package/dist/components/navigation/app-layout-drawer.d.ts +7 -0
- package/dist/components/navigation/app-layout-drawer.d.ts.map +1 -1
- package/dist/components/navigation/index.cjs +3 -3
- package/dist/components/navigation/index.js +2 -2
- package/dist/components/onboarding-guides/index.cjs +26 -26
- package/dist/components/onboarding-guides/index.js +4 -4
- package/dist/components/tickets/index.cjs +67 -67
- package/dist/components/tickets/index.js +5 -5
- package/dist/components/ui/actions-menu.d.ts +9 -0
- package/dist/components/ui/actions-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-button.d.ts +2 -2
- package/dist/components/ui/dropdown-button.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +9 -3
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.js +8 -2
- package/dist/components/ui/modal-v2.d.ts.map +1 -1
- package/dist/components/ui/more-actions-menu.d.ts +13 -0
- package/dist/components/ui/more-actions-menu.d.ts.map +1 -1
- package/dist/components/ui/square-avatar.d.ts +4 -0
- package/dist/components/ui/square-avatar.d.ts.map +1 -1
- package/dist/components/ui/textarea.d.ts.map +1 -1
- package/dist/hooks/index.cjs +2 -2
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/ui/use-auto-limit-tags.d.ts +7 -1
- package/dist/hooks/ui/use-auto-limit-tags.d.ts.map +1 -1
- package/dist/index.cjs +9 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8 -2
- package/package.json +1 -1
- package/src/components/chat/chat-archive-page.tsx +32 -7
- package/src/components/chat/chat-composer.tsx +6 -2
- package/src/components/chat/chat-message-enhanced.tsx +24 -7
- package/src/components/chat/chat-message-list.tsx +1 -1
- package/src/components/chat/chat-message-skeleton.tsx +60 -60
- package/src/components/chat/chat-panel-header-mobile.tsx +94 -0
- package/src/components/chat/chat-panel-header.tsx +78 -50
- package/src/components/chat/chat-quick-action-row.tsx +146 -0
- package/src/components/chat/embeddable-chat.tsx +140 -45
- package/src/components/chat/entity-cards/dispatch.tsx +770 -232
- package/src/components/chat/entity-cards/github-activity-card.tsx +9 -3
- package/src/components/chat/guide-welcome.tsx +11 -8
- package/src/components/chat/hooks/use-nats-chat-adapter.ts +80 -7
- package/src/components/chat/hooks/use-slash-commands.ts +39 -0
- package/src/components/chat/hooks/use-sse-chat-adapter.ts +49 -45
- package/src/components/chat/hooks/use-unified-chat.ts +31 -8
- package/src/components/chat/mingo-chat-history.tsx +118 -36
- package/src/components/chat/mingo-info-card.tsx +214 -0
- package/src/components/chat/mingo-welcome.tsx +89 -36
- package/src/components/chat/types/chat.types.ts +4 -0
- package/src/components/chat/types/unified-chat-state.types.ts +35 -0
- package/src/components/chat/utils/process-historical-messages.ts +8 -0
- package/src/components/content-loading-container.tsx +1 -1
- package/src/components/empty-state.tsx +3 -3
- package/src/components/faq-accordion.tsx +2 -2
- package/src/components/features/changelog-manager.tsx +2 -2
- package/src/components/features/highlight-config-section.tsx +2 -2
- package/src/components/features/og-editor-preview.tsx +3 -3
- package/src/components/features/release-media-manager.tsx +2 -2
- package/src/components/loading/card-skeleton.tsx +3 -3
- package/src/components/loading/device-card-skeleton.tsx +1 -1
- package/src/components/loading/margin-report-skeleton.tsx +2 -2
- package/src/components/loading/organization-card-skeleton.tsx +1 -1
- package/src/components/loading/organization-icon-skeleton.tsx +1 -1
- package/src/components/loading/page-layout-skeleton.tsx +9 -9
- package/src/components/loading/users-grid-skeleton.tsx +2 -2
- package/src/components/logs-list.tsx +1 -1
- package/src/components/media-carousel.tsx +1 -1
- package/src/components/navigation/app-layout-drawer.tsx +70 -6
- package/src/components/open-source-features.tsx +2 -2
- package/src/components/ui/actions-menu.tsx +36 -13
- package/src/components/ui/allowed-domains-input.tsx +3 -3
- package/src/components/ui/cursor-pagination.tsx +1 -1
- package/src/components/ui/dropdown-button.tsx +6 -6
- package/src/components/ui/info-row.tsx +2 -2
- package/src/components/ui/modal-v2.tsx +8 -1
- package/src/components/ui/more-actions-menu.tsx +13 -0
- package/src/components/ui/square-avatar.tsx +6 -1
- package/src/components/ui/tags-input.tsx +1 -1
- package/src/components/ui/textarea.tsx +18 -4
- package/src/components/vendor-icon.tsx +1 -1
- package/src/components/vendor-tag.tsx +1 -1
- package/src/components/why-it-matters.tsx +1 -1
- package/src/hooks/ui/use-auto-limit-tags.ts +22 -8
- package/src/stories/ActionsMenu.stories.tsx +256 -0
- package/src/stories/AppLayoutSidebar.stories.tsx +6 -0
- package/src/stories/Board.stories.tsx +1 -1
- package/src/stories/ChatMingoInfoCards.stories.tsx +748 -0
- package/src/stories/ChatTicketList.stories.tsx +1 -1
- package/src/stories/DataTable.stories.tsx +17 -13
- package/src/stories/EmbeddableChat.stories.tsx +233 -1
- package/src/stories/MingoInfoCard.stories.tsx +193 -0
- package/src/stories/MingoOnboardingCard.stories.tsx +1 -1
- package/src/stories/Modal.stories.tsx +1 -0
- package/src/stories/NotificationDrawer.stories.tsx +14 -3
- package/src/stories/PageActions.stories.tsx +4 -4
- package/src/stories/PageContainer.stories.tsx +5 -5
- package/src/stories/PageLayout.stories.tsx +1 -1
- package/src/stories/TabSelector.stories.tsx +2 -2
- package/src/stories/Tag.stories.tsx +10 -5
- package/src/stories/TicketInfoSection.stories.tsx +23 -11
- package/src/stories/Toaster.stories.tsx +5 -5
- package/src/stories/__fixtures__/chat-card-decorator.tsx +44 -0
- package/dist/chunk-AIKPR6BE.js.map +0 -1
- package/dist/chunk-KM4KK2A6.cjs.map +0 -1
- package/dist/chunk-ND24XSVT.js.map +0 -1
- package/dist/chunk-QNYH3WUU.cjs.map +0 -1
- package/dist/chunk-QYRV6MKX.js.map +0 -1
- package/src/stories/.TicketDescriptionViewer.stories.md +0 -39
- package/src/stories/.TicketKnowledgeBaseList.stories.md +0 -36
- package/src/stories/TicketDescriptionViewer.stories.tsx +0 -70
- package/src/stories/TicketKnowledgeBaseList.stories.tsx +0 -51
- /package/dist/{chunk-CCSEXVI4.js.map → chunk-GYYGA24C.js.map} +0 -0
- /package/dist/{chunk-RMOHKAHA.js.map → chunk-ISWWP2BH.js.map} +0 -0
- /package/dist/{chunk-HRIAZQ5D.js.map → chunk-WOKB6RJ7.js.map} +0 -0
|
@@ -67,7 +67,7 @@ function kindIcon(kind: GitHubActivityKind, className = 'h-4 w-4') {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
function kindLabel(kind: GitHubActivityKind): string {
|
|
70
|
+
export function kindLabel(kind: GitHubActivityKind): string {
|
|
71
71
|
switch (kind) {
|
|
72
72
|
case 'pull_request': return 'PR'
|
|
73
73
|
case 'pr_review': return 'Review'
|
|
@@ -76,14 +76,14 @@ function kindLabel(kind: GitHubActivityKind): string {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
function formatActivityId(id: string, kind: GitHubActivityKind): string {
|
|
79
|
+
export function formatActivityId(id: string, kind: GitHubActivityKind): string {
|
|
80
80
|
if (!id) return ''
|
|
81
81
|
if (kind === 'pull_request' || kind === 'pr_review') return `#${id}`
|
|
82
82
|
if (/^[0-9a-f]{40}$/i.test(id)) return id.slice(0, 7)
|
|
83
83
|
return id.length > 12 ? id.slice(0, 12) : id
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
function parseGithubTitle(title: string, kind: GitHubActivityKind): { display: string; reviewState: PrReviewState | null } {
|
|
86
|
+
export function parseGithubTitle(title: string, kind: GitHubActivityKind): { display: string; reviewState: PrReviewState | null } {
|
|
87
87
|
if (!title) return { display: '', reviewState: null }
|
|
88
88
|
|
|
89
89
|
// Split prefix-tag from rest by hand instead of one giant regex.
|
|
@@ -150,6 +150,12 @@ const REVIEW_STATE_STYLE: Record<PrReviewState, { label: string; className: stri
|
|
|
150
150
|
},
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
/** Short review-state label ("APPROVED" → "Approved") shared with the
|
|
154
|
+
* MingoInfoCard dispatch mapping so both surfaces read identically. */
|
|
155
|
+
export function reviewStateLabel(state: PrReviewState): string {
|
|
156
|
+
return (REVIEW_STATE_STYLE[state] ?? REVIEW_STATE_STYLE.COMMENTED).label
|
|
157
|
+
}
|
|
158
|
+
|
|
153
159
|
function ReviewStateBadge({ state, className = '' }: { state: PrReviewState; className?: string }) {
|
|
154
160
|
const { label, className: paint } = REVIEW_STATE_STYLE[state] ?? REVIEW_STATE_STYLE.COMMENTED
|
|
155
161
|
return (
|
|
@@ -4,7 +4,7 @@ import * as React from 'react'
|
|
|
4
4
|
import { cn } from '../../utils/cn'
|
|
5
5
|
import { MingoIcon } from '../icons'
|
|
6
6
|
import { Tag } from '../ui/tag'
|
|
7
|
-
import {
|
|
7
|
+
import { ActionsMenuDropdown } from '../ui/actions-menu'
|
|
8
8
|
import { Ellipsis01Icon } from '../icons-v2-generated'
|
|
9
9
|
|
|
10
10
|
// =============================================================================
|
|
@@ -174,14 +174,17 @@ export function GuideWelcome({
|
|
|
174
174
|
</button>
|
|
175
175
|
))}
|
|
176
176
|
{overflowActions.length > 0 && (
|
|
177
|
-
<
|
|
178
|
-
|
|
177
|
+
<ActionsMenuDropdown
|
|
178
|
+
triggerAriaLabel="More quick actions"
|
|
179
179
|
onCloseAutoFocus={(e) => e.preventDefault()}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
180
|
+
groups={[{
|
|
181
|
+
items: overflowActions.map((action) => ({
|
|
182
|
+
id: action.id,
|
|
183
|
+
label: action.label,
|
|
184
|
+
onClick: () => onQuickAction?.(action),
|
|
185
|
+
})),
|
|
186
|
+
}]}
|
|
187
|
+
customTrigger={
|
|
185
188
|
<button
|
|
186
189
|
type="button"
|
|
187
190
|
aria-label="More quick actions"
|
|
@@ -307,6 +307,16 @@ export interface UseNatsChatAdapterConfig {
|
|
|
307
307
|
|
|
308
308
|
/** Default page size for message history pagination. Defaults to 50. */
|
|
309
309
|
messagesPageSize?: number
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Baseline model display for the composer's `<ModelDisplay>` — used as the
|
|
313
|
+
* empty-state fallback before any streaming `metadata` frame arrives (e.g.
|
|
314
|
+
* a brand-new chat). The host typically sources these from its AI-config
|
|
315
|
+
* endpoint. Live `metadata` frames refine them per-turn. NATS-only; SSE
|
|
316
|
+
* (guide) derives its own model from the stream.
|
|
317
|
+
*/
|
|
318
|
+
modelProvider?: string | null
|
|
319
|
+
modelLabel?: string | null
|
|
310
320
|
}
|
|
311
321
|
|
|
312
322
|
/**
|
|
@@ -431,6 +441,8 @@ export function useNatsChatAdapter(
|
|
|
431
441
|
chatTypeFilter,
|
|
432
442
|
dialogsPageSize = 20,
|
|
433
443
|
messagesPageSize = 50,
|
|
444
|
+
modelProvider = null,
|
|
445
|
+
modelLabel = null,
|
|
434
446
|
} = config
|
|
435
447
|
|
|
436
448
|
// ─── Active dialog id resolution ──────────────────────────────────────────
|
|
@@ -467,6 +479,7 @@ export function useNatsChatAdapter(
|
|
|
467
479
|
const [dialogs, setDialogs] = useState<DialogItem[]>([])
|
|
468
480
|
const [dialogsNextCursor, setDialogsNextCursor] = useState<string | null>(null)
|
|
469
481
|
const [isDialogsLoading, setIsDialogsLoading] = useState<boolean>(false)
|
|
482
|
+
const [dialogsError, setDialogsError] = useState<boolean>(false)
|
|
470
483
|
const [isCreatingDialog, setIsCreatingDialog] = useState<boolean>(false)
|
|
471
484
|
|
|
472
485
|
// ─── Message-history pagination ───────────────────────────────────────────
|
|
@@ -480,6 +493,15 @@ export function useNatsChatAdapter(
|
|
|
480
493
|
null,
|
|
481
494
|
)
|
|
482
495
|
|
|
496
|
+
// ─── Live model metadata (from streaming `metadata` frames) ───────────────
|
|
497
|
+
// Refines the composer's model badge per-turn. Falls back to the config
|
|
498
|
+
// baseline (`modelProvider`/`modelLabel`) until the first frame lands.
|
|
499
|
+
const [liveModel, setLiveModel] = useState<{
|
|
500
|
+
provider: string | null
|
|
501
|
+
modelLabel: string | null
|
|
502
|
+
contextWindowMaxTokens: number | null
|
|
503
|
+
} | null>(null)
|
|
504
|
+
|
|
483
505
|
// ─── Connection state ─────────────────────────────────────────────────────
|
|
484
506
|
|
|
485
507
|
const [connectionState, setConnectionState] =
|
|
@@ -554,12 +576,29 @@ export function useNatsChatAdapter(
|
|
|
554
576
|
onSegmentsUpdate: (segments: MessageSegment[]) => void
|
|
555
577
|
onStreamStart: () => void
|
|
556
578
|
onStreamEnd: () => void
|
|
579
|
+
onTokenUsage: (data: DialogTokenUsage) => void
|
|
580
|
+
onMetadata: (meta: {
|
|
581
|
+
modelDisplayName?: string
|
|
582
|
+
modelName: string
|
|
583
|
+
providerName: string
|
|
584
|
+
contextWindow: number
|
|
585
|
+
}) => void
|
|
557
586
|
}> = useRef({
|
|
558
587
|
onSegmentsUpdate: (segments: MessageSegment[]) => {
|
|
559
588
|
setMessages((prev) => updateTrailingAssistant(prev, segments))
|
|
560
589
|
},
|
|
561
590
|
onStreamStart: () => setStreamingPhase('streaming'),
|
|
562
591
|
onStreamEnd: () => setStreamingPhase('idle'),
|
|
592
|
+
// Live cumulative token counter for the active dialog — drives the
|
|
593
|
+
// composer's "X / Y tokens used" tail as the assistant streams.
|
|
594
|
+
onTokenUsage: (data: DialogTokenUsage) => setDialogTokenUsage(data),
|
|
595
|
+
// Per-turn model badge (provider/label/context window).
|
|
596
|
+
onMetadata: (meta) =>
|
|
597
|
+
setLiveModel({
|
|
598
|
+
provider: meta.providerName || null,
|
|
599
|
+
modelLabel: meta.modelDisplayName || meta.modelName || null,
|
|
600
|
+
contextWindowMaxTokens: meta.contextWindow || null,
|
|
601
|
+
}),
|
|
563
602
|
})
|
|
564
603
|
|
|
565
604
|
// Real-time chunk → segment processor. Approval handlers route through
|
|
@@ -570,6 +609,8 @@ export function useNatsChatAdapter(
|
|
|
570
609
|
onSegmentsUpdate: (segments) => callbacksRef.current.onSegmentsUpdate(segments),
|
|
571
610
|
onStreamStart: () => callbacksRef.current.onStreamStart(),
|
|
572
611
|
onStreamEnd: () => callbacksRef.current.onStreamEnd(),
|
|
612
|
+
onTokenUsage: (data) => callbacksRef.current.onTokenUsage(data),
|
|
613
|
+
onMetadata: (meta) => callbacksRef.current.onMetadata(meta),
|
|
573
614
|
onApprove: accumApprove,
|
|
574
615
|
onReject: accumReject,
|
|
575
616
|
},
|
|
@@ -679,6 +720,9 @@ export function useNatsChatAdapter(
|
|
|
679
720
|
setMessages([])
|
|
680
721
|
setMessagesNextCursor(null)
|
|
681
722
|
setDialogTokenUsage(null)
|
|
723
|
+
// Clear per-dialog live model metadata too — otherwise the composer briefly
|
|
724
|
+
// shows the previous dialog's provider/model until the next chunk streams.
|
|
725
|
+
setLiveModel(null)
|
|
682
726
|
setStreamingPhase('idle')
|
|
683
727
|
// No load runs when there's no active dialog, so clear the flag here;
|
|
684
728
|
// otherwise the superseded load's guarded `finally` leaves it stuck on.
|
|
@@ -740,10 +784,16 @@ export function useNatsChatAdapter(
|
|
|
740
784
|
|
|
741
785
|
// ─── Dialog list management (managed-dialog mode) ─────────────────────────
|
|
742
786
|
|
|
787
|
+
// Forward-declared so `loadDialogsPage` can reset the initial-load guard on
|
|
788
|
+
// a first-page failure (enabling retry / auto-retry on re-activation).
|
|
789
|
+
const initialDialogsLoadedRef = useRef(false)
|
|
790
|
+
|
|
743
791
|
const loadDialogsPage = useCallback(
|
|
744
792
|
async (cursor?: string): Promise<void> => {
|
|
745
793
|
if (!fetchDialogs) return
|
|
746
794
|
setIsDialogsLoading(true)
|
|
795
|
+
// Clear a prior first-page error when (re)loading the first page.
|
|
796
|
+
if (cursor === undefined) setDialogsError(false)
|
|
747
797
|
try {
|
|
748
798
|
const result = await fetchDialogs({
|
|
749
799
|
cursor,
|
|
@@ -757,6 +807,13 @@ export function useNatsChatAdapter(
|
|
|
757
807
|
}
|
|
758
808
|
} catch (err) {
|
|
759
809
|
console.error('[useNatsChatAdapter] fetchDialogs failed:', err)
|
|
810
|
+
// Only the FIRST page failing is a "can't show the list" error — a
|
|
811
|
+
// pagination failure keeps the already-loaded list intact. Flag it and
|
|
812
|
+
// release the initial-load guard so a retry (or re-activation) re-runs.
|
|
813
|
+
if (cursor === undefined) {
|
|
814
|
+
setDialogsError(true)
|
|
815
|
+
initialDialogsLoadedRef.current = false
|
|
816
|
+
}
|
|
760
817
|
} finally {
|
|
761
818
|
setIsDialogsLoading(false)
|
|
762
819
|
}
|
|
@@ -764,8 +821,12 @@ export function useNatsChatAdapter(
|
|
|
764
821
|
[fetchDialogs, dialogsPageSize],
|
|
765
822
|
)
|
|
766
823
|
|
|
824
|
+
// Retry the initial dialog-list load after a failure.
|
|
825
|
+
const reloadDialogs = useCallback(() => {
|
|
826
|
+
void loadDialogsPage()
|
|
827
|
+
}, [loadDialogsPage])
|
|
828
|
+
|
|
767
829
|
// Initial dialog list load.
|
|
768
|
-
const initialDialogsLoadedRef = useRef(false)
|
|
769
830
|
useEffect(() => {
|
|
770
831
|
if (!fetchDialogs) return
|
|
771
832
|
if (!active) return
|
|
@@ -973,12 +1034,17 @@ export function useNatsChatAdapter(
|
|
|
973
1034
|
clearMessages,
|
|
974
1035
|
discussRef,
|
|
975
1036
|
displayRef,
|
|
976
|
-
//
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1037
|
+
// Model badge + token usage for the composer's `<ModelDisplay>`.
|
|
1038
|
+
// Model: live `metadata` frame → config baseline (host AI-config).
|
|
1039
|
+
// Tokens: live `token_usage` frame / dialog snapshot (`dialogTokenUsage`).
|
|
1040
|
+
// contextWindow uses the dialog's `contextSize` (the "X / Y" denominator,
|
|
1041
|
+
// matching the /mingo page). cacheHitRate/breakdown are SSE-only → null.
|
|
1042
|
+
currentProvider: liveModel?.provider ?? modelProvider ?? null,
|
|
1043
|
+
currentModelLabel: liveModel?.modelLabel ?? modelLabel ?? null,
|
|
1044
|
+
currentContextWindowMaxTokens:
|
|
1045
|
+
dialogTokenUsage?.contextSize ?? liveModel?.contextWindowMaxTokens ?? null,
|
|
1046
|
+
currentInputTokens: dialogTokenUsage?.inputTokensSize ?? null,
|
|
1047
|
+
currentOutputTokens: dialogTokenUsage?.outputTokensSize ?? null,
|
|
982
1048
|
currentCacheHitRatePct: null,
|
|
983
1049
|
currentUsageBreakdown: null,
|
|
984
1050
|
// Dialog management
|
|
@@ -990,6 +1056,8 @@ export function useNatsChatAdapter(
|
|
|
990
1056
|
renameDialog,
|
|
991
1057
|
archiveDialog,
|
|
992
1058
|
isDialogsLoading: isDialogsLoading || isCreatingDialog,
|
|
1059
|
+
dialogsError,
|
|
1060
|
+
reloadDialogs,
|
|
993
1061
|
isMessagesLoading,
|
|
994
1062
|
hasMoreDialogs,
|
|
995
1063
|
loadMoreDialogs,
|
|
@@ -1020,6 +1088,8 @@ export function useNatsChatAdapter(
|
|
|
1020
1088
|
renameDialog,
|
|
1021
1089
|
archiveDialog,
|
|
1022
1090
|
isDialogsLoading,
|
|
1091
|
+
dialogsError,
|
|
1092
|
+
reloadDialogs,
|
|
1023
1093
|
isCreatingDialog,
|
|
1024
1094
|
isMessagesLoading,
|
|
1025
1095
|
hasMoreDialogs,
|
|
@@ -1029,6 +1099,9 @@ export function useNatsChatAdapter(
|
|
|
1029
1099
|
approveRequest,
|
|
1030
1100
|
rejectRequest,
|
|
1031
1101
|
dialogTokenUsage,
|
|
1102
|
+
liveModel,
|
|
1103
|
+
modelProvider,
|
|
1104
|
+
modelLabel,
|
|
1032
1105
|
connectionState,
|
|
1033
1106
|
],
|
|
1034
1107
|
)
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { useEffect, useState } from "react";
|
|
17
|
+
import { useQuery } from "@tanstack/react-query";
|
|
17
18
|
import { embedAuthedFetch } from "../../../utils/embed-authed-fetch";
|
|
18
19
|
import type {
|
|
19
20
|
SlashCommandActionId,
|
|
@@ -113,3 +114,41 @@ export function useSlashCommands(
|
|
|
113
114
|
|
|
114
115
|
return { commands, loading };
|
|
115
116
|
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The full slash-command registry (empty-prefix fetch), shared via
|
|
120
|
+
* react-query so every consumer in one chat surface dedupes to a SINGLE
|
|
121
|
+
* network request.
|
|
122
|
+
*
|
|
123
|
+
* Keyed on `commandsUrl` ALONE — the request sends no `source` param (the
|
|
124
|
+
* hub resolves source server-side), so the URL fully determines the
|
|
125
|
+
* response. Both the onboarding-card list in `<EmbeddableChat>` and the
|
|
126
|
+
* SSE adapter's `displayRef` table lookup read from this one cache entry
|
|
127
|
+
* instead of each firing their own `fetchSlashCommands('')`.
|
|
128
|
+
*
|
|
129
|
+
* `staleTime`/`gcTime: Infinity` → static per session, so toggling modes
|
|
130
|
+
* or remounting the (close-on-unmount) drawer reads from cache, never
|
|
131
|
+
* refetches.
|
|
132
|
+
*
|
|
133
|
+
* `enabled` gates the live fetch: pass `activeMode === 'guide'` (or the
|
|
134
|
+
* SSE adapter's `active` flag) so opening the panel in Mingo mode does
|
|
135
|
+
* NOT hit the commands endpoint at all.
|
|
136
|
+
*/
|
|
137
|
+
export function useSlashCommandRegistry(
|
|
138
|
+
commandsUrl: string,
|
|
139
|
+
options?: { enabled?: boolean },
|
|
140
|
+
): { commands: SlashCommandSummary[]; loading: boolean; loaded: boolean } {
|
|
141
|
+
const query = useQuery({
|
|
142
|
+
queryKey: ["chat-slash-commands", commandsUrl],
|
|
143
|
+
queryFn: ({ signal }) => fetchSlashCommands("", signal, commandsUrl),
|
|
144
|
+
enabled: options?.enabled ?? true,
|
|
145
|
+
staleTime: Infinity,
|
|
146
|
+
gcTime: Infinity,
|
|
147
|
+
});
|
|
148
|
+
return {
|
|
149
|
+
commands: query.data ?? [],
|
|
150
|
+
loading: query.isLoading,
|
|
151
|
+
// "Loaded" = the fetch has settled, or it isn't running (disabled).
|
|
152
|
+
loaded: !query.isLoading,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
@@ -45,7 +45,7 @@ import { useRequiredChatRuntime } from '../../../contexts/chat-runtime-context'
|
|
|
45
45
|
import type { ChatRef } from '../chat-ref.types'
|
|
46
46
|
import { buildChatRefKey } from '../types/chat.types'
|
|
47
47
|
import type { MessageSegment } from '../types/message.types'
|
|
48
|
-
import {
|
|
48
|
+
import { useSlashCommandRegistry, type SlashCommandSummary } from './use-slash-commands'
|
|
49
49
|
import { getChatProxyAuth } from '../utils/chat-proxy-auth-storage'
|
|
50
50
|
import { chatAuthedFetch } from '../utils/chat-authed-fetch'
|
|
51
51
|
import { parseScrollAnchor, type ScrollAnchor } from '../utils/scroll-anchor'
|
|
@@ -170,6 +170,18 @@ export interface UseSseChatAdapterOptions {
|
|
|
170
170
|
tableIdForDocumentType?: (documentType: string) => string | null
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
export interface UseSseChatAdapterRuntimeOptions {
|
|
174
|
+
/**
|
|
175
|
+
* When `false` the adapter skips its background slash-command registry
|
|
176
|
+
* fetch (used to hydrate the `displayRef` table lookup). Mirrors the
|
|
177
|
+
* NATS adapter's `active` gate: `useUnifiedChat` passes `false` while
|
|
178
|
+
* Guide mode is configured-but-not-active, so opening the panel in
|
|
179
|
+
* Mingo mode does NOT hit the commands endpoint. Default `true` so
|
|
180
|
+
* standalone callers keep the eager prefetch.
|
|
181
|
+
*/
|
|
182
|
+
active?: boolean
|
|
183
|
+
}
|
|
184
|
+
|
|
173
185
|
// =============================================================================
|
|
174
186
|
// Internal helpers
|
|
175
187
|
// =============================================================================
|
|
@@ -679,7 +691,9 @@ function savePersistedChat(source: DocSource, state: PersistedChatState) {
|
|
|
679
691
|
*/
|
|
680
692
|
export function useSseChatAdapter(
|
|
681
693
|
options?: UseSseChatAdapterOptions,
|
|
694
|
+
runtimeOptions: UseSseChatAdapterRuntimeOptions = {},
|
|
682
695
|
): UnifiedChatState {
|
|
696
|
+
const { active = true } = runtimeOptions
|
|
683
697
|
// Chat-specific code REQUIRES a runtime — the lib's `<HubRuntimeProvider>`
|
|
684
698
|
// (hub) / embedder's provider must wrap the tree.
|
|
685
699
|
const runtime = useRequiredChatRuntime()
|
|
@@ -742,54 +756,41 @@ export function useSseChatAdapter(
|
|
|
742
756
|
],
|
|
743
757
|
)
|
|
744
758
|
|
|
745
|
-
// Per-source tableId → slash-command-id lookup
|
|
746
|
-
//
|
|
759
|
+
// Per-source tableId → slash-command-id lookup, derived from the shared
|
|
760
|
+
// slash-command registry. Used by `displayRef` to translate an
|
|
747
761
|
// inline-card's Display click into a `/<cmd> display "<value>"`
|
|
748
762
|
// invocation, picking the canonical command for the row's RAG table.
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
)
|
|
763
|
+
//
|
|
764
|
+
// Reads from the SAME react-query cache entry as `<EmbeddableChat>`'s
|
|
765
|
+
// onboarding-card list (keyed on `commandsUrl`), so Guide mode fetches
|
|
766
|
+
// `commands` ONCE. Gated on `active` so a Mingo-only panel — where this
|
|
767
|
+
// adapter is mounted but idle — never hits the endpoint.
|
|
752
768
|
const commandsUrl = runtime.endpoints.commandsUrl
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
})[0]
|
|
776
|
-
if (picked) map.set(tableId, picked.id)
|
|
777
|
-
}
|
|
778
|
-
setCmdIdByTableId(map)
|
|
779
|
-
})
|
|
780
|
-
.catch((err) => {
|
|
781
|
-
if (!cancelled && (err as Error)?.name !== 'AbortError') {
|
|
782
|
-
console.warn(
|
|
783
|
-
'[useSseChatAdapter] failed to fetch slash commands for displayRef:',
|
|
784
|
-
err,
|
|
785
|
-
)
|
|
786
|
-
}
|
|
787
|
-
})
|
|
788
|
-
return () => {
|
|
789
|
-
cancelled = true
|
|
790
|
-
ctrl.abort()
|
|
769
|
+
const { commands: slashCommands } = useSlashCommandRegistry(commandsUrl, {
|
|
770
|
+
enabled: active,
|
|
771
|
+
})
|
|
772
|
+
const cmdIdByTableId = useMemo(() => {
|
|
773
|
+
const buckets = new Map<string, SlashCommandSummary[]>()
|
|
774
|
+
for (const cmd of slashCommands) {
|
|
775
|
+
if (!cmd.primarySourceId) continue
|
|
776
|
+
const arr = buckets.get(cmd.primarySourceId) ?? []
|
|
777
|
+
arr.push(cmd)
|
|
778
|
+
buckets.set(cmd.primarySourceId, arr)
|
|
779
|
+
}
|
|
780
|
+
const map = new Map<string, string>()
|
|
781
|
+
for (const [tableId, cmds] of buckets) {
|
|
782
|
+
const display = cmds.find((c) => c.actions.some((a) => a.id === 'display'))
|
|
783
|
+
const picked =
|
|
784
|
+
display ??
|
|
785
|
+
[...cmds].sort((a, b) => {
|
|
786
|
+
const ao = a.displayOrder ?? Number.POSITIVE_INFINITY
|
|
787
|
+
const bo = b.displayOrder ?? Number.POSITIVE_INFINITY
|
|
788
|
+
return ao - bo
|
|
789
|
+
})[0]
|
|
790
|
+
if (picked) map.set(tableId, picked.id)
|
|
791
791
|
}
|
|
792
|
-
|
|
792
|
+
return map
|
|
793
|
+
}, [slashCommands])
|
|
793
794
|
|
|
794
795
|
// Persist on every messages change. Sources + sendCount live in refs,
|
|
795
796
|
// so we read their current values at write time.
|
|
@@ -1074,6 +1075,9 @@ export function useSseChatAdapter(
|
|
|
1074
1075
|
renameDialog: noopRenameDialog,
|
|
1075
1076
|
archiveDialog: noopArchiveDialog,
|
|
1076
1077
|
isDialogsLoading: false,
|
|
1078
|
+
// SSE/guide has no server-side dialog list — never errors, nothing to retry.
|
|
1079
|
+
dialogsError: false,
|
|
1080
|
+
reloadDialogs: noopAsync,
|
|
1077
1081
|
isMessagesLoading: false,
|
|
1078
1082
|
hasMoreDialogs: false,
|
|
1079
1083
|
loadMoreDialogs: noopAsync,
|
|
@@ -60,6 +60,19 @@ export interface UseUnifiedChatModes {
|
|
|
60
60
|
export interface UseUnifiedChatOptions {
|
|
61
61
|
modes: UseUnifiedChatModes
|
|
62
62
|
activeMode: ChatMode
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Pre-built Mingo-mode state, supplied by the host instead of letting
|
|
66
|
+
* the internal `useNatsChatAdapter` own it. When provided AND the active
|
|
67
|
+
* mode is `'mingo'`, this object is used verbatim as the active state and
|
|
68
|
+
* the internal NATS adapter stays idle (the host should also omit
|
|
69
|
+
* `modes.mingo` so no live subscription is opened here).
|
|
70
|
+
*
|
|
71
|
+
* This is the seam that lets a host keep chat data/streaming in its own
|
|
72
|
+
* store + cache (so it survives the panel unmounting) rather than in this
|
|
73
|
+
* hook's local React state. Guide mode is unaffected.
|
|
74
|
+
*/
|
|
75
|
+
mingoStateOverride?: UnifiedChatState
|
|
63
76
|
}
|
|
64
77
|
|
|
65
78
|
// =============================================================================
|
|
@@ -88,7 +101,7 @@ function createDisabledNatsConfig(): UseNatsChatAdapterConfig {
|
|
|
88
101
|
export function useUnifiedChat(
|
|
89
102
|
options: UseUnifiedChatOptions,
|
|
90
103
|
): UnifiedChatState {
|
|
91
|
-
const { modes, activeMode } = options
|
|
104
|
+
const { modes, activeMode, mingoStateOverride } = options
|
|
92
105
|
|
|
93
106
|
// The mingo config object identity matters — `useNatsChatAdapter`
|
|
94
107
|
// wires its `dialogId`/url/publish into deps. Stabilise the disabled
|
|
@@ -105,18 +118,21 @@ export function useUnifiedChat(
|
|
|
105
118
|
const sseActive = activeMode === 'guide' && modes.guide !== undefined
|
|
106
119
|
const natsActive = activeMode === 'mingo' && modes.mingo !== undefined
|
|
107
120
|
|
|
108
|
-
const sseState = useSseChatAdapter(modes.guide ?? EMPTY_SSE_OPTIONS
|
|
121
|
+
const sseState = useSseChatAdapter(modes.guide ?? EMPTY_SSE_OPTIONS, {
|
|
122
|
+
active: sseActive,
|
|
123
|
+
})
|
|
109
124
|
const natsState = useNatsChatAdapter(
|
|
110
125
|
modes.mingo ?? disabledNatsRef.current,
|
|
111
126
|
{ active: natsActive },
|
|
112
127
|
)
|
|
113
128
|
|
|
114
|
-
//
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
129
|
+
// Host-injected Mingo state wins when present: the internal `natsState`
|
|
130
|
+
// still runs (rules of hooks) but is idle (no `modes.mingo` → not active),
|
|
131
|
+
// and we hand the host's store-backed state straight through as active.
|
|
132
|
+
const activeState =
|
|
133
|
+
activeMode === 'guide'
|
|
134
|
+
? sseState
|
|
135
|
+
: (mingoStateOverride ?? natsState)
|
|
120
136
|
|
|
121
137
|
// Re-wrap so the returned identity is stable for the active state.
|
|
122
138
|
// Consumers shouldn't see the inactive adapter's state at all.
|
|
@@ -169,6 +185,10 @@ export function useUnifiedChat(
|
|
|
169
185
|
() => activeState.loadMoreDialogs(),
|
|
170
186
|
[activeState],
|
|
171
187
|
)
|
|
188
|
+
const reloadDialogs = useCallback(
|
|
189
|
+
() => activeState.reloadDialogs(),
|
|
190
|
+
[activeState],
|
|
191
|
+
)
|
|
172
192
|
const loadMoreMessages = useCallback(
|
|
173
193
|
() => activeState.loadMoreMessages(),
|
|
174
194
|
[activeState],
|
|
@@ -209,6 +229,8 @@ export function useUnifiedChat(
|
|
|
209
229
|
renameDialog,
|
|
210
230
|
archiveDialog,
|
|
211
231
|
isDialogsLoading: activeState.isDialogsLoading,
|
|
232
|
+
dialogsError: activeState.dialogsError,
|
|
233
|
+
reloadDialogs,
|
|
212
234
|
isMessagesLoading: activeState.isMessagesLoading,
|
|
213
235
|
hasMoreDialogs: activeState.hasMoreDialogs,
|
|
214
236
|
loadMoreDialogs,
|
|
@@ -234,6 +256,7 @@ export function useUnifiedChat(
|
|
|
234
256
|
renameDialog,
|
|
235
257
|
archiveDialog,
|
|
236
258
|
loadMoreDialogs,
|
|
259
|
+
reloadDialogs,
|
|
237
260
|
loadMoreMessages,
|
|
238
261
|
approveRequest,
|
|
239
262
|
rejectRequest,
|