@8wave/ai-elements 0.111.0-beta.3 → 0.111.0-beta.7

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 (150) hide show
  1. package/dist/_chunks/{Agent-Su_LDF9_.js → Agent-tE7ZJPxG.js} +80 -78
  2. package/dist/_chunks/Agent-tE7ZJPxG.js.map +1 -0
  3. package/dist/_chunks/{Document-DecVclEe.js → Document-Bmx6774B.js} +33 -21
  4. package/dist/_chunks/Document-Bmx6774B.js.map +1 -0
  5. package/dist/_chunks/Media-Cft7Pwrh.js +108 -0
  6. package/dist/_chunks/Media-Cft7Pwrh.js.map +1 -0
  7. package/dist/_chunks/{PkStreamingMarkdown-CwqsJnJJ.js → PkStreamingMarkdown-DgBS4Ebc.js} +69 -59
  8. package/dist/_chunks/PkStreamingMarkdown-DgBS4Ebc.js.map +1 -0
  9. package/dist/_chunks/{PkToolRequestGeolocation-OokLeTf1.js → PkToolRequestGeolocation-pVys3x9M.js} +2 -2
  10. package/dist/_chunks/{PkToolRequestGeolocation-OokLeTf1.js.map → PkToolRequestGeolocation-pVys3x9M.js.map} +1 -1
  11. package/dist/_chunks/{PkToolRequestOAuthConnection-CtqKG6Yb.js → PkToolRequestOAuthConnection-BGChb_eC.js} +2 -2
  12. package/dist/_chunks/{PkToolRequestOAuthConnection-CtqKG6Yb.js.map → PkToolRequestOAuthConnection-BGChb_eC.js.map} +1 -1
  13. package/dist/_chunks/{PkToolShowArtifact-M6jlSmyJ.js → PkToolShowArtifact-CkTBIdQd.js} +2 -2
  14. package/dist/_chunks/{PkToolShowArtifact-M6jlSmyJ.js.map → PkToolShowArtifact-CkTBIdQd.js.map} +1 -1
  15. package/dist/_chunks/{PkToolShowContactForm-D_dW59Dl.js → PkToolShowContactForm-Du7jX7K5.js} +2 -2
  16. package/dist/_chunks/{PkToolShowContactForm-D_dW59Dl.js.map → PkToolShowContactForm-Du7jX7K5.js.map} +1 -1
  17. package/dist/_chunks/PkToolShowDiagram-BdmG9gm8.js.map +1 -1
  18. package/dist/_chunks/{PkToolShowForm-DbJHMDbt.js → PkToolShowForm-Du2nk7pq.js} +3 -3
  19. package/dist/_chunks/PkToolShowForm-Du2nk7pq.js.map +1 -0
  20. package/dist/_chunks/{PkToolShowSources-Dot-W0Mj.js → PkToolShowSources-CsHLUF4L.js} +3 -3
  21. package/dist/_chunks/{PkToolShowSources-Dot-W0Mj.js.map → PkToolShowSources-CsHLUF4L.js.map} +1 -1
  22. package/dist/_chunks/{PkToolShowSuggestedReply-CKxSH0Y9.js → PkToolShowSuggestedReply-D7g_qymH.js} +2 -2
  23. package/dist/_chunks/{PkToolShowSuggestedReply-CKxSH0Y9.js.map → PkToolShowSuggestedReply-D7g_qymH.js.map} +1 -1
  24. package/dist/_chunks/PkToolShowWeather-LPd3tC77.js.map +1 -1
  25. package/dist/_chunks/PkUrl-BPbjZJ1A.js.map +1 -1
  26. package/dist/_chunks/{browser-NgY6LXg-.js → browser-B0Xnbqi7.js} +726 -751
  27. package/dist/_chunks/browser-B0Xnbqi7.js.map +1 -0
  28. package/dist/_chunks/text-DbSEK8si.js.map +1 -1
  29. package/dist/_chunks/utils-YJ0ZOLDG.js.map +1 -1
  30. package/dist/ai-elements.es.js +3010 -3052
  31. package/dist/ai-elements.es.js.map +1 -1
  32. package/dist-vue/PkChatbot.js +1 -1
  33. package/dist-vue/PkChatbotEmptyState.js +1 -1
  34. package/dist-vue/PkChatbotError.js +1 -1
  35. package/dist-vue/PkChatbotInput.js +1 -1
  36. package/dist-vue/PkChatbotMessages.js +1 -1
  37. package/dist-vue/PkChatbotSteps.js +1 -1
  38. package/dist-vue/PkChatbotViewChat.js +1 -1
  39. package/dist-vue/PkChatbotViewConversations.js +1 -1
  40. package/dist-vue/PkChatbotViewFiles.js +1 -1
  41. package/dist-vue/PkChatbotViewProfile.js +1 -1
  42. package/dist-vue/_chunks/{Agent-C8BsTAxk.js → Agent-De2gFNjR.js} +165 -176
  43. package/dist-vue/_chunks/Agent-De2gFNjR.js.map +1 -0
  44. package/dist-vue/_chunks/{Document-CaUfI_SZ.js → Document-8umjeTVS.js} +84 -72
  45. package/dist-vue/_chunks/Document-8umjeTVS.js.map +1 -0
  46. package/dist-vue/_chunks/Media-_HfFLHGD.js.map +1 -1
  47. package/dist-vue/_chunks/{PkChatbot-BPKSPIeC.js → PkChatbot-Di7R2CWN.js} +7 -7
  48. package/dist-vue/_chunks/PkChatbot-Di7R2CWN.js.map +1 -0
  49. package/dist-vue/_chunks/{PkChatbotEmptyState-BvaeBxhx.js → PkChatbotEmptyState-C_ITdvH7.js} +2 -2
  50. package/dist-vue/_chunks/{PkChatbotEmptyState-BvaeBxhx.js.map → PkChatbotEmptyState-C_ITdvH7.js.map} +1 -1
  51. package/dist-vue/_chunks/{PkChatbotError-CBP2mf-n.js → PkChatbotError-gvDpRcEz.js} +21 -19
  52. package/dist-vue/_chunks/PkChatbotError-gvDpRcEz.js.map +1 -0
  53. package/dist-vue/_chunks/{PkChatbotInput-JnHaRlfk.js → PkChatbotInput-pEl3D2O-.js} +139 -124
  54. package/dist-vue/_chunks/PkChatbotInput-pEl3D2O-.js.map +1 -0
  55. package/dist-vue/_chunks/{PkChatbotMessages-DAlkoMkY.js → PkChatbotMessages-CGALOKwe.js} +17 -17
  56. package/dist-vue/_chunks/PkChatbotMessages-CGALOKwe.js.map +1 -0
  57. package/dist-vue/_chunks/{PkChatbotSteps-rommD48p.js → PkChatbotSteps-BhFupvbz.js} +2 -2
  58. package/dist-vue/_chunks/{PkChatbotSteps-rommD48p.js.map → PkChatbotSteps-BhFupvbz.js.map} +1 -1
  59. package/dist-vue/_chunks/{PkChatbotViewChat-CEqzF1G9.js → PkChatbotViewChat-DT-rAU_r.js} +6 -6
  60. package/dist-vue/_chunks/{PkChatbotViewChat-CEqzF1G9.js.map → PkChatbotViewChat-DT-rAU_r.js.map} +1 -1
  61. package/dist-vue/_chunks/{PkChatbotViewConversations-C787v5ll.js → PkChatbotViewConversations-3LaZPFyw.js} +2 -2
  62. package/dist-vue/_chunks/{PkChatbotViewConversations-C787v5ll.js.map → PkChatbotViewConversations-3LaZPFyw.js.map} +1 -1
  63. package/dist-vue/_chunks/{PkChatbotViewFiles-CNFLt8YO.js → PkChatbotViewFiles-CTqnbsCj.js} +3 -3
  64. package/dist-vue/_chunks/{PkChatbotViewFiles-CNFLt8YO.js.map → PkChatbotViewFiles-CTqnbsCj.js.map} +1 -1
  65. package/dist-vue/_chunks/{PkChatbotViewProfile-7p0ci3qm.js → PkChatbotViewProfile-B-Mp1jGQ.js} +2 -2
  66. package/dist-vue/_chunks/{PkChatbotViewProfile-7p0ci3qm.js.map → PkChatbotViewProfile-B-Mp1jGQ.js.map} +1 -1
  67. package/dist-vue/_chunks/PkRelativeTime--1cIphlA.js.map +1 -1
  68. package/dist-vue/_chunks/{PkStreamingMarkdown-D8_LwZMR.js → PkStreamingMarkdown-DIaZEedG.js} +406 -396
  69. package/dist-vue/_chunks/PkStreamingMarkdown-DIaZEedG.js.map +1 -0
  70. package/dist-vue/_chunks/PkSvgViewer-D-0M5bqg.js.map +1 -1
  71. package/dist-vue/_chunks/{PkToolRequestGeolocation-Bxqz9oSo.js → PkToolRequestGeolocation-Q3N3jlO8.js} +2 -2
  72. package/dist-vue/_chunks/{PkToolRequestGeolocation-Bxqz9oSo.js.map → PkToolRequestGeolocation-Q3N3jlO8.js.map} +1 -1
  73. package/dist-vue/_chunks/{PkToolRequestOAuthConnection-C6rXgb0s.js → PkToolRequestOAuthConnection-C0LW5Evp.js} +2 -2
  74. package/dist-vue/_chunks/{PkToolRequestOAuthConnection-C6rXgb0s.js.map → PkToolRequestOAuthConnection-C0LW5Evp.js.map} +1 -1
  75. package/dist-vue/_chunks/{PkToolShowArtifact-CEXdfOGG.js → PkToolShowArtifact-BCCUucVQ.js} +2 -2
  76. package/dist-vue/_chunks/{PkToolShowArtifact-CEXdfOGG.js.map → PkToolShowArtifact-BCCUucVQ.js.map} +1 -1
  77. package/dist-vue/_chunks/{PkToolShowContactForm-DHmzAIVF.js → PkToolShowContactForm-BXGxWSc2.js} +2 -2
  78. package/dist-vue/_chunks/{PkToolShowContactForm-DHmzAIVF.js.map → PkToolShowContactForm-BXGxWSc2.js.map} +1 -1
  79. package/dist-vue/_chunks/{PkToolShowDiagram-dwCVZ1up.js → PkToolShowDiagram-CZgrWvBr.js} +2 -2
  80. package/dist-vue/_chunks/PkToolShowDiagram-CZgrWvBr.js.map +1 -0
  81. package/dist-vue/_chunks/{PkToolShowEmail-CavhsPvi.js → PkToolShowEmail-DpC517Vn.js} +2 -2
  82. package/dist-vue/_chunks/{PkToolShowEmail-CavhsPvi.js.map → PkToolShowEmail-DpC517Vn.js.map} +1 -1
  83. package/dist-vue/_chunks/{PkToolShowForm-CO5A_j9L.js → PkToolShowForm-CIZpfAGK.js} +3 -3
  84. package/dist-vue/_chunks/PkToolShowForm-CIZpfAGK.js.map +1 -0
  85. package/dist-vue/_chunks/{PkToolShowMessage-DQojxDiV.js → PkToolShowMessage-B7flxVCU.js} +2 -2
  86. package/dist-vue/_chunks/{PkToolShowMessage-DQojxDiV.js.map → PkToolShowMessage-B7flxVCU.js.map} +1 -1
  87. package/dist-vue/_chunks/{PkToolShowProductList-Cn0yewM3.js → PkToolShowProductList-B6fRtIpx.js} +2 -2
  88. package/dist-vue/_chunks/{PkToolShowProductList-Cn0yewM3.js.map → PkToolShowProductList-B6fRtIpx.js.map} +1 -1
  89. package/dist-vue/_chunks/{PkToolShowSources-7Q5Iogxi.js → PkToolShowSources-DDZokZow.js} +4 -4
  90. package/dist-vue/_chunks/{PkToolShowSources-7Q5Iogxi.js.map → PkToolShowSources-DDZokZow.js.map} +1 -1
  91. package/dist-vue/_chunks/{PkToolShowSuggestedReply-DQFOVonE.js → PkToolShowSuggestedReply-DWLkUh2L.js} +2 -2
  92. package/dist-vue/_chunks/{PkToolShowSuggestedReply-DQFOVonE.js.map → PkToolShowSuggestedReply-DWLkUh2L.js.map} +1 -1
  93. package/dist-vue/_chunks/PkToolShowWeather-Bzqalzh8.js.map +1 -1
  94. package/dist-vue/_chunks/{PkToolShowWebPages-Bzkkn9GV.js → PkToolShowWebPages-DY48ee6V.js} +2 -2
  95. package/dist-vue/_chunks/{PkToolShowWebPages-Bzkkn9GV.js.map → PkToolShowWebPages-DY48ee6V.js.map} +1 -1
  96. package/dist-vue/_chunks/{PkUrl-xUBKVJCv.js → PkUrl-DSGxrEM7.js} +2 -2
  97. package/dist-vue/_chunks/PkUrl-DSGxrEM7.js.map +1 -0
  98. package/dist-vue/_chunks/{createChatbotApiClient-D9f69brW.js → createChatbotApiClient-MkaPbGWB.js} +2 -2
  99. package/dist-vue/_chunks/createChatbotApiClient-MkaPbGWB.js.map +1 -0
  100. package/dist-vue/_chunks/{useChatbotStore-9Cw_oR6J.js → useChatbotStore-BzfqjiYz.js} +6 -3
  101. package/dist-vue/_chunks/useChatbotStore-BzfqjiYz.js.map +1 -0
  102. package/dist-vue/_chunks/useDialogConfirm-KWz0ohCQ.js.map +1 -1
  103. package/dist-vue/_chunks/utils-Coqik0XI.js.map +1 -1
  104. package/dist-vue/api.js +1 -1
  105. package/dist-vue/composables.js +2 -2
  106. package/dist-vue/index.js +3858 -3490
  107. package/dist-vue/index.js.map +1 -1
  108. package/dist-vue/locales.js +36 -8
  109. package/dist-vue/packages/components/src/chat/PkAgentSettingsPanel.d.ts +20 -3
  110. package/dist-vue/packages/components/src/chat/PkChatButton.d.ts +3 -2
  111. package/dist-vue/packages/components/src/chat/PkLanguageModel.d.ts +26 -2
  112. package/dist-vue/packages/components/src/chat/PkLanguageModelCombobox.d.ts +53 -1
  113. package/dist-vue/packages/components/src/chat/PkModelOption.d.ts +19 -0
  114. package/dist-vue/packages/components/src/chat/PkReasoningSettings.d.ts +6 -0
  115. package/dist-vue/packages/components/src/chat/constants.d.ts +5 -18
  116. package/dist-vue/packages/components/src/chat/index.d.ts +3 -1
  117. package/dist-vue/packages/components/src/chat/modelCatalog.d.ts +46 -0
  118. package/dist-vue/packages/components/src/table/PkTableSortable.d.ts +5 -1
  119. package/dist-vue/packages/composable/src/chatbot/useChatbotStore.d.ts +18 -0
  120. package/dist-vue/packages/composable/src/useChatbotError.d.ts +2 -0
  121. package/dist-vue/packages/models/src/schema/Agent.d.ts +70 -10
  122. package/dist-vue/packages/models/src/schema/Chat.d.ts +10 -0
  123. package/dist-vue/packages/models/src/schema/ModelProvider.d.ts +316 -0
  124. package/dist-vue/packages/models/src/schema/Organization.d.ts +142 -2
  125. package/dist-vue/packages/models/src/schema/ReasoningChat.d.ts +20 -0
  126. package/dist-vue/packages/models/src/schema/SubAgent.d.ts +20 -0
  127. package/dist-vue/packages/models/src/schema/UserOverview.d.ts +41 -0
  128. package/dist-vue/packages/models/src/schema/constants.d.ts +56 -91
  129. package/dist-vue/packages/models/src/schema/index.d.ts +1 -0
  130. package/dist-vue/style.css +1 -1
  131. package/package.json +1 -1
  132. package/dist/_chunks/Agent-Su_LDF9_.js.map +0 -1
  133. package/dist/_chunks/Document-DecVclEe.js.map +0 -1
  134. package/dist/_chunks/Media-C6SOQfJZ.js +0 -122
  135. package/dist/_chunks/Media-C6SOQfJZ.js.map +0 -1
  136. package/dist/_chunks/PkStreamingMarkdown-CwqsJnJJ.js.map +0 -1
  137. package/dist/_chunks/PkToolShowForm-DbJHMDbt.js.map +0 -1
  138. package/dist/_chunks/browser-NgY6LXg-.js.map +0 -1
  139. package/dist-vue/_chunks/Agent-C8BsTAxk.js.map +0 -1
  140. package/dist-vue/_chunks/Document-CaUfI_SZ.js.map +0 -1
  141. package/dist-vue/_chunks/PkChatbot-BPKSPIeC.js.map +0 -1
  142. package/dist-vue/_chunks/PkChatbotError-CBP2mf-n.js.map +0 -1
  143. package/dist-vue/_chunks/PkChatbotInput-JnHaRlfk.js.map +0 -1
  144. package/dist-vue/_chunks/PkChatbotMessages-DAlkoMkY.js.map +0 -1
  145. package/dist-vue/_chunks/PkStreamingMarkdown-D8_LwZMR.js.map +0 -1
  146. package/dist-vue/_chunks/PkToolShowDiagram-dwCVZ1up.js.map +0 -1
  147. package/dist-vue/_chunks/PkToolShowForm-CO5A_j9L.js.map +0 -1
  148. package/dist-vue/_chunks/PkUrl-xUBKVJCv.js.map +0 -1
  149. package/dist-vue/_chunks/createChatbotApiClient-D9f69brW.js.map +0 -1
  150. package/dist-vue/_chunks/useChatbotStore-9Cw_oR6J.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"text-DbSEK8si.js","names":[],"sources":["../../../../packages/utils/src/text.ts"],"sourcesContent":["export const removeAccents = (str: string) =>\n str.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\n\nexport const toCamelCase = <T extends string>(str?: string): T => {\n if (!str) return '' as unknown as T\n return removeAccents(str)\n .replace(/[^a-zA-Z0-9]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))\n .replace(/^(.)/, (match) => match.toLowerCase()) as unknown as T\n}\n\nexport const fromCamelCase = (str?: string): string => {\n if (!str) return ''\n return str.replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n}\n\nexport const fromAnyCase = (str?: string): string => {\n if (!str) return ''\n return str\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/[-_]+/g, ' ')\n}\n\nexport const toPascalCase = <T extends string>(str?: string): T => {\n if (!str) return '' as unknown as T\n return removeAccents(str)\n .replace(/[^a-zA-Z0-9]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))\n .replace(/^(.)/, (match) => match.toUpperCase()) as unknown as T\n}\n\nexport const toKebabCase = <T extends string>(str?: string): T => {\n if (!str) return '' as unknown as T\n return removeAccents(str)\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/[^a-zA-Z0-9]+/g, '-')\n .toLowerCase() as unknown as T\n}\n\nexport const fromKebabCase = (str?: string): string => {\n if (!str) return ''\n return str.replace(/-/g, ' ')\n}\n\nexport const toSnakeCase = <T extends string>(str?: string): T => {\n if (!str) return '' as unknown as T\n return removeAccents(str)\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/[^a-zA-Z0-9]+/g, '_')\n .toLowerCase() as unknown as T\n}\n\nexport const capitalizeFirstLetter = (str?: string) => {\n if (!str) return ''\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n\nexport const lowercaseFirstLetter = (str?: string) => {\n if (!str) return ''\n return str.charAt(0).toLowerCase() + str.slice(1)\n}\n"],"mappings":";AAAA,IAAa,KAAiB,MAC1B,EAAI,UAAU,KAAK,CAAC,CAAC,QAAQ,oBAAoB,EAAE,GA6B1C,KAAiC,MACrC,IACE,EAAc,CAAG,CAAC,CACpB,QAAQ,sBAAsB,OAAO,CAAC,CACtC,QAAQ,kBAAkB,GAAG,CAAC,CAC9B,YAAY,IAJA,IAYR,KAAiC,MACrC,IACE,EAAc,CAAG,CAAC,CACpB,QAAQ,sBAAsB,OAAO,CAAC,CACtC,QAAQ,kBAAkB,GAAG,CAAC,CAC9B,YAAY,IAJA"}
1
+ {"version":3,"file":"text-DbSEK8si.js","names":[],"sources":["../../../../packages/utils/src/text.ts"],"sourcesContent":["export const removeAccents = (str: string) =>\n str.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\n\nexport const toCamelCase = <T extends string>(str?: string): T => {\n if (!str) {\n return '' as unknown as T\n }\n return removeAccents(str)\n .replace(/[^a-zA-Z0-9]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))\n .replace(/^(.)/, (match) => match.toLowerCase()) as unknown as T\n}\n\nexport const fromCamelCase = (str?: string): string => {\n if (!str) {\n return ''\n }\n return str.replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n}\n\nexport const fromAnyCase = (str?: string): string => {\n if (!str) {\n return ''\n }\n return str\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/[-_]+/g, ' ')\n}\n\nexport const toPascalCase = <T extends string>(str?: string): T => {\n if (!str) {\n return '' as unknown as T\n }\n return removeAccents(str)\n .replace(/[^a-zA-Z0-9]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))\n .replace(/^(.)/, (match) => match.toUpperCase()) as unknown as T\n}\n\nexport const toKebabCase = <T extends string>(str?: string): T => {\n if (!str) {\n return '' as unknown as T\n }\n return removeAccents(str)\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/[^a-zA-Z0-9]+/g, '-')\n .toLowerCase() as unknown as T\n}\n\nexport const fromKebabCase = (str?: string): string => {\n if (!str) {\n return ''\n }\n return str.replace(/-/g, ' ')\n}\n\nexport const toSnakeCase = <T extends string>(str?: string): T => {\n if (!str) {\n return '' as unknown as T\n }\n return removeAccents(str)\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/[^a-zA-Z0-9]+/g, '_')\n .toLowerCase() as unknown as T\n}\n\nexport const capitalizeFirstLetter = (str?: string) => {\n if (!str) {\n return ''\n }\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n\nexport const lowercaseFirstLetter = (str?: string) => {\n if (!str) {\n return ''\n }\n return str.charAt(0).toLowerCase() + str.slice(1)\n}\n"],"mappings":";AAAA,IAAa,KAAiB,MAC1B,EAAI,UAAU,KAAK,CAAC,CAAC,QAAQ,oBAAoB,EAAE,GAqC1C,KAAiC,MACrC,IAGE,EAAc,CAAG,CAAC,CACpB,QAAQ,sBAAsB,OAAO,CAAC,CACtC,QAAQ,kBAAkB,GAAG,CAAC,CAC9B,YAAY,IALN,IAeF,KAAiC,MACrC,IAGE,EAAc,CAAG,CAAC,CACpB,QAAQ,sBAAsB,OAAO,CAAC,CACtC,QAAQ,kBAAkB,GAAG,CAAC,CAC9B,YAAY,IALN"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils-YJ0ZOLDG.js","names":[],"sources":["../../../../packages/utils/src/message.ts","../../../../packages/components/src/chat/utils.ts"],"sourcesContent":["import type { UIMessage } from 'ai'\nimport type { MediaSource, UIChatMessage } from 'models'\n\ntype MessagePart = UIMessage['parts'][number]\n\nexport function isTextPart(\n part?: MessagePart | null | undefined,\n): part is Extract<MessagePart, { type: 'text' }> {\n if (!part) {\n return false\n }\n return part.type === 'text'\n}\n\nexport function isToolPart(\n part?: MessagePart | null | undefined,\n): part is Extract<MessagePart, { type: `tool-${string}` }> {\n if (!part) {\n return false\n }\n return part.type.startsWith('tool-')\n}\n\nexport function getToolPartName(part?: MessagePart): string {\n if (!isToolPart(part)) {\n return ''\n }\n return part.type.slice('tool-'.length)\n}\n\nexport function isFilePart(\n part?: MessagePart | null | undefined,\n): part is Extract<MessagePart, { type: 'file' }> {\n if (!part) {\n return false\n }\n return part.type === 'file'\n}\n\n/**\n * Returns the persisted `MediaSource` carried by a file part, when present.\n * Uploaded attachments stash the full upload metadata (size, extension,\n * storage handle…) under `providerMetadata['8bot'].media`, which survives\n * persistence — so saved messages can surface size/details without a schema\n * change or extra request.\n */\nexport function getFilePartMedia(\n part?: MessagePart | null | undefined,\n): MediaSource | undefined {\n if (!isFilePart(part)) {\n return undefined\n }\n const container = part.providerMetadata?.['8bot'] as\n { media?: unknown } | undefined\n const media = container?.media\n return media && typeof media === 'object' && !Array.isArray(media)\n ? (media as MediaSource)\n : undefined\n}\n\nexport function isReasoningPart(\n part?: MessagePart | null | undefined,\n): part is Extract<MessagePart, { type: 'reasoning' }> {\n if (!part) {\n return false\n }\n return part.type === 'reasoning'\n}\n\nexport function hasPartText(\n part?: MessagePart | null | undefined,\n): part is Extract<MessagePart, { text: string }> {\n if (!part) {\n return false\n }\n if (isTextPart(part)) {\n return true\n }\n return (\n 'text' in part &&\n part.text !== undefined &&\n part.text !== null &&\n part.text !== ''\n )\n}\n\nexport function hasTextPart(\n message?: UIMessage | UIChatMessage | null | undefined,\n): boolean {\n if (!message) {\n return false\n }\n return (message as UIMessage).parts.some((part) => isTextPart(part))\n}\n\nexport function getTextPart(\n message?: UIMessage | UIChatMessage | null | undefined,\n): string | undefined {\n if (!message) {\n return undefined\n }\n const parts = (message as UIMessage).parts\n if (!Array.isArray(parts)) {\n return undefined\n }\n const textPart = parts.find((part) => isTextPart(part))\n return textPart?.text\n}\n\nexport function getMessageText(\n message?: UIMessage | UIChatMessage | null | undefined,\n): string {\n if (!message) {\n return ''\n }\n const parts = (message as UIMessage).parts\n if (!Array.isArray(parts)) {\n return ''\n }\n return parts\n .filter((p): p is Extract<MessagePart, { type: 'text' }> =>\n isTextPart(p),\n )\n .map((p) => p.text)\n .join('')\n}\n","import type { UIMessage } from 'ai'\nimport {\n isTextPart,\n isFilePart,\n isToolPart,\n isReasoningPart,\n hasPartText,\n hasTextPart,\n getTextPart,\n getMessageText,\n} from 'utils'\n\nexport {\n isTextPart,\n isFilePart,\n isToolPart,\n isReasoningPart,\n hasPartText,\n hasTextPart,\n getTextPart,\n getMessageText,\n}\n\n/**\n * Merges consecutive text parts into a single text part.\n * Claude (and other models) often produce multiple text parts during streaming\n * that should logically be a single block of text.\n */\nexport function mergeConsecutiveTextParts(\n parts: UIMessage['parts'],\n): UIMessage['parts'] {\n const merged: UIMessage['parts'] = []\n for (const part of parts) {\n if (!isTextPart(part)) {\n merged.push(part)\n continue\n }\n const prev = merged[merged.length - 1]\n if (prev && isTextPart(prev)) {\n merged[merged.length - 1] = { ...prev, text: prev.text + part.text }\n } else {\n merged.push(part)\n }\n }\n return merged\n}\n\nexport function isStreamingPart(\n part: UIMessage['parts'][number] | null | undefined,\n): part is Extract<UIMessage['parts'][number], { streaming?: boolean }> {\n if (!part) return false\n if ('state' in part) {\n return part.state === 'streaming' || part.state === 'input-streaming'\n }\n return false\n}\n\n/**\n * States a tool part goes through when it needs the user's approval. They are\n * rendered by `PkToolApprovalCard` whatever the tool is, so the decision (and\n * its outcome) stays visible in the transcript.\n */\nconst TOOL_APPROVAL_STATES = new Set([\n 'approval-requested',\n 'approval-responded',\n 'output-denied',\n])\n\nexport function isToolApprovalPart(\n part: UIMessage['parts'][number] | null | undefined,\n): boolean {\n if (!isToolPart(part)) {\n return false\n }\n if (TOOL_APPROVAL_STATES.has(part.state)) {\n return true\n }\n // An executed (or errored) call that went through the gate keeps its\n // verdict in `approval`: the card stays in the transcript, so the user's\n // decision remains visible in the chat and in the log viewers (parity\n // with requestConfirm, whose 'confirmed' output is persisted).\n return (part as { approval?: unknown }).approval != null\n}\n\n/**\n * The client-side tool the model uses to have an action it described approved.\n * It predates the SDK's approval gate and keeps its own round-trip (it resolves\n * through `addToolOutput`), but it asks the user the very same question, so it\n * shares `PkToolApprovalCard` instead of having a card of its own.\n */\nexport const CONFIRM_TOOL_NAME = 'requestConfirm'\n\nexport function isToolConfirmPart(\n part: UIMessage['parts'][number] | null | undefined,\n): boolean {\n return isToolPart(part) && part.type === `tool-${CONFIRM_TOOL_NAME}`\n}\n\n/** True for any part the confirmation card is responsible for. */\nexport function isConfirmationCardPart(\n part: UIMessage['parts'][number] | null | undefined,\n): boolean {\n return isToolApprovalPart(part) || isToolConfirmPart(part)\n}\n\n/** The id of the pending approval request on a tool part, if any. */\nexport function getToolApprovalId(\n part: UIMessage['parts'][number] | null | undefined,\n): string | undefined {\n if (!isToolPart(part)) {\n return undefined\n }\n return (part as { approval?: { id?: string } }).approval?.id\n}\n\nexport function getPartState(\n part: UIMessage['parts'][number] | null | undefined,\n): string | undefined {\n if (!part) return undefined\n if ('state' in part) {\n return part.state\n }\n return undefined\n}\n\nexport function isLoadingState(state?: string): boolean {\n if (!state) return false\n return ['streaming'].includes(state)\n}\n\nexport function getContrast(hexcolor: string = '000000'): 'black' | 'white' {\n let hex = hexcolor.replace('#', '')\n\n // Expand 3-character hex to 6-character (e.g., #ccc -> #cccccc)\n if (hex.length === 3) {\n hex = hex\n .split('')\n .map((char) => char + char)\n .join('')\n }\n\n // WCAG relative luminance\n const r = parseInt(hex.substring(0, 2), 16) / 255\n const g = parseInt(hex.substring(2, 4), 16) / 255\n const b = parseInt(hex.substring(4, 6), 16) / 255\n\n const linearize = (c: number) =>\n c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4\n\n const luminance =\n 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b)\n\n return luminance > 0.179 ? 'black' : 'white'\n}\n\n/**\n * Resolves the contrast color based on the user's `textColor` preference.\n * Falls back to WCAG auto-detection via `getContrast` when set to `'auto'` or `undefined`.\n */\nexport function resolveContrastColor(\n textColor: 'auto' | 'white' | 'black' | undefined,\n mainColor: string | undefined,\n): 'black' | 'white' {\n if (textColor === 'white' || textColor === 'black') {\n return textColor\n }\n return getContrast(mainColor)\n}\n\n/**\n * Formats a duration in milliseconds using the i18n `seconds` number format\n * (e.g. \"12,4 secondi\" / \"12.4 seconds\"). Returns undefined for durations\n * that would render as \"0 seconds\" (less than 0.05s).\n */\nexport function formatDuration(\n $n: (value: number, format: string) => string,\n ms?: number,\n): string | undefined {\n if (ms === undefined || ms < 50) {\n return undefined\n }\n return $n(ms / 1000, 'seconds')\n}\n\n/**\n * Stringifies a tool payload for the raw fallback view. Returns undefined for\n * empty values so the caller can skip rendering the block entirely.\n */\nexport function stringifyPayload(value: unknown): string | undefined {\n if (value === undefined) {\n return undefined\n }\n if (typeof value === 'string') {\n return value.trim() || undefined\n }\n try {\n const json = JSON.stringify(value, null, 2)\n return json === '{}' || json === '[]' ? undefined : json\n } catch {\n return undefined\n }\n}\n\n/**\n * True when a tool payload carries something worth rendering, so a caller can\n * skip the block without stringifying the value twice.\n */\nexport function hasPayload(value: unknown): boolean {\n return stringifyPayload(value) !== undefined\n}\n\n/**\n * Turns the answers of a form into the sentence the caller would have said.\n *\n * On a call the tool loop is over by the time the form is on screen, so the\n * answers go back to the agent as a user message (see `sendUserMessage` in\n * `useVoiceSession`). Each answer is paired with its question, because that is\n * how a person would say it and because the agent hears it with no widget\n * attached.\n */\nexport function formAnswerAsSpoken(\n part: unknown,\n answer: string | { answers: { id: string; value: unknown }[] },\n): string {\n const input = (\n part as {\n input?: {\n steps?: { id: string; question?: string }[]\n question?: string\n }\n }\n )?.input\n\n if (typeof answer === 'string') {\n const question = input?.question ?? input?.steps?.[0]?.question\n return question ? `${question} ${answer}` : answer\n }\n\n const questionById = new Map(\n (input?.steps ?? []).map((step) => [step.id, step.question]),\n )\n const lines = answer.answers\n .filter(\n ({ value }) =>\n value !== null &&\n value !== '' &&\n !(Array.isArray(value) && !value.length),\n )\n .map(({ id, value }) => {\n const said = Array.isArray(value) ? value.join(', ') : String(value)\n const question = questionById.get(id)\n return question ? `${question} ${said}` : said\n })\n\n return lines.join('. ')\n}\n\n/**\n * The choices of a form step, as the radio and checkbox editors take them.\n *\n * The `value` is the LABEL and not the position, because it is what travels\n * back to the model as the answer: it reads the words it wrote, not an index.\n * Nothing here caps the list, and nothing should: the number of options an\n * agent configures is advice to the model, so a step can legitimately carry\n * more (see `showForm.tool.ts`).\n */\nexport function formStepOptions(\n step: { options?: { label: string; description?: string }[] } | undefined,\n): { label: string; value: string; description?: string }[] {\n if (!step?.options) {\n return []\n }\n return step.options.map((option) => ({\n label: option.label,\n value: option.label,\n description: option.description,\n }))\n}\n\n/**\n * Spreads the answers a form comes back with onto one slot PER STEP.\n *\n * A form's answers travel paired with step ids, and the tool schema does not\n * enforce that those ids are unique: a `.refine()` there would refuse the whole\n * form over a duplicate, which is the failure the schema was just cured of (see\n * the gotchas entry \"A configurable cap does not belong in an inputSchema\").\n * So the duplicate has to be survivable here. Keyed by id, two steps sharing\n * one collapsed onto a single answer: the second question showed the first\n * one's reply, and submitting sent that reply twice. Keyed by position, each\n * step keeps its own.\n *\n * A duplicated id restores the same incoming value to every step claiming it,\n * which is as much as the payload allows: the ids are all it says.\n */\nexport function formAnswerSlots(\n steps: { id: string }[],\n output: unknown,\n): Record<number, unknown> {\n const slots: Record<number, unknown> = {}\n if (output === undefined || output === null) {\n return slots\n }\n // A legacy single-choice answer is the plain string, and it can only\n // belong to a single-step form.\n if (typeof output === 'string') {\n if (steps.length === 1) {\n slots[0] = output\n }\n return slots\n }\n const assign = (id: string, value: unknown) => {\n steps.forEach((step, index) => {\n if (step.id === id) {\n slots[index] = value\n }\n })\n }\n const list = (output as { answers?: unknown }).answers\n if (Array.isArray(list)) {\n for (const answer of list as { id?: unknown; value?: unknown }[]) {\n if (typeof answer?.id === 'string') {\n assign(answer.id, answer.value)\n }\n }\n return slots\n }\n // Forms answered on a platform channel (the Teams modal) come back as a\n // flat record keyed by step id.\n for (const [id, value] of Object.entries(\n output as Record<string, unknown>,\n )) {\n if (value !== undefined) {\n assign(id, value)\n }\n }\n return slots\n}\n\n// Provider-native web search tool part types\nexport const WEB_SEARCH_TOOL_TYPES = [\n 'tool-perplexity_search',\n 'tool-parallel_search',\n 'tool-web_search',\n 'tool-google_search',\n]\n\n// Tool part types with a dedicated rich rendering in PkChatbotStepToolDetail\nconst RICH_DETAIL_TOOL_TYPES = new Set([\n 'tool-searchInKnowledgeBase',\n 'tool-retrieveRevisedAnswers',\n 'tool-expandChunkContext',\n 'tool-readDocumentFile',\n 'tool-getWeather',\n 'tool-geocode',\n 'tool-recallUserMemory',\n 'tool-saveUserMemory',\n ...WEB_SEARCH_TOOL_TYPES,\n])\n\nexport function hasRichToolDetail(\n part?: UIMessage['parts'][number] | null,\n): boolean {\n return isToolPart(part) && RICH_DETAIL_TOOL_TYPES.has(part.type)\n}\n\nconst asRecord = (value: unknown): Record<string, unknown> | undefined =>\n value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n\nconst pickString = (\n record: Record<string, unknown> | undefined,\n ...keys: string[]\n): string | undefined => {\n for (const key of keys) {\n const value = record?.[key]\n if (typeof value === 'string' && value.trim()) {\n return value\n }\n }\n return undefined\n}\n\n/**\n * Returns a short inline summary for a tool part (search queries, location,\n * document name, ...) to be shown next to the step label without expanding\n * the step body.\n */\nexport function getToolPartSummary(\n part?: UIMessage['parts'][number] | null,\n): string | undefined {\n if (!isToolPart(part)) {\n return undefined\n }\n const input = asRecord('input' in part ? part.input : undefined)\n const output = asRecord('output' in part ? part.output : undefined)\n if (\n part.type === 'tool-searchInKnowledgeBase' ||\n WEB_SEARCH_TOOL_TYPES.includes(part.type)\n ) {\n const queries = input?.queries\n if (Array.isArray(queries)) {\n const valid = queries.filter(\n (query): query is string =>\n typeof query === 'string' && Boolean(query.trim()),\n )\n return valid.length ? valid.join(' · ') : undefined\n }\n return pickString(input, 'query', 'objective')\n }\n if (part.type === 'tool-retrieveRevisedAnswers') {\n return pickString(input, 'query')\n }\n if (part.type === 'tool-getWeather') {\n return (\n pickString(output, 'location') ?? pickString(input, 'locationName')\n )\n }\n if (part.type === 'tool-geocode') {\n return pickString(input, 'locationName')\n }\n if (part.type === 'tool-expandChunkContext') {\n return pickString(output, 'documentName')\n }\n if (part.type === 'tool-readDocumentFile') {\n return pickString(output, 'name')\n }\n if (part.type === 'tool-recallUserMemory') {\n return pickString(input, 'query')\n }\n if (part.type === 'tool-saveUserMemory') {\n return pickString(input, 'content', 'query')\n }\n return undefined\n}\n\n// Get part icon\nexport function getPartIcon(\n part?: UIMessage['parts'][number] | null,\n): string | undefined {\n if (isToolPart(part)) {\n if (part.type.includes('tool-subagent')) {\n return 'ri:robot-2-line'\n }\n if (part.type === 'tool-runWorker') {\n return 'ri:flow-chart'\n }\n if (part.type === 'tool-fetchTeamsChannelHistory') {\n return 'ri:chat-history-line'\n }\n if (part.type.includes('tool-mcp')) {\n return 'mcp'\n }\n if (part.type === 'tool-retrieveRevisedAnswers') {\n return 'ri:file-edit-line'\n }\n if (part.type === 'tool-searchInKnowledgeBase') {\n return 'ri:search-line'\n }\n if (part.type === 'tool-expandChunkContext') {\n return 'ri:file-search-line'\n }\n if (part.type === 'tool-readDocumentFile') {\n return 'ri:file-text-line'\n }\n if (part.type === 'tool-geocode') {\n return 'ri:map-2-line'\n }\n if (part.type === 'tool-getWeather') {\n return 'ri:sun-cloudy-line'\n }\n if (part.type === 'tool-recallUserMemory') {\n return 'ri:brain-line'\n }\n if (part.type === 'tool-saveUserMemory') {\n return 'ri:save-3-line'\n }\n if (part.type === 'tool-showWeather') {\n return 'ri:sun-line'\n }\n if (part.type === 'tool-showDiagram') {\n return 'ri:flow-chart'\n }\n if (part.type === 'tool-showSources') {\n return 'ri:book-2-line'\n }\n if (part.type === 'tool-showForm') {\n return 'ri:survey-line'\n }\n if (part.type === 'tool-showMultipleChoice') {\n return 'ri:checkbox-multiple-line'\n }\n if (part.type === 'tool-showArtifact') {\n return 'ri:file-code-line'\n }\n if (part.type === 'tool-showEmail') {\n return 'ri:mail-line'\n }\n if (part.type === 'tool-showMessage') {\n return 'ri:chat-1-line'\n }\n if (part.type === 'tool-showWebPages') {\n return 'ri:pages-line'\n }\n if (part.type === 'tool-showProductList') {\n return 'ri:shopping-bag-line'\n }\n if (part.type === 'tool-showContactForm') {\n return 'ri:send-plane-2-line'\n }\n if (part.type === 'tool-showCalendarEvent') {\n return 'ri:calendar-event-line'\n }\n if (part.type === 'tool-showComparison') {\n return 'ri:scales-line'\n }\n if (part.type === 'tool-showLocation') {\n return 'ri:map-pin-line'\n }\n if (part.type === 'tool-showQrCode') {\n return 'ri:qr-code-line'\n }\n if (part.type === 'tool-showImageGallery') {\n return 'ri:image-line'\n }\n if (part.type === 'tool-showVideo') {\n return 'ri:film-line'\n }\n if (part.type === 'tool-showSuggestedReply') {\n return 'ri:corner-down-right-line'\n }\n if (part.type === 'tool-requestGeolocation') {\n return 'ri:map-pin-user-line'\n }\n if (\n part.type === 'tool-perplexity_search' ||\n part.type === 'tool-parallel_search' ||\n part.type === 'tool-web_search' ||\n part.type === 'tool-google_search'\n ) {\n return 'ri:global-line'\n }\n return 'ri:tools-line'\n }\n if (isReasoningPart(part)) {\n return 'ri:lightbulb-line'\n }\n if (isTextPart(part)) {\n return 'ri:double-quotes-r'\n }\n return undefined\n}\n\n// Get part label\nexport function getToolPartLabel(\n $t: (key: string) => string,\n part?: UIMessage['parts'][number] | null,\n): string | undefined {\n if (isToolPart(part)) {\n if (part.type.includes('tool-subagent')) {\n return $t(`messagePart.runSubagent`)\n }\n if (part.type === 'tool-runWorker') {\n return $t(`messagePart.runWorker`)\n }\n if (part.type === 'tool-fetchTeamsChannelHistory') {\n return $t(`messagePart.fetchTeamsChannelHistory`)\n }\n if (part.type === 'tool-retrieveRevisedAnswers') {\n return $t(`messagePart.revisedAnswers`)\n }\n if (part.type === 'tool-searchInKnowledgeBase') {\n return $t(`messagePart.searchingDocuments`)\n }\n if (part.type === 'tool-expandChunkContext') {\n return $t(`messagePart.expandChunkContext`)\n }\n if (part.type === 'tool-readDocumentFile') {\n return $t(`messagePart.readDocumentFile`)\n }\n if (part.type === 'tool-geocode') {\n return $t(`messagePart.geocode`)\n }\n if (part.type === 'tool-getWeather') {\n return $t(`messagePart.getWeather`)\n }\n if (part.type === 'tool-recallUserMemory') {\n return $t(`messagePart.recallUserMemory`)\n }\n if (part.type === 'tool-saveUserMemory') {\n return $t(`messagePart.saveUserMemory`)\n }\n if (part.type === 'tool-showWeather') {\n return $t(`messagePart.showWeather`)\n }\n if (part.type === 'tool-showForm') {\n return $t(`messagePart.showForm`)\n }\n if (part.type === 'tool-showDiagram') {\n return $t(`messagePart.showDiagram`)\n }\n if (part.type === 'tool-showSources') {\n return $t(`messagePart.showSources`)\n }\n if (part.type === 'tool-showMultipleChoice') {\n return $t(`messagePart.showMultipleChoice`)\n }\n if (part.type === 'tool-showArtifact') {\n return $t(`messagePart.showArtifact`)\n }\n if (part.type === 'tool-showEmail') {\n return $t(`messagePart.showEmail`)\n }\n if (part.type === 'tool-showMessage') {\n return $t(`messagePart.showMessage`)\n }\n if (part.type === 'tool-showWebPages') {\n return $t(`messagePart.showWebPages`)\n }\n if (part.type === 'tool-showProducts') {\n return $t(`messagePart.showProducts`)\n }\n if (part.type === 'tool-showContactForm') {\n return $t(`messagePart.showContactForm`)\n }\n if (part.type === 'tool-showCalendarEvent') {\n return $t(`messagePart.showCalendarEvent`)\n }\n if (part.type === 'tool-showComparison') {\n return $t(`messagePart.showComparison`)\n }\n if (part.type === 'tool-showLocation') {\n return $t(`messagePart.showLocation`)\n }\n if (part.type === 'tool-showQrCode') {\n return $t(`messagePart.showQrCode`)\n }\n if (part.type === 'tool-showImageGallery') {\n return $t(`messagePart.showImageGallery`)\n }\n if (part.type === 'tool-showVideo') {\n return $t(`messagePart.showVideo`)\n }\n if (part.type === 'tool-showSuggestedReply') {\n return $t(`messagePart.showSuggestedReply`)\n }\n if (part.type === 'tool-requestGeolocation') {\n return $t(`messagePart.requestGeolocation`)\n }\n if (WEB_SEARCH_TOOL_TYPES.includes(part.type)) {\n return $t(`messagePart.webSearch`)\n }\n return $t(`messagePart.tool`)\n }\n if (isReasoningPart(part)) {\n return $t(`messagePart.reasoning`)\n }\n return $t(`messagePart.streaming`)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"utils-YJ0ZOLDG.js","names":[],"sources":["../../../../packages/utils/src/message.ts","../../../../packages/components/src/chat/utils.ts"],"sourcesContent":["import type { UIMessage } from 'ai'\nimport type { MediaSource, UIChatMessage } from 'models'\n\ntype MessagePart = UIMessage['parts'][number]\n\nexport function isTextPart(\n part?: MessagePart | null | undefined,\n): part is Extract<MessagePart, { type: 'text' }> {\n if (!part) {\n return false\n }\n return part.type === 'text'\n}\n\nexport function isToolPart(\n part?: MessagePart | null | undefined,\n): part is Extract<MessagePart, { type: `tool-${string}` }> {\n if (!part) {\n return false\n }\n return part.type.startsWith('tool-')\n}\n\nexport function getToolPartName(part?: MessagePart): string {\n if (!isToolPart(part)) {\n return ''\n }\n return part.type.slice('tool-'.length)\n}\n\nexport function isFilePart(\n part?: MessagePart | null | undefined,\n): part is Extract<MessagePart, { type: 'file' }> {\n if (!part) {\n return false\n }\n return part.type === 'file'\n}\n\n/**\n * Returns the persisted `MediaSource` carried by a file part, when present.\n * Uploaded attachments stash the full upload metadata (size, extension,\n * storage handle…) under `providerMetadata['8bot'].media`, which survives\n * persistence — so saved messages can surface size/details without a schema\n * change or extra request.\n */\nexport function getFilePartMedia(\n part?: MessagePart | null | undefined,\n): MediaSource | undefined {\n if (!isFilePart(part)) {\n return undefined\n }\n const container = part.providerMetadata?.['8bot'] as\n { media?: unknown } | undefined\n const media = container?.media\n return media && typeof media === 'object' && !Array.isArray(media)\n ? (media as MediaSource)\n : undefined\n}\n\nexport function isReasoningPart(\n part?: MessagePart | null | undefined,\n): part is Extract<MessagePart, { type: 'reasoning' }> {\n if (!part) {\n return false\n }\n return part.type === 'reasoning'\n}\n\nexport function hasPartText(\n part?: MessagePart | null | undefined,\n): part is Extract<MessagePart, { text: string }> {\n if (!part) {\n return false\n }\n if (isTextPart(part)) {\n return true\n }\n return (\n 'text' in part &&\n part.text !== undefined &&\n part.text !== null &&\n part.text !== ''\n )\n}\n\nexport function hasTextPart(\n message?: UIMessage | UIChatMessage | null | undefined,\n): boolean {\n if (!message) {\n return false\n }\n return (message as UIMessage).parts.some((part) => isTextPart(part))\n}\n\nexport function getTextPart(\n message?: UIMessage | UIChatMessage | null | undefined,\n): string | undefined {\n if (!message) {\n return undefined\n }\n const parts = (message as UIMessage).parts\n if (!Array.isArray(parts)) {\n return undefined\n }\n const textPart = parts.find((part) => isTextPart(part))\n return textPart?.text\n}\n\nexport function getMessageText(\n message?: UIMessage | UIChatMessage | null | undefined,\n): string {\n if (!message) {\n return ''\n }\n const parts = (message as UIMessage).parts\n if (!Array.isArray(parts)) {\n return ''\n }\n return parts\n .filter((p): p is Extract<MessagePart, { type: 'text' }> =>\n isTextPart(p),\n )\n .map((p) => p.text)\n .join('')\n}\n","import type { UIMessage } from 'ai'\nimport {\n isTextPart,\n isFilePart,\n isToolPart,\n isReasoningPart,\n hasPartText,\n hasTextPart,\n getTextPart,\n getMessageText,\n} from 'utils'\n\nexport {\n isTextPart,\n isFilePart,\n isToolPart,\n isReasoningPart,\n hasPartText,\n hasTextPart,\n getTextPart,\n getMessageText,\n}\n\n/**\n * Merges consecutive text parts into a single text part.\n * Claude (and other models) often produce multiple text parts during streaming\n * that should logically be a single block of text.\n */\nexport function mergeConsecutiveTextParts(\n parts: UIMessage['parts'],\n): UIMessage['parts'] {\n const merged: UIMessage['parts'] = []\n for (const part of parts) {\n if (!isTextPart(part)) {\n merged.push(part)\n continue\n }\n const prev = merged[merged.length - 1]\n if (prev && isTextPart(prev)) {\n merged[merged.length - 1] = { ...prev, text: prev.text + part.text }\n } else {\n merged.push(part)\n }\n }\n return merged\n}\n\nexport function isStreamingPart(\n part: UIMessage['parts'][number] | null | undefined,\n): part is Extract<UIMessage['parts'][number], { streaming?: boolean }> {\n if (!part) {\n return false\n }\n if ('state' in part) {\n return part.state === 'streaming' || part.state === 'input-streaming'\n }\n return false\n}\n\n/**\n * States a tool part goes through when it needs the user's approval. They are\n * rendered by `PkToolApprovalCard` whatever the tool is, so the decision (and\n * its outcome) stays visible in the transcript.\n */\nconst TOOL_APPROVAL_STATES = new Set([\n 'approval-requested',\n 'approval-responded',\n 'output-denied',\n])\n\nexport function isToolApprovalPart(\n part: UIMessage['parts'][number] | null | undefined,\n): boolean {\n if (!isToolPart(part)) {\n return false\n }\n if (TOOL_APPROVAL_STATES.has(part.state)) {\n return true\n }\n // An executed (or errored) call that went through the gate keeps its\n // verdict in `approval`: the card stays in the transcript, so the user's\n // decision remains visible in the chat and in the log viewers (parity\n // with requestConfirm, whose 'confirmed' output is persisted).\n return (part as { approval?: unknown }).approval != null\n}\n\n/**\n * The client-side tool the model uses to have an action it described approved.\n * It predates the SDK's approval gate and keeps its own round-trip (it resolves\n * through `addToolOutput`), but it asks the user the very same question, so it\n * shares `PkToolApprovalCard` instead of having a card of its own.\n */\nexport const CONFIRM_TOOL_NAME = 'requestConfirm'\n\nexport function isToolConfirmPart(\n part: UIMessage['parts'][number] | null | undefined,\n): boolean {\n return isToolPart(part) && part.type === `tool-${CONFIRM_TOOL_NAME}`\n}\n\n/** True for any part the confirmation card is responsible for. */\nexport function isConfirmationCardPart(\n part: UIMessage['parts'][number] | null | undefined,\n): boolean {\n return isToolApprovalPart(part) || isToolConfirmPart(part)\n}\n\n/** The id of the pending approval request on a tool part, if any. */\nexport function getToolApprovalId(\n part: UIMessage['parts'][number] | null | undefined,\n): string | undefined {\n if (!isToolPart(part)) {\n return undefined\n }\n return (part as { approval?: { id?: string } }).approval?.id\n}\n\nexport function getPartState(\n part: UIMessage['parts'][number] | null | undefined,\n): string | undefined {\n if (!part) {\n return undefined\n }\n if ('state' in part) {\n return part.state\n }\n return undefined\n}\n\nexport function isLoadingState(state?: string): boolean {\n if (!state) {\n return false\n }\n return ['streaming'].includes(state)\n}\n\nexport function getContrast(hexcolor: string = '000000'): 'black' | 'white' {\n let hex = hexcolor.replace('#', '')\n\n // Expand 3-character hex to 6-character (e.g., #ccc -> #cccccc)\n if (hex.length === 3) {\n hex = hex\n .split('')\n .map((char) => char + char)\n .join('')\n }\n\n // WCAG relative luminance\n const r = parseInt(hex.substring(0, 2), 16) / 255\n const g = parseInt(hex.substring(2, 4), 16) / 255\n const b = parseInt(hex.substring(4, 6), 16) / 255\n\n const linearize = (c: number) =>\n c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4\n\n const luminance =\n 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b)\n\n return luminance > 0.179 ? 'black' : 'white'\n}\n\n/**\n * Resolves the contrast color based on the user's `textColor` preference.\n * Falls back to WCAG auto-detection via `getContrast` when set to `'auto'` or `undefined`.\n */\nexport function resolveContrastColor(\n textColor: 'auto' | 'white' | 'black' | undefined,\n mainColor: string | undefined,\n): 'black' | 'white' {\n if (textColor === 'white' || textColor === 'black') {\n return textColor\n }\n return getContrast(mainColor)\n}\n\n/**\n * Formats a duration in milliseconds using the i18n `seconds` number format\n * (e.g. \"12,4 secondi\" / \"12.4 seconds\"). Returns undefined for durations\n * that would render as \"0 seconds\" (less than 0.05s).\n */\nexport function formatDuration(\n $n: (value: number, format: string) => string,\n ms?: number,\n): string | undefined {\n if (ms === undefined || ms < 50) {\n return undefined\n }\n return $n(ms / 1000, 'seconds')\n}\n\n/**\n * Stringifies a tool payload for the raw fallback view. Returns undefined for\n * empty values so the caller can skip rendering the block entirely.\n */\nexport function stringifyPayload(value: unknown): string | undefined {\n if (value === undefined) {\n return undefined\n }\n if (typeof value === 'string') {\n return value.trim() || undefined\n }\n try {\n const json = JSON.stringify(value, null, 2)\n return json === '{}' || json === '[]' ? undefined : json\n } catch {\n return undefined\n }\n}\n\n/**\n * True when a tool payload carries something worth rendering, so a caller can\n * skip the block without stringifying the value twice.\n */\nexport function hasPayload(value: unknown): boolean {\n return stringifyPayload(value) !== undefined\n}\n\n/**\n * Turns the answers of a form into the sentence the caller would have said.\n *\n * On a call the tool loop is over by the time the form is on screen, so the\n * answers go back to the agent as a user message (see `sendUserMessage` in\n * `useVoiceSession`). Each answer is paired with its question, because that is\n * how a person would say it and because the agent hears it with no widget\n * attached.\n */\nexport function formAnswerAsSpoken(\n part: unknown,\n answer: string | { answers: { id: string; value: unknown }[] },\n): string {\n const input = (\n part as {\n input?: {\n steps?: { id: string; question?: string }[]\n question?: string\n }\n }\n )?.input\n\n if (typeof answer === 'string') {\n const question = input?.question ?? input?.steps?.[0]?.question\n return question ? `${question} ${answer}` : answer\n }\n\n const questionById = new Map(\n (input?.steps ?? []).map((step) => [step.id, step.question]),\n )\n const lines = answer.answers\n .filter(\n ({ value }) =>\n value !== null &&\n value !== '' &&\n !(Array.isArray(value) && !value.length),\n )\n .map(({ id, value }) => {\n const said = Array.isArray(value) ? value.join(', ') : String(value)\n const question = questionById.get(id)\n return question ? `${question} ${said}` : said\n })\n\n return lines.join('. ')\n}\n\n/**\n * The choices of a form step, as the radio and checkbox editors take them.\n *\n * The `value` is the LABEL and not the position, because it is what travels\n * back to the model as the answer: it reads the words it wrote, not an index.\n * Nothing here caps the list, and nothing should: the number of options an\n * agent configures is advice to the model, so a step can legitimately carry\n * more (see `showForm.tool.ts`).\n */\nexport function formStepOptions(\n step: { options?: { label: string; description?: string }[] } | undefined,\n): { label: string; value: string; description?: string }[] {\n if (!step?.options) {\n return []\n }\n return step.options.map((option) => ({\n label: option.label,\n value: option.label,\n description: option.description,\n }))\n}\n\n/**\n * Spreads the answers a form comes back with onto one slot PER STEP.\n *\n * A form's answers travel paired with step ids, and the tool schema does not\n * enforce that those ids are unique: a `.refine()` there would refuse the whole\n * form over a duplicate, which is the failure the schema was just cured of (see\n * the gotchas entry \"A configurable cap does not belong in an inputSchema\").\n * So the duplicate has to be survivable here. Keyed by id, two steps sharing\n * one collapsed onto a single answer: the second question showed the first\n * one's reply, and submitting sent that reply twice. Keyed by position, each\n * step keeps its own.\n *\n * A duplicated id restores the same incoming value to every step claiming it,\n * which is as much as the payload allows: the ids are all it says.\n */\nexport function formAnswerSlots(\n steps: { id: string }[],\n output: unknown,\n): Record<number, unknown> {\n const slots: Record<number, unknown> = {}\n if (output === undefined || output === null) {\n return slots\n }\n // A legacy single-choice answer is the plain string, and it can only\n // belong to a single-step form.\n if (typeof output === 'string') {\n if (steps.length === 1) {\n slots[0] = output\n }\n return slots\n }\n const assign = (id: string, value: unknown) => {\n steps.forEach((step, index) => {\n if (step.id === id) {\n slots[index] = value\n }\n })\n }\n const list = (output as { answers?: unknown }).answers\n if (Array.isArray(list)) {\n for (const answer of list as { id?: unknown; value?: unknown }[]) {\n if (typeof answer?.id === 'string') {\n assign(answer.id, answer.value)\n }\n }\n return slots\n }\n // Forms answered on a platform channel (the Teams modal) come back as a\n // flat record keyed by step id.\n for (const [id, value] of Object.entries(\n output as Record<string, unknown>,\n )) {\n if (value !== undefined) {\n assign(id, value)\n }\n }\n return slots\n}\n\n// Provider-native web search tool part types\nexport const WEB_SEARCH_TOOL_TYPES = [\n 'tool-perplexity_search',\n 'tool-parallel_search',\n 'tool-web_search',\n 'tool-google_search',\n]\n\n// Tool part types with a dedicated rich rendering in PkChatbotStepToolDetail\nconst RICH_DETAIL_TOOL_TYPES = new Set([\n 'tool-searchInKnowledgeBase',\n 'tool-retrieveRevisedAnswers',\n 'tool-expandChunkContext',\n 'tool-readDocumentFile',\n 'tool-getWeather',\n 'tool-geocode',\n 'tool-recallUserMemory',\n 'tool-saveUserMemory',\n ...WEB_SEARCH_TOOL_TYPES,\n])\n\nexport function hasRichToolDetail(\n part?: UIMessage['parts'][number] | null,\n): boolean {\n return isToolPart(part) && RICH_DETAIL_TOOL_TYPES.has(part.type)\n}\n\nconst asRecord = (value: unknown): Record<string, unknown> | undefined =>\n value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n\nconst pickString = (\n record: Record<string, unknown> | undefined,\n ...keys: string[]\n): string | undefined => {\n for (const key of keys) {\n const value = record?.[key]\n if (typeof value === 'string' && value.trim()) {\n return value\n }\n }\n return undefined\n}\n\n/**\n * Returns a short inline summary for a tool part (search queries, location,\n * document name, ...) to be shown next to the step label without expanding\n * the step body.\n */\nexport function getToolPartSummary(\n part?: UIMessage['parts'][number] | null,\n): string | undefined {\n if (!isToolPart(part)) {\n return undefined\n }\n const input = asRecord('input' in part ? part.input : undefined)\n const output = asRecord('output' in part ? part.output : undefined)\n if (\n part.type === 'tool-searchInKnowledgeBase' ||\n WEB_SEARCH_TOOL_TYPES.includes(part.type)\n ) {\n const queries = input?.queries\n if (Array.isArray(queries)) {\n const valid = queries.filter(\n (query): query is string =>\n typeof query === 'string' && Boolean(query.trim()),\n )\n return valid.length ? valid.join(' · ') : undefined\n }\n return pickString(input, 'query', 'objective')\n }\n if (part.type === 'tool-retrieveRevisedAnswers') {\n return pickString(input, 'query')\n }\n if (part.type === 'tool-getWeather') {\n return (\n pickString(output, 'location') ?? pickString(input, 'locationName')\n )\n }\n if (part.type === 'tool-geocode') {\n return pickString(input, 'locationName')\n }\n if (part.type === 'tool-expandChunkContext') {\n return pickString(output, 'documentName')\n }\n if (part.type === 'tool-readDocumentFile') {\n return pickString(output, 'name')\n }\n if (part.type === 'tool-recallUserMemory') {\n return pickString(input, 'query')\n }\n if (part.type === 'tool-saveUserMemory') {\n return pickString(input, 'content', 'query')\n }\n return undefined\n}\n\n// Get part icon\nexport function getPartIcon(\n part?: UIMessage['parts'][number] | null,\n): string | undefined {\n if (isToolPart(part)) {\n if (part.type.includes('tool-subagent')) {\n return 'ri:robot-2-line'\n }\n if (part.type === 'tool-runWorker') {\n return 'ri:flow-chart'\n }\n if (part.type === 'tool-fetchTeamsChannelHistory') {\n return 'ri:chat-history-line'\n }\n if (part.type.includes('tool-mcp')) {\n return 'mcp'\n }\n if (part.type === 'tool-retrieveRevisedAnswers') {\n return 'ri:file-edit-line'\n }\n if (part.type === 'tool-searchInKnowledgeBase') {\n return 'ri:search-line'\n }\n if (part.type === 'tool-expandChunkContext') {\n return 'ri:file-search-line'\n }\n if (part.type === 'tool-readDocumentFile') {\n return 'ri:file-text-line'\n }\n if (part.type === 'tool-geocode') {\n return 'ri:map-2-line'\n }\n if (part.type === 'tool-getWeather') {\n return 'ri:sun-cloudy-line'\n }\n if (part.type === 'tool-recallUserMemory') {\n return 'ri:brain-line'\n }\n if (part.type === 'tool-saveUserMemory') {\n return 'ri:save-3-line'\n }\n if (part.type === 'tool-showWeather') {\n return 'ri:sun-line'\n }\n if (part.type === 'tool-showDiagram') {\n return 'ri:flow-chart'\n }\n if (part.type === 'tool-showSources') {\n return 'ri:book-2-line'\n }\n if (part.type === 'tool-showForm') {\n return 'ri:survey-line'\n }\n if (part.type === 'tool-showMultipleChoice') {\n return 'ri:checkbox-multiple-line'\n }\n if (part.type === 'tool-showArtifact') {\n return 'ri:file-code-line'\n }\n if (part.type === 'tool-showEmail') {\n return 'ri:mail-line'\n }\n if (part.type === 'tool-showMessage') {\n return 'ri:chat-1-line'\n }\n if (part.type === 'tool-showWebPages') {\n return 'ri:pages-line'\n }\n if (part.type === 'tool-showProductList') {\n return 'ri:shopping-bag-line'\n }\n if (part.type === 'tool-showContactForm') {\n return 'ri:send-plane-2-line'\n }\n if (part.type === 'tool-showCalendarEvent') {\n return 'ri:calendar-event-line'\n }\n if (part.type === 'tool-showComparison') {\n return 'ri:scales-line'\n }\n if (part.type === 'tool-showLocation') {\n return 'ri:map-pin-line'\n }\n if (part.type === 'tool-showQrCode') {\n return 'ri:qr-code-line'\n }\n if (part.type === 'tool-showImageGallery') {\n return 'ri:image-line'\n }\n if (part.type === 'tool-showVideo') {\n return 'ri:film-line'\n }\n if (part.type === 'tool-showSuggestedReply') {\n return 'ri:corner-down-right-line'\n }\n if (part.type === 'tool-requestGeolocation') {\n return 'ri:map-pin-user-line'\n }\n if (\n part.type === 'tool-perplexity_search' ||\n part.type === 'tool-parallel_search' ||\n part.type === 'tool-web_search' ||\n part.type === 'tool-google_search'\n ) {\n return 'ri:global-line'\n }\n return 'ri:tools-line'\n }\n if (isReasoningPart(part)) {\n return 'ri:lightbulb-line'\n }\n if (isTextPart(part)) {\n return 'ri:double-quotes-r'\n }\n return undefined\n}\n\n// Get part label\nexport function getToolPartLabel(\n $t: (key: string) => string,\n part?: UIMessage['parts'][number] | null,\n): string | undefined {\n if (isToolPart(part)) {\n if (part.type.includes('tool-subagent')) {\n return $t(`messagePart.runSubagent`)\n }\n if (part.type === 'tool-runWorker') {\n return $t(`messagePart.runWorker`)\n }\n if (part.type === 'tool-fetchTeamsChannelHistory') {\n return $t(`messagePart.fetchTeamsChannelHistory`)\n }\n if (part.type === 'tool-retrieveRevisedAnswers') {\n return $t(`messagePart.revisedAnswers`)\n }\n if (part.type === 'tool-searchInKnowledgeBase') {\n return $t(`messagePart.searchingDocuments`)\n }\n if (part.type === 'tool-expandChunkContext') {\n return $t(`messagePart.expandChunkContext`)\n }\n if (part.type === 'tool-readDocumentFile') {\n return $t(`messagePart.readDocumentFile`)\n }\n if (part.type === 'tool-geocode') {\n return $t(`messagePart.geocode`)\n }\n if (part.type === 'tool-getWeather') {\n return $t(`messagePart.getWeather`)\n }\n if (part.type === 'tool-recallUserMemory') {\n return $t(`messagePart.recallUserMemory`)\n }\n if (part.type === 'tool-saveUserMemory') {\n return $t(`messagePart.saveUserMemory`)\n }\n if (part.type === 'tool-showWeather') {\n return $t(`messagePart.showWeather`)\n }\n if (part.type === 'tool-showForm') {\n return $t(`messagePart.showForm`)\n }\n if (part.type === 'tool-showDiagram') {\n return $t(`messagePart.showDiagram`)\n }\n if (part.type === 'tool-showSources') {\n return $t(`messagePart.showSources`)\n }\n if (part.type === 'tool-showMultipleChoice') {\n return $t(`messagePart.showMultipleChoice`)\n }\n if (part.type === 'tool-showArtifact') {\n return $t(`messagePart.showArtifact`)\n }\n if (part.type === 'tool-showEmail') {\n return $t(`messagePart.showEmail`)\n }\n if (part.type === 'tool-showMessage') {\n return $t(`messagePart.showMessage`)\n }\n if (part.type === 'tool-showWebPages') {\n return $t(`messagePart.showWebPages`)\n }\n if (part.type === 'tool-showProducts') {\n return $t(`messagePart.showProducts`)\n }\n if (part.type === 'tool-showContactForm') {\n return $t(`messagePart.showContactForm`)\n }\n if (part.type === 'tool-showCalendarEvent') {\n return $t(`messagePart.showCalendarEvent`)\n }\n if (part.type === 'tool-showComparison') {\n return $t(`messagePart.showComparison`)\n }\n if (part.type === 'tool-showLocation') {\n return $t(`messagePart.showLocation`)\n }\n if (part.type === 'tool-showQrCode') {\n return $t(`messagePart.showQrCode`)\n }\n if (part.type === 'tool-showImageGallery') {\n return $t(`messagePart.showImageGallery`)\n }\n if (part.type === 'tool-showVideo') {\n return $t(`messagePart.showVideo`)\n }\n if (part.type === 'tool-showSuggestedReply') {\n return $t(`messagePart.showSuggestedReply`)\n }\n if (part.type === 'tool-requestGeolocation') {\n return $t(`messagePart.requestGeolocation`)\n }\n if (WEB_SEARCH_TOOL_TYPES.includes(part.type)) {\n return $t(`messagePart.webSearch`)\n }\n return $t(`messagePart.tool`)\n }\n if (isReasoningPart(part)) {\n return $t(`messagePart.reasoning`)\n }\n return $t(`messagePart.streaming`)\n}\n"],"mappings":"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"}