@flamingo-stack/openframe-frontend-core 0.0.584-1973.5461.1 → 0.0.584

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 (162) hide show
  1. package/dist/chat-protocol/events.d.ts +2 -8
  2. package/dist/chat-protocol/events.d.ts.map +1 -1
  3. package/dist/chat-protocol/index.cjs +0 -188
  4. package/dist/chat-protocol/index.cjs.map +1 -1
  5. package/dist/chat-protocol/index.js +0 -188
  6. package/dist/chat-protocol/index.js.map +1 -1
  7. package/dist/chat-protocol/nats-decoder.d.ts.map +1 -1
  8. package/dist/{chunk-U7MJV2V7.cjs → chunk-33DHEEMP.cjs} +33 -33
  9. package/dist/{chunk-U7MJV2V7.cjs.map → chunk-33DHEEMP.cjs.map} +1 -1
  10. package/dist/{chunk-23VBGHBL.js → chunk-3ELW4VML.js} +2 -2
  11. package/dist/{chunk-7KBKLN2Z.cjs → chunk-3ZA2OYRE.cjs} +3 -3
  12. package/dist/{chunk-7KBKLN2Z.cjs.map → chunk-3ZA2OYRE.cjs.map} +1 -1
  13. package/dist/{chunk-73XDYWYG.js → chunk-4T5KOD3G.js} +5 -5
  14. package/dist/{chunk-MI6PPL3P.js → chunk-5CJKZHWO.js} +5 -5
  15. package/dist/{chunk-E7Q24T4G.js → chunk-6BJYPG2V.js} +3 -3
  16. package/dist/{chunk-YXNMLGFI.cjs → chunk-7X5TCK4R.cjs} +10 -10
  17. package/dist/{chunk-YXNMLGFI.cjs.map → chunk-7X5TCK4R.cjs.map} +1 -1
  18. package/dist/{chunk-7DEGEI7G.js → chunk-EJKEDCTH.js} +6 -6
  19. package/dist/{chunk-XIV5VDWL.cjs → chunk-HCKEDTKJ.cjs} +10 -10
  20. package/dist/{chunk-XIV5VDWL.cjs.map → chunk-HCKEDTKJ.cjs.map} +1 -1
  21. package/dist/{chunk-EQGAYDTC.cjs → chunk-IIT5HWLY.cjs} +9 -9
  22. package/dist/{chunk-EQGAYDTC.cjs.map → chunk-IIT5HWLY.cjs.map} +1 -1
  23. package/dist/{chunk-7SMYBCYH.cjs → chunk-IKUSKKFZ.cjs} +540 -883
  24. package/dist/chunk-IKUSKKFZ.cjs.map +1 -0
  25. package/dist/{chunk-JKYALZB7.cjs → chunk-JAJQ5P2Q.cjs} +22 -22
  26. package/dist/{chunk-JKYALZB7.cjs.map → chunk-JAJQ5P2Q.cjs.map} +1 -1
  27. package/dist/{chunk-WAXL3E3B.cjs → chunk-JFKK3ZOA.cjs} +43 -43
  28. package/dist/{chunk-WAXL3E3B.cjs.map → chunk-JFKK3ZOA.cjs.map} +1 -1
  29. package/dist/{chunk-AWAHYAII.js → chunk-JVWRMLQZ.js} +2 -2
  30. package/dist/{chunk-PZ27ELFP.cjs → chunk-JWKAJTNA.cjs} +43 -33
  31. package/dist/chunk-JWKAJTNA.cjs.map +1 -0
  32. package/dist/{chunk-PISJGXXI.js → chunk-KP6VJP36.js} +3 -3
  33. package/dist/{chunk-NSDZAUJK.js → chunk-LNKULR4V.js} +2 -2
  34. package/dist/{chunk-AFQB4YL7.cjs → chunk-MEJFHD5N.cjs} +15 -15
  35. package/dist/{chunk-AFQB4YL7.cjs.map → chunk-MEJFHD5N.cjs.map} +1 -1
  36. package/dist/{chunk-5VHCSN44.js → chunk-MYEG5ZDT.js} +2 -2
  37. package/dist/{chunk-MMA3MTJD.cjs → chunk-P2VRLSAP.cjs} +21 -21
  38. package/dist/{chunk-MMA3MTJD.cjs.map → chunk-P2VRLSAP.cjs.map} +1 -1
  39. package/dist/{chunk-7Q34BVL7.cjs → chunk-Q66AMADB.cjs} +4 -4
  40. package/dist/{chunk-7Q34BVL7.cjs.map → chunk-Q66AMADB.cjs.map} +1 -1
  41. package/dist/{chunk-4ARYZTGV.cjs → chunk-QJR32JM2.cjs} +159 -159
  42. package/dist/{chunk-4ARYZTGV.cjs.map → chunk-QJR32JM2.cjs.map} +1 -1
  43. package/dist/{chunk-M4IIK3B7.js → chunk-RURZ6QLN.js} +3 -3
  44. package/dist/{chunk-TCEU6DCF.js → chunk-TLKHLGAB.js} +3 -3
  45. package/dist/{chunk-JCWUJHOD.js → chunk-TOUD3AGK.js} +23 -13
  46. package/dist/chunk-TOUD3AGK.js.map +1 -0
  47. package/dist/{chunk-CHI7GJ3K.cjs → chunk-UCNEQKIT.cjs} +5 -5
  48. package/dist/{chunk-CHI7GJ3K.cjs.map → chunk-UCNEQKIT.cjs.map} +1 -1
  49. package/dist/{chunk-ZRGBLM6W.cjs → chunk-VOAZU46B.cjs} +69 -69
  50. package/dist/{chunk-ZRGBLM6W.cjs.map → chunk-VOAZU46B.cjs.map} +1 -1
  51. package/dist/{chunk-GYJVLFK5.js → chunk-VZSTL5VG.js} +2 -2
  52. package/dist/{chunk-3CAC3AAE.js → chunk-XPJKQ63S.js} +3 -3
  53. package/dist/{chunk-KSC5LNSY.js → chunk-XWBND4G5.js} +187 -530
  54. package/dist/chunk-XWBND4G5.js.map +1 -0
  55. package/dist/{chunk-22DWXIV3.js → chunk-YFZDIEVC.js} +5 -5
  56. package/dist/{chunk-7J7XDGY6.cjs → chunk-ZHUBNWEX.cjs} +3 -3
  57. package/dist/{chunk-7J7XDGY6.cjs.map → chunk-ZHUBNWEX.cjs.map} +1 -1
  58. package/dist/components/case-studies/index.cjs +9 -9
  59. package/dist/components/case-studies/index.js +3 -3
  60. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  61. package/dist/components/chat/chat-message-list.d.ts.map +1 -1
  62. package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
  63. package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
  64. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +1 -4
  65. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
  66. package/dist/components/chat/hooks/use-slash-commands.d.ts +3 -3
  67. package/dist/components/chat/hooks/use-slash-commands.d.ts.map +1 -1
  68. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +28 -2
  69. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  70. package/dist/components/chat/index.cjs +2 -2
  71. package/dist/components/chat/index.js +1 -1
  72. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +1 -1
  73. package/dist/components/chat/tool-execution-display.d.ts.map +1 -1
  74. package/dist/components/chat/types/component.types.d.ts +0 -4
  75. package/dist/components/chat/types/component.types.d.ts.map +1 -1
  76. package/dist/components/chat/types/message.types.d.ts +1 -35
  77. package/dist/components/chat/types/message.types.d.ts.map +1 -1
  78. package/dist/components/chat/types/unified-chat-state.types.d.ts +3 -3
  79. package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
  80. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  81. package/dist/components/contact/index.cjs +4 -4
  82. package/dist/components/contact/index.js +3 -3
  83. package/dist/components/docs/index.cjs +7 -7
  84. package/dist/components/docs/index.js +6 -6
  85. package/dist/components/embeds/index.cjs +4 -4
  86. package/dist/components/embeds/index.js +3 -3
  87. package/dist/components/faq/index.cjs +4 -4
  88. package/dist/components/faq/index.js +3 -3
  89. package/dist/components/features/index.cjs +3 -3
  90. package/dist/components/features/index.js +2 -2
  91. package/dist/components/help-center-pages/index.cjs +23 -23
  92. package/dist/components/help-center-pages/index.js +14 -14
  93. package/dist/components/index.cjs +36 -36
  94. package/dist/components/index.js +13 -13
  95. package/dist/components/meeting-scheduler/index.cjs +21 -21
  96. package/dist/components/meeting-scheduler/index.js +2 -2
  97. package/dist/components/navigation/index.cjs +6 -6
  98. package/dist/components/navigation/index.js +5 -5
  99. package/dist/components/navigation/navigation-sidebar-item.d.ts.map +1 -1
  100. package/dist/components/onboarding-guides/index.cjs +6 -6
  101. package/dist/components/onboarding-guides/index.js +5 -5
  102. package/dist/components/tickets/index.cjs +7 -7
  103. package/dist/components/tickets/index.js +6 -6
  104. package/dist/components/ui/hover-dropdown.d.ts.map +1 -1
  105. package/dist/components/ui/index.cjs +3 -3
  106. package/dist/components/ui/index.js +2 -2
  107. package/dist/index.cjs +7 -7
  108. package/dist/index.js +6 -6
  109. package/dist/utils/index.cjs.map +1 -1
  110. package/dist/utils/index.js.map +1 -1
  111. package/package.json +1 -1
  112. package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +0 -130
  113. package/src/chat-protocol/events.ts +1 -9
  114. package/src/chat-protocol/nats-decoder.ts +0 -7
  115. package/src/components/chat/__tests__/chat-message-list.test.tsx +0 -70
  116. package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +0 -86
  117. package/src/components/chat/chat-message-enhanced.tsx +13 -28
  118. package/src/components/chat/chat-message-list.tsx +22 -27
  119. package/src/components/chat/embeddable-chat.tsx +36 -55
  120. package/src/components/chat/entity-cards/dispatch.tsx +17 -86
  121. package/src/components/chat/hooks/use-nats-chat-adapter.ts +0 -7
  122. package/src/components/chat/hooks/use-slash-commands.ts +5 -9
  123. package/src/components/chat/hooks/use-sse-chat-adapter.ts +29 -2
  124. package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +0 -56
  125. package/src/components/chat/stream/chat-stream-reducer.ts +0 -31
  126. package/src/components/chat/tool-execution-display.tsx +2 -5
  127. package/src/components/chat/types/component.types.ts +0 -4
  128. package/src/components/chat/types/message.types.ts +0 -39
  129. package/src/components/chat/types/unified-chat-state.types.ts +3 -4
  130. package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +0 -57
  131. package/src/components/chat/utils/process-historical-messages.ts +1 -19
  132. package/src/components/navigation/navigation-sidebar-item.tsx +19 -9
  133. package/src/components/ui/hover-dropdown.tsx +3 -8
  134. package/dist/chat-protocol/source-metadata.d.ts +0 -5
  135. package/dist/chat-protocol/source-metadata.d.ts.map +0 -1
  136. package/dist/chunk-7SMYBCYH.cjs.map +0 -1
  137. package/dist/chunk-JCWUJHOD.js.map +0 -1
  138. package/dist/chunk-KSC5LNSY.js.map +0 -1
  139. package/dist/chunk-PZ27ELFP.cjs.map +0 -1
  140. package/dist/components/chat/utils/chat-source-metadata.d.ts +0 -5
  141. package/dist/components/chat/utils/chat-source-metadata.d.ts.map +0 -1
  142. package/src/chat-protocol/__tests__/source-metadata.test.ts +0 -74
  143. package/src/chat-protocol/source-metadata.ts +0 -202
  144. package/src/components/chat/__tests__/embeddable-chat-sources.test.tsx +0 -411
  145. package/src/components/chat/__tests__/tool-execution-display.test.tsx +0 -93
  146. package/src/components/chat/entity-cards/__tests__/dispatch-video-refs.test.tsx +0 -74
  147. package/src/components/chat/hooks/__tests__/use-slash-commands.test.ts +0 -64
  148. package/src/components/chat/utils/chat-source-metadata.ts +0 -19
  149. /package/dist/{chunk-23VBGHBL.js.map → chunk-3ELW4VML.js.map} +0 -0
  150. /package/dist/{chunk-73XDYWYG.js.map → chunk-4T5KOD3G.js.map} +0 -0
  151. /package/dist/{chunk-MI6PPL3P.js.map → chunk-5CJKZHWO.js.map} +0 -0
  152. /package/dist/{chunk-E7Q24T4G.js.map → chunk-6BJYPG2V.js.map} +0 -0
  153. /package/dist/{chunk-7DEGEI7G.js.map → chunk-EJKEDCTH.js.map} +0 -0
  154. /package/dist/{chunk-AWAHYAII.js.map → chunk-JVWRMLQZ.js.map} +0 -0
  155. /package/dist/{chunk-PISJGXXI.js.map → chunk-KP6VJP36.js.map} +0 -0
  156. /package/dist/{chunk-NSDZAUJK.js.map → chunk-LNKULR4V.js.map} +0 -0
  157. /package/dist/{chunk-5VHCSN44.js.map → chunk-MYEG5ZDT.js.map} +0 -0
  158. /package/dist/{chunk-M4IIK3B7.js.map → chunk-RURZ6QLN.js.map} +0 -0
  159. /package/dist/{chunk-TCEU6DCF.js.map → chunk-TLKHLGAB.js.map} +0 -0
  160. /package/dist/{chunk-GYJVLFK5.js.map → chunk-VZSTL5VG.js.map} +0 -0
  161. /package/dist/{chunk-3CAC3AAE.js.map → chunk-XPJKQ63S.js.map} +0 -0
  162. /package/dist/{chunk-22DWXIV3.js.map → chunk-YFZDIEVC.js.map} +0 -0
@@ -30,7 +30,6 @@
30
30
  */
31
31
 
32
32
  import React, { type ReactNode } from 'react';
33
- import { isSourceMetadataCardRef } from '../../../chat-protocol/source-metadata';
34
33
  import { useRequiredChatRuntime } from '../../../contexts/chat-runtime-context';
35
34
  import Image from '../../../embed-shims/next-image';
36
35
  import { useRouter } from '../../../embed-shims/next-navigation';
@@ -42,7 +41,6 @@ import {
42
41
  formatTimeWithTimezone,
43
42
  formatDurationFromRange,
44
43
  } from '../../../utils/format';
45
- import { extractYouTubeId } from '../../features/video';
46
44
  import { MingoIcon } from '../../icons';
47
45
  import { ArrowRightUpIcon } from '../../icons-v2-generated/arrows/arrow-right-up-icon';
48
46
  import { ClickupLogoIcon } from '../../icons-v2-generated/brand-logos/clickup-logo-icon';
@@ -424,15 +422,6 @@ function hubspotStatusToVariant(status: string | undefined): MingoInfoCardStatus
424
422
  * which renders the marker as plain text (same anti-hallucination
425
423
  * posture as every other card type).
426
424
  */
427
- function validatedHttpsUrl(value: unknown): string | null {
428
- if (typeof value !== 'string') return null;
429
- try {
430
- return new URL(value).protocol === 'https:' ? value : null;
431
- } catch {
432
- return null;
433
- }
434
- }
435
-
436
425
  function decodeVideoMarkerId(id: string): { videoUrl?: string; youtubeUrl?: string } | null {
437
426
  // Prefix checks FIRST: an id like `mux-1234567` (11 chars) would also
438
427
  // satisfy the bare-YouTube-id pattern below.
@@ -450,8 +439,8 @@ function decodeVideoMarkerId(id: string): { videoUrl?: string; youtubeUrl?: stri
450
439
  const url = atob(b64);
451
440
  // https-only — the id is model-emitted text; never let a marker
452
441
  // smuggle a non-https src into a player.
453
- const safeUrl = validatedHttpsUrl(url);
454
- return safeUrl ? { videoUrl: safeUrl } : null;
442
+ if (!/^https:\/\//.test(url)) return null;
443
+ return { videoUrl: url };
455
444
  } catch {
456
445
  return null;
457
446
  }
@@ -460,29 +449,6 @@ function decodeVideoMarkerId(id: string): { videoUrl?: string; youtubeUrl?: stri
460
449
  return null;
461
450
  }
462
451
 
463
- function validatedVideoMetadata(chatRef: ChatRef): Record<string, unknown> | null {
464
- const input = chatRef.metadata ?? {};
465
- const metadata: Record<string, unknown> = {};
466
- for (const key of ['videoUrl', 'highlightVideoUrl', 'videoPoster', 'highlightVideoPoster'] as const) {
467
- const url = validatedHttpsUrl(input[key]);
468
- if (url) metadata[key] = url;
469
- }
470
- const youtubeUrl = input.youtubeUrl;
471
- if (typeof youtubeUrl === 'string' && /^[A-Za-z0-9_-]{11}$/.test(youtubeUrl)) {
472
- metadata.youtubeUrl = youtubeUrl;
473
- }
474
-
475
- const safeUrl = validatedHttpsUrl(chatRef.url);
476
- if (safeUrl) {
477
- const youtubeId = extractYouTubeId(safeUrl);
478
- delete metadata.videoUrl;
479
- delete metadata.youtubeUrl;
480
- metadata[youtubeId ? 'youtubeUrl' : 'videoUrl'] = youtubeId ?? safeUrl;
481
- }
482
-
483
- return Object.keys(metadata).length > 0 ? metadata : null;
484
- }
485
-
486
452
  /** Read hero-video metadata off a FETCHED item — the API-driven
487
453
  * replacement for the retired refs-frame `metadata.videoUrl` check. Two item
488
454
  * shapes: ChatRef-shaped items (per-object hydration routes) carry the
@@ -1262,10 +1228,6 @@ interface ChatCardRegistryEntry {
1262
1228
  * point — a host that re-homes a type must be able to say so even when
1263
1229
  * the row already carries the content host's own url. */
1264
1230
  noComposedHref?: boolean;
1265
- /** Render a document card from same-turn SOURCES metadata when its optional
1266
- * hydration endpoint has no row. Only doc refs opt in: their source record
1267
- * already carries the complete title/path/navigation fallback. */
1268
- renderFromSourceMetadata?: boolean;
1269
1231
  }
1270
1232
 
1271
1233
  /**
@@ -1288,7 +1250,6 @@ function refHydratedEntry(
1288
1250
  docType: string,
1289
1251
  label: string,
1290
1252
  renderRef: (displayRef: ChatRef, opts: ChatCardRenderOptions) => React.ReactNode,
1291
- renderFromSourceMetadata = false,
1292
1253
  ): ChatCardRegistryEntry {
1293
1254
  return {
1294
1255
  label,
@@ -1298,19 +1259,6 @@ function refHydratedEntry(
1298
1259
  fallbackHref: (item: { url?: string | null }) => item?.url ?? null,
1299
1260
  skeleton: () => <MingoInfoCardSkeleton />,
1300
1261
  render: (item, chatRef, opts) => renderRef(fetchedItemDisplayRef(item, chatRef), opts),
1301
- renderFromSourceMetadata,
1302
- };
1303
- }
1304
-
1305
- function sourceMetadataCardItem(chatRef: ChatRef): ChatCardItem {
1306
- return {
1307
- type: chatRef.type,
1308
- id: chatRef.id,
1309
- title: chatRef.title,
1310
- url: chatRef.url,
1311
- targetPlatform: chatRef.targetPlatform,
1312
- sourceRepo: chatRef.sourceRepo,
1313
- metadata: chatRef.metadata,
1314
1262
  };
1315
1263
  }
1316
1264
 
@@ -1506,18 +1454,12 @@ const CHAT_CARD_REGISTRY: Record<string, ChatCardRegistryEntry> = {
1506
1454
  hubspot_ticket_self: refHydratedEntry('hubspot_ticket_self', 'HubSpot ticket (self)', (displayRef, opts) => (
1507
1455
  <HubspotTicketChatCard chatRef={displayRef} isNewTab={opts.isNewTab} discuss={opts.discuss} />
1508
1456
  )),
1509
- data_room_doc: refHydratedEntry(
1510
- 'data_room_doc',
1511
- 'Data-room doc',
1512
- (displayRef, opts) => <DataRoomDocChatCard chatRef={displayRef} isNewTab={opts.isNewTab} discuss={opts.discuss} />,
1513
- true,
1514
- ),
1515
- markdown: refHydratedEntry(
1516
- 'markdown',
1517
- 'Doc page (markdown)',
1518
- (displayRef, opts) => <DataRoomDocChatCard chatRef={displayRef} isNewTab={opts.isNewTab} discuss={opts.discuss} />,
1519
- true,
1520
- ),
1457
+ data_room_doc: refHydratedEntry('data_room_doc', 'Data-room doc', (displayRef, opts) => (
1458
+ <DataRoomDocChatCard chatRef={displayRef} isNewTab={opts.isNewTab} discuss={opts.discuss} />
1459
+ )),
1460
+ markdown: refHydratedEntry('markdown', 'Doc page (markdown)', (displayRef, opts) => (
1461
+ <DataRoomDocChatCard chatRef={displayRef} isNewTab={opts.isNewTab} discuss={opts.discuss} />
1462
+ )),
1521
1463
  // Body-synthesized video ids (`shortVideoId` content hashes / YouTube
1522
1464
  // ids) have no backing table row to fetch — ref-only by nature.
1523
1465
  video: {
@@ -1960,13 +1902,6 @@ export function ChatCardLoader({
1960
1902
  }
1961
1903
  if (isLoading) return <>{fetchEntry.skeleton?.() ?? null}</>;
1962
1904
  if (!item) {
1963
- const hasSourceMetadata =
1964
- fetchEntry.renderFromSourceMetadata &&
1965
- isSourceMetadataCardRef(chatRef) &&
1966
- typeof finalChatRef.metadata?.path === 'string';
1967
- if (hasSourceMetadata) {
1968
- return finish(fetchEntry.render(sourceMetadataCardItem(finalChatRef), finalChatRef, renderOpts));
1969
- }
1970
1905
  // FAIL LOUD (explicit product decision 2026-08-13): a card that
1971
1906
  // cannot hydrate renders a VISIBLE error card — silent removal made
1972
1907
  // broken answers look fine. Three distinguishable states:
@@ -2048,28 +1983,24 @@ export function renderChatInlineEntityCard(
2048
1983
  />
2049
1984
  );
2050
1985
 
2051
- // SOURCES metadata may enrich an opaque video marker with its playable URL.
2052
- // Self-describing marker ids remain transport-independent through
2053
- // `decodeVideoMarkerId`; undecodable ids without matching metadata fall
2054
- // through to the loader and degrade to plain text.
1986
+ // Embedded videos are SELF-DESCRIBING: the marker id alone recovers the
1987
+ // playable URL (`decodeVideoMarkerId`), so the player renders on ANY
1988
+ // transport with zero refs/fetch. Undecodable ids (legacy sha1 hashes,
1989
+ // hallucinations) fall through to the loader → plain-text degrade.
2055
1990
  // Hero videos on FETCHED entity types (webinars, releases, …) are
2056
1991
  // handled post-fetch inside ChatCardLoader (`itemVideoMetadata`) — the
2057
- // marker metadata is not required for that post-fetch path.
1992
+ // marker's ref plays no part in either path.
2058
1993
  if (chatRef.type === 'video') {
2059
- const enrichedMetadata = validatedVideoMetadata(chatRef);
2060
1994
  const decoded = decodeVideoMarkerId(chatRef.id);
2061
- const playableMetadata = enrichedMetadata ?? decoded;
2062
- if (playableMetadata) {
1995
+ if (decoded) {
2063
1996
  const displayRef: ChatRef = {
2064
1997
  ...chatRef,
2065
1998
  title: chatRef.title && chatRef.title !== chatRef.id ? chatRef.title : 'Video',
2066
1999
  url:
2067
2000
  chatRef.url ??
2068
- (typeof playableMetadata.videoUrl === 'string' ? playableMetadata.videoUrl : null) ??
2069
- (typeof playableMetadata.youtubeUrl === 'string'
2070
- ? `https://www.youtube.com/watch?v=${playableMetadata.youtubeUrl}`
2071
- : null),
2072
- metadata: playableMetadata,
2001
+ decoded.videoUrl ??
2002
+ (decoded.youtubeUrl ? `https://www.youtube.com/watch?v=${decoded.youtubeUrl}` : null),
2003
+ metadata: { ...(chatRef.metadata ?? {}), ...decoded },
2073
2004
  };
2074
2005
  return (
2075
2006
  <BlockCard inline={<ChatInlineVideoPill chatRef={displayRef} />}>
@@ -61,7 +61,6 @@ import type {
61
61
  MessageSegment,
62
62
  NatsMessageType,
63
63
  ChatApprovalStatus,
64
- ChatSource,
65
64
  } from '../types';
66
65
  import type { DialogItem } from '../types/component.types';
67
66
  import type {
@@ -353,8 +352,6 @@ export function mapProcessedToUnified(
353
352
  role: 'user' | 'assistant' | 'error';
354
353
  content: string | MessageSegment[];
355
354
  name?: string;
356
- sources?: ChatSource[];
357
- refs?: ChatRef[];
358
355
  }>,
359
356
  ): UnifiedChatMessage[] {
360
357
  const out: UnifiedChatMessage[] = [];
@@ -366,16 +363,12 @@ export function mapProcessedToUnified(
366
363
  role: m.role,
367
364
  content: '',
368
365
  segments: m.content,
369
- ...(m.sources ? { sources: m.sources } : {}),
370
- ...(m.refs ? { refs: m.refs } : {}),
371
366
  });
372
367
  } else {
373
368
  out.push({
374
369
  id: m.id,
375
370
  role: m.role,
376
371
  content: m.content,
377
- ...(m.sources ? { sources: m.sources } : {}),
378
- ...(m.refs ? { refs: m.refs } : {}),
379
372
  });
380
373
  }
381
374
  }
@@ -24,12 +24,10 @@ import type { SlashCommandActionId, SlashCommandSummaryAction, SlashCommandSumma
24
24
  // canonical declaration.
25
25
  export type { SlashCommandActionId, SlashCommandSummaryAction, SlashCommandSummary };
26
26
 
27
- const COMMANDS_MAX_RESULTS = 10;
28
-
29
27
  /**
30
- * Fetch the full slash-command registry for the CURRENT deployment platform,
31
- * then match id-prefix `prefix` locally. The chat source is server-resolved —
32
- * the client sends NO `source` param on the URL.
28
+ * Fetch slash-command suggestions for the CURRENT deployment platform,
29
+ * matching id-prefix `prefix`. The chat source is server-resolved — the
30
+ * client sends NO `source` param on the URL.
33
31
  *
34
32
  * `commandsUrl` is required — supplied by `useChatRuntime().endpoints.commandsUrl`
35
33
  * at the call site. NO default value.
@@ -58,15 +56,13 @@ export async function fetchSlashCommands(
58
56
  ): Promise<SlashCommandSummary[]> {
59
57
  try {
60
58
  const url = new URL(commandsUrl, window.location.origin);
59
+ if (prefix) url.searchParams.set('q', prefix);
61
60
  // `headers: {}` opts out of the default `Content-Type: application/json`
62
61
  // — this is a bare GET with no body, so no content-type is needed.
63
62
  const res = await embedAuthedFetch(url.toString(), { signal, headers: {} });
64
63
  if (!res.ok) return [];
65
64
  const data = (await res.json()) as { commands?: SlashCommandSummary[] };
66
- const commands = data.commands ?? [];
67
- const normalizedPrefix = prefix.trim().toLowerCase();
68
- if (!normalizedPrefix) return commands;
69
- return commands.filter(({ id }) => id.startsWith(normalizedPrefix)).slice(0, COMMANDS_MAX_RESULTS);
65
+ return data.commands ?? [];
70
66
  } catch (err) {
71
67
  // Cancellation (unmount / dep change) MUST propagate so react-query treats
72
68
  // it as cancelled, not as a successful empty result. Every OTHER failure
@@ -63,7 +63,7 @@ import type { ChatDialogStore } from '../stream/chat-dialog-store';
63
63
  import type { ChatStreamReducerOptions } from '../stream/chat-stream-reducer';
64
64
  import { useChatStreamReducer } from '../stream/use-chat-stream-reducer';
65
65
  import type { DialogItem } from '../types/component.types';
66
- import type { ChatSource, Message, MessageSegment } from '../types/message.types';
66
+ import type { Message, MessageSegment } from '../types/message.types';
67
67
  import type {
68
68
  UnifiedChatState,
69
69
  UnifiedChatMessage,
@@ -81,7 +81,6 @@ import { useSlashCommandRegistry, type SlashCommandSummary } from './use-slash-c
81
81
  // Canonical home of the per-turn meta row moved to the stream module in
82
82
  // Phase 3; re-exported here to keep the legacy import path stable.
83
83
  export type { ChatTurnMeta } from '../stream/chat-stream-reducer';
84
- export type { ChatSource } from '../types/message.types';
85
84
 
86
85
  // ─── Stable no-op references for the Guide-mode dialog-management stubs ──
87
86
  // Plain module-scope constants so the adapter's return identity stays
@@ -129,6 +128,34 @@ const noopBumpMetaTick = (): void => {};
129
128
  * hub-side platform-utils, not in lib). */
130
129
  export type DocSource = string;
131
130
 
131
+ export interface ChatSource {
132
+ index: number;
133
+ name: string;
134
+ path: string;
135
+ documentType: string;
136
+ externalUrl?: string;
137
+ /** Platform that owns the destination at `externalUrl`. */
138
+ targetPlatform?: string | null;
139
+ /** Primary-key value for single-row chips. */
140
+ id?: string;
141
+ /** Per-row items for grouped chips. */
142
+ items?: Array<{
143
+ id: string;
144
+ documentType: string;
145
+ name: string;
146
+ externalUrl?: string;
147
+ targetPlatform?: string | null;
148
+ /** In-app doc-tree path for markdown / data-room-doc rows so the
149
+ * grouped chip's anchor can trigger an in-page doc-tree swap via
150
+ * `handleChatNavClick` (parity with single-row chips + cards). */
151
+ path?: string | null;
152
+ }>;
153
+ /** RagTableConfig.id for this source. */
154
+ sourceRepo?: string;
155
+ /** Optional display label override returned by the chat API. */
156
+ label?: string;
157
+ }
158
+
132
159
  export interface DocChatMessage {
133
160
  id: string;
134
161
  role: 'user' | 'assistant';
@@ -1289,59 +1289,3 @@ describe('createChatStreamReducer — ask cards', () => {
1289
1289
  expect(last.segments?.map(s => s.type)).toEqual(['ask', 'ask']);
1290
1290
  });
1291
1291
  });
1292
-
1293
- describe('createChatStreamReducer — Mingo source metadata', () => {
1294
- const sources = [
1295
- {
1296
- index: 1,
1297
- name: 'Enroll devices',
1298
- path: 'docs/enroll.md',
1299
- documentType: 'markdown',
1300
- },
1301
- ];
1302
-
1303
- it('attaches metadata received before text to the same assistant turn', () => {
1304
- const reducer = createChatStreamReducer({ transport: 'nats' });
1305
- const refs = [
1306
- {
1307
- type: 'video',
1308
- id: 'mux-9b6586b494',
1309
- title: 'Community demo',
1310
- url: 'https://stream.mux.com/playback-id.m3u8',
1311
- metadata: { videoUrl: 'https://stream.mux.com/playback-id.m3u8' },
1312
- },
1313
- ];
1314
-
1315
- reducer.apply({ type: 'turn-start', seq: 1 });
1316
- reducer.apply({ type: 'sources', sources, refs, seq: 2 });
1317
- reducer.apply({ type: 'text-delta', text: 'Follow the guide [1].', seq: 3 });
1318
-
1319
- expect(reducer.state.messages).toHaveLength(1);
1320
- expect(reducer.state.messages[0]).toMatchObject({ sources, refs });
1321
- });
1322
-
1323
- it('deduplicates cumulative metadata and does not leak it into the next turn', () => {
1324
- const reducer = createChatStreamReducer({ transport: 'nats' });
1325
-
1326
- reducer.apply({ type: 'turn-start', seq: 1 });
1327
- reducer.apply({ type: 'sources', sources, seq: 2 });
1328
- reducer.apply({
1329
- type: 'sources',
1330
- sources: [
1331
- { ...sources[0], name: 'Duplicate' },
1332
- { index: 2, name: 'Install agent', path: 'docs/install.md', documentType: 'markdown' },
1333
- ],
1334
- seq: 3,
1335
- });
1336
- reducer.apply({ type: 'text-delta', text: 'First answer [1] [2].', seq: 4 });
1337
- reducer.apply({ type: 'turn-end', seq: 5 });
1338
- reducer.apply({ type: 'turn-start', seq: 6 });
1339
- reducer.apply({ type: 'text-delta', text: 'Second answer.', seq: 7 });
1340
-
1341
- expect(reducer.state.messages[0].sources).toEqual([
1342
- sources[0],
1343
- { index: 2, name: 'Install agent', path: 'docs/install.md', documentType: 'markdown' },
1344
- ]);
1345
- expect(reducer.state.messages[1].sources).toBeUndefined();
1346
- });
1347
- });
@@ -60,7 +60,6 @@ import {
60
60
  type ParticipantEvent,
61
61
  type UsageEvent,
62
62
  } from '../../../chat-protocol/events';
63
- import type { ChatRef } from '../chat-ref.types';
64
63
  import type {
65
64
  ApprovalBatchSegment,
66
65
  ApprovalRequestSegment,
@@ -71,7 +70,6 @@ import type {
71
70
  ToolExecutionSegment,
72
71
  ExecutingToolState,
73
72
  } from '../types';
74
- import type { ChatSource } from '../types/message.types';
75
73
  import type { PendingApproval } from '../types/processing.types';
76
74
  import type {
77
75
  DialogTokenUsage,
@@ -80,7 +78,6 @@ import type {
80
78
  UnifiedUsageBreakdown,
81
79
  } from '../types/unified-chat-state.types';
82
80
  import { approvalDisplaysInline } from '../utils/approval-display';
83
- import { mergeChatRefs, mergeChatSources } from '../utils/chat-source-metadata';
84
81
  import {
85
82
  type MessageSegmentAccumulator,
86
83
  createMessageSegmentAccumulator,
@@ -679,9 +676,6 @@ export function createChatStreamReducer(options: ChatStreamReducerOptions = {}):
679
676
  let sendCount = 0;
680
677
  let sseCurrentText = '';
681
678
 
682
- let pendingSources: ChatSource[] | undefined;
683
- let pendingRefs: ChatRef[] | undefined;
684
-
685
679
  // ── Snapshot cache ─────────────────────────────────────────────────────
686
680
  let stateCache: ChatReducerState | null = null;
687
681
  function invalidate(): void {
@@ -779,18 +773,6 @@ export function createChatStreamReducer(options: ChatStreamReducerOptions = {}):
779
773
  setMessagesInternal(stampTrailingAssistantSeq(updateTrailingAssistant(messages, segments), seq));
780
774
  }
781
775
 
782
- function attachPendingSourceMetadata(): void {
783
- if (!pendingSources && !pendingRefs) return;
784
- const last = messages[messages.length - 1];
785
- if (!last || last.role !== 'assistant') return;
786
- const next = {
787
- ...last,
788
- ...(pendingSources ? { sources: pendingSources } : {}),
789
- ...(pendingRefs ? { refs: pendingRefs } : {}),
790
- };
791
- setMessagesInternal([...messages.slice(0, -1), next]);
792
- }
793
-
794
776
  function applyStreamStartToState(): void {
795
777
  setPhaseInternal('streaming');
796
778
  // A new stream must never overwrite a COMPLETED trailing assistant
@@ -984,8 +966,6 @@ export function createChatStreamReducer(options: ChatStreamReducerOptions = {}):
984
966
 
985
967
  switch (event.type) {
986
968
  case 'turn-start': {
987
- pendingSources = undefined;
988
- pendingRefs = undefined;
989
969
  isInStream = true;
990
970
  hasEverStreamed = true;
991
971
  turnStartedAt = Date.now();
@@ -1001,15 +981,6 @@ export function createChatStreamReducer(options: ChatStreamReducerOptions = {}):
1001
981
  emit('onStreamEnd');
1002
982
  setPhaseInternal('idle');
1003
983
  accumulator.resetSegments();
1004
- pendingSources = undefined;
1005
- pendingRefs = undefined;
1006
- break;
1007
- }
1008
-
1009
- case 'sources': {
1010
- pendingSources = mergeChatSources(pendingSources, event.sources);
1011
- if (event.refs) pendingRefs = mergeChatRefs(pendingRefs, event.refs);
1012
- attachPendingSourceMetadata();
1013
984
  break;
1014
985
  }
1015
986
 
@@ -1046,12 +1017,10 @@ export function createChatStreamReducer(options: ChatStreamReducerOptions = {}):
1046
1017
  if (isInStream || !hasEverStreamed) {
1047
1018
  emitSegments(segments);
1048
1019
  applySegmentsToState(segments, withSeqMeta(undefined));
1049
- attachPendingSourceMetadata();
1050
1020
  } else {
1051
1021
  const delta: MessageSegment[] = [{ type: kind, text: event.text }];
1052
1022
  emitSegments(delta, { append: true });
1053
1023
  applySegmentsToState(delta, withSeqMeta({ append: true }));
1054
- attachPendingSourceMetadata();
1055
1024
  }
1056
1025
  break;
1057
1026
  }
@@ -54,9 +54,6 @@ const ToolExecutionDisplay = forwardRef<HTMLDivElement, ToolExecutionDisplayProp
54
54
 
55
55
  const hasResult = isExecuted && typeof message.result === 'string' && message.result.length > 0;
56
56
  const hasBody = argEntries.length > 0 || hasResult || isExecuting;
57
- const isConciseRemoteRead =
58
- !message.integratedToolType && !!message.toolTitle?.trim() && argEntries.length === 0 && !hasResult;
59
- const isStaticRow = isClientView || isConciseRemoteRead;
60
57
 
61
58
  const renderStatusIcon = () => {
62
59
  if (isExecuting) return <DotsLoaderIcon size={16} className="text-ods-text-secondary" />;
@@ -85,7 +82,7 @@ const ToolExecutionDisplay = forwardRef<HTMLDivElement, ToolExecutionDisplayProp
85
82
  {previewText}
86
83
  </div>
87
84
  <div className="flex h-5 w-5 shrink-0 items-center justify-center">{renderStatusIcon()}</div>
88
- {!isStaticRow && (
85
+ {!isClientView && (
89
86
  <div className="flex h-5 w-5 shrink-0 items-center justify-center">
90
87
  <ExpandChevron expanded={expanded} />
91
88
  </div>
@@ -104,7 +101,7 @@ const ToolExecutionDisplay = forwardRef<HTMLDivElement, ToolExecutionDisplayProp
104
101
  )}
105
102
  {...props}
106
103
  >
107
- {isStaticRow ? (
104
+ {isClientView ? (
108
105
  // Client (Fae end-user): static, non-expandable row — no chevron, no
109
106
  // body. Just the explanation + status; command/args/result are hidden.
110
107
  <div className="flex w-full items-start gap-[var(--spacing-system-xs)] p-[var(--spacing-system-s)] text-left">
@@ -195,8 +195,6 @@ export interface ChatMessageEnhancedProps extends Omit<HTMLAttributes<HTMLDivEle
195
195
  * back to plain text title-only.
196
196
  */
197
197
  renderEntityCard?: (reference: ChatRef) => ReactNode;
198
- /** Enriched references associated with this assistant answer. */
199
- refs?: ChatRef[];
200
198
  /**
201
199
  * Host-provided anchor component for markdown links. When supplied, the
202
200
  * `<a>` override in the markdown renderer delegates to this component
@@ -306,8 +304,6 @@ export interface ChatMessageListProps extends HTMLAttributes<HTMLDivElement> {
306
304
  * ChatMessageEnhanced; the host sends the received label as the user's next
307
305
  * message. Omit to render ask cards read-only. */
308
306
  onAskSelect?: (label: string) => void;
309
- /** Renders content owned by one message directly after that message. */
310
- renderAfterMessage?: (message: Message, index: number) => ReactNode;
311
307
  }
312
308
 
313
309
  export interface ChatMessageListRef {
@@ -3,7 +3,6 @@
3
3
  * Contains all message structures, segments, and content types
4
4
  */
5
5
 
6
- import type { ChatRef } from '../chat-ref.types';
7
6
  import type { AssistantType, AuthorType, ChatApprovalStatus, MessageOwner } from './chat.types';
8
7
 
9
8
  // ========== Message Type Definitions ==========
@@ -11,8 +10,6 @@ import type { AssistantType, AuthorType, ChatApprovalStatus, MessageOwner } from
11
10
  export const MESSAGE_TYPE = {
12
11
  TEXT: 'TEXT',
13
12
  THINKING: 'THINKING',
14
- GUIDE: 'GUIDE',
15
- SOURCES: 'SOURCES',
16
13
  ASK: 'ASK',
17
14
  EXECUTING_TOOL: 'EXECUTING_TOOL',
18
15
  EXECUTED_TOOL: 'EXECUTED_TOOL',
@@ -49,26 +46,6 @@ export const SCROLL_ANCHOR = { TOP: 'top', BOTTOM: 'bottom' } as const;
49
46
 
50
47
  export type ScrollAnchor = (typeof SCROLL_ANCHOR)[keyof typeof SCROLL_ANCHOR];
51
48
 
52
- export interface ChatSource {
53
- index: number;
54
- name: string;
55
- path: string;
56
- documentType: string;
57
- externalUrl?: string;
58
- targetPlatform?: string | null;
59
- id?: string;
60
- items?: Array<{
61
- id: string;
62
- documentType: string;
63
- name: string;
64
- externalUrl?: string;
65
- targetPlatform?: string | null;
66
- path?: string | null;
67
- }>;
68
- sourceRepo?: string;
69
- label?: string;
70
- }
71
-
72
49
  // ========== Tool Execution Types ==========
73
50
 
74
51
  export interface ToolExecutionData {
@@ -414,16 +391,6 @@ export interface ThinkingMessageData extends MessageDataBase {
414
391
  text?: string;
415
392
  }
416
393
 
417
- export interface GuideMessageData extends MessageDataBase {
418
- type: 'GUIDE';
419
- payload?: Record<string, unknown>;
420
- }
421
-
422
- export interface SourcesMessageData extends MessageDataBase {
423
- type: 'SOURCES';
424
- payload?: Record<string, unknown>;
425
- }
426
-
427
394
  /** Persisted `ASK` row (GraphQL `AskData`). `text` is the intro sentence, which
428
395
  * history replays as a text segment ahead of the card — same split the live
429
396
  * `ASK` chunk carries. */
@@ -565,8 +532,6 @@ export interface ContextCompactionEndMessageData extends MessageDataBase {
565
532
  export type MessageData =
566
533
  | TextMessageData
567
534
  | ThinkingMessageData
568
- | GuideMessageData
569
- | SourcesMessageData
570
535
  | AskMessageData
571
536
  | ExecutingToolMessageData
572
537
  | ExecutedToolMessageData
@@ -611,8 +576,6 @@ export interface ProcessedMessage {
611
576
  authorType?: AuthorType;
612
577
  timestamp: Date;
613
578
  avatar?: string;
614
- sources?: ChatSource[];
615
- refs?: ChatRef[];
616
579
  /** Persisted last-chunk stream sequence carried through from
617
580
  * `HistoricalMessage.lastChunkStreamSeq` (for assistant turns: the MAX
618
581
  * across the grouped rows). Hosts stamp it onto the rendered message's
@@ -635,8 +598,6 @@ export interface Message {
635
598
  authorType?: AuthorType;
636
599
  timestamp?: Date;
637
600
  avatar?: string | null;
638
- sources?: ChatSource[];
639
- refs?: ChatRef[];
640
601
  /** Highest CONTENT chunk streamSeq that composed this message. Stamped on
641
602
  * realtime synthetics so `mergeHistoryWithRealtime` can decide history
642
603
  * coverage per-message (see `MergeableChatMessage.streamSeq`). */
@@ -17,11 +17,12 @@
17
17
  */
18
18
 
19
19
  import type { ChatRef } from '../chat-ref.types';
20
+ import type { ChatSource } from '../hooks/use-sse-chat-adapter';
20
21
  import type { ChatAttachment } from '../utils/chat-attachment-markdown';
21
22
  import type { AuthorType } from './chat.types';
22
23
  import type { DialogItem } from './component.types';
23
24
  import type { ChatContextItem } from './context-item.types';
24
- import type { ChatSource, MessageSegment, ScrollAnchor } from './message.types';
25
+ import type { MessageSegment, ScrollAnchor } from './message.types';
25
26
 
26
27
  // ─── Per-dialog token usage (Mingo backend telemetry) ────────────────────────
27
28
 
@@ -168,11 +169,9 @@ export interface UnifiedChatMessage {
168
169
  */
169
170
  timestamp?: Date | string | number;
170
171
 
171
- /** Document citations for a Guide answer over SSE or NATS. */
172
+ /** Guide/SSE-only: document citations. Undefined in Mingo mode. */
172
173
  sources?: ChatSource[];
173
174
 
174
- refs?: ChatRef[];
175
-
176
175
  /**
177
176
  * Per-message viewport-positioning hint. Common to both modes; the
178
177
  * message-list reads it to override default tail-on-stream behaviour