@flamingo-stack/openframe-frontend-core 0.0.207 → 0.0.208

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.
Files changed (132) hide show
  1. package/dist/{chunk-Z3GQGR5E.js → chunk-2HMZSCJY.js} +3158 -2074
  2. package/dist/chunk-2HMZSCJY.js.map +1 -0
  3. package/dist/chunk-4XLJWX2N.js +12 -0
  4. package/dist/chunk-4XLJWX2N.js.map +1 -0
  5. package/dist/{chunk-APM6KBPU.cjs → chunk-C5EC5AZM.cjs} +1644 -560
  6. package/dist/chunk-C5EC5AZM.cjs.map +1 -0
  7. package/dist/chunk-VFKQMAUF.cjs +12 -0
  8. package/dist/chunk-VFKQMAUF.cjs.map +1 -0
  9. package/dist/components/chat/embeddable-chat.d.ts +35 -2
  10. package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
  11. package/dist/components/chat/hooks/index.d.ts +3 -0
  12. package/dist/components/chat/hooks/index.d.ts.map +1 -1
  13. package/dist/components/chat/hooks/use-embedded-chat.d.ts +10 -169
  14. package/dist/components/chat/hooks/use-embedded-chat.d.ts.map +1 -1
  15. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +85 -0
  16. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -0
  17. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +124 -0
  18. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -0
  19. package/dist/components/chat/hooks/use-unified-chat.d.ts +33 -0
  20. package/dist/components/chat/hooks/use-unified-chat.d.ts.map +1 -0
  21. package/dist/components/chat/index.cjs +8 -2
  22. package/dist/components/chat/index.cjs.map +1 -1
  23. package/dist/components/chat/index.js +11 -5
  24. package/dist/components/chat/types/index.d.ts +1 -0
  25. package/dist/components/chat/types/index.d.ts.map +1 -1
  26. package/dist/components/chat/types/unified-chat-state.types.d.ts +185 -0
  27. package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -0
  28. package/dist/components/features/index.cjs +3 -2
  29. package/dist/components/features/index.cjs.map +1 -1
  30. package/dist/components/features/index.js +2 -1
  31. package/dist/components/index.cjs +26 -2
  32. package/dist/components/index.cjs.map +1 -1
  33. package/dist/components/index.d.ts +4 -0
  34. package/dist/components/index.d.ts.map +1 -1
  35. package/dist/components/index.js +27 -3
  36. package/dist/components/navigation/index.cjs +3 -2
  37. package/dist/components/navigation/index.cjs.map +1 -1
  38. package/dist/components/navigation/index.js +2 -1
  39. package/dist/components/shared/delivery/delivery-lists.d.ts +16 -0
  40. package/dist/components/shared/delivery/delivery-lists.d.ts.map +1 -0
  41. package/dist/components/shared/delivery/delivery-table.d.ts +12 -0
  42. package/dist/components/shared/delivery/delivery-table.d.ts.map +1 -0
  43. package/dist/components/shared/delivery/index.d.ts +3 -0
  44. package/dist/components/shared/delivery/index.d.ts.map +1 -0
  45. package/dist/components/shared/dev-section/dev-section-page.d.ts +31 -0
  46. package/dist/components/shared/dev-section/dev-section-page.d.ts.map +1 -0
  47. package/dist/components/shared/dev-section/dev-section-view.d.ts +34 -0
  48. package/dist/components/shared/dev-section/dev-section-view.d.ts.map +1 -0
  49. package/dist/components/shared/dev-section/index.d.ts +3 -0
  50. package/dist/components/shared/dev-section/index.d.ts.map +1 -0
  51. package/dist/components/shared/legal-document/index.d.ts +10 -0
  52. package/dist/components/shared/legal-document/index.d.ts.map +1 -0
  53. package/dist/components/shared/legal-document/legal-document-page.d.ts +66 -0
  54. package/dist/components/shared/legal-document/legal-document-page.d.ts.map +1 -0
  55. package/dist/components/shared/legal-document/use-legal-docs.d.ts +40 -0
  56. package/dist/components/shared/legal-document/use-legal-docs.d.ts.map +1 -0
  57. package/dist/components/shared/product-release/index.d.ts +2 -1
  58. package/dist/components/shared/product-release/index.d.ts.map +1 -1
  59. package/dist/components/shared/product-release/release-detail-page.d.ts +11 -7
  60. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  61. package/dist/components/shared/roadmap/index.d.ts +18 -0
  62. package/dist/components/shared/roadmap/index.d.ts.map +1 -0
  63. package/dist/components/shared/roadmap/roadmap-grid-skeleton.d.ts +24 -0
  64. package/dist/components/shared/roadmap/roadmap-grid-skeleton.d.ts.map +1 -0
  65. package/dist/components/shared/roadmap/roadmap-grid.d.ts +18 -0
  66. package/dist/components/shared/roadmap/roadmap-grid.d.ts.map +1 -0
  67. package/dist/components/shared/roadmap/use-roadmap-voting.d.ts +25 -0
  68. package/dist/components/shared/roadmap/use-roadmap-voting.d.ts.map +1 -0
  69. package/dist/components/ui/index.cjs +8 -2
  70. package/dist/components/ui/index.cjs.map +1 -1
  71. package/dist/components/ui/index.js +11 -5
  72. package/dist/components/ui/release-changelog-section.d.ts +13 -2
  73. package/dist/components/ui/release-changelog-section.d.ts.map +1 -1
  74. package/dist/embed-shims/index.cjs +1 -6
  75. package/dist/embed-shims/index.cjs.map +1 -1
  76. package/dist/embed-shims/index.js +1 -6
  77. package/dist/embed-shims/index.js.map +1 -1
  78. package/dist/index.cjs +18 -2
  79. package/dist/index.cjs.map +1 -1
  80. package/dist/index.js +19 -3
  81. package/dist/types/delivery.d.ts +49 -0
  82. package/dist/types/delivery.d.ts.map +1 -0
  83. package/dist/types/index.cjs +13 -0
  84. package/dist/types/index.cjs.map +1 -1
  85. package/dist/types/index.d.ts +1 -0
  86. package/dist/types/index.d.ts.map +1 -1
  87. package/dist/types/index.js +12 -1
  88. package/dist/types/index.js.map +1 -1
  89. package/dist/utils/dev-sections/index.d.ts +11 -0
  90. package/dist/utils/dev-sections/index.d.ts.map +1 -0
  91. package/dist/utils/dev-sections/openframe-dev-sections.d.ts +209 -0
  92. package/dist/utils/dev-sections/openframe-dev-sections.d.ts.map +1 -0
  93. package/dist/utils/index.cjs +82 -0
  94. package/dist/utils/index.cjs.map +1 -1
  95. package/dist/utils/index.d.ts +1 -0
  96. package/dist/utils/index.d.ts.map +1 -1
  97. package/dist/utils/index.js +81 -2
  98. package/dist/utils/index.js.map +1 -1
  99. package/package.json +1 -1
  100. package/src/components/chat/embeddable-chat.tsx +123 -8
  101. package/src/components/chat/hooks/index.ts +9 -2
  102. package/src/components/chat/hooks/use-embedded-chat.ts +18 -1016
  103. package/src/components/chat/hooks/use-nats-chat-adapter.ts +372 -0
  104. package/src/components/chat/hooks/use-sse-chat-adapter.ts +1058 -0
  105. package/src/components/chat/hooks/use-unified-chat.ts +171 -0
  106. package/src/components/chat/types/index.ts +1 -0
  107. package/src/components/chat/types/unified-chat-state.types.ts +215 -0
  108. package/src/components/index.ts +8 -0
  109. package/src/components/shared/delivery/delivery-lists.tsx +199 -0
  110. package/src/components/shared/delivery/delivery-table.tsx +174 -0
  111. package/src/components/shared/delivery/index.ts +9 -0
  112. package/src/components/shared/dev-section/dev-section-page.tsx +72 -0
  113. package/src/components/shared/dev-section/dev-section-view.tsx +129 -0
  114. package/src/components/shared/dev-section/index.ts +2 -0
  115. package/src/components/shared/legal-document/index.ts +19 -0
  116. package/src/components/shared/legal-document/legal-document-page.tsx +178 -0
  117. package/src/components/shared/legal-document/use-legal-docs.ts +123 -0
  118. package/src/components/shared/product-release/index.ts +14 -3
  119. package/src/components/shared/product-release/release-detail-page.tsx +45 -7
  120. package/src/components/shared/roadmap/index.ts +23 -0
  121. package/src/components/shared/roadmap/roadmap-grid-skeleton.tsx +74 -0
  122. package/src/components/shared/roadmap/roadmap-grid.tsx +106 -0
  123. package/src/components/shared/roadmap/use-roadmap-voting.ts +163 -0
  124. package/src/components/ui/release-changelog-section.tsx +113 -32
  125. package/src/stories/EmbeddableChat.stories.tsx +186 -0
  126. package/src/types/delivery.ts +54 -0
  127. package/src/types/index.ts +1 -0
  128. package/src/utils/dev-sections/index.ts +17 -0
  129. package/src/utils/dev-sections/openframe-dev-sections.ts +148 -0
  130. package/src/utils/index.ts +6 -1
  131. package/dist/chunk-APM6KBPU.cjs.map +0 -1
  132. package/dist/chunk-Z3GQGR5E.js.map +0 -1
@@ -0,0 +1,372 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * useNatsChatAdapter — the NATS/Mingo-mode transport adapter for the
5
+ * unified chat surface. Companion of `useSseChatAdapter` (Guide mode);
6
+ * both implement the same `UnifiedChatState` contract so the public
7
+ * `useChat({ mode })` can dispatch between them with zero shell-side
8
+ * branching.
9
+ *
10
+ * Composition (no new logic — all the pieces already exist in the lib):
11
+ *
12
+ * ┌──────────────────────────────────────────────────────────────┐
13
+ * │ useNatsDialogSubscription live tail of agent events │
14
+ * │ ↓ │
15
+ * │ onEvent → processChunk │
16
+ * │ ↓ │
17
+ * │ useRealtimeChunkProcessor chunk → MessageSegment[] │
18
+ * │ ↓ │
19
+ * │ onSegmentsUpdate → updates assistant message in state │
20
+ * │ │
21
+ * │ useChunkCatchup back-fill missed chunks after │
22
+ * │ activation / reconnect │
23
+ * │ │
24
+ * │ config.publishUserMessage consumer-owned send (HTTP/NATS) │
25
+ * └──────────────────────────────────────────────────────────────┘
26
+ *
27
+ * Why publish is consumer-owned: the NATS module exposes a low-level
28
+ * `publishBytes/String/Json` but the actual user-message endpoint varies
29
+ * by deployment (REST POST in some, NATS subject in others). The adapter
30
+ * stays agnostic — caller wires up "user typed something, do X" via
31
+ * the `publishUserMessage` callback.
32
+ *
33
+ * The `active` option gates the live subscription so the unified chat
34
+ * shell can keep both adapters mounted while only paying network cost
35
+ * for the currently-displayed mode.
36
+ */
37
+
38
+ import {
39
+ useCallback,
40
+ useEffect,
41
+ useMemo,
42
+ useRef,
43
+ useState,
44
+ type MutableRefObject,
45
+ } from 'react'
46
+ import { useNatsDialogSubscription } from './use-nats-dialog-subscription'
47
+ import { useRealtimeChunkProcessor } from './use-realtime-chunk-processor'
48
+ import { useChunkCatchup } from './use-chunk-catchup'
49
+ import type {
50
+ ChunkData,
51
+ FetchChunksFunction,
52
+ MessageSegment,
53
+ NatsMessageType,
54
+ StreamingPhase,
55
+ } from '../types'
56
+ import type {
57
+ UnifiedChatState,
58
+ UnifiedChatMessage,
59
+ UnifiedSendMessageOptions,
60
+ } from '../types/unified-chat-state.types'
61
+ import type { ChatRef } from '../chat-ref.types'
62
+
63
+ // =============================================================================
64
+ // Config + options
65
+ // =============================================================================
66
+
67
+ /**
68
+ * Consumer-supplied configuration for the NATS chat adapter.
69
+ *
70
+ * Every field is consumer-owned — the lib does not assume a particular
71
+ * backend protocol or auth scheme. Hosts wire these up against their
72
+ * own OpenFrame deployment.
73
+ */
74
+ export interface UseNatsChatAdapterConfig {
75
+ /**
76
+ * Active conversation/dialog id. When `null` the adapter stays
77
+ * subscription-idle (no NATS connection, no catchup fetch). Set this
78
+ * once the consumer's "open new conversation" flow has allocated an
79
+ * id from the backend.
80
+ */
81
+ dialogId: string | null
82
+
83
+ /**
84
+ * Build the NATS WebSocket URL. Returning `null` short-circuits the
85
+ * subscription — same contract as `useNatsDialogSubscription`.
86
+ */
87
+ getNatsWsUrl: () => string | null
88
+
89
+ /**
90
+ * Optional NATS client auth.
91
+ */
92
+ clientConfig?: {
93
+ name?: string
94
+ user?: string
95
+ pass?: string
96
+ }
97
+
98
+ /**
99
+ * Send a user message upstream. Consumer-owned: typically an
100
+ * authenticated HTTP POST to the OpenFrame chat endpoint, or a
101
+ * direct NATS publish to a dedicated subject.
102
+ *
103
+ * The adapter does NOT couple to the wire format — it only:
104
+ * 1. appends the user message to local state for immediate render
105
+ * 2. flips streamingPhase to 'thinking' so the input UI shows status
106
+ * 3. calls this callback
107
+ *
108
+ * Reply arrives asynchronously as NATS chunks via the live tail and
109
+ * is accumulated into the trailing assistant message.
110
+ */
111
+ publishUserMessage: (
112
+ text: string,
113
+ options: { hidden?: boolean; dialogId: string | null },
114
+ ) => Promise<void> | void
115
+
116
+ /**
117
+ * Historical-chunk fetcher used by `useChunkCatchup` to back-fill
118
+ * events that happened while the user was in another mode or before
119
+ * the websocket came online. Consumer-owned: typically a REST GET
120
+ * against the OpenFrame chat-history endpoint.
121
+ *
122
+ * When omitted, `useChunkCatchup` falls back to its own default
123
+ * fetch implementation — see hook docs for the contract.
124
+ */
125
+ fetchChunks?: FetchChunksFunction
126
+
127
+ /**
128
+ * Whether THINKING chunks are surfaced as segments. Default `false`
129
+ * (parity with the existing `useRealtimeChunkProcessor` default).
130
+ */
131
+ enableThinking?: boolean
132
+
133
+ /**
134
+ * Mirrors `UseRealtimeChunkProcessorOptions.batchApprovalsEnabled`.
135
+ * Default `true` — single batch card per APPROVAL_REQUEST with
136
+ * `toolCalls[]`. Set `false` to fall back to legacy per-tool cards.
137
+ */
138
+ batchApprovalsEnabled?: boolean
139
+ }
140
+
141
+ /**
142
+ * Per-call options for `useNatsChatAdapter`. Carries only the
143
+ * activation gate — config travels through the config object so it
144
+ * survives mode swaps without re-mounting.
145
+ */
146
+ export interface UseNatsChatAdapterOptions {
147
+ /**
148
+ * When `false` the adapter goes idle: no NATS subscription, no
149
+ * catchup fetch, no publish. Local message state is preserved so
150
+ * the user sees their history when the mode flips back to active.
151
+ * Default `true`.
152
+ */
153
+ active?: boolean
154
+ }
155
+
156
+ // =============================================================================
157
+ // Internal helpers
158
+ // =============================================================================
159
+
160
+ function nextId(role: 'user' | 'assistant'): string {
161
+ // Date.now() + counter sliver keeps ids monotonic even when two
162
+ // messages are produced inside the same ms tick (user + assistant
163
+ // placeholder fire back-to-back from a single sendMessage call).
164
+ return `${role}-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`
165
+ }
166
+
167
+ /**
168
+ * Replace (or append) the trailing assistant message with the latest
169
+ * accumulated segments. Mirrors the use-chat.ts pattern so render
170
+ * behaviour matches the SSE adapter exactly.
171
+ */
172
+ function updateTrailingAssistant(
173
+ prev: UnifiedChatMessage[],
174
+ segments: MessageSegment[],
175
+ ): UnifiedChatMessage[] {
176
+ const last = prev[prev.length - 1]
177
+ if (!last || last.role !== 'assistant') {
178
+ // No placeholder exists — append a fresh assistant message.
179
+ return [
180
+ ...prev,
181
+ {
182
+ id: nextId('assistant'),
183
+ role: 'assistant',
184
+ content: '',
185
+ segments,
186
+ },
187
+ ]
188
+ }
189
+ return [
190
+ ...prev.slice(0, -1),
191
+ { ...last, segments },
192
+ ]
193
+ }
194
+
195
+ // =============================================================================
196
+ // Hook
197
+ // =============================================================================
198
+
199
+ export function useNatsChatAdapter(
200
+ config: UseNatsChatAdapterConfig,
201
+ options: UseNatsChatAdapterOptions = {},
202
+ ): UnifiedChatState {
203
+ const { active = true } = options
204
+ const {
205
+ dialogId,
206
+ getNatsWsUrl,
207
+ clientConfig,
208
+ publishUserMessage,
209
+ fetchChunks,
210
+ enableThinking,
211
+ batchApprovalsEnabled,
212
+ } = config
213
+
214
+ const [messages, setMessages] = useState<UnifiedChatMessage[]>([])
215
+ const [streamingPhase, setStreamingPhase] = useState<StreamingPhase>('idle')
216
+
217
+ // Stable callback ref so `useRealtimeChunkProcessor`'s options object
218
+ // doesn't churn every render and tear down the accumulator state.
219
+ const callbacksRef: MutableRefObject<{
220
+ onSegmentsUpdate: (segments: MessageSegment[]) => void
221
+ onStreamStart: () => void
222
+ onStreamEnd: () => void
223
+ }> = useRef({
224
+ onSegmentsUpdate: (segments: MessageSegment[]) => {
225
+ setMessages((prev) => updateTrailingAssistant(prev, segments))
226
+ },
227
+ onStreamStart: () => setStreamingPhase('streaming'),
228
+ onStreamEnd: () => setStreamingPhase('idle'),
229
+ })
230
+
231
+ // Real-time chunk → segment processor.
232
+ const { processChunk, reset: resetAccumulator } = useRealtimeChunkProcessor({
233
+ callbacks: {
234
+ onSegmentsUpdate: (segments) => callbacksRef.current.onSegmentsUpdate(segments),
235
+ onStreamStart: () => callbacksRef.current.onStreamStart(),
236
+ onStreamEnd: () => callbacksRef.current.onStreamEnd(),
237
+ },
238
+ enableThinking,
239
+ batchApprovalsEnabled,
240
+ })
241
+
242
+ // History catchup — back-fills chunks emitted while the adapter was
243
+ // inactive or before the WS came online.
244
+ const {
245
+ processChunk: catchupProcessChunk,
246
+ catchUpChunks,
247
+ startInitialBuffering,
248
+ resetChunkTracking,
249
+ } = useChunkCatchup({
250
+ dialogId: active ? dialogId : null,
251
+ onChunkReceived: (chunk: ChunkData) => processChunk(chunk),
252
+ fetchChunks,
253
+ })
254
+
255
+ // Trigger initial backfill whenever a fresh dialog activates. Mirrors the
256
+ // pattern in `.use-chunk-catchup.md`: enable buffering first so realtime
257
+ // chunks queue behind the historical fetch, then flush in order.
258
+ useEffect(() => {
259
+ if (!active || !dialogId) return
260
+ resetChunkTracking()
261
+ startInitialBuffering()
262
+ catchUpChunks().catch((err) => {
263
+ console.error('[useNatsChatAdapter] initial catchup failed:', err)
264
+ })
265
+ }, [active, dialogId, resetChunkTracking, startInitialBuffering, catchUpChunks])
266
+
267
+ // Live tail subscription. `enabled` is gated on both `active` and a
268
+ // non-null dialogId so the consumer doesn't pay socket cost before
269
+ // a conversation exists.
270
+ useNatsDialogSubscription({
271
+ enabled: active && dialogId != null,
272
+ dialogId,
273
+ getNatsWsUrl,
274
+ clientConfig,
275
+ onEvent: (payload: unknown, messageType: NatsMessageType) => {
276
+ // Route via catchup so the buffer/dedupe logic stays consistent
277
+ // with historical playback. `useChunkCatchup` itself forwards to
278
+ // `processChunk` once dedupe checks pass.
279
+ catchupProcessChunk(payload as ChunkData, messageType)
280
+ },
281
+ })
282
+
283
+ // ─── Public API ───────────────────────────────────────────────────────────
284
+
285
+ const sendMessage = useCallback(
286
+ async (
287
+ text: string,
288
+ sendOptions?: UnifiedSendMessageOptions,
289
+ ): Promise<void> => {
290
+ const hidden = sendOptions?.hidden ?? false
291
+
292
+ // Optimistically append the user bubble + an empty assistant
293
+ // placeholder. The assistant body fills in as NATS chunks land.
294
+ setMessages((prev) => [
295
+ ...prev,
296
+ {
297
+ id: nextId('user'),
298
+ role: 'user',
299
+ content: text,
300
+ ...(hidden ? { hidden: true } : {}),
301
+ },
302
+ {
303
+ id: nextId('assistant'),
304
+ role: 'assistant',
305
+ content: '',
306
+ segments: [],
307
+ },
308
+ ])
309
+ setStreamingPhase('thinking')
310
+
311
+ await publishUserMessage(text, { hidden, dialogId })
312
+ },
313
+ [publishUserMessage, dialogId],
314
+ )
315
+
316
+ const stopMessage = useCallback(() => {
317
+ // NATS streams are driven server-side; the client can't really
318
+ // "cancel" an in-flight agent task without backend cooperation.
319
+ // For now we just drop the UI status — incoming chunks will still
320
+ // be accepted and rendered if the agent completes anyway.
321
+ setStreamingPhase('idle')
322
+ }, [])
323
+
324
+ const clearMessages = useCallback(() => {
325
+ setMessages([])
326
+ resetAccumulator()
327
+ setStreamingPhase('idle')
328
+ }, [resetAccumulator])
329
+
330
+ // No-op refs — Mingo agent has no RAG entity-card affordances.
331
+ const discussRef = useCallback((_ref: ChatRef) => {
332
+ /* no-op in Mingo mode */
333
+ }, [])
334
+ const displayRef = useCallback((_ref: ChatRef) => {
335
+ /* no-op in Mingo mode */
336
+ }, [])
337
+
338
+ // ─── Return shape ─────────────────────────────────────────────────────────
339
+
340
+ const isLoading = streamingPhase !== 'idle'
341
+
342
+ return useMemo<UnifiedChatState>(
343
+ () => ({
344
+ messages,
345
+ isLoading,
346
+ streamingPhase,
347
+ sendMessage,
348
+ stopMessage,
349
+ clearMessages,
350
+ discussRef,
351
+ displayRef,
352
+ // SSE-only telemetry — null in NATS mode.
353
+ currentProvider: null,
354
+ currentModelLabel: null,
355
+ currentContextWindowMaxTokens: null,
356
+ currentInputTokens: null,
357
+ currentOutputTokens: null,
358
+ currentCacheHitRatePct: null,
359
+ currentUsageBreakdown: null,
360
+ }),
361
+ [
362
+ messages,
363
+ isLoading,
364
+ streamingPhase,
365
+ sendMessage,
366
+ stopMessage,
367
+ clearMessages,
368
+ discussRef,
369
+ displayRef,
370
+ ],
371
+ )
372
+ }