@8wave/ai-elements 0.119.0-beta.22 → 0.119.0-beta.27

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 (208) hide show
  1. package/dist/_chunks/{Agent-D8YrsP52.js → Agent-Gdgpd3LA.js} +66 -66
  2. package/dist/_chunks/Agent-Gdgpd3LA.js.map +1 -0
  3. package/dist/_chunks/{PkStreamingMarkdown-Bry3y6Ru.js → PkStreamingMarkdown-BK9O_NLx.js} +889 -852
  4. package/dist/_chunks/{PkStreamingMarkdown-Bry3y6Ru.js.map → PkStreamingMarkdown-BK9O_NLx.js.map} +1 -1
  5. package/dist/_chunks/{PkToolEditSpreadsheet-5vHzEy4P.js → PkToolEditSpreadsheet-D-RCfnrN.js} +2 -2
  6. package/dist/_chunks/{PkToolEditSpreadsheet-5vHzEy4P.js.map → PkToolEditSpreadsheet-D-RCfnrN.js.map} +1 -1
  7. package/dist/_chunks/{PkToolRequestGeolocation-Cj8hTfNF.js → PkToolRequestGeolocation-PxhQxMP1.js} +2 -2
  8. package/dist/_chunks/{PkToolRequestGeolocation-Cj8hTfNF.js.map → PkToolRequestGeolocation-PxhQxMP1.js.map} +1 -1
  9. package/dist/_chunks/{PkToolRequestOAuthConnection-BWxR1hV4.js → PkToolRequestOAuthConnection-QYDJPUFF.js} +5 -4
  10. package/dist/_chunks/PkToolRequestOAuthConnection-QYDJPUFF.js.map +1 -0
  11. package/dist/_chunks/{PkToolShowArtifact-CfJLe8vD.js → PkToolShowArtifact-DGUj8f1k.js} +3 -3
  12. package/dist/_chunks/PkToolShowArtifact-DGUj8f1k.js.map +1 -0
  13. package/dist/_chunks/{PkToolShowCalendarEvent-Bp_yv8S7.js → PkToolShowCalendarEvent-BEjPZC1F.js} +4 -3
  14. package/dist/_chunks/PkToolShowCalendarEvent-BEjPZC1F.js.map +1 -0
  15. package/dist/_chunks/{PkToolShowComparison-Bvd4f4tJ.js → PkToolShowComparison-DLC22e1W.js} +4 -3
  16. package/dist/_chunks/PkToolShowComparison-DLC22e1W.js.map +1 -0
  17. package/dist/_chunks/{PkToolShowContactForm--9XOVqNB.js → PkToolShowContactForm-DXJI0MPZ.js} +5 -4
  18. package/dist/_chunks/PkToolShowContactForm-DXJI0MPZ.js.map +1 -0
  19. package/dist/_chunks/{PkToolShowDiagram-C-pNbC9n.js → PkToolShowDiagram-C5mSqZDp.js} +9 -8
  20. package/dist/_chunks/PkToolShowDiagram-C5mSqZDp.js.map +1 -0
  21. package/dist/_chunks/{PkToolShowEmail-BKel_O29.js → PkToolShowEmail-C7mUCqGL.js} +4 -3
  22. package/dist/_chunks/PkToolShowEmail-C7mUCqGL.js.map +1 -0
  23. package/dist/_chunks/{PkToolShowForm-CGAc1O6K.js → PkToolShowForm-UQo0Xdiq.js} +6 -5
  24. package/dist/_chunks/PkToolShowForm-UQo0Xdiq.js.map +1 -0
  25. package/dist/_chunks/{PkToolShowImageGallery-CIhIrIcY.js → PkToolShowImageGallery-rZ3AtIEP.js} +2 -2
  26. package/dist/_chunks/{PkToolShowImageGallery-CIhIrIcY.js.map → PkToolShowImageGallery-rZ3AtIEP.js.map} +1 -1
  27. package/dist/_chunks/{PkToolShowLocation-78C7jFiV.js → PkToolShowLocation-BOmxHZKd.js} +4 -3
  28. package/dist/_chunks/PkToolShowLocation-BOmxHZKd.js.map +1 -0
  29. package/dist/_chunks/{PkToolShowMessage-BScy-w4J.js → PkToolShowMessage-vw4XS4TR.js} +4 -3
  30. package/dist/_chunks/PkToolShowMessage-vw4XS4TR.js.map +1 -0
  31. package/dist/_chunks/{PkToolShowProductList-BjWKnbyD.js → PkToolShowProductList-ByeSoIwq.js} +2 -2
  32. package/dist/_chunks/{PkToolShowProductList-BjWKnbyD.js.map → PkToolShowProductList-ByeSoIwq.js.map} +1 -1
  33. package/dist/_chunks/{PkToolShowQrCode-B70jPHDw.js → PkToolShowQrCode-BhcAUXSZ.js} +4 -3
  34. package/dist/_chunks/PkToolShowQrCode-BhcAUXSZ.js.map +1 -0
  35. package/dist/_chunks/{PkToolShowSources-BJ-XFrLD.js → PkToolShowSources-q4XBOwJl.js} +51 -50
  36. package/dist/_chunks/PkToolShowSources-q4XBOwJl.js.map +1 -0
  37. package/dist/_chunks/{PkToolShowSuggestedReply-0KahUIlw.js → PkToolShowSuggestedReply-BISQY1ce.js} +2 -2
  38. package/dist/_chunks/{PkToolShowSuggestedReply-0KahUIlw.js.map → PkToolShowSuggestedReply-BISQY1ce.js.map} +1 -1
  39. package/dist/_chunks/{PkToolShowVideo-_V_d-PDr.js → PkToolShowVideo-BmHHW4Ep.js} +2 -2
  40. package/dist/_chunks/{PkToolShowVideo-_V_d-PDr.js.map → PkToolShowVideo-BmHHW4Ep.js.map} +1 -1
  41. package/dist/_chunks/{PkToolShowWebPages-D55VEPjK.js → PkToolShowWebPages-BaapF0CC.js} +2 -2
  42. package/dist/_chunks/{PkToolShowWebPages-D55VEPjK.js.map → PkToolShowWebPages-BaapF0CC.js.map} +1 -1
  43. package/dist/_chunks/VvButtonLocalized-DV-zbH9b.js +21 -0
  44. package/dist/_chunks/VvButtonLocalized-DV-zbH9b.js.map +1 -0
  45. package/dist/_chunks/{chatImagePolicy-DXkhb-N_.js → chatImagePolicy-CDNkMKdT.js} +2 -2
  46. package/dist/_chunks/{chatImagePolicy-DXkhb-N_.js.map → chatImagePolicy-CDNkMKdT.js.map} +1 -1
  47. package/dist/_chunks/{markdown-DpoAzJSk.js → markdown-BbaLt57-.js} +8 -8
  48. package/dist/_chunks/{markdown-DpoAzJSk.js.map → markdown-BbaLt57-.js.map} +1 -1
  49. package/dist/_chunks/text-BHCGblDQ.js +6 -0
  50. package/dist/_chunks/text-BHCGblDQ.js.map +1 -0
  51. package/dist/ai-elements.es.js +2819 -2544
  52. package/dist/ai-elements.es.js.map +1 -1
  53. package/dist-vue/PkChatbot.js +1 -1
  54. package/dist-vue/PkChatbotAuth.js +1 -1
  55. package/dist-vue/PkChatbotEmptyState.js +1 -1
  56. package/dist-vue/PkChatbotError.js +1 -1
  57. package/dist-vue/PkChatbotFeedbackForm.js +1 -1
  58. package/dist-vue/PkChatbotInput.js +1 -1
  59. package/dist-vue/PkChatbotMessages.js +1 -1
  60. package/dist-vue/PkChatbotStepPayload.js +1 -1
  61. package/dist-vue/PkChatbotStepToolDetail.js +1 -1
  62. package/dist-vue/PkChatbotSteps.js +1 -1
  63. package/dist-vue/PkChatbotViewChat.js +1 -1
  64. package/dist-vue/PkChatbotViewConversations.js +1 -1
  65. package/dist-vue/PkChatbotViewFiles.js +1 -1
  66. package/dist-vue/PkChatbotViewProfile.js +1 -1
  67. package/dist-vue/PkChatbotWakeupBar.js +1 -1
  68. package/dist-vue/_chunks/{Agent-dGF8mkG9.js → Agent-DU1WWaHR.js} +87 -87
  69. package/dist-vue/_chunks/Agent-DU1WWaHR.js.map +1 -0
  70. package/dist-vue/_chunks/{Document-CV-RJu_p.js → Document-Cto-Qws0.js} +2 -2
  71. package/dist-vue/_chunks/{Document-CV-RJu_p.js.map → Document-Cto-Qws0.js.map} +1 -1
  72. package/dist-vue/_chunks/{PkChatbot-536vsOfp.js → PkChatbot-D0BQ3VnX.js} +86 -85
  73. package/dist-vue/_chunks/PkChatbot-D0BQ3VnX.js.map +1 -0
  74. package/dist-vue/_chunks/{PkChatbotAuth-BMLLTSwK.js → PkChatbotAuth-BVZzjbK9.js} +4 -3
  75. package/dist-vue/_chunks/PkChatbotAuth-BVZzjbK9.js.map +1 -0
  76. package/dist-vue/_chunks/{PkChatbotEmptyState-Toj4CqXV.js → PkChatbotEmptyState-CGjFcwwB.js} +2 -2
  77. package/dist-vue/_chunks/{PkChatbotEmptyState-Toj4CqXV.js.map → PkChatbotEmptyState-CGjFcwwB.js.map} +1 -1
  78. package/dist-vue/_chunks/{PkChatbotError-CRGbK09-.js → PkChatbotError-BV5ga7hk.js} +4 -3
  79. package/dist-vue/_chunks/PkChatbotError-BV5ga7hk.js.map +1 -0
  80. package/dist-vue/_chunks/{PkChatbotFeedbackForm-CMFXjoKR.js → PkChatbotFeedbackForm-B5cYsWBr.js} +8 -7
  81. package/dist-vue/_chunks/PkChatbotFeedbackForm-B5cYsWBr.js.map +1 -0
  82. package/dist-vue/_chunks/{PkChatbotInput-BfZqRpQ2.js → PkChatbotInput-BVBQY0V5.js} +8 -7
  83. package/dist-vue/_chunks/PkChatbotInput-BVBQY0V5.js.map +1 -0
  84. package/dist-vue/_chunks/PkChatbotMessages-CK0lhcDj.js +876 -0
  85. package/dist-vue/_chunks/PkChatbotMessages-CK0lhcDj.js.map +1 -0
  86. package/dist-vue/_chunks/{PkChatbotStepPayload-D0eoPBQ8.js → PkChatbotStepPayload-l57qHqVf.js} +2 -2
  87. package/dist-vue/_chunks/{PkChatbotStepPayload-D0eoPBQ8.js.map → PkChatbotStepPayload-l57qHqVf.js.map} +1 -1
  88. package/dist-vue/_chunks/{PkChatbotStepToolDetail-CMx4cw1D.js → PkChatbotStepToolDetail-ChrOa4W4.js} +16 -16
  89. package/dist-vue/_chunks/{PkChatbotStepToolDetail-CMx4cw1D.js.map → PkChatbotStepToolDetail-ChrOa4W4.js.map} +1 -1
  90. package/dist-vue/_chunks/{PkChatbotSteps-DeZQhGRU.js → PkChatbotSteps-DnU9r4XT.js} +40 -40
  91. package/dist-vue/_chunks/{PkChatbotSteps-DeZQhGRU.js.map → PkChatbotSteps-DnU9r4XT.js.map} +1 -1
  92. package/dist-vue/_chunks/{PkChatbotViewChat-CVT6OUIv.js → PkChatbotViewChat-DIx3nwEg.js} +12 -12
  93. package/dist-vue/_chunks/{PkChatbotViewChat-CVT6OUIv.js.map → PkChatbotViewChat-DIx3nwEg.js.map} +1 -1
  94. package/dist-vue/_chunks/PkChatbotViewConversations-DDWO1Ci_.js +199 -0
  95. package/dist-vue/_chunks/PkChatbotViewConversations-DDWO1Ci_.js.map +1 -0
  96. package/dist-vue/_chunks/{PkChatbotViewFiles-CA20TBFY.js → PkChatbotViewFiles-O9YjrGP0.js} +18 -17
  97. package/dist-vue/_chunks/PkChatbotViewFiles-O9YjrGP0.js.map +1 -0
  98. package/dist-vue/_chunks/{PkChatbotViewProfile-CyzRxE3D.js → PkChatbotViewProfile-BoImMMj2.js} +11 -10
  99. package/dist-vue/_chunks/PkChatbotViewProfile-BoImMMj2.js.map +1 -0
  100. package/dist-vue/_chunks/{PkChatbotWakeupBar-jBti21FQ.js → PkChatbotWakeupBar-Cjgarxnw.js} +3 -2
  101. package/dist-vue/_chunks/PkChatbotWakeupBar-Cjgarxnw.js.map +1 -0
  102. package/dist-vue/_chunks/{PkStreamingMarkdown-C55Fi0Pd.js → PkStreamingMarkdown-JEkbkY5k.js} +23 -23
  103. package/dist-vue/_chunks/{PkStreamingMarkdown-C55Fi0Pd.js.map → PkStreamingMarkdown-JEkbkY5k.js.map} +1 -1
  104. package/dist-vue/_chunks/{PkSvgViewer-Ts3gQ1hB.js → PkSvgViewer-DrA4yi8Q.js} +7 -6
  105. package/dist-vue/_chunks/PkSvgViewer-DrA4yi8Q.js.map +1 -0
  106. package/dist-vue/_chunks/{PkToolEditSpreadsheet-HAskd6d3.js → PkToolEditSpreadsheet-BX_h8Hut.js} +2 -2
  107. package/dist-vue/_chunks/{PkToolEditSpreadsheet-HAskd6d3.js.map → PkToolEditSpreadsheet-BX_h8Hut.js.map} +1 -1
  108. package/dist-vue/_chunks/{PkToolRequestGeolocation-BE22qwxB.js → PkToolRequestGeolocation-JZYgc-2X.js} +2 -2
  109. package/dist-vue/_chunks/{PkToolRequestGeolocation-BE22qwxB.js.map → PkToolRequestGeolocation-JZYgc-2X.js.map} +1 -1
  110. package/dist-vue/_chunks/{PkToolRequestOAuthConnection-GfSalEJG.js → PkToolRequestOAuthConnection-Bwj84qHq.js} +11 -10
  111. package/dist-vue/_chunks/PkToolRequestOAuthConnection-Bwj84qHq.js.map +1 -0
  112. package/dist-vue/_chunks/{PkToolShowArtifact-z1qTnFkA.js → PkToolShowArtifact-BIvl5I2I.js} +5 -5
  113. package/dist-vue/_chunks/PkToolShowArtifact-BIvl5I2I.js.map +1 -0
  114. package/dist-vue/_chunks/{PkToolShowCalendarEvent-Dv_rss26.js → PkToolShowCalendarEvent-ve1I0xaV.js} +7 -6
  115. package/dist-vue/_chunks/PkToolShowCalendarEvent-ve1I0xaV.js.map +1 -0
  116. package/dist-vue/_chunks/{PkToolShowComparison-DQs3E6-k.js → PkToolShowComparison-c2e239T4.js} +3 -2
  117. package/dist-vue/_chunks/PkToolShowComparison-c2e239T4.js.map +1 -0
  118. package/dist-vue/_chunks/{PkToolShowContactForm-Y0lrHXhr.js → PkToolShowContactForm-CddxrLBZ.js} +13 -12
  119. package/dist-vue/_chunks/PkToolShowContactForm-CddxrLBZ.js.map +1 -0
  120. package/dist-vue/_chunks/{PkToolShowDiagram-7WxDObZ6.js → PkToolShowDiagram-DdR4x6pP.js} +10 -9
  121. package/dist-vue/_chunks/PkToolShowDiagram-DdR4x6pP.js.map +1 -0
  122. package/dist-vue/_chunks/{PkToolShowEmail-C591LR5N.js → PkToolShowEmail-CUgZN0J5.js} +8 -7
  123. package/dist-vue/_chunks/PkToolShowEmail-CUgZN0J5.js.map +1 -0
  124. package/dist-vue/_chunks/{PkToolShowForm-CZFWZub7.js → PkToolShowForm-DiXcYws_.js} +14 -13
  125. package/dist-vue/_chunks/PkToolShowForm-DiXcYws_.js.map +1 -0
  126. package/dist-vue/_chunks/{PkToolShowImageGallery-CkfXP_lD.js → PkToolShowImageGallery-COrJEjSv.js} +2 -2
  127. package/dist-vue/_chunks/{PkToolShowImageGallery-CkfXP_lD.js.map → PkToolShowImageGallery-COrJEjSv.js.map} +1 -1
  128. package/dist-vue/_chunks/{PkToolShowLocation-Dyz6h_0n.js → PkToolShowLocation-CHi_cONJ.js} +13 -12
  129. package/dist-vue/_chunks/PkToolShowLocation-CHi_cONJ.js.map +1 -0
  130. package/dist-vue/_chunks/{PkToolShowMessage-CbXERPHI.js → PkToolShowMessage-ATTN5Hac.js} +8 -7
  131. package/dist-vue/_chunks/PkToolShowMessage-ATTN5Hac.js.map +1 -0
  132. package/dist-vue/_chunks/{PkToolShowProductList-De-PtmD-.js → PkToolShowProductList-BIvJlpMT.js} +2 -2
  133. package/dist-vue/_chunks/{PkToolShowProductList-De-PtmD-.js.map → PkToolShowProductList-BIvJlpMT.js.map} +1 -1
  134. package/dist-vue/_chunks/{PkToolShowQrCode-DEAvfLFu.js → PkToolShowQrCode-D_5VUtEB.js} +3 -2
  135. package/dist-vue/_chunks/PkToolShowQrCode-D_5VUtEB.js.map +1 -0
  136. package/dist-vue/_chunks/{PkToolShowSources-CSN7S0zo.js → PkToolShowSources-CC-0Oh4K.js} +57 -56
  137. package/dist-vue/_chunks/PkToolShowSources-CC-0Oh4K.js.map +1 -0
  138. package/dist-vue/_chunks/{PkToolShowSuggestedReply-DjutyiEi.js → PkToolShowSuggestedReply-I6FBos-F.js} +2 -2
  139. package/dist-vue/_chunks/{PkToolShowSuggestedReply-DjutyiEi.js.map → PkToolShowSuggestedReply-I6FBos-F.js.map} +1 -1
  140. package/dist-vue/_chunks/{PkToolShowVideo-B_Q93E2y.js → PkToolShowVideo-UUNkUlrg.js} +2 -2
  141. package/dist-vue/_chunks/{PkToolShowVideo-B_Q93E2y.js.map → PkToolShowVideo-UUNkUlrg.js.map} +1 -1
  142. package/dist-vue/_chunks/{PkToolShowWebPages-D3CdjJUc.js → PkToolShowWebPages-CLYx_PgL.js} +2 -2
  143. package/dist-vue/_chunks/{PkToolShowWebPages-D3CdjJUc.js.map → PkToolShowWebPages-CLYx_PgL.js.map} +1 -1
  144. package/dist-vue/_chunks/VvButtonLocalized-BuzLsXp3.js +20 -0
  145. package/dist-vue/_chunks/VvButtonLocalized-BuzLsXp3.js.map +1 -0
  146. package/dist-vue/_chunks/{createChatbotApiClient-DSLxswr4.js → createChatbotApiClient-BdmGCAQR.js} +17 -17
  147. package/dist-vue/_chunks/{createChatbotApiClient-DSLxswr4.js.map → createChatbotApiClient-BdmGCAQR.js.map} +1 -1
  148. package/dist-vue/_chunks/{useChatbotStore-rtl-oKqU.js → useChatbotStore-BAv5K91p.js} +3 -3
  149. package/dist-vue/_chunks/{useChatbotStore-rtl-oKqU.js.map → useChatbotStore-BAv5K91p.js.map} +1 -1
  150. package/dist-vue/_chunks/{utils-CwIMEuAv.js → utils-BqPJ6DJT.js} +142 -78
  151. package/dist-vue/_chunks/utils-BqPJ6DJT.js.map +1 -0
  152. package/dist-vue/api.js +1 -1
  153. package/dist-vue/composables.js +306 -42
  154. package/dist-vue/composables.js.map +1 -1
  155. package/dist-vue/index.js +4215 -4187
  156. package/dist-vue/index.js.map +1 -1
  157. package/dist-vue/locales.js +48 -12
  158. package/dist-vue/packages/ability/src/index.d.ts +4 -0
  159. package/dist-vue/packages/components/src/PkEditorMarkdown.d.ts +3 -2
  160. package/dist-vue/packages/components/src/VvButtonLocalized.d.ts +11 -0
  161. package/dist-vue/packages/components/src/agentGlyphs.d.ts +5 -3
  162. package/dist-vue/packages/components/src/chat/index.d.ts +1 -0
  163. package/dist-vue/packages/components/src/chat/utils.d.ts +30 -0
  164. package/dist-vue/packages/components/src/index.d.ts +1 -0
  165. package/dist-vue/packages/models/src/schema/Invitation.d.ts +1 -1
  166. package/package.json +1 -1
  167. package/dist/_chunks/Agent-D8YrsP52.js.map +0 -1
  168. package/dist/_chunks/PkToolRequestOAuthConnection-BWxR1hV4.js.map +0 -1
  169. package/dist/_chunks/PkToolShowArtifact-CfJLe8vD.js.map +0 -1
  170. package/dist/_chunks/PkToolShowCalendarEvent-Bp_yv8S7.js.map +0 -1
  171. package/dist/_chunks/PkToolShowComparison-Bvd4f4tJ.js.map +0 -1
  172. package/dist/_chunks/PkToolShowContactForm--9XOVqNB.js.map +0 -1
  173. package/dist/_chunks/PkToolShowDiagram-C-pNbC9n.js.map +0 -1
  174. package/dist/_chunks/PkToolShowEmail-BKel_O29.js.map +0 -1
  175. package/dist/_chunks/PkToolShowForm-CGAc1O6K.js.map +0 -1
  176. package/dist/_chunks/PkToolShowLocation-78C7jFiV.js.map +0 -1
  177. package/dist/_chunks/PkToolShowMessage-BScy-w4J.js.map +0 -1
  178. package/dist/_chunks/PkToolShowQrCode-B70jPHDw.js.map +0 -1
  179. package/dist/_chunks/PkToolShowSources-BJ-XFrLD.js.map +0 -1
  180. package/dist/_chunks/text-DbSEK8si.js +0 -6
  181. package/dist/_chunks/text-DbSEK8si.js.map +0 -1
  182. package/dist-vue/_chunks/Agent-dGF8mkG9.js.map +0 -1
  183. package/dist-vue/_chunks/PkChatbot-536vsOfp.js.map +0 -1
  184. package/dist-vue/_chunks/PkChatbotAuth-BMLLTSwK.js.map +0 -1
  185. package/dist-vue/_chunks/PkChatbotError-CRGbK09-.js.map +0 -1
  186. package/dist-vue/_chunks/PkChatbotFeedbackForm-CMFXjoKR.js.map +0 -1
  187. package/dist-vue/_chunks/PkChatbotInput-BfZqRpQ2.js.map +0 -1
  188. package/dist-vue/_chunks/PkChatbotMessages-CnI3e9wF.js +0 -869
  189. package/dist-vue/_chunks/PkChatbotMessages-CnI3e9wF.js.map +0 -1
  190. package/dist-vue/_chunks/PkChatbotViewConversations-DHeFtAfN.js +0 -197
  191. package/dist-vue/_chunks/PkChatbotViewConversations-DHeFtAfN.js.map +0 -1
  192. package/dist-vue/_chunks/PkChatbotViewFiles-CA20TBFY.js.map +0 -1
  193. package/dist-vue/_chunks/PkChatbotViewProfile-CyzRxE3D.js.map +0 -1
  194. package/dist-vue/_chunks/PkChatbotWakeupBar-jBti21FQ.js.map +0 -1
  195. package/dist-vue/_chunks/PkSvgViewer-Ts3gQ1hB.js.map +0 -1
  196. package/dist-vue/_chunks/PkToolRequestOAuthConnection-GfSalEJG.js.map +0 -1
  197. package/dist-vue/_chunks/PkToolShowArtifact-z1qTnFkA.js.map +0 -1
  198. package/dist-vue/_chunks/PkToolShowCalendarEvent-Dv_rss26.js.map +0 -1
  199. package/dist-vue/_chunks/PkToolShowComparison-DQs3E6-k.js.map +0 -1
  200. package/dist-vue/_chunks/PkToolShowContactForm-Y0lrHXhr.js.map +0 -1
  201. package/dist-vue/_chunks/PkToolShowDiagram-7WxDObZ6.js.map +0 -1
  202. package/dist-vue/_chunks/PkToolShowEmail-C591LR5N.js.map +0 -1
  203. package/dist-vue/_chunks/PkToolShowForm-CZFWZub7.js.map +0 -1
  204. package/dist-vue/_chunks/PkToolShowLocation-Dyz6h_0n.js.map +0 -1
  205. package/dist-vue/_chunks/PkToolShowMessage-CbXERPHI.js.map +0 -1
  206. package/dist-vue/_chunks/PkToolShowQrCode-DEAvfLFu.js.map +0 -1
  207. package/dist-vue/_chunks/PkToolShowSources-CSN7S0zo.js.map +0 -1
  208. package/dist-vue/_chunks/utils-CwIMEuAv.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PkChatbotStepPayload-D0eoPBQ8.js","names":["__unplugin_components_0","_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_createVNode","_Fragment","_renderList","_createBlock","_resolveDynamicComponent","_withCtx","_createCommentVNode","_sfc_main","stringifyPayload","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","PREVIEW_LENGTH","PkChatbotStepPayload_default","defineComponent","props","__props","$t","useI18n","stringify","value","indent","toPreview","single","entries","computed","index","item","own","rows","key","preview","full","text","summary","list","row","isOpen","ref","expandedRows","reactive","toggleRow","_component_VvIcon","VvIcon","openBlock","createElementBlock","createElementVNode","_cache","toDisplayString","createVNode","Fragment","renderList","createBlock","resolveDynamicComponent","withCtx","createCommentVNode"],"sources":["../../../../packages/components/src/chat/PkChatbotStepPayload.vue","../../../../packages/components/src/chat/PkChatbotStepPayload.vue"],"sourcesContent":["<script lang=\"ts\" setup>\n import { computed, reactive, ref } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { stringifyPayload } from './utils'\n\n interface PayloadRow {\n key: string\n preview: string\n full?: string\n }\n\n const props = defineProps<{\n label: string\n value: unknown\n }>()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n // A preview stays on a single line: long enough to recognize the value,\n // short enough to keep the payload readable without expanding anything.\n const PREVIEW_LENGTH = 120\n\n const stringify = (value: unknown, indent = 0): string | undefined => {\n try {\n return JSON.stringify(value, null, indent)\n } catch {\n return undefined\n }\n }\n\n const toPreview = (value: unknown): string => {\n if (value === undefined) {\n return ''\n }\n const text =\n typeof value === 'string' ? value : (stringify(value) ?? '')\n const single = text.replace(/\\s+/g, ' ').trim()\n return single.length > PREVIEW_LENGTH\n ? `${single.slice(0, PREVIEW_LENGTH)}…`\n : single\n }\n\n // Objects are listed by key, arrays by position: either way the payload\n // becomes a list of short lines instead of one wall of JSON.\n const entries = computed<[string, unknown][] | undefined>(() => {\n const value = props.value\n if (Array.isArray(value)) {\n return value.length\n ? value.map(\n (item, index) =>\n [`${index + 1}`, item] as [string, unknown],\n )\n : undefined\n }\n if (value && typeof value === 'object') {\n const own = Object.entries(value as Record<string, unknown>)\n return own.length ? own : undefined\n }\n return undefined\n })\n\n const rows = computed<PayloadRow[] | undefined>(() =>\n entries.value?.map(([key, value]) => {\n const preview = toPreview(value)\n const full = typeof value === 'string' ? value : stringify(value, 2)\n return {\n key,\n preview: preview || '-',\n // Only a value the preview had to cut (long, multiline or\n // nested) is worth its own expandable block.\n full: full && full.trim() !== preview ? full : undefined,\n }\n }),\n )\n\n // Scalars and strings have no rows: they fall back to the plain payload.\n const text = computed(() =>\n rows.value ? undefined : stringifyPayload(props.value),\n )\n\n const summary = computed(() => {\n const list = rows.value\n if (!list) {\n return toPreview(props.value)\n }\n if (Array.isArray(props.value)) {\n return $t('messagePart.stepItems', list.length)\n }\n if (list.length === 1) {\n return `${list[0].key}: ${list[0].preview}`\n }\n return list.map((row) => row.key).join(' · ')\n })\n\n const isOpen = ref(false)\n const expandedRows = reactive(new Set<string>())\n const toggleRow = (key: string) => {\n if (expandedRows.has(key)) {\n expandedRows.delete(key)\n } else {\n expandedRows.add(key)\n }\n }\n</script>\n\n<template>\n <div v-if=\"rows || text\" class=\"pk-chatbot-step-payload\">\n <button\n type=\"button\"\n class=\"pk-chatbot-step-payload__header\"\n :aria-expanded=\"isOpen\"\n @click=\"isOpen = !isOpen\">\n <span class=\"pk-chatbot-step-payload__label\">{{ label }}</span>\n <span class=\"pk-chatbot-step-payload__summary\">\n {{ summary }}\n </span>\n <VvIcon\n :name=\"isOpen ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\"\n class=\"shrink-0\" />\n </button>\n <ul v-if=\"isOpen && rows\" class=\"pk-chatbot-step-payload__rows\">\n <li v-for=\"row in rows\" :key=\"row.key\">\n <component\n :is=\"row.full ? 'button' : 'div'\"\n :type=\"row.full ? 'button' : undefined\"\n class=\"pk-chatbot-step-payload__row\"\n :aria-expanded=\"\n row.full ? expandedRows.has(row.key) : undefined\n \"\n @click=\"row.full ? toggleRow(row.key) : undefined\">\n <span class=\"pk-chatbot-step-payload__key\">\n {{ row.key }}\n </span>\n <span class=\"pk-chatbot-step-payload__value\">\n {{ row.preview }}\n </span>\n <VvIcon\n v-if=\"row.full\"\n :name=\"\n expandedRows.has(row.key)\n ? 'ri:arrow-up-s-line'\n : 'ri:arrow-down-s-line'\n \"\n class=\"shrink-0\" />\n </component>\n <pre\n v-if=\"row.full && expandedRows.has(row.key)\"\n class=\"pk-chatbot-step-payload__full\"\n >{{ row.full }}</pre>\n </li>\n </ul>\n <pre v-else-if=\"isOpen\" class=\"pk-chatbot-step-payload__full\">{{\n text\n }}</pre>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-step-payload {\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded);\n background-color: var(--color-surface-1);\n overflow: hidden;\n\n &__header {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n width: 100%;\n min-height: var(--spacing-28);\n padding: var(--spacing-4) var(--spacing-8);\n text-align: left;\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n }\n\n &__label {\n flex-shrink: 0;\n font-weight: 600;\n font-size: var(--text-10);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--color-word-3);\n }\n\n &__summary {\n flex: 1 1 0;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--font-mono);\n font-size: var(--text-10);\n color: var(--color-word-4);\n }\n\n &__rows > li {\n border-top: var(--spacing-px) solid var(--color-surface-3);\n }\n\n &__row {\n display: flex;\n align-items: baseline;\n gap: var(--spacing-8);\n width: 100%;\n padding: var(--spacing-4) var(--spacing-8);\n text-align: left;\n font-size: var(--text-10);\n\n &:is(button) {\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n }\n }\n\n &__key {\n flex-shrink: 0;\n max-width: 40%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--font-mono);\n color: var(--color-word-4);\n }\n\n &__value {\n flex: 1 1 0;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--color-word-2);\n }\n\n &__full {\n padding: var(--spacing-8);\n border-top: var(--spacing-px) solid var(--color-surface-3);\n max-height: var(--spacing-160);\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: var(--font-mono);\n font-size: var(--text-10);\n color: var(--color-word-3);\n }\n }\n</style>\n","<script lang=\"ts\" setup>\n import { computed, reactive, ref } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { stringifyPayload } from './utils'\n\n interface PayloadRow {\n key: string\n preview: string\n full?: string\n }\n\n const props = defineProps<{\n label: string\n value: unknown\n }>()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n // A preview stays on a single line: long enough to recognize the value,\n // short enough to keep the payload readable without expanding anything.\n const PREVIEW_LENGTH = 120\n\n const stringify = (value: unknown, indent = 0): string | undefined => {\n try {\n return JSON.stringify(value, null, indent)\n } catch {\n return undefined\n }\n }\n\n const toPreview = (value: unknown): string => {\n if (value === undefined) {\n return ''\n }\n const text =\n typeof value === 'string' ? value : (stringify(value) ?? '')\n const single = text.replace(/\\s+/g, ' ').trim()\n return single.length > PREVIEW_LENGTH\n ? `${single.slice(0, PREVIEW_LENGTH)}…`\n : single\n }\n\n // Objects are listed by key, arrays by position: either way the payload\n // becomes a list of short lines instead of one wall of JSON.\n const entries = computed<[string, unknown][] | undefined>(() => {\n const value = props.value\n if (Array.isArray(value)) {\n return value.length\n ? value.map(\n (item, index) =>\n [`${index + 1}`, item] as [string, unknown],\n )\n : undefined\n }\n if (value && typeof value === 'object') {\n const own = Object.entries(value as Record<string, unknown>)\n return own.length ? own : undefined\n }\n return undefined\n })\n\n const rows = computed<PayloadRow[] | undefined>(() =>\n entries.value?.map(([key, value]) => {\n const preview = toPreview(value)\n const full = typeof value === 'string' ? value : stringify(value, 2)\n return {\n key,\n preview: preview || '-',\n // Only a value the preview had to cut (long, multiline or\n // nested) is worth its own expandable block.\n full: full && full.trim() !== preview ? full : undefined,\n }\n }),\n )\n\n // Scalars and strings have no rows: they fall back to the plain payload.\n const text = computed(() =>\n rows.value ? undefined : stringifyPayload(props.value),\n )\n\n const summary = computed(() => {\n const list = rows.value\n if (!list) {\n return toPreview(props.value)\n }\n if (Array.isArray(props.value)) {\n return $t('messagePart.stepItems', list.length)\n }\n if (list.length === 1) {\n return `${list[0].key}: ${list[0].preview}`\n }\n return list.map((row) => row.key).join(' · ')\n })\n\n const isOpen = ref(false)\n const expandedRows = reactive(new Set<string>())\n const toggleRow = (key: string) => {\n if (expandedRows.has(key)) {\n expandedRows.delete(key)\n } else {\n expandedRows.add(key)\n }\n }\n</script>\n\n<template>\n <div v-if=\"rows || text\" class=\"pk-chatbot-step-payload\">\n <button\n type=\"button\"\n class=\"pk-chatbot-step-payload__header\"\n :aria-expanded=\"isOpen\"\n @click=\"isOpen = !isOpen\">\n <span class=\"pk-chatbot-step-payload__label\">{{ label }}</span>\n <span class=\"pk-chatbot-step-payload__summary\">\n {{ summary }}\n </span>\n <VvIcon\n :name=\"isOpen ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\"\n class=\"shrink-0\" />\n </button>\n <ul v-if=\"isOpen && rows\" class=\"pk-chatbot-step-payload__rows\">\n <li v-for=\"row in rows\" :key=\"row.key\">\n <component\n :is=\"row.full ? 'button' : 'div'\"\n :type=\"row.full ? 'button' : undefined\"\n class=\"pk-chatbot-step-payload__row\"\n :aria-expanded=\"\n row.full ? expandedRows.has(row.key) : undefined\n \"\n @click=\"row.full ? toggleRow(row.key) : undefined\">\n <span class=\"pk-chatbot-step-payload__key\">\n {{ row.key }}\n </span>\n <span class=\"pk-chatbot-step-payload__value\">\n {{ row.preview }}\n </span>\n <VvIcon\n v-if=\"row.full\"\n :name=\"\n expandedRows.has(row.key)\n ? 'ri:arrow-up-s-line'\n : 'ri:arrow-down-s-line'\n \"\n class=\"shrink-0\" />\n </component>\n <pre\n v-if=\"row.full && expandedRows.has(row.key)\"\n class=\"pk-chatbot-step-payload__full\"\n >{{ row.full }}</pre>\n </li>\n </ul>\n <pre v-else-if=\"isOpen\" class=\"pk-chatbot-step-payload__full\">{{\n text\n }}</pre>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-step-payload {\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded);\n background-color: var(--color-surface-1);\n overflow: hidden;\n\n &__header {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n width: 100%;\n min-height: var(--spacing-28);\n padding: var(--spacing-4) var(--spacing-8);\n text-align: left;\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n }\n\n &__label {\n flex-shrink: 0;\n font-weight: 600;\n font-size: var(--text-10);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--color-word-3);\n }\n\n &__summary {\n flex: 1 1 0;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--font-mono);\n font-size: var(--text-10);\n color: var(--color-word-4);\n }\n\n &__rows > li {\n border-top: var(--spacing-px) solid var(--color-surface-3);\n }\n\n &__row {\n display: flex;\n align-items: baseline;\n gap: var(--spacing-8);\n width: 100%;\n padding: var(--spacing-4) var(--spacing-8);\n text-align: left;\n font-size: var(--text-10);\n\n &:is(button) {\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n }\n }\n\n &__key {\n flex-shrink: 0;\n max-width: 40%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--font-mono);\n color: var(--color-word-4);\n }\n\n &__value {\n flex: 1 1 0;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--color-word-2);\n }\n\n &__full {\n padding: var(--spacing-8);\n border-top: var(--spacing-px) solid var(--color-surface-3);\n max-height: var(--spacing-160);\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: var(--font-mono);\n font-size: var(--text-10);\n color: var(--color-word-3);\n }\n }\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"PkChatbotStepPayload-l57qHqVf.js","names":["__unplugin_components_0","_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_createVNode","_Fragment","_renderList","_createBlock","_resolveDynamicComponent","_withCtx","_createCommentVNode","_sfc_main","stringifyPayload","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","PREVIEW_LENGTH","PkChatbotStepPayload_default","defineComponent","props","__props","$t","useI18n","stringify","value","indent","toPreview","single","entries","computed","index","item","own","rows","key","preview","full","text","summary","list","row","isOpen","ref","expandedRows","reactive","toggleRow","_component_VvIcon","VvIcon","openBlock","createElementBlock","createElementVNode","_cache","toDisplayString","createVNode","Fragment","renderList","createBlock","resolveDynamicComponent","withCtx","createCommentVNode"],"sources":["../../../../packages/components/src/chat/PkChatbotStepPayload.vue","../../../../packages/components/src/chat/PkChatbotStepPayload.vue"],"sourcesContent":["<script lang=\"ts\" setup>\n import { computed, reactive, ref } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { stringifyPayload } from './utils'\n\n interface PayloadRow {\n key: string\n preview: string\n full?: string\n }\n\n const props = defineProps<{\n label: string\n value: unknown\n }>()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n // A preview stays on a single line: long enough to recognize the value,\n // short enough to keep the payload readable without expanding anything.\n const PREVIEW_LENGTH = 120\n\n const stringify = (value: unknown, indent = 0): string | undefined => {\n try {\n return JSON.stringify(value, null, indent)\n } catch {\n return undefined\n }\n }\n\n const toPreview = (value: unknown): string => {\n if (value === undefined) {\n return ''\n }\n const text =\n typeof value === 'string' ? value : (stringify(value) ?? '')\n const single = text.replace(/\\s+/g, ' ').trim()\n return single.length > PREVIEW_LENGTH\n ? `${single.slice(0, PREVIEW_LENGTH)}…`\n : single\n }\n\n // Objects are listed by key, arrays by position: either way the payload\n // becomes a list of short lines instead of one wall of JSON.\n const entries = computed<[string, unknown][] | undefined>(() => {\n const value = props.value\n if (Array.isArray(value)) {\n return value.length\n ? value.map(\n (item, index) =>\n [`${index + 1}`, item] as [string, unknown],\n )\n : undefined\n }\n if (value && typeof value === 'object') {\n const own = Object.entries(value as Record<string, unknown>)\n return own.length ? own : undefined\n }\n return undefined\n })\n\n const rows = computed<PayloadRow[] | undefined>(() =>\n entries.value?.map(([key, value]) => {\n const preview = toPreview(value)\n const full = typeof value === 'string' ? value : stringify(value, 2)\n return {\n key,\n preview: preview || '-',\n // Only a value the preview had to cut (long, multiline or\n // nested) is worth its own expandable block.\n full: full && full.trim() !== preview ? full : undefined,\n }\n }),\n )\n\n // Scalars and strings have no rows: they fall back to the plain payload.\n const text = computed(() =>\n rows.value ? undefined : stringifyPayload(props.value),\n )\n\n const summary = computed(() => {\n const list = rows.value\n if (!list) {\n return toPreview(props.value)\n }\n if (Array.isArray(props.value)) {\n return $t('messagePart.stepItems', list.length)\n }\n if (list.length === 1) {\n return `${list[0].key}: ${list[0].preview}`\n }\n return list.map((row) => row.key).join(' · ')\n })\n\n const isOpen = ref(false)\n const expandedRows = reactive(new Set<string>())\n const toggleRow = (key: string) => {\n if (expandedRows.has(key)) {\n expandedRows.delete(key)\n } else {\n expandedRows.add(key)\n }\n }\n</script>\n\n<template>\n <div v-if=\"rows || text\" class=\"pk-chatbot-step-payload\">\n <button\n type=\"button\"\n class=\"pk-chatbot-step-payload__header\"\n :aria-expanded=\"isOpen\"\n @click=\"isOpen = !isOpen\">\n <span class=\"pk-chatbot-step-payload__label\">{{ label }}</span>\n <span class=\"pk-chatbot-step-payload__summary\">\n {{ summary }}\n </span>\n <VvIcon\n :name=\"isOpen ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\"\n class=\"shrink-0\" />\n </button>\n <ul v-if=\"isOpen && rows\" class=\"pk-chatbot-step-payload__rows\">\n <li v-for=\"row in rows\" :key=\"row.key\">\n <component\n :is=\"row.full ? 'button' : 'div'\"\n :type=\"row.full ? 'button' : undefined\"\n class=\"pk-chatbot-step-payload__row\"\n :aria-expanded=\"\n row.full ? expandedRows.has(row.key) : undefined\n \"\n @click=\"row.full ? toggleRow(row.key) : undefined\">\n <span class=\"pk-chatbot-step-payload__key\">\n {{ row.key }}\n </span>\n <span class=\"pk-chatbot-step-payload__value\">\n {{ row.preview }}\n </span>\n <VvIcon\n v-if=\"row.full\"\n :name=\"\n expandedRows.has(row.key)\n ? 'ri:arrow-up-s-line'\n : 'ri:arrow-down-s-line'\n \"\n class=\"shrink-0\" />\n </component>\n <pre\n v-if=\"row.full && expandedRows.has(row.key)\"\n class=\"pk-chatbot-step-payload__full\"\n >{{ row.full }}</pre>\n </li>\n </ul>\n <pre v-else-if=\"isOpen\" class=\"pk-chatbot-step-payload__full\">{{\n text\n }}</pre>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-step-payload {\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded);\n background-color: var(--color-surface-1);\n overflow: hidden;\n\n &__header {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n width: 100%;\n min-height: var(--spacing-28);\n padding: var(--spacing-4) var(--spacing-8);\n text-align: left;\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n }\n\n &__label {\n flex-shrink: 0;\n font-weight: 600;\n font-size: var(--text-10);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--color-word-3);\n }\n\n &__summary {\n flex: 1 1 0;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--font-mono);\n font-size: var(--text-10);\n color: var(--color-word-4);\n }\n\n &__rows > li {\n border-top: var(--spacing-px) solid var(--color-surface-3);\n }\n\n &__row {\n display: flex;\n align-items: baseline;\n gap: var(--spacing-8);\n width: 100%;\n padding: var(--spacing-4) var(--spacing-8);\n text-align: left;\n font-size: var(--text-10);\n\n &:is(button) {\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n }\n }\n\n &__key {\n flex-shrink: 0;\n max-width: 40%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--font-mono);\n color: var(--color-word-4);\n }\n\n &__value {\n flex: 1 1 0;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--color-word-2);\n }\n\n &__full {\n padding: var(--spacing-8);\n border-top: var(--spacing-px) solid var(--color-surface-3);\n max-height: var(--spacing-160);\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: var(--font-mono);\n font-size: var(--text-10);\n color: var(--color-word-3);\n }\n }\n</style>\n","<script lang=\"ts\" setup>\n import { computed, reactive, ref } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { stringifyPayload } from './utils'\n\n interface PayloadRow {\n key: string\n preview: string\n full?: string\n }\n\n const props = defineProps<{\n label: string\n value: unknown\n }>()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n // A preview stays on a single line: long enough to recognize the value,\n // short enough to keep the payload readable without expanding anything.\n const PREVIEW_LENGTH = 120\n\n const stringify = (value: unknown, indent = 0): string | undefined => {\n try {\n return JSON.stringify(value, null, indent)\n } catch {\n return undefined\n }\n }\n\n const toPreview = (value: unknown): string => {\n if (value === undefined) {\n return ''\n }\n const text =\n typeof value === 'string' ? value : (stringify(value) ?? '')\n const single = text.replace(/\\s+/g, ' ').trim()\n return single.length > PREVIEW_LENGTH\n ? `${single.slice(0, PREVIEW_LENGTH)}…`\n : single\n }\n\n // Objects are listed by key, arrays by position: either way the payload\n // becomes a list of short lines instead of one wall of JSON.\n const entries = computed<[string, unknown][] | undefined>(() => {\n const value = props.value\n if (Array.isArray(value)) {\n return value.length\n ? value.map(\n (item, index) =>\n [`${index + 1}`, item] as [string, unknown],\n )\n : undefined\n }\n if (value && typeof value === 'object') {\n const own = Object.entries(value as Record<string, unknown>)\n return own.length ? own : undefined\n }\n return undefined\n })\n\n const rows = computed<PayloadRow[] | undefined>(() =>\n entries.value?.map(([key, value]) => {\n const preview = toPreview(value)\n const full = typeof value === 'string' ? value : stringify(value, 2)\n return {\n key,\n preview: preview || '-',\n // Only a value the preview had to cut (long, multiline or\n // nested) is worth its own expandable block.\n full: full && full.trim() !== preview ? full : undefined,\n }\n }),\n )\n\n // Scalars and strings have no rows: they fall back to the plain payload.\n const text = computed(() =>\n rows.value ? undefined : stringifyPayload(props.value),\n )\n\n const summary = computed(() => {\n const list = rows.value\n if (!list) {\n return toPreview(props.value)\n }\n if (Array.isArray(props.value)) {\n return $t('messagePart.stepItems', list.length)\n }\n if (list.length === 1) {\n return `${list[0].key}: ${list[0].preview}`\n }\n return list.map((row) => row.key).join(' · ')\n })\n\n const isOpen = ref(false)\n const expandedRows = reactive(new Set<string>())\n const toggleRow = (key: string) => {\n if (expandedRows.has(key)) {\n expandedRows.delete(key)\n } else {\n expandedRows.add(key)\n }\n }\n</script>\n\n<template>\n <div v-if=\"rows || text\" class=\"pk-chatbot-step-payload\">\n <button\n type=\"button\"\n class=\"pk-chatbot-step-payload__header\"\n :aria-expanded=\"isOpen\"\n @click=\"isOpen = !isOpen\">\n <span class=\"pk-chatbot-step-payload__label\">{{ label }}</span>\n <span class=\"pk-chatbot-step-payload__summary\">\n {{ summary }}\n </span>\n <VvIcon\n :name=\"isOpen ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\"\n class=\"shrink-0\" />\n </button>\n <ul v-if=\"isOpen && rows\" class=\"pk-chatbot-step-payload__rows\">\n <li v-for=\"row in rows\" :key=\"row.key\">\n <component\n :is=\"row.full ? 'button' : 'div'\"\n :type=\"row.full ? 'button' : undefined\"\n class=\"pk-chatbot-step-payload__row\"\n :aria-expanded=\"\n row.full ? expandedRows.has(row.key) : undefined\n \"\n @click=\"row.full ? toggleRow(row.key) : undefined\">\n <span class=\"pk-chatbot-step-payload__key\">\n {{ row.key }}\n </span>\n <span class=\"pk-chatbot-step-payload__value\">\n {{ row.preview }}\n </span>\n <VvIcon\n v-if=\"row.full\"\n :name=\"\n expandedRows.has(row.key)\n ? 'ri:arrow-up-s-line'\n : 'ri:arrow-down-s-line'\n \"\n class=\"shrink-0\" />\n </component>\n <pre\n v-if=\"row.full && expandedRows.has(row.key)\"\n class=\"pk-chatbot-step-payload__full\"\n >{{ row.full }}</pre>\n </li>\n </ul>\n <pre v-else-if=\"isOpen\" class=\"pk-chatbot-step-payload__full\">{{\n text\n }}</pre>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-step-payload {\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded);\n background-color: var(--color-surface-1);\n overflow: hidden;\n\n &__header {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n width: 100%;\n min-height: var(--spacing-28);\n padding: var(--spacing-4) var(--spacing-8);\n text-align: left;\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n }\n\n &__label {\n flex-shrink: 0;\n font-weight: 600;\n font-size: var(--text-10);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--color-word-3);\n }\n\n &__summary {\n flex: 1 1 0;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--font-mono);\n font-size: var(--text-10);\n color: var(--color-word-4);\n }\n\n &__rows > li {\n border-top: var(--spacing-px) solid var(--color-surface-3);\n }\n\n &__row {\n display: flex;\n align-items: baseline;\n gap: var(--spacing-8);\n width: 100%;\n padding: var(--spacing-4) var(--spacing-8);\n text-align: left;\n font-size: var(--text-10);\n\n &:is(button) {\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n }\n }\n\n &__key {\n flex-shrink: 0;\n max-width: 40%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--font-mono);\n color: var(--color-word-4);\n }\n\n &__value {\n flex: 1 1 0;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--color-word-2);\n }\n\n &__full {\n padding: var(--spacing-8);\n border-top: var(--spacing-px) solid var(--color-surface-3);\n max-height: var(--spacing-160);\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: var(--font-mono);\n font-size: var(--text-10);\n color: var(--color-word-3);\n }\n }\n</style>\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { _ as e, r as t } from "./utils-CwIMEuAv.js";
2
- import { t as n } from "./PkChatbotStepPayload-D0eoPBQ8.js";
1
+ import { r as e, v as t } from "./utils-BqPJ6DJT.js";
2
+ import { t as n } from "./PkChatbotStepPayload-l57qHqVf.js";
3
3
  import { VvIcon as r } from "@volverjs/ui-vue/components";
4
4
  import { Fragment as i, computed as a, createBlock as o, createCommentVNode as s, createElementBlock as c, createElementVNode as l, createVNode as u, defineComponent as d, normalizeStyle as f, openBlock as p, reactive as m, renderList as h, resolveDynamicComponent as g, toDisplayString as _, unref as v, withCtx as y, withModifiers as b } from "vue";
5
5
  import { useI18n as x } from "vue-i18n";
@@ -120,16 +120,16 @@ var S = { class: "pk-chatbot-step-detail" }, C = {
120
120
  hits: e,
121
121
  showEmpty: e !== void 0 && !e.length
122
122
  }), ae = () => {
123
- let e = F.part.type;
124
- if (e === "tool-searchInKnowledgeBase") {
123
+ let t = F.part.type;
124
+ if (t === "tool-searchInKnowledgeBase") {
125
125
  let e = Z(q.value);
126
126
  return J.value && (e.facts = [{
127
127
  icon: "ri:history-line",
128
128
  text: I("messagePart.stepRepeated", J.value)
129
129
  }], e.showEmpty = !1), e;
130
130
  }
131
- if (e === "tool-retrieveRevisedAnswers") return Z(ie.value);
132
- if (e === "tool-expandChunkContext") {
131
+ if (t === "tool-retrieveRevisedAnswers") return Z(ie.value);
132
+ if (t === "tool-expandChunkContext") {
133
133
  let e = R(U.value, "content");
134
134
  if (!e) return {};
135
135
  let t = U.value?.totalChunksReturned;
@@ -139,7 +139,7 @@ var S = { class: "pk-chatbot-step-detail" }, C = {
139
139
  content: e
140
140
  } };
141
141
  }
142
- if (e === "tool-readDocumentFile") {
142
+ if (t === "tool-readDocumentFile") {
143
143
  let e = R(U.value, "name");
144
144
  if (!e) return {};
145
145
  let t = R(U.value, "mimeType");
@@ -148,7 +148,7 @@ var S = { class: "pk-chatbot-step-detail" }, C = {
148
148
  text: t ? `${e} (${t})` : e
149
149
  }] };
150
150
  }
151
- if (e === "tool-getWeather") {
151
+ if (t === "tool-getWeather") {
152
152
  let e = R(U.value, "location") ?? R(H.value, "locationName") ?? z(H.value);
153
153
  if (!e) return {};
154
154
  let t = R(H.value, "startDate"), n = R(H.value, "endDate");
@@ -157,15 +157,15 @@ var S = { class: "pk-chatbot-step-detail" }, C = {
157
157
  text: `${e}${t ? n && n !== t ? ` · ${t} → ${n}` : ` · ${t}` : ""}`
158
158
  }] };
159
159
  }
160
- if (e === "tool-geocode") {
160
+ if (t === "tool-geocode") {
161
161
  let e = R(H.value, "locationName") ?? z(H.value), t = R(U.value, "name", "displayName", "locationName", "label") ?? z(U.value), n = e && t && e !== t ? `${e} → ${t}` : e ?? t;
162
162
  return n ? { facts: [{
163
163
  icon: "ri:map-pin-line",
164
164
  text: n
165
165
  }] } : {};
166
166
  }
167
- if (e === "tool-recallUserMemory") return Z(X(U.value?.memories));
168
- if (e === "tool-saveUserMemory") {
167
+ if (t === "tool-recallUserMemory") return Z(X(U.value?.memories));
168
+ if (t === "tool-saveUserMemory") {
169
169
  let e = X(U.value?.candidates);
170
170
  if (e) return Z(e);
171
171
  let t = R(H.value, "content") ?? R(U.value, "message", "error");
@@ -174,7 +174,7 @@ var S = { class: "pk-chatbot-step-detail" }, C = {
174
174
  text: t
175
175
  }] } : {};
176
176
  }
177
- return t.includes(e) ? {
177
+ return e.includes(t) ? {
178
178
  chips: W.value,
179
179
  rawOutput: V.value
180
180
  } : {};
@@ -184,7 +184,7 @@ var S = { class: "pk-chatbot-step-detail" }, C = {
184
184
  }), $ = m(/* @__PURE__ */ new Set()), oe = (e) => {
185
185
  $.has(e) ? $.delete(e) : $.add(e);
186
186
  };
187
- return (t, a) => {
187
+ return (e, a) => {
188
188
  let d = r;
189
189
  return p(), c("div", S, [
190
190
  Q.value.chips?.length ? (p(), c("ul", C, [(p(!0), c(i, null, h(Q.value.chips, (e, t) => (p(), c("li", {
@@ -245,12 +245,12 @@ var S = { class: "pk-chatbot-step-detail" }, C = {
245
245
  l("span", re, [l("span", M, _(Q.value.passage.title ?? v(I)("messagePart.stepDocument")), 1)]),
246
246
  Q.value.passage.meta ? (p(), c("span", N, _(Q.value.passage.meta), 1)) : s("", !0)
247
247
  ]), l("div", P, _(Q.value.passage.content), 1)])) : s("", !0),
248
- v(e)(Q.value.rawInput) ? (p(), o(n, {
248
+ v(t)(Q.value.rawInput) ? (p(), o(n, {
249
249
  key: 4,
250
250
  label: v(I)("messagePart.stepInput"),
251
251
  value: Q.value.rawInput
252
252
  }, null, 8, ["label", "value"])) : s("", !0),
253
- v(e)(Q.value.rawOutput) ? (p(), o(n, {
253
+ v(t)(Q.value.rawOutput) ? (p(), o(n, {
254
254
  key: 5,
255
255
  label: v(I)("messagePart.stepOutput"),
256
256
  value: Q.value.rawOutput
@@ -262,4 +262,4 @@ var S = { class: "pk-chatbot-step-detail" }, C = {
262
262
  //#endregion
263
263
  export { F as t };
264
264
 
265
- //# sourceMappingURL=PkChatbotStepToolDetail-CMx4cw1D.js.map
265
+ //# sourceMappingURL=PkChatbotStepToolDetail-ChrOa4W4.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PkChatbotStepToolDetail-CMx4cw1D.js","names":["__unplugin_components_0","_openBlock","_createElementBlock","_Fragment","_renderList","_createVNode","_createElementVNode","_toDisplayString","_createCommentVNode","_unref","_createBlock","_resolveDynamicComponent","_withCtx","_withModifiers","_normalizeStyle","PkChatbotStepPayload","_sfc_main","hasPayload","WEB_SEARCH_TOOL_TYPES","PkChatbotStepPayload_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","PkChatbotStepToolDetail_default","defineComponent","props","__props","$t","useI18n","asRecord","value","pickString","keys","key","record","formatCoordinates","latitude","longitude","rawInputValue","computed","rawOutputValue","input","output","queryChips","raw","query","spreadRelevance","min","scores","max","score","scoredRecords","records","item","relevances","index","knowledgeHits","results","groups","result","document","source","id","similarity","group","list","g","repeatedCount","count","searchFacts","facts","dropped","unavailable","queries","revisedAnswerHits","memoryHits","content","hitsDetail","hits","buildDetail","type","knowledge","totalChunks","name","mimeType","location","startDate","endDate","from","to","text","candidates","detail","expandedHits","reactive","toggleHit","_component_VvIcon","VvIcon","openBlock","createElementBlock","Fragment","renderList","chipIndex","chip","createVNode","createElementVNode","toDisplayString","createCommentVNode","factIndex","fact","unref","hit","createBlock","resolveDynamicComponent","withCtx","_cache","withModifiers","normalizeStyle"],"sources":["../../../../packages/components/src/chat/PkChatbotStepToolDetail.vue","../../../../packages/components/src/chat/PkChatbotStepToolDetail.vue"],"sourcesContent":["<script lang=\"ts\" setup>\n import { computed, reactive } from 'vue'\n import { useI18n } from 'vue-i18n'\n import type { UIChatMessage } from 'models'\n import PkChatbotStepPayload from './PkChatbotStepPayload.vue'\n import { hasPayload, WEB_SEARCH_TOOL_TYPES } from './utils'\n\n type MessagePart = UIChatMessage['parts'][number]\n\n interface DetailHit {\n key: string\n icon: string\n title: string\n url?: string\n meta?: string\n relevance?: number\n body?: string\n }\n\n interface DetailFact {\n icon: string\n text: string\n }\n\n interface Detail {\n chips?: string[]\n facts?: DetailFact[]\n hits?: DetailHit[]\n showEmpty?: boolean\n passage?: { title?: string; meta?: string; content: string }\n rawInput?: unknown\n rawOutput?: unknown\n }\n\n const props = defineProps<{\n part: MessagePart\n }>()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n const asRecord = (value: unknown): Record<string, unknown> | undefined =>\n value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n\n const 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 const formatCoordinates = (\n record?: Record<string, unknown>,\n ): string | undefined => {\n const latitude = record?.latitude\n const longitude = record?.longitude\n if (typeof latitude !== 'number' || typeof longitude !== 'number') {\n return undefined\n }\n return `${latitude.toFixed(4)}, ${longitude.toFixed(4)}`\n }\n\n const rawInputValue = computed(() =>\n 'input' in props.part ? props.part.input : undefined,\n )\n const rawOutputValue = computed(() =>\n 'output' in props.part ? props.part.output : undefined,\n )\n const input = computed(() => asRecord(rawInputValue.value))\n const output = computed(() => asRecord(rawOutputValue.value))\n\n // Search queries shown as chips (queries[], query or objective)\n const queryChips = computed<string[]>(() => {\n const raw =\n input.value?.queries ?? input.value?.query ?? input.value?.objective\n if (typeof raw === 'string' && raw.trim()) {\n return [raw]\n }\n if (Array.isArray(raw)) {\n return raw.filter(\n (query): query is string =>\n typeof query === 'string' && Boolean(query.trim()),\n )\n }\n return []\n })\n\n // Raw scores live on different scales depending on the agent search mode\n // (RRF ~0.03, cosine 0 to 1) and tend to cluster, so a plain ratio on the\n // max renders every bar as ~100%. Spread them on a min/max scale with a\n // floor so the ordering stays visible, and hide the bar entirely when it\n // carries no information (single hit or identical scores).\n const spreadRelevance = (scores: number[]): (number | undefined)[] => {\n const min = Math.min(...scores)\n const max = Math.max(...scores)\n if (scores.length < 2 || max <= min) {\n return scores.map(() => undefined)\n }\n const floor = 0.15\n return scores.map(\n (score) => floor + ((score - min) / (max - min)) * (1 - floor),\n )\n }\n\n // Normalizes a raw result array into records paired with a spread\n // relevance derived from each record's `similarity` score.\n const scoredRecords = (\n raw: unknown,\n ):\n | { record: Record<string, unknown>; relevance?: number }[]\n | undefined => {\n if (!Array.isArray(raw)) {\n return undefined\n }\n const records = raw\n .map((item) => asRecord(item))\n .filter((record): record is Record<string, unknown> =>\n Boolean(record),\n )\n const relevances = spreadRelevance(\n records.map((record) =>\n typeof record.similarity === 'number' ? record.similarity : 0,\n ),\n )\n return records.map((record, index) => ({\n record,\n relevance: relevances[index],\n }))\n }\n\n // searchInKnowledgeBase: group chunks by document, relevance compares the\n // best chunk score of each document within the result set.\n const knowledgeHits = computed<DetailHit[] | undefined>(() => {\n const results = output.value?.results\n if (!Array.isArray(results)) {\n return undefined\n }\n interface DocumentGroup {\n id: string\n type: string\n title: string\n url?: string\n similarity: number\n chunks: string[]\n }\n const groups = new Map<string, DocumentGroup>()\n for (const [index, raw] of results.entries()) {\n const result = asRecord(raw)\n if (!result) {\n continue\n }\n const document = asRecord(result.document)\n const source = asRecord(document?.source)\n const id =\n typeof document?.id === 'string' ? document.id : `doc-${index}`\n const similarity =\n typeof result.similarity === 'number' ? result.similarity : 0\n let group = groups.get(id)\n if (!group) {\n group = {\n id,\n type:\n typeof document?.type === 'string' ? document.type : '',\n title:\n pickString(document, 'name') ??\n pickString(source, 'filename', 'url') ??\n $t('messagePart.stepDocument'),\n url: pickString(source, 'url'),\n similarity,\n chunks: [],\n }\n groups.set(id, group)\n }\n group.similarity = Math.max(group.similarity, similarity)\n if (typeof result.content === 'string' && result.content.trim()) {\n group.chunks.push(result.content)\n }\n }\n const list = [...groups.values()]\n const relevances = spreadRelevance(list.map((g) => g.similarity))\n return list.map((group, index) => ({\n key: group.id,\n icon: group.type === 'url' ? 'ri:global-line' : 'ri:file-text-line',\n title: group.title,\n url: group.url,\n meta: $t('messagePart.stepExcerpts', group.chunks.length || 1),\n relevance: relevances[index],\n body: group.chunks.join('\\n\\n· · ·\\n\\n') || undefined,\n }))\n })\n\n // Chunks this turn had already returned come back as references without\n // content (spec retrieval-payload-per-turn, R2). They carry no document\n // name to group by, so they are summarized in one line: without it a\n // search that found only known passages reads as \"no results\".\n const repeatedCount = computed<number>(() => {\n const count = asRecord(output.value?.repeated)?.count\n return typeof count === 'number' ? count : 0\n })\n\n // Two declarations every search tool can attach to its output, and the\n // only ones the model is explicitly told not to read as an answer: a\n // query dropped for exceeding the tool's cap, and a search that ran out\n // of time. Without them a timeout renders as \"no results\", which is the\n // reading whoever opens a chat log would take away too.\n const searchFacts = computed<DetailFact[]>(() => {\n const facts: DetailFact[] = []\n const dropped = asRecord(output.value?.inputTruncated)?.dropped\n if (Array.isArray(dropped) && dropped.length) {\n facts.push({\n icon: 'ri:scissors-cut-line',\n text: $t('messagePart.stepDropped', dropped.length),\n })\n }\n const unavailable = asRecord(output.value?.searchUnavailable)\n if (unavailable) {\n // The corrected-answers tool declares one lookup without naming\n // its query, so an absent list means one search, not none.\n const queries = unavailable.queries\n facts.push({\n icon: 'ri:time-line',\n text: $t(\n 'messagePart.stepTimedOut',\n Array.isArray(queries) ? queries.length : 1,\n ),\n })\n }\n return facts\n })\n\n // retrieveRevisedAnswers: one hit per matched question, the corrected\n // answer is the expandable body.\n const revisedAnswerHits = computed<DetailHit[] | undefined>(() =>\n scoredRecords(output.value?.results)?.map(\n ({ record, relevance }, index) => ({\n key:\n pickString(record, 'revisedAnswerId') ?? `revised-${index}`,\n icon: 'ri:file-edit-line',\n title:\n pickString(record, 'userQuestion') ??\n $t('messagePart.revisedAnswers'),\n relevance,\n body: pickString(record, 'revisedMessage'),\n }),\n ),\n )\n\n // recallUserMemory / saveUserMemory delete candidates: one hit per\n // memory, long facts expand to their full text.\n const memoryHits = (raw: unknown): DetailHit[] | undefined =>\n scoredRecords(raw)?.map(({ record, relevance }, index) => {\n const content = pickString(record, 'content') ?? ''\n return {\n key: pickString(record, 'id') ?? `memory-${index}`,\n icon: 'ri:brain-line',\n title: content,\n meta: pickString(record, 'updatedAt')?.slice(0, 10),\n relevance,\n body: content.length > 120 ? content : undefined,\n }\n })\n\n // Query chips over a list of hits, flagging an explicit empty state so the\n // \"no results\" message shows once the tool has run (hits defined, length 0).\n const hitsDetail = (hits: DetailHit[] | undefined): Detail => ({\n chips: queryChips.value,\n hits,\n showEmpty: hits !== undefined && !hits.length,\n })\n\n // Rich, tool-specific view of the step. Returns {} when the tool has\n // nothing meaningful to show yet (the raw fallback is applied by `detail`).\n const buildDetail = (): Detail => {\n const type = props.part.type\n if (type === 'tool-searchInKnowledgeBase') {\n const knowledge = hitsDetail(knowledgeHits.value)\n if (repeatedCount.value) {\n knowledge.facts = [\n {\n icon: 'ri:history-line',\n text: $t(\n 'messagePart.stepRepeated',\n repeatedCount.value,\n ),\n },\n ]\n knowledge.showEmpty = false\n }\n return knowledge\n }\n if (type === 'tool-retrieveRevisedAnswers') {\n return hitsDetail(revisedAnswerHits.value)\n }\n if (type === 'tool-expandChunkContext') {\n const content = pickString(output.value, 'content')\n if (!content) {\n return {}\n }\n const totalChunks = output.value?.totalChunksReturned\n return {\n passage: {\n title: pickString(output.value, 'documentName'),\n meta:\n typeof totalChunks === 'number'\n ? $t('messagePart.stepExcerpts', totalChunks)\n : undefined,\n content,\n },\n }\n }\n if (type === 'tool-readDocumentFile') {\n const name = pickString(output.value, 'name')\n if (!name) {\n return {}\n }\n const mimeType = pickString(output.value, 'mimeType')\n return {\n facts: [\n {\n icon: 'ri:file-text-line',\n text: mimeType ? `${name} (${mimeType})` : name,\n },\n ],\n }\n }\n if (type === 'tool-getWeather') {\n const location =\n pickString(output.value, 'location') ??\n pickString(input.value, 'locationName') ??\n formatCoordinates(input.value)\n if (!location) {\n return {}\n }\n const startDate = pickString(input.value, 'startDate')\n const endDate = pickString(input.value, 'endDate')\n const dateRange = startDate\n ? endDate && endDate !== startDate\n ? ` · ${startDate} → ${endDate}`\n : ` · ${startDate}`\n : ''\n return {\n facts: [\n {\n icon: 'ri:sun-cloudy-line',\n text: `${location}${dateRange}`,\n },\n ],\n }\n }\n if (type === 'tool-geocode') {\n const from =\n pickString(input.value, 'locationName') ??\n formatCoordinates(input.value)\n const to =\n pickString(\n output.value,\n 'name',\n 'displayName',\n 'locationName',\n 'label',\n ) ?? formatCoordinates(output.value)\n const text =\n from && to && from !== to ? `${from} → ${to}` : (from ?? to)\n if (!text) {\n return {}\n }\n return {\n facts: [\n {\n icon: 'ri:map-pin-line',\n text,\n },\n ],\n }\n }\n if (type === 'tool-recallUserMemory') {\n return hitsDetail(memoryHits(output.value?.memories))\n }\n if (type === 'tool-saveUserMemory') {\n const candidates = memoryHits(output.value?.candidates)\n if (candidates) {\n return hitsDetail(candidates)\n }\n const text =\n pickString(input.value, 'content') ??\n pickString(output.value, 'message', 'error')\n if (!text) {\n return {}\n }\n return {\n facts: [\n {\n icon:\n pickString(input.value, 'action') === 'delete'\n ? 'ri:delete-bin-line'\n : 'ri:save-3-line',\n text,\n },\n ],\n }\n }\n if (WEB_SEARCH_TOOL_TYPES.includes(type)) {\n return {\n chips: queryChips.value,\n rawOutput: rawOutputValue.value,\n }\n }\n return {}\n }\n\n const detail = computed<Detail>(() => {\n const result = buildDetail()\n if (searchFacts.value.length) {\n result.facts = [...searchFacts.value, ...(result.facts ?? [])]\n }\n if (output.value?.searchUnavailable) {\n // \"No results found\" under a search that never answered is the\n // one sentence this fact exists to prevent.\n result.showEmpty = false\n }\n // Nothing meaningful to show for this tool yet (e.g. still running):\n // fall back to the raw payloads so the step body is never empty.\n const hasRichContent =\n result.chips?.length ||\n result.facts?.length ||\n result.passage ||\n result.showEmpty ||\n result.hits?.length\n if (!hasRichContent) {\n result.rawInput = rawInputValue.value\n result.rawOutput ??= rawOutputValue.value\n }\n return result\n })\n\n const expandedHits = reactive(new Set<string>())\n const toggleHit = (key: string) => {\n if (expandedHits.has(key)) {\n expandedHits.delete(key)\n } else {\n expandedHits.add(key)\n }\n }\n</script>\n\n<template>\n <div class=\"pk-chatbot-step-detail\">\n <ul v-if=\"detail.chips?.length\" class=\"pk-chatbot-step-detail__chips\">\n <li\n v-for=\"(chip, chipIndex) in detail.chips\"\n :key=\"`${chipIndex}-${chip}`\"\n class=\"pk-chatbot-step-detail__chip\">\n <VvIcon name=\"ri:search-line\" class=\"shrink-0\" />\n <span class=\"pk-chatbot-step-detail__chip-text\">\n {{ chip }}\n </span>\n </li>\n </ul>\n <div\n v-for=\"(fact, factIndex) in detail.facts\"\n :key=\"`${factIndex}-${fact.text}`\"\n class=\"pk-chatbot-step-detail__fact\">\n <VvIcon :name=\"fact.icon\" class=\"shrink-0\" />\n <span>{{ fact.text }}</span>\n </div>\n <div v-if=\"detail.showEmpty\" class=\"pk-chatbot-step-detail__empty\">\n {{ $t('messagePart.stepNoResults') }}\n </div>\n <ul\n v-else-if=\"detail.hits?.length\"\n class=\"pk-chatbot-step-detail__hits\">\n <li v-for=\"hit in detail.hits\" :key=\"hit.key\">\n <component\n :is=\"hit.body ? 'button' : 'div'\"\n :type=\"hit.body ? 'button' : undefined\"\n class=\"pk-chatbot-step-detail__hit-header\"\n :aria-expanded=\"\n hit.body ? expandedHits.has(hit.key) : undefined\n \"\n @click=\"hit.body ? toggleHit(hit.key) : undefined\">\n <VvIcon\n :name=\"hit.icon\"\n class=\"pk-chatbot-step-detail__hit-icon\" />\n <span class=\"pk-chatbot-step-detail__hit-heading\">\n <span class=\"pk-chatbot-step-detail__hit-title\">\n {{ hit.title }}\n </span>\n <a\n v-if=\"hit.url\"\n :href=\"hit.url\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"pk-chatbot-step-detail__link\"\n @click.stop>\n <VvIcon name=\"ri:external-link-line\" />\n </a>\n </span>\n <span\n v-if=\"hit.meta\"\n class=\"pk-chatbot-step-detail__hit-meta\">\n {{ hit.meta }}\n </span>\n <span\n v-if=\"hit.relevance !== undefined\"\n class=\"pk-chatbot-step-detail__relevance\"\n aria-hidden=\"true\">\n <span\n class=\"pk-chatbot-step-detail__relevance-fill\"\n :style=\"{\n width: `${Math.round(hit.relevance * 100)}%`,\n }\" />\n </span>\n <VvIcon\n v-if=\"hit.body\"\n :name=\"\n expandedHits.has(hit.key)\n ? 'ri:arrow-up-s-line'\n : 'ri:arrow-down-s-line'\n \"\n class=\"shrink-0\" />\n </component>\n <div\n v-if=\"hit.body && expandedHits.has(hit.key)\"\n class=\"pk-chatbot-step-detail__hit-body\">\n {{ hit.body }}\n </div>\n </li>\n </ul>\n <div v-if=\"detail.passage\" class=\"pk-chatbot-step-detail__passage\">\n <div class=\"pk-chatbot-step-detail__passage-header\">\n <VvIcon name=\"ri:file-text-line\" class=\"shrink-0\" />\n <span class=\"pk-chatbot-step-detail__hit-heading\">\n <span class=\"pk-chatbot-step-detail__hit-title\">\n {{\n detail.passage.title ??\n $t('messagePart.stepDocument')\n }}\n </span>\n </span>\n <span\n v-if=\"detail.passage.meta\"\n class=\"pk-chatbot-step-detail__hit-meta\">\n {{ detail.passage.meta }}\n </span>\n </div>\n <div class=\"pk-chatbot-step-detail__passage-content\">\n {{ detail.passage.content }}\n </div>\n </div>\n <PkChatbotStepPayload\n v-if=\"hasPayload(detail.rawInput)\"\n :label=\"$t('messagePart.stepInput')\"\n :value=\"detail.rawInput\" />\n <PkChatbotStepPayload\n v-if=\"hasPayload(detail.rawOutput)\"\n :label=\"$t('messagePart.stepOutput')\"\n :value=\"detail.rawOutput\" />\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-step-detail {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-8);\n font-size: var(--text-12);\n color: var(--color-word-3);\n\n &__chips {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-4);\n }\n\n &__chip {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-4);\n max-width: 100%;\n padding: var(--spacing-2) var(--spacing-8);\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded-full);\n background-color: var(--color-surface-1);\n color: var(--color-word-2);\n }\n\n &__chip-text {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &__fact {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n color: var(--color-word-2);\n }\n\n &__empty {\n color: var(--color-word-4);\n font-style: italic;\n }\n\n &__hits {\n display: flex;\n flex-direction: column;\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded);\n background-color: var(--color-surface-1);\n overflow: hidden;\n\n > li + li {\n border-top: var(--spacing-px) solid var(--color-surface-3);\n }\n }\n\n &__hit-header {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n width: 100%;\n min-height: var(--spacing-32);\n padding: var(--spacing-4) var(--spacing-8);\n text-align: left;\n\n &:is(button) {\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n }\n }\n\n &__hit-icon {\n flex-shrink: 0;\n color: var(--color-word-3);\n }\n\n // Grows to fill the row so meta, relevance and chevron stay aligned;\n // the title inside only shrinks, keeping the link icon next to the\n // title text instead of pushed to the right edge.\n &__hit-heading {\n display: flex;\n align-items: center;\n gap: var(--spacing-4);\n flex: 1 1 0;\n min-width: 0;\n }\n\n &__hit-title {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--color-word-2);\n }\n\n &__hit-meta {\n color: var(--color-word-4);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n }\n\n &__relevance {\n flex-shrink: 0;\n width: var(--spacing-40);\n height: var(--spacing-4);\n border-radius: var(--rounded-full);\n background-color: var(--color-surface-3);\n overflow: hidden;\n }\n\n &__relevance-fill {\n display: block;\n height: 100%;\n border-radius: inherit;\n background-color: var(--chatbot-main-color, var(--color-word-4));\n }\n\n &__link {\n flex-shrink: 0;\n display: inline-flex;\n color: var(--color-word-4);\n\n &:hover {\n color: var(--color-word-1);\n }\n }\n\n &__hit-body,\n &__passage-content {\n padding: var(--spacing-8);\n max-height: var(--spacing-160);\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n color: var(--color-word-3);\n }\n\n &__hit-body {\n border-top: var(--spacing-px) solid var(--color-surface-3);\n }\n\n &__passage {\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded);\n background-color: var(--color-surface-1);\n overflow: hidden;\n }\n\n &__passage-header {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n min-height: var(--spacing-32);\n padding: var(--spacing-4) var(--spacing-8);\n border-bottom: var(--spacing-px) solid var(--color-surface-3);\n }\n }\n</style>\n","<script lang=\"ts\" setup>\n import { computed, reactive } from 'vue'\n import { useI18n } from 'vue-i18n'\n import type { UIChatMessage } from 'models'\n import PkChatbotStepPayload from './PkChatbotStepPayload.vue'\n import { hasPayload, WEB_SEARCH_TOOL_TYPES } from './utils'\n\n type MessagePart = UIChatMessage['parts'][number]\n\n interface DetailHit {\n key: string\n icon: string\n title: string\n url?: string\n meta?: string\n relevance?: number\n body?: string\n }\n\n interface DetailFact {\n icon: string\n text: string\n }\n\n interface Detail {\n chips?: string[]\n facts?: DetailFact[]\n hits?: DetailHit[]\n showEmpty?: boolean\n passage?: { title?: string; meta?: string; content: string }\n rawInput?: unknown\n rawOutput?: unknown\n }\n\n const props = defineProps<{\n part: MessagePart\n }>()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n const asRecord = (value: unknown): Record<string, unknown> | undefined =>\n value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n\n const 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 const formatCoordinates = (\n record?: Record<string, unknown>,\n ): string | undefined => {\n const latitude = record?.latitude\n const longitude = record?.longitude\n if (typeof latitude !== 'number' || typeof longitude !== 'number') {\n return undefined\n }\n return `${latitude.toFixed(4)}, ${longitude.toFixed(4)}`\n }\n\n const rawInputValue = computed(() =>\n 'input' in props.part ? props.part.input : undefined,\n )\n const rawOutputValue = computed(() =>\n 'output' in props.part ? props.part.output : undefined,\n )\n const input = computed(() => asRecord(rawInputValue.value))\n const output = computed(() => asRecord(rawOutputValue.value))\n\n // Search queries shown as chips (queries[], query or objective)\n const queryChips = computed<string[]>(() => {\n const raw =\n input.value?.queries ?? input.value?.query ?? input.value?.objective\n if (typeof raw === 'string' && raw.trim()) {\n return [raw]\n }\n if (Array.isArray(raw)) {\n return raw.filter(\n (query): query is string =>\n typeof query === 'string' && Boolean(query.trim()),\n )\n }\n return []\n })\n\n // Raw scores live on different scales depending on the agent search mode\n // (RRF ~0.03, cosine 0 to 1) and tend to cluster, so a plain ratio on the\n // max renders every bar as ~100%. Spread them on a min/max scale with a\n // floor so the ordering stays visible, and hide the bar entirely when it\n // carries no information (single hit or identical scores).\n const spreadRelevance = (scores: number[]): (number | undefined)[] => {\n const min = Math.min(...scores)\n const max = Math.max(...scores)\n if (scores.length < 2 || max <= min) {\n return scores.map(() => undefined)\n }\n const floor = 0.15\n return scores.map(\n (score) => floor + ((score - min) / (max - min)) * (1 - floor),\n )\n }\n\n // Normalizes a raw result array into records paired with a spread\n // relevance derived from each record's `similarity` score.\n const scoredRecords = (\n raw: unknown,\n ):\n | { record: Record<string, unknown>; relevance?: number }[]\n | undefined => {\n if (!Array.isArray(raw)) {\n return undefined\n }\n const records = raw\n .map((item) => asRecord(item))\n .filter((record): record is Record<string, unknown> =>\n Boolean(record),\n )\n const relevances = spreadRelevance(\n records.map((record) =>\n typeof record.similarity === 'number' ? record.similarity : 0,\n ),\n )\n return records.map((record, index) => ({\n record,\n relevance: relevances[index],\n }))\n }\n\n // searchInKnowledgeBase: group chunks by document, relevance compares the\n // best chunk score of each document within the result set.\n const knowledgeHits = computed<DetailHit[] | undefined>(() => {\n const results = output.value?.results\n if (!Array.isArray(results)) {\n return undefined\n }\n interface DocumentGroup {\n id: string\n type: string\n title: string\n url?: string\n similarity: number\n chunks: string[]\n }\n const groups = new Map<string, DocumentGroup>()\n for (const [index, raw] of results.entries()) {\n const result = asRecord(raw)\n if (!result) {\n continue\n }\n const document = asRecord(result.document)\n const source = asRecord(document?.source)\n const id =\n typeof document?.id === 'string' ? document.id : `doc-${index}`\n const similarity =\n typeof result.similarity === 'number' ? result.similarity : 0\n let group = groups.get(id)\n if (!group) {\n group = {\n id,\n type:\n typeof document?.type === 'string' ? document.type : '',\n title:\n pickString(document, 'name') ??\n pickString(source, 'filename', 'url') ??\n $t('messagePart.stepDocument'),\n url: pickString(source, 'url'),\n similarity,\n chunks: [],\n }\n groups.set(id, group)\n }\n group.similarity = Math.max(group.similarity, similarity)\n if (typeof result.content === 'string' && result.content.trim()) {\n group.chunks.push(result.content)\n }\n }\n const list = [...groups.values()]\n const relevances = spreadRelevance(list.map((g) => g.similarity))\n return list.map((group, index) => ({\n key: group.id,\n icon: group.type === 'url' ? 'ri:global-line' : 'ri:file-text-line',\n title: group.title,\n url: group.url,\n meta: $t('messagePart.stepExcerpts', group.chunks.length || 1),\n relevance: relevances[index],\n body: group.chunks.join('\\n\\n· · ·\\n\\n') || undefined,\n }))\n })\n\n // Chunks this turn had already returned come back as references without\n // content (spec retrieval-payload-per-turn, R2). They carry no document\n // name to group by, so they are summarized in one line: without it a\n // search that found only known passages reads as \"no results\".\n const repeatedCount = computed<number>(() => {\n const count = asRecord(output.value?.repeated)?.count\n return typeof count === 'number' ? count : 0\n })\n\n // Two declarations every search tool can attach to its output, and the\n // only ones the model is explicitly told not to read as an answer: a\n // query dropped for exceeding the tool's cap, and a search that ran out\n // of time. Without them a timeout renders as \"no results\", which is the\n // reading whoever opens a chat log would take away too.\n const searchFacts = computed<DetailFact[]>(() => {\n const facts: DetailFact[] = []\n const dropped = asRecord(output.value?.inputTruncated)?.dropped\n if (Array.isArray(dropped) && dropped.length) {\n facts.push({\n icon: 'ri:scissors-cut-line',\n text: $t('messagePart.stepDropped', dropped.length),\n })\n }\n const unavailable = asRecord(output.value?.searchUnavailable)\n if (unavailable) {\n // The corrected-answers tool declares one lookup without naming\n // its query, so an absent list means one search, not none.\n const queries = unavailable.queries\n facts.push({\n icon: 'ri:time-line',\n text: $t(\n 'messagePart.stepTimedOut',\n Array.isArray(queries) ? queries.length : 1,\n ),\n })\n }\n return facts\n })\n\n // retrieveRevisedAnswers: one hit per matched question, the corrected\n // answer is the expandable body.\n const revisedAnswerHits = computed<DetailHit[] | undefined>(() =>\n scoredRecords(output.value?.results)?.map(\n ({ record, relevance }, index) => ({\n key:\n pickString(record, 'revisedAnswerId') ?? `revised-${index}`,\n icon: 'ri:file-edit-line',\n title:\n pickString(record, 'userQuestion') ??\n $t('messagePart.revisedAnswers'),\n relevance,\n body: pickString(record, 'revisedMessage'),\n }),\n ),\n )\n\n // recallUserMemory / saveUserMemory delete candidates: one hit per\n // memory, long facts expand to their full text.\n const memoryHits = (raw: unknown): DetailHit[] | undefined =>\n scoredRecords(raw)?.map(({ record, relevance }, index) => {\n const content = pickString(record, 'content') ?? ''\n return {\n key: pickString(record, 'id') ?? `memory-${index}`,\n icon: 'ri:brain-line',\n title: content,\n meta: pickString(record, 'updatedAt')?.slice(0, 10),\n relevance,\n body: content.length > 120 ? content : undefined,\n }\n })\n\n // Query chips over a list of hits, flagging an explicit empty state so the\n // \"no results\" message shows once the tool has run (hits defined, length 0).\n const hitsDetail = (hits: DetailHit[] | undefined): Detail => ({\n chips: queryChips.value,\n hits,\n showEmpty: hits !== undefined && !hits.length,\n })\n\n // Rich, tool-specific view of the step. Returns {} when the tool has\n // nothing meaningful to show yet (the raw fallback is applied by `detail`).\n const buildDetail = (): Detail => {\n const type = props.part.type\n if (type === 'tool-searchInKnowledgeBase') {\n const knowledge = hitsDetail(knowledgeHits.value)\n if (repeatedCount.value) {\n knowledge.facts = [\n {\n icon: 'ri:history-line',\n text: $t(\n 'messagePart.stepRepeated',\n repeatedCount.value,\n ),\n },\n ]\n knowledge.showEmpty = false\n }\n return knowledge\n }\n if (type === 'tool-retrieveRevisedAnswers') {\n return hitsDetail(revisedAnswerHits.value)\n }\n if (type === 'tool-expandChunkContext') {\n const content = pickString(output.value, 'content')\n if (!content) {\n return {}\n }\n const totalChunks = output.value?.totalChunksReturned\n return {\n passage: {\n title: pickString(output.value, 'documentName'),\n meta:\n typeof totalChunks === 'number'\n ? $t('messagePart.stepExcerpts', totalChunks)\n : undefined,\n content,\n },\n }\n }\n if (type === 'tool-readDocumentFile') {\n const name = pickString(output.value, 'name')\n if (!name) {\n return {}\n }\n const mimeType = pickString(output.value, 'mimeType')\n return {\n facts: [\n {\n icon: 'ri:file-text-line',\n text: mimeType ? `${name} (${mimeType})` : name,\n },\n ],\n }\n }\n if (type === 'tool-getWeather') {\n const location =\n pickString(output.value, 'location') ??\n pickString(input.value, 'locationName') ??\n formatCoordinates(input.value)\n if (!location) {\n return {}\n }\n const startDate = pickString(input.value, 'startDate')\n const endDate = pickString(input.value, 'endDate')\n const dateRange = startDate\n ? endDate && endDate !== startDate\n ? ` · ${startDate} → ${endDate}`\n : ` · ${startDate}`\n : ''\n return {\n facts: [\n {\n icon: 'ri:sun-cloudy-line',\n text: `${location}${dateRange}`,\n },\n ],\n }\n }\n if (type === 'tool-geocode') {\n const from =\n pickString(input.value, 'locationName') ??\n formatCoordinates(input.value)\n const to =\n pickString(\n output.value,\n 'name',\n 'displayName',\n 'locationName',\n 'label',\n ) ?? formatCoordinates(output.value)\n const text =\n from && to && from !== to ? `${from} → ${to}` : (from ?? to)\n if (!text) {\n return {}\n }\n return {\n facts: [\n {\n icon: 'ri:map-pin-line',\n text,\n },\n ],\n }\n }\n if (type === 'tool-recallUserMemory') {\n return hitsDetail(memoryHits(output.value?.memories))\n }\n if (type === 'tool-saveUserMemory') {\n const candidates = memoryHits(output.value?.candidates)\n if (candidates) {\n return hitsDetail(candidates)\n }\n const text =\n pickString(input.value, 'content') ??\n pickString(output.value, 'message', 'error')\n if (!text) {\n return {}\n }\n return {\n facts: [\n {\n icon:\n pickString(input.value, 'action') === 'delete'\n ? 'ri:delete-bin-line'\n : 'ri:save-3-line',\n text,\n },\n ],\n }\n }\n if (WEB_SEARCH_TOOL_TYPES.includes(type)) {\n return {\n chips: queryChips.value,\n rawOutput: rawOutputValue.value,\n }\n }\n return {}\n }\n\n const detail = computed<Detail>(() => {\n const result = buildDetail()\n if (searchFacts.value.length) {\n result.facts = [...searchFacts.value, ...(result.facts ?? [])]\n }\n if (output.value?.searchUnavailable) {\n // \"No results found\" under a search that never answered is the\n // one sentence this fact exists to prevent.\n result.showEmpty = false\n }\n // Nothing meaningful to show for this tool yet (e.g. still running):\n // fall back to the raw payloads so the step body is never empty.\n const hasRichContent =\n result.chips?.length ||\n result.facts?.length ||\n result.passage ||\n result.showEmpty ||\n result.hits?.length\n if (!hasRichContent) {\n result.rawInput = rawInputValue.value\n result.rawOutput ??= rawOutputValue.value\n }\n return result\n })\n\n const expandedHits = reactive(new Set<string>())\n const toggleHit = (key: string) => {\n if (expandedHits.has(key)) {\n expandedHits.delete(key)\n } else {\n expandedHits.add(key)\n }\n }\n</script>\n\n<template>\n <div class=\"pk-chatbot-step-detail\">\n <ul v-if=\"detail.chips?.length\" class=\"pk-chatbot-step-detail__chips\">\n <li\n v-for=\"(chip, chipIndex) in detail.chips\"\n :key=\"`${chipIndex}-${chip}`\"\n class=\"pk-chatbot-step-detail__chip\">\n <VvIcon name=\"ri:search-line\" class=\"shrink-0\" />\n <span class=\"pk-chatbot-step-detail__chip-text\">\n {{ chip }}\n </span>\n </li>\n </ul>\n <div\n v-for=\"(fact, factIndex) in detail.facts\"\n :key=\"`${factIndex}-${fact.text}`\"\n class=\"pk-chatbot-step-detail__fact\">\n <VvIcon :name=\"fact.icon\" class=\"shrink-0\" />\n <span>{{ fact.text }}</span>\n </div>\n <div v-if=\"detail.showEmpty\" class=\"pk-chatbot-step-detail__empty\">\n {{ $t('messagePart.stepNoResults') }}\n </div>\n <ul\n v-else-if=\"detail.hits?.length\"\n class=\"pk-chatbot-step-detail__hits\">\n <li v-for=\"hit in detail.hits\" :key=\"hit.key\">\n <component\n :is=\"hit.body ? 'button' : 'div'\"\n :type=\"hit.body ? 'button' : undefined\"\n class=\"pk-chatbot-step-detail__hit-header\"\n :aria-expanded=\"\n hit.body ? expandedHits.has(hit.key) : undefined\n \"\n @click=\"hit.body ? toggleHit(hit.key) : undefined\">\n <VvIcon\n :name=\"hit.icon\"\n class=\"pk-chatbot-step-detail__hit-icon\" />\n <span class=\"pk-chatbot-step-detail__hit-heading\">\n <span class=\"pk-chatbot-step-detail__hit-title\">\n {{ hit.title }}\n </span>\n <a\n v-if=\"hit.url\"\n :href=\"hit.url\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"pk-chatbot-step-detail__link\"\n @click.stop>\n <VvIcon name=\"ri:external-link-line\" />\n </a>\n </span>\n <span\n v-if=\"hit.meta\"\n class=\"pk-chatbot-step-detail__hit-meta\">\n {{ hit.meta }}\n </span>\n <span\n v-if=\"hit.relevance !== undefined\"\n class=\"pk-chatbot-step-detail__relevance\"\n aria-hidden=\"true\">\n <span\n class=\"pk-chatbot-step-detail__relevance-fill\"\n :style=\"{\n width: `${Math.round(hit.relevance * 100)}%`,\n }\" />\n </span>\n <VvIcon\n v-if=\"hit.body\"\n :name=\"\n expandedHits.has(hit.key)\n ? 'ri:arrow-up-s-line'\n : 'ri:arrow-down-s-line'\n \"\n class=\"shrink-0\" />\n </component>\n <div\n v-if=\"hit.body && expandedHits.has(hit.key)\"\n class=\"pk-chatbot-step-detail__hit-body\">\n {{ hit.body }}\n </div>\n </li>\n </ul>\n <div v-if=\"detail.passage\" class=\"pk-chatbot-step-detail__passage\">\n <div class=\"pk-chatbot-step-detail__passage-header\">\n <VvIcon name=\"ri:file-text-line\" class=\"shrink-0\" />\n <span class=\"pk-chatbot-step-detail__hit-heading\">\n <span class=\"pk-chatbot-step-detail__hit-title\">\n {{\n detail.passage.title ??\n $t('messagePart.stepDocument')\n }}\n </span>\n </span>\n <span\n v-if=\"detail.passage.meta\"\n class=\"pk-chatbot-step-detail__hit-meta\">\n {{ detail.passage.meta }}\n </span>\n </div>\n <div class=\"pk-chatbot-step-detail__passage-content\">\n {{ detail.passage.content }}\n </div>\n </div>\n <PkChatbotStepPayload\n v-if=\"hasPayload(detail.rawInput)\"\n :label=\"$t('messagePart.stepInput')\"\n :value=\"detail.rawInput\" />\n <PkChatbotStepPayload\n v-if=\"hasPayload(detail.rawOutput)\"\n :label=\"$t('messagePart.stepOutput')\"\n :value=\"detail.rawOutput\" />\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-step-detail {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-8);\n font-size: var(--text-12);\n color: var(--color-word-3);\n\n &__chips {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-4);\n }\n\n &__chip {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-4);\n max-width: 100%;\n padding: var(--spacing-2) var(--spacing-8);\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded-full);\n background-color: var(--color-surface-1);\n color: var(--color-word-2);\n }\n\n &__chip-text {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &__fact {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n color: var(--color-word-2);\n }\n\n &__empty {\n color: var(--color-word-4);\n font-style: italic;\n }\n\n &__hits {\n display: flex;\n flex-direction: column;\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded);\n background-color: var(--color-surface-1);\n overflow: hidden;\n\n > li + li {\n border-top: var(--spacing-px) solid var(--color-surface-3);\n }\n }\n\n &__hit-header {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n width: 100%;\n min-height: var(--spacing-32);\n padding: var(--spacing-4) var(--spacing-8);\n text-align: left;\n\n &:is(button) {\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n }\n }\n\n &__hit-icon {\n flex-shrink: 0;\n color: var(--color-word-3);\n }\n\n // Grows to fill the row so meta, relevance and chevron stay aligned;\n // the title inside only shrinks, keeping the link icon next to the\n // title text instead of pushed to the right edge.\n &__hit-heading {\n display: flex;\n align-items: center;\n gap: var(--spacing-4);\n flex: 1 1 0;\n min-width: 0;\n }\n\n &__hit-title {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--color-word-2);\n }\n\n &__hit-meta {\n color: var(--color-word-4);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n }\n\n &__relevance {\n flex-shrink: 0;\n width: var(--spacing-40);\n height: var(--spacing-4);\n border-radius: var(--rounded-full);\n background-color: var(--color-surface-3);\n overflow: hidden;\n }\n\n &__relevance-fill {\n display: block;\n height: 100%;\n border-radius: inherit;\n background-color: var(--chatbot-main-color, var(--color-word-4));\n }\n\n &__link {\n flex-shrink: 0;\n display: inline-flex;\n color: var(--color-word-4);\n\n &:hover {\n color: var(--color-word-1);\n }\n }\n\n &__hit-body,\n &__passage-content {\n padding: var(--spacing-8);\n max-height: var(--spacing-160);\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n color: var(--color-word-3);\n }\n\n &__hit-body {\n border-top: var(--spacing-px) solid var(--color-surface-3);\n }\n\n &__passage {\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded);\n background-color: var(--color-surface-1);\n overflow: hidden;\n }\n\n &__passage-header {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n min-height: var(--spacing-32);\n padding: var(--spacing-4) var(--spacing-8);\n border-bottom: var(--spacing-px) solid var(--color-surface-3);\n }\n }\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"PkChatbotStepToolDetail-ChrOa4W4.js","names":["__unplugin_components_0","_openBlock","_createElementBlock","_Fragment","_renderList","_createVNode","_createElementVNode","_toDisplayString","_createCommentVNode","_unref","_createBlock","_resolveDynamicComponent","_withCtx","_withModifiers","_normalizeStyle","PkChatbotStepPayload","_sfc_main","WEB_SEARCH_TOOL_TYPES","hasPayload","PkChatbotStepPayload_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","PkChatbotStepToolDetail_default","defineComponent","props","__props","$t","useI18n","asRecord","value","pickString","keys","key","record","formatCoordinates","latitude","longitude","rawInputValue","computed","rawOutputValue","input","output","queryChips","raw","query","spreadRelevance","min","scores","max","score","scoredRecords","records","item","relevances","index","knowledgeHits","results","groups","result","document","source","id","similarity","group","list","g","repeatedCount","count","searchFacts","facts","dropped","unavailable","queries","revisedAnswerHits","memoryHits","content","hitsDetail","hits","buildDetail","type","knowledge","totalChunks","name","mimeType","location","startDate","endDate","from","to","text","candidates","detail","expandedHits","reactive","toggleHit","_component_VvIcon","VvIcon","openBlock","createElementBlock","Fragment","renderList","chipIndex","chip","createVNode","createElementVNode","toDisplayString","createCommentVNode","factIndex","fact","unref","hit","createBlock","resolveDynamicComponent","withCtx","_cache","withModifiers","normalizeStyle"],"sources":["../../../../packages/components/src/chat/PkChatbotStepToolDetail.vue","../../../../packages/components/src/chat/PkChatbotStepToolDetail.vue"],"sourcesContent":["<script lang=\"ts\" setup>\n import { computed, reactive } from 'vue'\n import { useI18n } from 'vue-i18n'\n import type { UIChatMessage } from 'models'\n import PkChatbotStepPayload from './PkChatbotStepPayload.vue'\n import { hasPayload, WEB_SEARCH_TOOL_TYPES } from './utils'\n\n type MessagePart = UIChatMessage['parts'][number]\n\n interface DetailHit {\n key: string\n icon: string\n title: string\n url?: string\n meta?: string\n relevance?: number\n body?: string\n }\n\n interface DetailFact {\n icon: string\n text: string\n }\n\n interface Detail {\n chips?: string[]\n facts?: DetailFact[]\n hits?: DetailHit[]\n showEmpty?: boolean\n passage?: { title?: string; meta?: string; content: string }\n rawInput?: unknown\n rawOutput?: unknown\n }\n\n const props = defineProps<{\n part: MessagePart\n }>()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n const asRecord = (value: unknown): Record<string, unknown> | undefined =>\n value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n\n const 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 const formatCoordinates = (\n record?: Record<string, unknown>,\n ): string | undefined => {\n const latitude = record?.latitude\n const longitude = record?.longitude\n if (typeof latitude !== 'number' || typeof longitude !== 'number') {\n return undefined\n }\n return `${latitude.toFixed(4)}, ${longitude.toFixed(4)}`\n }\n\n const rawInputValue = computed(() =>\n 'input' in props.part ? props.part.input : undefined,\n )\n const rawOutputValue = computed(() =>\n 'output' in props.part ? props.part.output : undefined,\n )\n const input = computed(() => asRecord(rawInputValue.value))\n const output = computed(() => asRecord(rawOutputValue.value))\n\n // Search queries shown as chips (queries[], query or objective)\n const queryChips = computed<string[]>(() => {\n const raw =\n input.value?.queries ?? input.value?.query ?? input.value?.objective\n if (typeof raw === 'string' && raw.trim()) {\n return [raw]\n }\n if (Array.isArray(raw)) {\n return raw.filter(\n (query): query is string =>\n typeof query === 'string' && Boolean(query.trim()),\n )\n }\n return []\n })\n\n // Raw scores live on different scales depending on the agent search mode\n // (RRF ~0.03, cosine 0 to 1) and tend to cluster, so a plain ratio on the\n // max renders every bar as ~100%. Spread them on a min/max scale with a\n // floor so the ordering stays visible, and hide the bar entirely when it\n // carries no information (single hit or identical scores).\n const spreadRelevance = (scores: number[]): (number | undefined)[] => {\n const min = Math.min(...scores)\n const max = Math.max(...scores)\n if (scores.length < 2 || max <= min) {\n return scores.map(() => undefined)\n }\n const floor = 0.15\n return scores.map(\n (score) => floor + ((score - min) / (max - min)) * (1 - floor),\n )\n }\n\n // Normalizes a raw result array into records paired with a spread\n // relevance derived from each record's `similarity` score.\n const scoredRecords = (\n raw: unknown,\n ):\n | { record: Record<string, unknown>; relevance?: number }[]\n | undefined => {\n if (!Array.isArray(raw)) {\n return undefined\n }\n const records = raw\n .map((item) => asRecord(item))\n .filter((record): record is Record<string, unknown> =>\n Boolean(record),\n )\n const relevances = spreadRelevance(\n records.map((record) =>\n typeof record.similarity === 'number' ? record.similarity : 0,\n ),\n )\n return records.map((record, index) => ({\n record,\n relevance: relevances[index],\n }))\n }\n\n // searchInKnowledgeBase: group chunks by document, relevance compares the\n // best chunk score of each document within the result set.\n const knowledgeHits = computed<DetailHit[] | undefined>(() => {\n const results = output.value?.results\n if (!Array.isArray(results)) {\n return undefined\n }\n interface DocumentGroup {\n id: string\n type: string\n title: string\n url?: string\n similarity: number\n chunks: string[]\n }\n const groups = new Map<string, DocumentGroup>()\n for (const [index, raw] of results.entries()) {\n const result = asRecord(raw)\n if (!result) {\n continue\n }\n const document = asRecord(result.document)\n const source = asRecord(document?.source)\n const id =\n typeof document?.id === 'string' ? document.id : `doc-${index}`\n const similarity =\n typeof result.similarity === 'number' ? result.similarity : 0\n let group = groups.get(id)\n if (!group) {\n group = {\n id,\n type:\n typeof document?.type === 'string' ? document.type : '',\n title:\n pickString(document, 'name') ??\n pickString(source, 'filename', 'url') ??\n $t('messagePart.stepDocument'),\n url: pickString(source, 'url'),\n similarity,\n chunks: [],\n }\n groups.set(id, group)\n }\n group.similarity = Math.max(group.similarity, similarity)\n if (typeof result.content === 'string' && result.content.trim()) {\n group.chunks.push(result.content)\n }\n }\n const list = [...groups.values()]\n const relevances = spreadRelevance(list.map((g) => g.similarity))\n return list.map((group, index) => ({\n key: group.id,\n icon: group.type === 'url' ? 'ri:global-line' : 'ri:file-text-line',\n title: group.title,\n url: group.url,\n meta: $t('messagePart.stepExcerpts', group.chunks.length || 1),\n relevance: relevances[index],\n body: group.chunks.join('\\n\\n· · ·\\n\\n') || undefined,\n }))\n })\n\n // Chunks this turn had already returned come back as references without\n // content (spec retrieval-payload-per-turn, R2). They carry no document\n // name to group by, so they are summarized in one line: without it a\n // search that found only known passages reads as \"no results\".\n const repeatedCount = computed<number>(() => {\n const count = asRecord(output.value?.repeated)?.count\n return typeof count === 'number' ? count : 0\n })\n\n // Two declarations every search tool can attach to its output, and the\n // only ones the model is explicitly told not to read as an answer: a\n // query dropped for exceeding the tool's cap, and a search that ran out\n // of time. Without them a timeout renders as \"no results\", which is the\n // reading whoever opens a chat log would take away too.\n const searchFacts = computed<DetailFact[]>(() => {\n const facts: DetailFact[] = []\n const dropped = asRecord(output.value?.inputTruncated)?.dropped\n if (Array.isArray(dropped) && dropped.length) {\n facts.push({\n icon: 'ri:scissors-cut-line',\n text: $t('messagePart.stepDropped', dropped.length),\n })\n }\n const unavailable = asRecord(output.value?.searchUnavailable)\n if (unavailable) {\n // The corrected-answers tool declares one lookup without naming\n // its query, so an absent list means one search, not none.\n const queries = unavailable.queries\n facts.push({\n icon: 'ri:time-line',\n text: $t(\n 'messagePart.stepTimedOut',\n Array.isArray(queries) ? queries.length : 1,\n ),\n })\n }\n return facts\n })\n\n // retrieveRevisedAnswers: one hit per matched question, the corrected\n // answer is the expandable body.\n const revisedAnswerHits = computed<DetailHit[] | undefined>(() =>\n scoredRecords(output.value?.results)?.map(\n ({ record, relevance }, index) => ({\n key:\n pickString(record, 'revisedAnswerId') ?? `revised-${index}`,\n icon: 'ri:file-edit-line',\n title:\n pickString(record, 'userQuestion') ??\n $t('messagePart.revisedAnswers'),\n relevance,\n body: pickString(record, 'revisedMessage'),\n }),\n ),\n )\n\n // recallUserMemory / saveUserMemory delete candidates: one hit per\n // memory, long facts expand to their full text.\n const memoryHits = (raw: unknown): DetailHit[] | undefined =>\n scoredRecords(raw)?.map(({ record, relevance }, index) => {\n const content = pickString(record, 'content') ?? ''\n return {\n key: pickString(record, 'id') ?? `memory-${index}`,\n icon: 'ri:brain-line',\n title: content,\n meta: pickString(record, 'updatedAt')?.slice(0, 10),\n relevance,\n body: content.length > 120 ? content : undefined,\n }\n })\n\n // Query chips over a list of hits, flagging an explicit empty state so the\n // \"no results\" message shows once the tool has run (hits defined, length 0).\n const hitsDetail = (hits: DetailHit[] | undefined): Detail => ({\n chips: queryChips.value,\n hits,\n showEmpty: hits !== undefined && !hits.length,\n })\n\n // Rich, tool-specific view of the step. Returns {} when the tool has\n // nothing meaningful to show yet (the raw fallback is applied by `detail`).\n const buildDetail = (): Detail => {\n const type = props.part.type\n if (type === 'tool-searchInKnowledgeBase') {\n const knowledge = hitsDetail(knowledgeHits.value)\n if (repeatedCount.value) {\n knowledge.facts = [\n {\n icon: 'ri:history-line',\n text: $t(\n 'messagePart.stepRepeated',\n repeatedCount.value,\n ),\n },\n ]\n knowledge.showEmpty = false\n }\n return knowledge\n }\n if (type === 'tool-retrieveRevisedAnswers') {\n return hitsDetail(revisedAnswerHits.value)\n }\n if (type === 'tool-expandChunkContext') {\n const content = pickString(output.value, 'content')\n if (!content) {\n return {}\n }\n const totalChunks = output.value?.totalChunksReturned\n return {\n passage: {\n title: pickString(output.value, 'documentName'),\n meta:\n typeof totalChunks === 'number'\n ? $t('messagePart.stepExcerpts', totalChunks)\n : undefined,\n content,\n },\n }\n }\n if (type === 'tool-readDocumentFile') {\n const name = pickString(output.value, 'name')\n if (!name) {\n return {}\n }\n const mimeType = pickString(output.value, 'mimeType')\n return {\n facts: [\n {\n icon: 'ri:file-text-line',\n text: mimeType ? `${name} (${mimeType})` : name,\n },\n ],\n }\n }\n if (type === 'tool-getWeather') {\n const location =\n pickString(output.value, 'location') ??\n pickString(input.value, 'locationName') ??\n formatCoordinates(input.value)\n if (!location) {\n return {}\n }\n const startDate = pickString(input.value, 'startDate')\n const endDate = pickString(input.value, 'endDate')\n const dateRange = startDate\n ? endDate && endDate !== startDate\n ? ` · ${startDate} → ${endDate}`\n : ` · ${startDate}`\n : ''\n return {\n facts: [\n {\n icon: 'ri:sun-cloudy-line',\n text: `${location}${dateRange}`,\n },\n ],\n }\n }\n if (type === 'tool-geocode') {\n const from =\n pickString(input.value, 'locationName') ??\n formatCoordinates(input.value)\n const to =\n pickString(\n output.value,\n 'name',\n 'displayName',\n 'locationName',\n 'label',\n ) ?? formatCoordinates(output.value)\n const text =\n from && to && from !== to ? `${from} → ${to}` : (from ?? to)\n if (!text) {\n return {}\n }\n return {\n facts: [\n {\n icon: 'ri:map-pin-line',\n text,\n },\n ],\n }\n }\n if (type === 'tool-recallUserMemory') {\n return hitsDetail(memoryHits(output.value?.memories))\n }\n if (type === 'tool-saveUserMemory') {\n const candidates = memoryHits(output.value?.candidates)\n if (candidates) {\n return hitsDetail(candidates)\n }\n const text =\n pickString(input.value, 'content') ??\n pickString(output.value, 'message', 'error')\n if (!text) {\n return {}\n }\n return {\n facts: [\n {\n icon:\n pickString(input.value, 'action') === 'delete'\n ? 'ri:delete-bin-line'\n : 'ri:save-3-line',\n text,\n },\n ],\n }\n }\n if (WEB_SEARCH_TOOL_TYPES.includes(type)) {\n return {\n chips: queryChips.value,\n rawOutput: rawOutputValue.value,\n }\n }\n return {}\n }\n\n const detail = computed<Detail>(() => {\n const result = buildDetail()\n if (searchFacts.value.length) {\n result.facts = [...searchFacts.value, ...(result.facts ?? [])]\n }\n if (output.value?.searchUnavailable) {\n // \"No results found\" under a search that never answered is the\n // one sentence this fact exists to prevent.\n result.showEmpty = false\n }\n // Nothing meaningful to show for this tool yet (e.g. still running):\n // fall back to the raw payloads so the step body is never empty.\n const hasRichContent =\n result.chips?.length ||\n result.facts?.length ||\n result.passage ||\n result.showEmpty ||\n result.hits?.length\n if (!hasRichContent) {\n result.rawInput = rawInputValue.value\n result.rawOutput ??= rawOutputValue.value\n }\n return result\n })\n\n const expandedHits = reactive(new Set<string>())\n const toggleHit = (key: string) => {\n if (expandedHits.has(key)) {\n expandedHits.delete(key)\n } else {\n expandedHits.add(key)\n }\n }\n</script>\n\n<template>\n <div class=\"pk-chatbot-step-detail\">\n <ul v-if=\"detail.chips?.length\" class=\"pk-chatbot-step-detail__chips\">\n <li\n v-for=\"(chip, chipIndex) in detail.chips\"\n :key=\"`${chipIndex}-${chip}`\"\n class=\"pk-chatbot-step-detail__chip\">\n <VvIcon name=\"ri:search-line\" class=\"shrink-0\" />\n <span class=\"pk-chatbot-step-detail__chip-text\">\n {{ chip }}\n </span>\n </li>\n </ul>\n <div\n v-for=\"(fact, factIndex) in detail.facts\"\n :key=\"`${factIndex}-${fact.text}`\"\n class=\"pk-chatbot-step-detail__fact\">\n <VvIcon :name=\"fact.icon\" class=\"shrink-0\" />\n <span>{{ fact.text }}</span>\n </div>\n <div v-if=\"detail.showEmpty\" class=\"pk-chatbot-step-detail__empty\">\n {{ $t('messagePart.stepNoResults') }}\n </div>\n <ul\n v-else-if=\"detail.hits?.length\"\n class=\"pk-chatbot-step-detail__hits\">\n <li v-for=\"hit in detail.hits\" :key=\"hit.key\">\n <component\n :is=\"hit.body ? 'button' : 'div'\"\n :type=\"hit.body ? 'button' : undefined\"\n class=\"pk-chatbot-step-detail__hit-header\"\n :aria-expanded=\"\n hit.body ? expandedHits.has(hit.key) : undefined\n \"\n @click=\"hit.body ? toggleHit(hit.key) : undefined\">\n <VvIcon\n :name=\"hit.icon\"\n class=\"pk-chatbot-step-detail__hit-icon\" />\n <span class=\"pk-chatbot-step-detail__hit-heading\">\n <span class=\"pk-chatbot-step-detail__hit-title\">\n {{ hit.title }}\n </span>\n <a\n v-if=\"hit.url\"\n :href=\"hit.url\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"pk-chatbot-step-detail__link\"\n @click.stop>\n <VvIcon name=\"ri:external-link-line\" />\n </a>\n </span>\n <span\n v-if=\"hit.meta\"\n class=\"pk-chatbot-step-detail__hit-meta\">\n {{ hit.meta }}\n </span>\n <span\n v-if=\"hit.relevance !== undefined\"\n class=\"pk-chatbot-step-detail__relevance\"\n aria-hidden=\"true\">\n <span\n class=\"pk-chatbot-step-detail__relevance-fill\"\n :style=\"{\n width: `${Math.round(hit.relevance * 100)}%`,\n }\" />\n </span>\n <VvIcon\n v-if=\"hit.body\"\n :name=\"\n expandedHits.has(hit.key)\n ? 'ri:arrow-up-s-line'\n : 'ri:arrow-down-s-line'\n \"\n class=\"shrink-0\" />\n </component>\n <div\n v-if=\"hit.body && expandedHits.has(hit.key)\"\n class=\"pk-chatbot-step-detail__hit-body\">\n {{ hit.body }}\n </div>\n </li>\n </ul>\n <div v-if=\"detail.passage\" class=\"pk-chatbot-step-detail__passage\">\n <div class=\"pk-chatbot-step-detail__passage-header\">\n <VvIcon name=\"ri:file-text-line\" class=\"shrink-0\" />\n <span class=\"pk-chatbot-step-detail__hit-heading\">\n <span class=\"pk-chatbot-step-detail__hit-title\">\n {{\n detail.passage.title ??\n $t('messagePart.stepDocument')\n }}\n </span>\n </span>\n <span\n v-if=\"detail.passage.meta\"\n class=\"pk-chatbot-step-detail__hit-meta\">\n {{ detail.passage.meta }}\n </span>\n </div>\n <div class=\"pk-chatbot-step-detail__passage-content\">\n {{ detail.passage.content }}\n </div>\n </div>\n <PkChatbotStepPayload\n v-if=\"hasPayload(detail.rawInput)\"\n :label=\"$t('messagePart.stepInput')\"\n :value=\"detail.rawInput\" />\n <PkChatbotStepPayload\n v-if=\"hasPayload(detail.rawOutput)\"\n :label=\"$t('messagePart.stepOutput')\"\n :value=\"detail.rawOutput\" />\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-step-detail {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-8);\n font-size: var(--text-12);\n color: var(--color-word-3);\n\n &__chips {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-4);\n }\n\n &__chip {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-4);\n max-width: 100%;\n padding: var(--spacing-2) var(--spacing-8);\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded-full);\n background-color: var(--color-surface-1);\n color: var(--color-word-2);\n }\n\n &__chip-text {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &__fact {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n color: var(--color-word-2);\n }\n\n &__empty {\n color: var(--color-word-4);\n font-style: italic;\n }\n\n &__hits {\n display: flex;\n flex-direction: column;\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded);\n background-color: var(--color-surface-1);\n overflow: hidden;\n\n > li + li {\n border-top: var(--spacing-px) solid var(--color-surface-3);\n }\n }\n\n &__hit-header {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n width: 100%;\n min-height: var(--spacing-32);\n padding: var(--spacing-4) var(--spacing-8);\n text-align: left;\n\n &:is(button) {\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n }\n }\n\n &__hit-icon {\n flex-shrink: 0;\n color: var(--color-word-3);\n }\n\n // Grows to fill the row so meta, relevance and chevron stay aligned;\n // the title inside only shrinks, keeping the link icon next to the\n // title text instead of pushed to the right edge.\n &__hit-heading {\n display: flex;\n align-items: center;\n gap: var(--spacing-4);\n flex: 1 1 0;\n min-width: 0;\n }\n\n &__hit-title {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--color-word-2);\n }\n\n &__hit-meta {\n color: var(--color-word-4);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n }\n\n &__relevance {\n flex-shrink: 0;\n width: var(--spacing-40);\n height: var(--spacing-4);\n border-radius: var(--rounded-full);\n background-color: var(--color-surface-3);\n overflow: hidden;\n }\n\n &__relevance-fill {\n display: block;\n height: 100%;\n border-radius: inherit;\n background-color: var(--chatbot-main-color, var(--color-word-4));\n }\n\n &__link {\n flex-shrink: 0;\n display: inline-flex;\n color: var(--color-word-4);\n\n &:hover {\n color: var(--color-word-1);\n }\n }\n\n &__hit-body,\n &__passage-content {\n padding: var(--spacing-8);\n max-height: var(--spacing-160);\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n color: var(--color-word-3);\n }\n\n &__hit-body {\n border-top: var(--spacing-px) solid var(--color-surface-3);\n }\n\n &__passage {\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded);\n background-color: var(--color-surface-1);\n overflow: hidden;\n }\n\n &__passage-header {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n min-height: var(--spacing-32);\n padding: var(--spacing-4) var(--spacing-8);\n border-bottom: var(--spacing-px) solid var(--color-surface-3);\n }\n }\n</style>\n","<script lang=\"ts\" setup>\n import { computed, reactive } from 'vue'\n import { useI18n } from 'vue-i18n'\n import type { UIChatMessage } from 'models'\n import PkChatbotStepPayload from './PkChatbotStepPayload.vue'\n import { hasPayload, WEB_SEARCH_TOOL_TYPES } from './utils'\n\n type MessagePart = UIChatMessage['parts'][number]\n\n interface DetailHit {\n key: string\n icon: string\n title: string\n url?: string\n meta?: string\n relevance?: number\n body?: string\n }\n\n interface DetailFact {\n icon: string\n text: string\n }\n\n interface Detail {\n chips?: string[]\n facts?: DetailFact[]\n hits?: DetailHit[]\n showEmpty?: boolean\n passage?: { title?: string; meta?: string; content: string }\n rawInput?: unknown\n rawOutput?: unknown\n }\n\n const props = defineProps<{\n part: MessagePart\n }>()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n const asRecord = (value: unknown): Record<string, unknown> | undefined =>\n value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n\n const 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 const formatCoordinates = (\n record?: Record<string, unknown>,\n ): string | undefined => {\n const latitude = record?.latitude\n const longitude = record?.longitude\n if (typeof latitude !== 'number' || typeof longitude !== 'number') {\n return undefined\n }\n return `${latitude.toFixed(4)}, ${longitude.toFixed(4)}`\n }\n\n const rawInputValue = computed(() =>\n 'input' in props.part ? props.part.input : undefined,\n )\n const rawOutputValue = computed(() =>\n 'output' in props.part ? props.part.output : undefined,\n )\n const input = computed(() => asRecord(rawInputValue.value))\n const output = computed(() => asRecord(rawOutputValue.value))\n\n // Search queries shown as chips (queries[], query or objective)\n const queryChips = computed<string[]>(() => {\n const raw =\n input.value?.queries ?? input.value?.query ?? input.value?.objective\n if (typeof raw === 'string' && raw.trim()) {\n return [raw]\n }\n if (Array.isArray(raw)) {\n return raw.filter(\n (query): query is string =>\n typeof query === 'string' && Boolean(query.trim()),\n )\n }\n return []\n })\n\n // Raw scores live on different scales depending on the agent search mode\n // (RRF ~0.03, cosine 0 to 1) and tend to cluster, so a plain ratio on the\n // max renders every bar as ~100%. Spread them on a min/max scale with a\n // floor so the ordering stays visible, and hide the bar entirely when it\n // carries no information (single hit or identical scores).\n const spreadRelevance = (scores: number[]): (number | undefined)[] => {\n const min = Math.min(...scores)\n const max = Math.max(...scores)\n if (scores.length < 2 || max <= min) {\n return scores.map(() => undefined)\n }\n const floor = 0.15\n return scores.map(\n (score) => floor + ((score - min) / (max - min)) * (1 - floor),\n )\n }\n\n // Normalizes a raw result array into records paired with a spread\n // relevance derived from each record's `similarity` score.\n const scoredRecords = (\n raw: unknown,\n ):\n | { record: Record<string, unknown>; relevance?: number }[]\n | undefined => {\n if (!Array.isArray(raw)) {\n return undefined\n }\n const records = raw\n .map((item) => asRecord(item))\n .filter((record): record is Record<string, unknown> =>\n Boolean(record),\n )\n const relevances = spreadRelevance(\n records.map((record) =>\n typeof record.similarity === 'number' ? record.similarity : 0,\n ),\n )\n return records.map((record, index) => ({\n record,\n relevance: relevances[index],\n }))\n }\n\n // searchInKnowledgeBase: group chunks by document, relevance compares the\n // best chunk score of each document within the result set.\n const knowledgeHits = computed<DetailHit[] | undefined>(() => {\n const results = output.value?.results\n if (!Array.isArray(results)) {\n return undefined\n }\n interface DocumentGroup {\n id: string\n type: string\n title: string\n url?: string\n similarity: number\n chunks: string[]\n }\n const groups = new Map<string, DocumentGroup>()\n for (const [index, raw] of results.entries()) {\n const result = asRecord(raw)\n if (!result) {\n continue\n }\n const document = asRecord(result.document)\n const source = asRecord(document?.source)\n const id =\n typeof document?.id === 'string' ? document.id : `doc-${index}`\n const similarity =\n typeof result.similarity === 'number' ? result.similarity : 0\n let group = groups.get(id)\n if (!group) {\n group = {\n id,\n type:\n typeof document?.type === 'string' ? document.type : '',\n title:\n pickString(document, 'name') ??\n pickString(source, 'filename', 'url') ??\n $t('messagePart.stepDocument'),\n url: pickString(source, 'url'),\n similarity,\n chunks: [],\n }\n groups.set(id, group)\n }\n group.similarity = Math.max(group.similarity, similarity)\n if (typeof result.content === 'string' && result.content.trim()) {\n group.chunks.push(result.content)\n }\n }\n const list = [...groups.values()]\n const relevances = spreadRelevance(list.map((g) => g.similarity))\n return list.map((group, index) => ({\n key: group.id,\n icon: group.type === 'url' ? 'ri:global-line' : 'ri:file-text-line',\n title: group.title,\n url: group.url,\n meta: $t('messagePart.stepExcerpts', group.chunks.length || 1),\n relevance: relevances[index],\n body: group.chunks.join('\\n\\n· · ·\\n\\n') || undefined,\n }))\n })\n\n // Chunks this turn had already returned come back as references without\n // content (spec retrieval-payload-per-turn, R2). They carry no document\n // name to group by, so they are summarized in one line: without it a\n // search that found only known passages reads as \"no results\".\n const repeatedCount = computed<number>(() => {\n const count = asRecord(output.value?.repeated)?.count\n return typeof count === 'number' ? count : 0\n })\n\n // Two declarations every search tool can attach to its output, and the\n // only ones the model is explicitly told not to read as an answer: a\n // query dropped for exceeding the tool's cap, and a search that ran out\n // of time. Without them a timeout renders as \"no results\", which is the\n // reading whoever opens a chat log would take away too.\n const searchFacts = computed<DetailFact[]>(() => {\n const facts: DetailFact[] = []\n const dropped = asRecord(output.value?.inputTruncated)?.dropped\n if (Array.isArray(dropped) && dropped.length) {\n facts.push({\n icon: 'ri:scissors-cut-line',\n text: $t('messagePart.stepDropped', dropped.length),\n })\n }\n const unavailable = asRecord(output.value?.searchUnavailable)\n if (unavailable) {\n // The corrected-answers tool declares one lookup without naming\n // its query, so an absent list means one search, not none.\n const queries = unavailable.queries\n facts.push({\n icon: 'ri:time-line',\n text: $t(\n 'messagePart.stepTimedOut',\n Array.isArray(queries) ? queries.length : 1,\n ),\n })\n }\n return facts\n })\n\n // retrieveRevisedAnswers: one hit per matched question, the corrected\n // answer is the expandable body.\n const revisedAnswerHits = computed<DetailHit[] | undefined>(() =>\n scoredRecords(output.value?.results)?.map(\n ({ record, relevance }, index) => ({\n key:\n pickString(record, 'revisedAnswerId') ?? `revised-${index}`,\n icon: 'ri:file-edit-line',\n title:\n pickString(record, 'userQuestion') ??\n $t('messagePart.revisedAnswers'),\n relevance,\n body: pickString(record, 'revisedMessage'),\n }),\n ),\n )\n\n // recallUserMemory / saveUserMemory delete candidates: one hit per\n // memory, long facts expand to their full text.\n const memoryHits = (raw: unknown): DetailHit[] | undefined =>\n scoredRecords(raw)?.map(({ record, relevance }, index) => {\n const content = pickString(record, 'content') ?? ''\n return {\n key: pickString(record, 'id') ?? `memory-${index}`,\n icon: 'ri:brain-line',\n title: content,\n meta: pickString(record, 'updatedAt')?.slice(0, 10),\n relevance,\n body: content.length > 120 ? content : undefined,\n }\n })\n\n // Query chips over a list of hits, flagging an explicit empty state so the\n // \"no results\" message shows once the tool has run (hits defined, length 0).\n const hitsDetail = (hits: DetailHit[] | undefined): Detail => ({\n chips: queryChips.value,\n hits,\n showEmpty: hits !== undefined && !hits.length,\n })\n\n // Rich, tool-specific view of the step. Returns {} when the tool has\n // nothing meaningful to show yet (the raw fallback is applied by `detail`).\n const buildDetail = (): Detail => {\n const type = props.part.type\n if (type === 'tool-searchInKnowledgeBase') {\n const knowledge = hitsDetail(knowledgeHits.value)\n if (repeatedCount.value) {\n knowledge.facts = [\n {\n icon: 'ri:history-line',\n text: $t(\n 'messagePart.stepRepeated',\n repeatedCount.value,\n ),\n },\n ]\n knowledge.showEmpty = false\n }\n return knowledge\n }\n if (type === 'tool-retrieveRevisedAnswers') {\n return hitsDetail(revisedAnswerHits.value)\n }\n if (type === 'tool-expandChunkContext') {\n const content = pickString(output.value, 'content')\n if (!content) {\n return {}\n }\n const totalChunks = output.value?.totalChunksReturned\n return {\n passage: {\n title: pickString(output.value, 'documentName'),\n meta:\n typeof totalChunks === 'number'\n ? $t('messagePart.stepExcerpts', totalChunks)\n : undefined,\n content,\n },\n }\n }\n if (type === 'tool-readDocumentFile') {\n const name = pickString(output.value, 'name')\n if (!name) {\n return {}\n }\n const mimeType = pickString(output.value, 'mimeType')\n return {\n facts: [\n {\n icon: 'ri:file-text-line',\n text: mimeType ? `${name} (${mimeType})` : name,\n },\n ],\n }\n }\n if (type === 'tool-getWeather') {\n const location =\n pickString(output.value, 'location') ??\n pickString(input.value, 'locationName') ??\n formatCoordinates(input.value)\n if (!location) {\n return {}\n }\n const startDate = pickString(input.value, 'startDate')\n const endDate = pickString(input.value, 'endDate')\n const dateRange = startDate\n ? endDate && endDate !== startDate\n ? ` · ${startDate} → ${endDate}`\n : ` · ${startDate}`\n : ''\n return {\n facts: [\n {\n icon: 'ri:sun-cloudy-line',\n text: `${location}${dateRange}`,\n },\n ],\n }\n }\n if (type === 'tool-geocode') {\n const from =\n pickString(input.value, 'locationName') ??\n formatCoordinates(input.value)\n const to =\n pickString(\n output.value,\n 'name',\n 'displayName',\n 'locationName',\n 'label',\n ) ?? formatCoordinates(output.value)\n const text =\n from && to && from !== to ? `${from} → ${to}` : (from ?? to)\n if (!text) {\n return {}\n }\n return {\n facts: [\n {\n icon: 'ri:map-pin-line',\n text,\n },\n ],\n }\n }\n if (type === 'tool-recallUserMemory') {\n return hitsDetail(memoryHits(output.value?.memories))\n }\n if (type === 'tool-saveUserMemory') {\n const candidates = memoryHits(output.value?.candidates)\n if (candidates) {\n return hitsDetail(candidates)\n }\n const text =\n pickString(input.value, 'content') ??\n pickString(output.value, 'message', 'error')\n if (!text) {\n return {}\n }\n return {\n facts: [\n {\n icon:\n pickString(input.value, 'action') === 'delete'\n ? 'ri:delete-bin-line'\n : 'ri:save-3-line',\n text,\n },\n ],\n }\n }\n if (WEB_SEARCH_TOOL_TYPES.includes(type)) {\n return {\n chips: queryChips.value,\n rawOutput: rawOutputValue.value,\n }\n }\n return {}\n }\n\n const detail = computed<Detail>(() => {\n const result = buildDetail()\n if (searchFacts.value.length) {\n result.facts = [...searchFacts.value, ...(result.facts ?? [])]\n }\n if (output.value?.searchUnavailable) {\n // \"No results found\" under a search that never answered is the\n // one sentence this fact exists to prevent.\n result.showEmpty = false\n }\n // Nothing meaningful to show for this tool yet (e.g. still running):\n // fall back to the raw payloads so the step body is never empty.\n const hasRichContent =\n result.chips?.length ||\n result.facts?.length ||\n result.passage ||\n result.showEmpty ||\n result.hits?.length\n if (!hasRichContent) {\n result.rawInput = rawInputValue.value\n result.rawOutput ??= rawOutputValue.value\n }\n return result\n })\n\n const expandedHits = reactive(new Set<string>())\n const toggleHit = (key: string) => {\n if (expandedHits.has(key)) {\n expandedHits.delete(key)\n } else {\n expandedHits.add(key)\n }\n }\n</script>\n\n<template>\n <div class=\"pk-chatbot-step-detail\">\n <ul v-if=\"detail.chips?.length\" class=\"pk-chatbot-step-detail__chips\">\n <li\n v-for=\"(chip, chipIndex) in detail.chips\"\n :key=\"`${chipIndex}-${chip}`\"\n class=\"pk-chatbot-step-detail__chip\">\n <VvIcon name=\"ri:search-line\" class=\"shrink-0\" />\n <span class=\"pk-chatbot-step-detail__chip-text\">\n {{ chip }}\n </span>\n </li>\n </ul>\n <div\n v-for=\"(fact, factIndex) in detail.facts\"\n :key=\"`${factIndex}-${fact.text}`\"\n class=\"pk-chatbot-step-detail__fact\">\n <VvIcon :name=\"fact.icon\" class=\"shrink-0\" />\n <span>{{ fact.text }}</span>\n </div>\n <div v-if=\"detail.showEmpty\" class=\"pk-chatbot-step-detail__empty\">\n {{ $t('messagePart.stepNoResults') }}\n </div>\n <ul\n v-else-if=\"detail.hits?.length\"\n class=\"pk-chatbot-step-detail__hits\">\n <li v-for=\"hit in detail.hits\" :key=\"hit.key\">\n <component\n :is=\"hit.body ? 'button' : 'div'\"\n :type=\"hit.body ? 'button' : undefined\"\n class=\"pk-chatbot-step-detail__hit-header\"\n :aria-expanded=\"\n hit.body ? expandedHits.has(hit.key) : undefined\n \"\n @click=\"hit.body ? toggleHit(hit.key) : undefined\">\n <VvIcon\n :name=\"hit.icon\"\n class=\"pk-chatbot-step-detail__hit-icon\" />\n <span class=\"pk-chatbot-step-detail__hit-heading\">\n <span class=\"pk-chatbot-step-detail__hit-title\">\n {{ hit.title }}\n </span>\n <a\n v-if=\"hit.url\"\n :href=\"hit.url\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"pk-chatbot-step-detail__link\"\n @click.stop>\n <VvIcon name=\"ri:external-link-line\" />\n </a>\n </span>\n <span\n v-if=\"hit.meta\"\n class=\"pk-chatbot-step-detail__hit-meta\">\n {{ hit.meta }}\n </span>\n <span\n v-if=\"hit.relevance !== undefined\"\n class=\"pk-chatbot-step-detail__relevance\"\n aria-hidden=\"true\">\n <span\n class=\"pk-chatbot-step-detail__relevance-fill\"\n :style=\"{\n width: `${Math.round(hit.relevance * 100)}%`,\n }\" />\n </span>\n <VvIcon\n v-if=\"hit.body\"\n :name=\"\n expandedHits.has(hit.key)\n ? 'ri:arrow-up-s-line'\n : 'ri:arrow-down-s-line'\n \"\n class=\"shrink-0\" />\n </component>\n <div\n v-if=\"hit.body && expandedHits.has(hit.key)\"\n class=\"pk-chatbot-step-detail__hit-body\">\n {{ hit.body }}\n </div>\n </li>\n </ul>\n <div v-if=\"detail.passage\" class=\"pk-chatbot-step-detail__passage\">\n <div class=\"pk-chatbot-step-detail__passage-header\">\n <VvIcon name=\"ri:file-text-line\" class=\"shrink-0\" />\n <span class=\"pk-chatbot-step-detail__hit-heading\">\n <span class=\"pk-chatbot-step-detail__hit-title\">\n {{\n detail.passage.title ??\n $t('messagePart.stepDocument')\n }}\n </span>\n </span>\n <span\n v-if=\"detail.passage.meta\"\n class=\"pk-chatbot-step-detail__hit-meta\">\n {{ detail.passage.meta }}\n </span>\n </div>\n <div class=\"pk-chatbot-step-detail__passage-content\">\n {{ detail.passage.content }}\n </div>\n </div>\n <PkChatbotStepPayload\n v-if=\"hasPayload(detail.rawInput)\"\n :label=\"$t('messagePart.stepInput')\"\n :value=\"detail.rawInput\" />\n <PkChatbotStepPayload\n v-if=\"hasPayload(detail.rawOutput)\"\n :label=\"$t('messagePart.stepOutput')\"\n :value=\"detail.rawOutput\" />\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-step-detail {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-8);\n font-size: var(--text-12);\n color: var(--color-word-3);\n\n &__chips {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-4);\n }\n\n &__chip {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-4);\n max-width: 100%;\n padding: var(--spacing-2) var(--spacing-8);\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded-full);\n background-color: var(--color-surface-1);\n color: var(--color-word-2);\n }\n\n &__chip-text {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &__fact {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n color: var(--color-word-2);\n }\n\n &__empty {\n color: var(--color-word-4);\n font-style: italic;\n }\n\n &__hits {\n display: flex;\n flex-direction: column;\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded);\n background-color: var(--color-surface-1);\n overflow: hidden;\n\n > li + li {\n border-top: var(--spacing-px) solid var(--color-surface-3);\n }\n }\n\n &__hit-header {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n width: 100%;\n min-height: var(--spacing-32);\n padding: var(--spacing-4) var(--spacing-8);\n text-align: left;\n\n &:is(button) {\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n }\n }\n\n &__hit-icon {\n flex-shrink: 0;\n color: var(--color-word-3);\n }\n\n // Grows to fill the row so meta, relevance and chevron stay aligned;\n // the title inside only shrinks, keeping the link icon next to the\n // title text instead of pushed to the right edge.\n &__hit-heading {\n display: flex;\n align-items: center;\n gap: var(--spacing-4);\n flex: 1 1 0;\n min-width: 0;\n }\n\n &__hit-title {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--color-word-2);\n }\n\n &__hit-meta {\n color: var(--color-word-4);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n }\n\n &__relevance {\n flex-shrink: 0;\n width: var(--spacing-40);\n height: var(--spacing-4);\n border-radius: var(--rounded-full);\n background-color: var(--color-surface-3);\n overflow: hidden;\n }\n\n &__relevance-fill {\n display: block;\n height: 100%;\n border-radius: inherit;\n background-color: var(--chatbot-main-color, var(--color-word-4));\n }\n\n &__link {\n flex-shrink: 0;\n display: inline-flex;\n color: var(--color-word-4);\n\n &:hover {\n color: var(--color-word-1);\n }\n }\n\n &__hit-body,\n &__passage-content {\n padding: var(--spacing-8);\n max-height: var(--spacing-160);\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n color: var(--color-word-3);\n }\n\n &__hit-body {\n border-top: var(--spacing-px) solid var(--color-surface-3);\n }\n\n &__passage {\n border: var(--spacing-px) solid var(--color-surface-3);\n border-radius: var(--rounded);\n background-color: var(--color-surface-1);\n overflow: hidden;\n }\n\n &__passage-header {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n min-height: var(--spacing-32);\n padding: var(--spacing-4) var(--spacing-8);\n border-bottom: var(--spacing-px) solid var(--color-surface-3);\n }\n }\n</style>\n"],"mappings":"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"}