@xpert-ai/chatkit-ui 0.0.20 → 0.1.1

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 (611) hide show
  1. package/dist/app/assets/_baseUniq-p9H3Gzep.js +1 -0
  2. package/dist/app/assets/abap-bJX3iBqH.js +1 -0
  3. package/dist/app/assets/abnf-BoiZ35EE.js +1 -0
  4. package/dist/app/assets/actionscript-D-H9vZ8b.js +1 -0
  5. package/dist/app/assets/ada-Bne3WpOl.js +1 -0
  6. package/dist/app/assets/agda-C938cagi.js +1 -0
  7. package/dist/app/assets/al-Dcxw3Vj0.js +1 -0
  8. package/dist/app/assets/antlr4-uTm2QqyV.js +1 -0
  9. package/dist/app/assets/apacheconf-D52D513G.js +1 -0
  10. package/dist/app/assets/apex-B76H7J4g.js +1 -0
  11. package/dist/app/assets/apl-CzLk42pF.js +1 -0
  12. package/dist/app/assets/applescript-Dx8Ig-Eo.js +1 -0
  13. package/dist/app/assets/aql-wjx32tAU.js +1 -0
  14. package/dist/app/assets/arc-B32_yhh0.js +1 -0
  15. package/dist/app/assets/architectureDiagram-Q4EWVU46-Ba-C8DAI.js +36 -0
  16. package/dist/app/assets/arduino-BwKDxTSS.js +1 -0
  17. package/dist/app/assets/arff-DrkRViyY.js +1 -0
  18. package/dist/app/assets/asciidoc-BGLZq9v8.js +1 -0
  19. package/dist/app/assets/asm6502-MsEWIyJj.js +1 -0
  20. package/dist/app/assets/asmatmel-CeHxqS5T.js +1 -0
  21. package/dist/app/assets/aspnet-CmsQfR5a.js +1 -0
  22. package/dist/app/assets/autohotkey-Cusm-zTm.js +1 -0
  23. package/dist/app/assets/autoit-Da8gsEm-.js +1 -0
  24. package/dist/app/assets/avisynth-C46xLzyo.js +1 -0
  25. package/dist/app/assets/avro-idl-D2WmoYBG.js +1 -0
  26. package/dist/app/assets/{basic-B-OOkRrw.js → bash-BrsKn3za.js} +1 -1
  27. package/dist/app/assets/basic-Dt5oGQ8B.js +1 -0
  28. package/dist/app/assets/batch-DtrIlfXi.js +1 -0
  29. package/dist/app/assets/bbcode-BWYlAYoE.js +1 -0
  30. package/dist/app/assets/bicep-C4sxks0f.js +1 -0
  31. package/dist/app/assets/birb-gYyyIZ-F.js +1 -0
  32. package/dist/app/assets/bison-or-umhj6.js +1 -0
  33. package/dist/app/assets/blockDiagram-DXYQGD6D-5oqbPp8P.js +132 -0
  34. package/dist/app/assets/bnf-BQR7hfk2.js +1 -0
  35. package/dist/app/assets/brainfuck-DkQqhNHv.js +1 -0
  36. package/dist/app/assets/brightscript-rGhg0HBT.js +1 -0
  37. package/dist/app/assets/bro-CIgtBg0f.js +1 -0
  38. package/dist/app/assets/bsl-C4geIkQv.js +1 -0
  39. package/dist/app/assets/c-Cw5181Rv.js +1 -0
  40. package/dist/app/assets/c4Diagram-AHTNJAMY-BKyN5n0Y.js +10 -0
  41. package/dist/app/assets/cfscript-DHPNMvWS.js +1 -0
  42. package/dist/app/assets/chaiscript-Cd8c0hJ8.js +1 -0
  43. package/dist/app/assets/channel-Cx11sSAI.js +1 -0
  44. package/dist/app/assets/chunk-4BX2VUAB-CfLubn_X.js +1 -0
  45. package/dist/app/assets/chunk-4TB4RGXK-Bhehm3S4.js +206 -0
  46. package/dist/app/assets/chunk-55IACEB6-D0Zgi2qX.js +1 -0
  47. package/dist/app/assets/chunk-EDXVE4YY-DzMULs0l.js +1 -0
  48. package/dist/app/assets/chunk-FMBD7UC4-CEU9agAN.js +15 -0
  49. package/dist/app/assets/chunk-OYMX7WX6-C-avxOs6.js +231 -0
  50. package/dist/app/assets/chunk-QZHKN3VN-C66xsvBW.js +1 -0
  51. package/dist/app/assets/chunk-YZCP3GAM-DZlwMcoL.js +1 -0
  52. package/dist/app/assets/cil-L3oWT8Nl.js +1 -0
  53. package/dist/app/assets/classDiagram-6PBFFD2Q-BQrwJXsB.js +1 -0
  54. package/dist/app/assets/classDiagram-v2-HSJHXN6E-BQrwJXsB.js +1 -0
  55. package/dist/app/assets/clike-CHF9NJQa.js +1 -0
  56. package/dist/app/assets/clojure-YgRWUbgr.js +1 -0
  57. package/dist/app/assets/clone-DHPdZQ_6.js +1 -0
  58. package/dist/app/assets/cmake-TK-Cvlxu.js +1 -0
  59. package/dist/app/assets/cobol-XSbSVVcZ.js +1 -0
  60. package/dist/app/assets/coffeescript-HxNd9-Ob.js +1 -0
  61. package/dist/app/assets/concurnas-DK3wUjjD.js +1 -0
  62. package/dist/app/assets/coq-B9Rq7NUE.js +1 -0
  63. package/dist/app/assets/core-B1vWjEfj.js +1 -0
  64. package/dist/app/assets/cose-bilkent-S5V4N54A-4PebjqsX.js +1 -0
  65. package/dist/app/assets/cpp-DUWMh-8O.js +1 -0
  66. package/dist/app/assets/crystal-rYgGF4lS.js +1 -0
  67. package/dist/app/assets/csharp-eqTMyksU.js +1 -0
  68. package/dist/app/assets/cshtml-DSv9-mpk.js +1 -0
  69. package/dist/app/assets/csp-DyZfVzvb.js +1 -0
  70. package/dist/app/assets/css-DYXyUyJe.js +1 -0
  71. package/dist/app/assets/css-extras-FP15zHq8.js +1 -0
  72. package/dist/app/assets/csv-Bp1iUR7c.js +1 -0
  73. package/dist/app/assets/cypher-BjXgs7Y3.js +1 -0
  74. package/dist/app/assets/cytoscape.esm-DkOyvmE4.js +321 -0
  75. package/dist/app/assets/d-Bquc1S6a.js +1 -0
  76. package/dist/app/assets/dagre-KV5264BT-D9OICDLb.js +4 -0
  77. package/dist/app/assets/dart-DrKyO7TC.js +1 -0
  78. package/dist/app/assets/dataweave-BgpsWzO7.js +1 -0
  79. package/dist/app/assets/dax-BwP1SyCZ.js +1 -0
  80. package/dist/app/assets/defaultLocale-DX6XiGOO.js +1 -0
  81. package/dist/app/assets/dhall-BA5nXB8V.js +1 -0
  82. package/dist/app/assets/diagram-5BDNPKRD-BIFTIy6n.js +10 -0
  83. package/dist/app/assets/diagram-G4DWMVQ6-BCVIBrZ2.js +24 -0
  84. package/dist/app/assets/diagram-MMDJMWI5-43z4NaFN.js +43 -0
  85. package/dist/app/assets/diagram-TYMM5635-BDZjM1c_.js +24 -0
  86. package/dist/app/assets/diff-Yc6a7YOT.js +3 -0
  87. package/dist/app/assets/django-B61BBi1t.js +1 -0
  88. package/dist/app/assets/dns-zone-file-DtXhOJHq.js +1 -0
  89. package/dist/app/assets/docker-BLh9n10i.js +1 -0
  90. package/dist/app/assets/dot-BbSnn0Ap.js +1 -0
  91. package/dist/app/assets/ebnf-D_ljHBdb.js +1 -0
  92. package/dist/app/assets/editorconfig-BQXrLGC5.js +1 -0
  93. package/dist/app/assets/eiffel-Cm3FUI5X.js +1 -0
  94. package/dist/app/assets/ejs-CIp2UdDw.js +1 -0
  95. package/dist/app/assets/elixir-DXlWBe5R.js +1 -0
  96. package/dist/app/assets/elm-ECxjLCR-.js +1 -0
  97. package/dist/app/assets/erDiagram-SMLLAGMA-B9I89ndp.js +85 -0
  98. package/dist/app/assets/erb-FzgX8ydn.js +1 -0
  99. package/dist/app/assets/erlang-CzvdSvoz.js +1 -0
  100. package/dist/app/assets/etlua-C3Zsz3RA.js +1 -0
  101. package/dist/app/assets/excel-formula-Cua38PQJ.js +1 -0
  102. package/dist/app/assets/factor-CSAzXoQb.js +1 -0
  103. package/dist/app/assets/false-NSFMCUjP.js +1 -0
  104. package/dist/app/assets/firestore-security-rules-BjNYwvNe.js +1 -0
  105. package/dist/app/assets/flow-BuZaM8y6.js +1 -0
  106. package/dist/app/assets/flowDiagram-DWJPFMVM-CWmW_muY.js +162 -0
  107. package/dist/app/assets/fortran-Cc_f_mSH.js +1 -0
  108. package/dist/app/assets/fsharp-IelQ4Z-Z.js +1 -0
  109. package/dist/app/assets/ftl-Ddl9DDyG.js +1 -0
  110. package/dist/app/assets/ganttDiagram-T4ZO3ILL-CuR1J7dx.js +292 -0
  111. package/dist/app/assets/gap-D3W6p-Jp.js +1 -0
  112. package/dist/app/assets/gcode-Bn8O4UOx.js +1 -0
  113. package/dist/app/assets/gdscript-B4nck3Az.js +1 -0
  114. package/dist/app/assets/gedcom-BCTZRsxn.js +1 -0
  115. package/dist/app/assets/gherkin-CFCJQug9.js +1 -0
  116. package/dist/app/assets/git-Dd2t83_l.js +1 -0
  117. package/dist/app/assets/gitGraphDiagram-UUTBAWPF-DzscVnaS.js +106 -0
  118. package/dist/app/assets/glsl-NXGZDuA9.js +1 -0
  119. package/dist/app/assets/gml-DtS9_99j.js +1 -0
  120. package/dist/app/assets/gn-C6VmNt4U.js +1 -0
  121. package/dist/app/assets/go-module-CmBM8SA1.js +1 -0
  122. package/dist/app/assets/go-otK-v_nb.js +1 -0
  123. package/dist/app/assets/graph-BelNBDAZ.js +1 -0
  124. package/dist/app/assets/graphql-JPlPKrhh.js +1 -0
  125. package/dist/app/assets/groovy-CkMUqzIt.js +1 -0
  126. package/dist/app/assets/haml-DwaIQOGd.js +1 -0
  127. package/dist/app/assets/handlebars-Ck6RB1iw.js +1 -0
  128. package/dist/app/assets/haskell-BxYLBxBa.js +1 -0
  129. package/dist/app/assets/haxe-C4OMV9zJ.js +1 -0
  130. package/dist/app/assets/hcl-DVznmODf.js +1 -0
  131. package/dist/app/assets/hlsl-Z_ySkish.js +1 -0
  132. package/dist/app/assets/hoon-UWT3k4H8.js +1 -0
  133. package/dist/app/assets/hpkp-CXa39f7J.js +1 -0
  134. package/dist/app/assets/hsts-CJF4yNvU.js +1 -0
  135. package/dist/app/assets/http-BxOKxlr4.js +1 -0
  136. package/dist/app/assets/ichigojam-Csb66zY2.js +1 -0
  137. package/dist/app/assets/icon-DxphTQI9.js +1 -0
  138. package/dist/app/assets/icu-message-format-CSZfssuP.js +1 -0
  139. package/dist/app/assets/idris-BmXANiaa.js +1 -0
  140. package/dist/app/assets/iecst-FfznJdjL.js +1 -0
  141. package/dist/app/assets/ignore-C3IKkXMi.js +1 -0
  142. package/dist/app/assets/index-D972kqET.css +1 -0
  143. package/dist/app/assets/index-DmMWBDJR.js +747 -0
  144. package/dist/app/assets/infoDiagram-42DDH7IO-rTeQPEt4.js +2 -0
  145. package/dist/app/assets/inform7-Dk4gPo4b.js +1 -0
  146. package/dist/app/assets/ini-CClGKGMe.js +1 -0
  147. package/dist/app/assets/init-Gi6I4Gst.js +1 -0
  148. package/dist/app/assets/io-6YtqLtET.js +1 -0
  149. package/dist/app/assets/ishikawaDiagram-UXIWVN3A-BBnJ9iuN.js +70 -0
  150. package/dist/app/assets/j-DBPrIcAG.js +1 -0
  151. package/dist/app/assets/java-CopGP3Lu.js +1 -0
  152. package/dist/app/assets/javadoc-C8F3ifW2.js +1 -0
  153. package/dist/app/assets/javadoclike-BNVFpoJC.js +1 -0
  154. package/dist/app/assets/javascript-BMkkas2q.js +1 -0
  155. package/dist/app/assets/javastacktrace-DuykBujE.js +1 -0
  156. package/dist/app/assets/jexl-BSWOm8s5.js +1 -0
  157. package/dist/app/assets/jolie-CdkOmKFM.js +1 -0
  158. package/dist/app/assets/journeyDiagram-VCZTEJTY-CRDpL_1T.js +139 -0
  159. package/dist/app/assets/jq-Nr0Kxpxc.js +1 -0
  160. package/dist/app/assets/js-extras-CA8iZ_E5.js +1 -0
  161. package/dist/app/assets/js-templates-BoqcQW67.js +1 -0
  162. package/dist/app/assets/jsdoc-CeMFl6xP.js +1 -0
  163. package/dist/app/assets/json-CrSHUueM.js +1 -0
  164. package/dist/app/assets/json5-BBfX460l.js +1 -0
  165. package/dist/app/assets/jsonp-DHEqmGWL.js +1 -0
  166. package/dist/app/assets/jsstacktrace-BK3SuvsS.js +1 -0
  167. package/dist/app/assets/jsx-CjR3dp14.js +1 -0
  168. package/dist/app/assets/julia-BJJ6LUnI.js +1 -0
  169. package/dist/app/assets/kanban-definition-6JOO6SKY-Dztk4Auy.js +89 -0
  170. package/dist/app/assets/keepalived-CjGUJvsk.js +1 -0
  171. package/dist/app/assets/keyman-Bogz-7f0.js +1 -0
  172. package/dist/app/assets/kotlin-DGdetcAk.js +1 -0
  173. package/dist/app/assets/kumir-Czhml4-j.js +1 -0
  174. package/dist/app/assets/kusto-BuL9qwXk.js +1 -0
  175. package/dist/app/assets/latex-BAc_zS_4.js +1 -0
  176. package/dist/app/assets/latte-BzZFX_wH.js +1 -0
  177. package/dist/app/assets/layout-DOHRtR3x.js +1 -0
  178. package/dist/app/assets/less-DATW_Ot3.js +1 -0
  179. package/dist/app/assets/lilypond-DSmAdE7B.js +1 -0
  180. package/dist/app/assets/linear-rr7FzlEM.js +1 -0
  181. package/dist/app/assets/liquid-CF8lqz9m.js +1 -0
  182. package/dist/app/assets/lisp-BUPAsWUh.js +1 -0
  183. package/dist/app/assets/livescript-B8CIEQDH.js +1 -0
  184. package/dist/app/assets/llvm-DGaRc9w0.js +1 -0
  185. package/dist/app/assets/log-XuE3Wqn5.js +1 -0
  186. package/dist/app/assets/lolcode-Clk-p_j2.js +1 -0
  187. package/dist/app/assets/{java-CNwVyXY2.js → lua-BLczZbJa.js} +1 -1
  188. package/dist/app/assets/magma-DTO3ftgF.js +1 -0
  189. package/dist/app/assets/makefile-OSVaZHmV.js +1 -0
  190. package/dist/app/assets/markdown-InD7dXs9.js +1 -0
  191. package/dist/app/assets/markup-BN6MlRZT.js +1 -0
  192. package/dist/app/assets/markup-templating-DRXAmI1c.js +1 -0
  193. package/dist/app/assets/matlab-CV_q70_G.js +1 -0
  194. package/dist/app/assets/maxscript-Ck_8H__C.js +1 -0
  195. package/dist/app/assets/mel-D9MU0rZa.js +1 -0
  196. package/dist/app/assets/mermaid-DshECBS6.js +1 -0
  197. package/dist/app/assets/min-CfLzpwyh.js +1 -0
  198. package/dist/app/assets/mindmap-definition-QFDTVHPH-C7XGlydX.js +96 -0
  199. package/dist/app/assets/mizar-WBJ-SwIG.js +1 -0
  200. package/dist/app/assets/mongodb-CmzRTKBq.js +1 -0
  201. package/dist/app/assets/monkey-W1yB--1T.js +1 -0
  202. package/dist/app/assets/moonscript-BD5hlCXn.js +1 -0
  203. package/dist/app/assets/n1ql-CwugAEoM.js +1 -0
  204. package/dist/app/assets/n4js-tFC-Lsvd.js +1 -0
  205. package/dist/app/assets/nand2tetris-hdl-hzvfBJxH.js +1 -0
  206. package/dist/app/assets/naniscript-DUtjoUL1.js +1 -0
  207. package/dist/app/assets/nasm-Dcckq6ib.js +1 -0
  208. package/dist/app/assets/neon-DeVv09BE.js +1 -0
  209. package/dist/app/assets/nevod-CAq9Kfwt.js +1 -0
  210. package/dist/app/assets/nginx-C8GHDEqt.js +1 -0
  211. package/dist/app/assets/nim-BqdyUedD.js +1 -0
  212. package/dist/app/assets/nix-514mCcjs.js +1 -0
  213. package/dist/app/assets/nsis-CdKqXn3g.js +1 -0
  214. package/dist/app/assets/objectivec-uPp8iMUn.js +1 -0
  215. package/dist/app/assets/ocaml-D4EB6rFL.js +1 -0
  216. package/dist/app/assets/opencl-BN8tmrp-.js +1 -0
  217. package/dist/app/assets/openqasm-CZT9yVLH.js +1 -0
  218. package/dist/app/assets/ordinal-Cboi1Yqb.js +1 -0
  219. package/dist/app/assets/oz-xEnzbfGI.js +1 -0
  220. package/dist/app/assets/parigp-PN33G_ZS.js +1 -0
  221. package/dist/app/assets/parser-YigtK2Gn.js +1 -0
  222. package/dist/app/assets/pascal-BSQHqJO2.js +1 -0
  223. package/dist/app/assets/pascaligo-B3om_nlX.js +1 -0
  224. package/dist/app/assets/pcaxis-B_qwjIH4.js +1 -0
  225. package/dist/app/assets/peoplecode-G3CTxh8q.js +1 -0
  226. package/dist/app/assets/perl-CBvGMSZZ.js +1 -0
  227. package/dist/app/assets/php-DewJLtev.js +1 -0
  228. package/dist/app/assets/php-extras-BT2DdjGn.js +1 -0
  229. package/dist/app/assets/phpdoc-DiQXOd9D.js +1 -0
  230. package/dist/app/assets/pieDiagram-DEJITSTG-CYXmqIpD.js +30 -0
  231. package/dist/app/assets/plsql-BzUO3h3t.js +1 -0
  232. package/dist/app/assets/powerquery-D_713gdU.js +1 -0
  233. package/dist/app/assets/powershell-D7IGyPyT.js +1 -0
  234. package/dist/app/assets/processing-CULfTuKk.js +1 -0
  235. package/dist/app/assets/prolog-DI8sHw_1.js +1 -0
  236. package/dist/app/assets/promql-DdWPpZzX.js +1 -0
  237. package/dist/app/assets/properties-UUBptvjg.js +1 -0
  238. package/dist/app/assets/protobuf-Yh4lBroy.js +1 -0
  239. package/dist/app/assets/psl-CKuqp255.js +1 -0
  240. package/dist/app/assets/pug-Duz4hJlP.js +1 -0
  241. package/dist/app/assets/puppet-Tenfq4aE.js +1 -0
  242. package/dist/app/assets/pure-CTE3YKFb.js +1 -0
  243. package/dist/app/assets/purebasic-BzV6ZqWW.js +1 -0
  244. package/dist/app/assets/purescript-CjSCYtGb.js +1 -0
  245. package/dist/app/assets/q-BTX8RKFy.js +1 -0
  246. package/dist/app/assets/qml-CGjBjP81.js +1 -0
  247. package/dist/app/assets/qore-5Gggmt2I.js +1 -0
  248. package/dist/app/assets/qsharp-DhqE1FPx.js +1 -0
  249. package/dist/app/assets/quadrantDiagram-34T5L4WZ-BbnPMKp-.js +7 -0
  250. package/dist/app/assets/r-Dr0jr5tD.js +1 -0
  251. package/dist/app/assets/racket-NVUa01EO.js +1 -0
  252. package/dist/app/assets/reason-Bx5CI0l0.js +1 -0
  253. package/dist/app/assets/regex-12879jLK.js +1 -0
  254. package/dist/app/assets/rego-w2Fhvb_N.js +1 -0
  255. package/dist/app/assets/renpy-gPxX0z3Q.js +1 -0
  256. package/dist/app/assets/requirementDiagram-MS252O5E-BhOU7uOd.js +84 -0
  257. package/dist/app/assets/rest-C39bU2b1.js +1 -0
  258. package/dist/app/assets/rip-RLtTVF0Y.js +1 -0
  259. package/dist/app/assets/roboconf-BJckt4oD.js +1 -0
  260. package/dist/app/assets/robotframework-DCR96jiT.js +1 -0
  261. package/dist/app/assets/ruby-CRs8uxXB.js +1 -0
  262. package/dist/app/assets/rust-C0bGL254.js +1 -0
  263. package/dist/app/assets/sankeyDiagram-XADWPNL6-CFgkd6GO.js +10 -0
  264. package/dist/app/assets/sas-CkLtpL1M.js +1 -0
  265. package/dist/app/assets/sass-FNfCYuQd.js +1 -0
  266. package/dist/app/assets/scala-Dy5lip5O.js +1 -0
  267. package/dist/app/assets/scheme-pkKED5As.js +1 -0
  268. package/dist/app/assets/scss-DrZ4F_S5.js +1 -0
  269. package/dist/app/assets/sequenceDiagram-FGHM5R23-t5z2WRg9.js +157 -0
  270. package/dist/app/assets/shell-session-tfqRzQ64.js +1 -0
  271. package/dist/app/assets/smali-D9oJJF_a.js +1 -0
  272. package/dist/app/assets/smalltalk-FhicZwdZ.js +1 -0
  273. package/dist/app/assets/smarty-RTVkhvGe.js +1 -0
  274. package/dist/app/assets/sml-8jU1U62j.js +1 -0
  275. package/dist/app/assets/solidity-DLvpuywG.js +1 -0
  276. package/dist/app/assets/solution-file-BOwCbL9x.js +1 -0
  277. package/dist/app/assets/soy-Dye6FppK.js +1 -0
  278. package/dist/app/assets/sparql-BRIOTA6e.js +1 -0
  279. package/dist/app/assets/splunk-spl-xjEKSM5T.js +1 -0
  280. package/dist/app/assets/sqf-BTXRZqz9.js +1 -0
  281. package/dist/app/assets/sql-LIGcsz7H.js +1 -0
  282. package/dist/app/assets/squirrel-D1i-yP9F.js +1 -0
  283. package/dist/app/assets/stan-Bz-MTQlG.js +1 -0
  284. package/dist/app/assets/stateDiagram-FHFEXIEX-INV79XkW.js +1 -0
  285. package/dist/app/assets/stateDiagram-v2-QKLJ7IA2-DkwGLXRp.js +1 -0
  286. package/dist/app/assets/stylus-CPcHbGGR.js +1 -0
  287. package/dist/app/assets/swift-CMnIAhC_.js +1 -0
  288. package/dist/app/assets/systemd-CnQ86vtn.js +2 -0
  289. package/dist/app/assets/t4-cs-ClADD8kZ.js +1 -0
  290. package/dist/app/assets/t4-templating-BxEXIn9V.js +1 -0
  291. package/dist/app/assets/t4-vb-BuQFrDQM.js +1 -0
  292. package/dist/app/assets/tap-D-OeTv7J.js +1 -0
  293. package/dist/app/assets/tcl-D4EWmvqA.js +1 -0
  294. package/dist/app/assets/textile-vCa5WeBr.js +1 -0
  295. package/dist/app/assets/timeline-definition-GMOUNBTQ-CZVpkWZR.js +120 -0
  296. package/dist/app/assets/toml-CyQfWyMg.js +1 -0
  297. package/dist/app/assets/tremor-DTpakXR3.js +1 -0
  298. package/dist/app/assets/tt2-I3k-jzpY.js +1 -0
  299. package/dist/app/assets/turtle-BjS87MX7.js +1 -0
  300. package/dist/app/assets/twig-BYK2hDMY.js +1 -0
  301. package/dist/app/assets/typescript-DNEOvUVG.js +1 -0
  302. package/dist/app/assets/typoscript-hqzFge6d.js +1 -0
  303. package/dist/app/assets/unrealscript-_-NzaZj0.js +1 -0
  304. package/dist/app/assets/uorazor-BMR9qMW5.js +1 -0
  305. package/dist/app/assets/uri-BSGWfMxZ.js +1 -0
  306. package/dist/app/assets/v-CLtdeXIK.js +1 -0
  307. package/dist/app/assets/vala-wzCcqtKA.js +1 -0
  308. package/dist/app/assets/{turtle-D8pkqXh1.js → vbnet-DGCLmXdC.js} +1 -1
  309. package/dist/app/assets/velocity-DX_5gTOq.js +1 -0
  310. package/dist/app/assets/vennDiagram-DHZGUBPP-Dq1FXdcO.js +34 -0
  311. package/dist/app/assets/verilog-DeAFTKrK.js +1 -0
  312. package/dist/app/assets/vhdl-CgPp3m3I.js +1 -0
  313. package/dist/app/assets/vim-ZY6C4NgO.js +1 -0
  314. package/dist/app/assets/visual-basic-DmV7laqn.js +1 -0
  315. package/dist/app/assets/wardley-RL74JXVD-OqiGOeix.js +162 -0
  316. package/dist/app/assets/wardleyDiagram-NUSXRM2D-XXEOUAR6.js +20 -0
  317. package/dist/app/assets/warpscript-CST9Acbf.js +1 -0
  318. package/dist/app/assets/wasm-D44TvCcf.js +1 -0
  319. package/dist/app/assets/web-idl-CUAX3ogm.js +1 -0
  320. package/dist/app/assets/wiki-KNEqZQWK.js +1 -0
  321. package/dist/app/assets/wolfram-CZdD1bRd.js +1 -0
  322. package/dist/app/assets/wren-PITvEkQ4.js +1 -0
  323. package/dist/app/assets/xeora-BM_ABt9y.js +1 -0
  324. package/dist/app/assets/xml-doc-249eg8mF.js +1 -0
  325. package/dist/app/assets/xojo-M3SASV_b.js +1 -0
  326. package/dist/app/assets/xquery-BWv2VkcM.js +1 -0
  327. package/dist/app/assets/xychartDiagram-5P7HB3ND-CvXT15VO.js +7 -0
  328. package/dist/app/assets/yaml-B70AwQ7Y.js +1 -0
  329. package/dist/app/assets/yang-DffrsIpd.js +1 -0
  330. package/dist/app/assets/zig-C9vlYfKL.js +1 -0
  331. package/dist/app/index.html +2 -2
  332. package/dist/index.cjs +2734 -595
  333. package/dist/index.d.cts +20 -5
  334. package/dist/index.d.ts +20 -5
  335. package/dist/index.js +2768 -592
  336. package/package.json +8 -4
  337. package/dist/app/assets/abap-CabZ0vYL.js +0 -1
  338. package/dist/app/assets/abnf-CPoubvVG.js +0 -1
  339. package/dist/app/assets/actionscript-CL1BPQFv.js +0 -1
  340. package/dist/app/assets/ada-BOt55oS4.js +0 -1
  341. package/dist/app/assets/agda-DKyUkxie.js +0 -1
  342. package/dist/app/assets/al-Jnhqb7P-.js +0 -1
  343. package/dist/app/assets/antlr4-BeT3YbbK.js +0 -1
  344. package/dist/app/assets/apacheconf-Ck_DRZXY.js +0 -1
  345. package/dist/app/assets/apex-CPjbO0O4.js +0 -1
  346. package/dist/app/assets/apl-Ccs4_jOU.js +0 -1
  347. package/dist/app/assets/applescript-C6i7vo8F.js +0 -1
  348. package/dist/app/assets/aql-D3ZWY-VL.js +0 -1
  349. package/dist/app/assets/arduino-xTj3TTXg.js +0 -1
  350. package/dist/app/assets/arff-BOuVccGR.js +0 -1
  351. package/dist/app/assets/asciidoc-BmShvnn0.js +0 -1
  352. package/dist/app/assets/asm6502-6FWPK68i.js +0 -1
  353. package/dist/app/assets/asmatmel-KLAd82QV.js +0 -1
  354. package/dist/app/assets/aspnet-vZiSZd1y.js +0 -1
  355. package/dist/app/assets/autohotkey-tcBDP1b7.js +0 -1
  356. package/dist/app/assets/autoit-Bwt0tLM_.js +0 -1
  357. package/dist/app/assets/avisynth-Bzz43Lfu.js +0 -1
  358. package/dist/app/assets/avro-idl-Bt9aSyrD.js +0 -1
  359. package/dist/app/assets/bash-BloO3C-T.js +0 -1
  360. package/dist/app/assets/batch-aOUu2msA.js +0 -1
  361. package/dist/app/assets/bbcode-C4D8vm8O.js +0 -1
  362. package/dist/app/assets/bicep-BtBByAYv.js +0 -1
  363. package/dist/app/assets/birb-BKXLouTf.js +0 -1
  364. package/dist/app/assets/bison-CniuHJJN.js +0 -1
  365. package/dist/app/assets/bnf-CGcuZYv2.js +0 -1
  366. package/dist/app/assets/brainfuck-C9dlh056.js +0 -1
  367. package/dist/app/assets/brightscript-nhHFw9_4.js +0 -1
  368. package/dist/app/assets/bro-BTsReVOc.js +0 -1
  369. package/dist/app/assets/bsl-CmOTwcFR.js +0 -1
  370. package/dist/app/assets/c-Yjfq4oES.js +0 -1
  371. package/dist/app/assets/cfscript-DGhYlgJ7.js +0 -1
  372. package/dist/app/assets/chaiscript-CpP8bBSU.js +0 -1
  373. package/dist/app/assets/cil-CZ7j4pcz.js +0 -1
  374. package/dist/app/assets/clike-D581thF2.js +0 -1
  375. package/dist/app/assets/clojure-AXVmar0o.js +0 -1
  376. package/dist/app/assets/cmake-BozSSfax.js +0 -1
  377. package/dist/app/assets/cobol-OciN9vwY.js +0 -1
  378. package/dist/app/assets/coffeescript-B9yMzVL5.js +0 -1
  379. package/dist/app/assets/concurnas-DeQIM64O.js +0 -1
  380. package/dist/app/assets/coq-CicPksao.js +0 -1
  381. package/dist/app/assets/core-BIcqXTaK.js +0 -1
  382. package/dist/app/assets/cpp-DKQF7403.js +0 -1
  383. package/dist/app/assets/crystal-Bcau7QFZ.js +0 -1
  384. package/dist/app/assets/csharp-BYghYpTl.js +0 -1
  385. package/dist/app/assets/cshtml-BIxIGrsH.js +0 -1
  386. package/dist/app/assets/csp-CzDOD-m1.js +0 -1
  387. package/dist/app/assets/css-CPRwU6oY.js +0 -1
  388. package/dist/app/assets/css-extras-C28yWYxN.js +0 -1
  389. package/dist/app/assets/csv-D8IAZwKO.js +0 -1
  390. package/dist/app/assets/cypher-0hMRBt8D.js +0 -1
  391. package/dist/app/assets/d-B5PQgXXo.js +0 -1
  392. package/dist/app/assets/dart-CvCyf8me.js +0 -1
  393. package/dist/app/assets/dataweave-Izl0xtz9.js +0 -1
  394. package/dist/app/assets/dax-D-bGAkbS.js +0 -1
  395. package/dist/app/assets/dhall-DXIOSM5Q.js +0 -1
  396. package/dist/app/assets/diff-BE-xKdIi.js +0 -3
  397. package/dist/app/assets/django-DxEZdkeU.js +0 -1
  398. package/dist/app/assets/dns-zone-file-D406E4S7.js +0 -1
  399. package/dist/app/assets/docker-BZkb2U00.js +0 -1
  400. package/dist/app/assets/dot-BGJNVmx1.js +0 -1
  401. package/dist/app/assets/ebnf-_PEATas2.js +0 -1
  402. package/dist/app/assets/editorconfig-C1UuLwJC.js +0 -1
  403. package/dist/app/assets/eiffel-PzXVtlzf.js +0 -1
  404. package/dist/app/assets/ejs-707c0691.js +0 -1
  405. package/dist/app/assets/elixir-Bd3zWMjP.js +0 -1
  406. package/dist/app/assets/elm-DvEDEOdK.js +0 -1
  407. package/dist/app/assets/erb-B6lZT1P9.js +0 -1
  408. package/dist/app/assets/erlang-BwhqRmQk.js +0 -1
  409. package/dist/app/assets/etlua-Bkg93PrU.js +0 -1
  410. package/dist/app/assets/excel-formula-BD0I0dyD.js +0 -1
  411. package/dist/app/assets/factor-CiQgOsxY.js +0 -1
  412. package/dist/app/assets/false-DlJ-f_Rc.js +0 -1
  413. package/dist/app/assets/firestore-security-rules-CxrEhPSm.js +0 -1
  414. package/dist/app/assets/flow-DOjTBDi4.js +0 -1
  415. package/dist/app/assets/fortran-D6uA-pWI.js +0 -1
  416. package/dist/app/assets/fsharp-CFL1DcvT.js +0 -1
  417. package/dist/app/assets/ftl-DzWZwecM.js +0 -1
  418. package/dist/app/assets/gap-DatQeRFY.js +0 -1
  419. package/dist/app/assets/gcode-5FSxboIT.js +0 -1
  420. package/dist/app/assets/gdscript-Dz-OC8bG.js +0 -1
  421. package/dist/app/assets/gedcom-BS0539Ys.js +0 -1
  422. package/dist/app/assets/gherkin-BJKrWYAT.js +0 -1
  423. package/dist/app/assets/git-DCjIevVw.js +0 -1
  424. package/dist/app/assets/glsl-toSXKJrw.js +0 -1
  425. package/dist/app/assets/gml-DODsSWU7.js +0 -1
  426. package/dist/app/assets/gn-CzmtMWMm.js +0 -1
  427. package/dist/app/assets/go-BCQUEKVv.js +0 -1
  428. package/dist/app/assets/go-module-BbcV-9oG.js +0 -1
  429. package/dist/app/assets/graphql-C_KxCYJO.js +0 -1
  430. package/dist/app/assets/groovy-Cj97iKYK.js +0 -1
  431. package/dist/app/assets/haml-tLXJGYDb.js +0 -1
  432. package/dist/app/assets/handlebars-DIdVe3xN.js +0 -1
  433. package/dist/app/assets/haskell-DPqw5u4H.js +0 -1
  434. package/dist/app/assets/haxe-AsnHNCIR.js +0 -1
  435. package/dist/app/assets/hcl-C6aoWR34.js +0 -1
  436. package/dist/app/assets/hlsl-B2hhU30-.js +0 -1
  437. package/dist/app/assets/hoon-Bs-KhWO3.js +0 -1
  438. package/dist/app/assets/hpkp-C-J4O-Mp.js +0 -1
  439. package/dist/app/assets/hsts-BNFEkSnm.js +0 -1
  440. package/dist/app/assets/http-D7UlQANy.js +0 -1
  441. package/dist/app/assets/ichigojam-B01TJ8BA.js +0 -1
  442. package/dist/app/assets/icon-Ca_ghvQd.js +0 -1
  443. package/dist/app/assets/icu-message-format-CkcsJ0ML.js +0 -1
  444. package/dist/app/assets/idris-BApVxI9a.js +0 -1
  445. package/dist/app/assets/iecst-CXLR8sGn.js +0 -1
  446. package/dist/app/assets/ignore-7LzAeAFj.js +0 -1
  447. package/dist/app/assets/index-BUg2yVDW.js +0 -439
  448. package/dist/app/assets/index-om2E9pNd.css +0 -1
  449. package/dist/app/assets/inform7-CtnRN-Iq.js +0 -1
  450. package/dist/app/assets/ini-Cjpl6yTL.js +0 -1
  451. package/dist/app/assets/io-C6W_EboY.js +0 -1
  452. package/dist/app/assets/j-BOBDun2W.js +0 -1
  453. package/dist/app/assets/javadoc-DS6hxu7_.js +0 -1
  454. package/dist/app/assets/javadoclike-J6YT11JS.js +0 -1
  455. package/dist/app/assets/javascript-IbEfuVSB.js +0 -1
  456. package/dist/app/assets/javastacktrace-DjxwGV26.js +0 -1
  457. package/dist/app/assets/jexl-TLHmHaQ5.js +0 -1
  458. package/dist/app/assets/jolie-CLk71kur.js +0 -1
  459. package/dist/app/assets/jq-DZKnIQZM.js +0 -1
  460. package/dist/app/assets/js-extras-CJab09ti.js +0 -1
  461. package/dist/app/assets/js-templates-CQGqrHhi.js +0 -1
  462. package/dist/app/assets/jsdoc--ymvl4aq.js +0 -1
  463. package/dist/app/assets/json-D9b-V85G.js +0 -1
  464. package/dist/app/assets/json5-LgA47n7A.js +0 -1
  465. package/dist/app/assets/jsonp-Cvwp3f8M.js +0 -1
  466. package/dist/app/assets/jsstacktrace-z8t2H6h6.js +0 -1
  467. package/dist/app/assets/jsx-B71LrwNd.js +0 -1
  468. package/dist/app/assets/julia-DCATdxwO.js +0 -1
  469. package/dist/app/assets/keepalived-DVYYbgrL.js +0 -1
  470. package/dist/app/assets/keyman-DLyOXnhf.js +0 -1
  471. package/dist/app/assets/kotlin-CYoDfyDA.js +0 -1
  472. package/dist/app/assets/kumir-CPWiEvmL.js +0 -1
  473. package/dist/app/assets/kusto-BkfRYk0W.js +0 -1
  474. package/dist/app/assets/latex-BEjZ0ppC.js +0 -1
  475. package/dist/app/assets/latte-DaZOqdGV.js +0 -1
  476. package/dist/app/assets/less-BmKsj1gN.js +0 -1
  477. package/dist/app/assets/lilypond-mmng28aJ.js +0 -1
  478. package/dist/app/assets/liquid-BuuJO6_6.js +0 -1
  479. package/dist/app/assets/lisp-DnffFM5N.js +0 -1
  480. package/dist/app/assets/livescript-BSsr00Wr.js +0 -1
  481. package/dist/app/assets/llvm-37YjcHN5.js +0 -1
  482. package/dist/app/assets/log-D3l5N3To.js +0 -1
  483. package/dist/app/assets/lolcode-C0Q2M_6s.js +0 -1
  484. package/dist/app/assets/lua-DcLwN4Tg.js +0 -1
  485. package/dist/app/assets/magma-CK0Amip9.js +0 -1
  486. package/dist/app/assets/makefile-CtpS-RoO.js +0 -1
  487. package/dist/app/assets/markdown-BNK3F4ql.js +0 -1
  488. package/dist/app/assets/markup-C9GIL65H.js +0 -1
  489. package/dist/app/assets/markup-templating-Du1J3ADP.js +0 -1
  490. package/dist/app/assets/matlab-DEM6O1Ul.js +0 -1
  491. package/dist/app/assets/maxscript-DMvqa3gf.js +0 -1
  492. package/dist/app/assets/mel-C8DBIw1g.js +0 -1
  493. package/dist/app/assets/mermaid-CVko6NSq.js +0 -1
  494. package/dist/app/assets/mizar-CwYm3_It.js +0 -1
  495. package/dist/app/assets/mongodb-DRqGwjq6.js +0 -1
  496. package/dist/app/assets/monkey-BxiKe6Nr.js +0 -1
  497. package/dist/app/assets/moonscript-CJyt1xoM.js +0 -1
  498. package/dist/app/assets/n1ql-BBmjIGEU.js +0 -1
  499. package/dist/app/assets/n4js-ByKsJMJL.js +0 -1
  500. package/dist/app/assets/nand2tetris-hdl-BTSXj71h.js +0 -1
  501. package/dist/app/assets/naniscript-C4jykFVF.js +0 -1
  502. package/dist/app/assets/nasm-DPA0eXtX.js +0 -1
  503. package/dist/app/assets/neon-upN4Ak64.js +0 -1
  504. package/dist/app/assets/nevod-CdttHB8F.js +0 -1
  505. package/dist/app/assets/nginx-DI1fsQ3j.js +0 -1
  506. package/dist/app/assets/nim-D7kc_mK9.js +0 -1
  507. package/dist/app/assets/nix-BUG5ppr9.js +0 -1
  508. package/dist/app/assets/nsis-BnXhmmxO.js +0 -1
  509. package/dist/app/assets/objectivec-Bu4dOfb9.js +0 -1
  510. package/dist/app/assets/ocaml-aT7VVPiL.js +0 -1
  511. package/dist/app/assets/opencl-BzyWcYkI.js +0 -1
  512. package/dist/app/assets/openqasm-b2yFBJdq.js +0 -1
  513. package/dist/app/assets/oz-D46TtIuw.js +0 -1
  514. package/dist/app/assets/parigp-BAJyhdut.js +0 -1
  515. package/dist/app/assets/parser-B-ALvauC.js +0 -1
  516. package/dist/app/assets/pascal-B0ap4FDW.js +0 -1
  517. package/dist/app/assets/pascaligo-ChOneu9-.js +0 -1
  518. package/dist/app/assets/pcaxis-DTAmxHgs.js +0 -1
  519. package/dist/app/assets/peoplecode-dQfUy8zn.js +0 -1
  520. package/dist/app/assets/perl-CYk00e1Q.js +0 -1
  521. package/dist/app/assets/php-DvSqFnSN.js +0 -1
  522. package/dist/app/assets/php-extras-BFjUbIU6.js +0 -1
  523. package/dist/app/assets/phpdoc-Di7rKCNL.js +0 -1
  524. package/dist/app/assets/plsql-dX0-BKqD.js +0 -1
  525. package/dist/app/assets/powerquery-3xq4KaAs.js +0 -1
  526. package/dist/app/assets/powershell-BbXooszO.js +0 -1
  527. package/dist/app/assets/processing-GWbfNCzH.js +0 -1
  528. package/dist/app/assets/prolog-Tb2TbunJ.js +0 -1
  529. package/dist/app/assets/promql-QS8vHhL7.js +0 -1
  530. package/dist/app/assets/properties-BJ8AWlqX.js +0 -1
  531. package/dist/app/assets/protobuf-De-puAg3.js +0 -1
  532. package/dist/app/assets/psl-hZft3C8K.js +0 -1
  533. package/dist/app/assets/pug-BcYHdk-i.js +0 -1
  534. package/dist/app/assets/puppet-BWbqDQJD.js +0 -1
  535. package/dist/app/assets/pure-Bz2pjTxR.js +0 -1
  536. package/dist/app/assets/purebasic-BlO48lYx.js +0 -1
  537. package/dist/app/assets/purescript-BxSMm2Br.js +0 -1
  538. package/dist/app/assets/q-DDUTW9aK.js +0 -1
  539. package/dist/app/assets/qml-DisOV-LV.js +0 -1
  540. package/dist/app/assets/qore-FNRP4gBF.js +0 -1
  541. package/dist/app/assets/qsharp-DhtMV0oO.js +0 -1
  542. package/dist/app/assets/r-CyiuHjNN.js +0 -1
  543. package/dist/app/assets/racket-DFgoSckH.js +0 -1
  544. package/dist/app/assets/reason-HhYbY7K3.js +0 -1
  545. package/dist/app/assets/regex-jU5TpvM-.js +0 -1
  546. package/dist/app/assets/rego-BCjDPrQO.js +0 -1
  547. package/dist/app/assets/renpy-BTSgQi2v.js +0 -1
  548. package/dist/app/assets/rest-BLcZ4e-5.js +0 -1
  549. package/dist/app/assets/rip-SltRJnuI.js +0 -1
  550. package/dist/app/assets/roboconf-B-GZm2Oe.js +0 -1
  551. package/dist/app/assets/robotframework-BOt8S6cX.js +0 -1
  552. package/dist/app/assets/ruby-CVfYH0zM.js +0 -1
  553. package/dist/app/assets/rust-B6mEp4Sj.js +0 -1
  554. package/dist/app/assets/sas-DvEI8RJ0.js +0 -1
  555. package/dist/app/assets/sass-Cv25Jxqq.js +0 -1
  556. package/dist/app/assets/scala-CyqNr7Uv.js +0 -1
  557. package/dist/app/assets/scheme-ji0XoXLf.js +0 -1
  558. package/dist/app/assets/scss-B7_0neO_.js +0 -1
  559. package/dist/app/assets/shell-session-CqZEoMQD.js +0 -1
  560. package/dist/app/assets/smali-DKSzZYkI.js +0 -1
  561. package/dist/app/assets/smalltalk-BOA4piuq.js +0 -1
  562. package/dist/app/assets/smarty-Du99BSgN.js +0 -1
  563. package/dist/app/assets/sml-BJedIA4B.js +0 -1
  564. package/dist/app/assets/solidity-DidQwG5Z.js +0 -1
  565. package/dist/app/assets/solution-file-Bx0d9qN8.js +0 -1
  566. package/dist/app/assets/soy-BBLv3Cfa.js +0 -1
  567. package/dist/app/assets/sparql-Da5WZKbL.js +0 -1
  568. package/dist/app/assets/splunk-spl-DbJKl8So.js +0 -1
  569. package/dist/app/assets/sqf-CYrx0jxf.js +0 -1
  570. package/dist/app/assets/sql-Gv-aOlOf.js +0 -1
  571. package/dist/app/assets/squirrel-FpIGPPw4.js +0 -1
  572. package/dist/app/assets/stan-Dq001Nrk.js +0 -1
  573. package/dist/app/assets/stylus-aatfgWwe.js +0 -1
  574. package/dist/app/assets/swift-pn7VW95d.js +0 -1
  575. package/dist/app/assets/systemd-9capsVJ6.js +0 -2
  576. package/dist/app/assets/t4-cs-CKXcczci.js +0 -1
  577. package/dist/app/assets/t4-templating-1wTayb8u.js +0 -1
  578. package/dist/app/assets/t4-vb-B_O7wBow.js +0 -1
  579. package/dist/app/assets/tap-D-TV5_gQ.js +0 -1
  580. package/dist/app/assets/tcl-BaVob1Om.js +0 -1
  581. package/dist/app/assets/textile-COMk-HmI.js +0 -1
  582. package/dist/app/assets/toml-D9NJpArC.js +0 -1
  583. package/dist/app/assets/tremor-rCNHwdQL.js +0 -1
  584. package/dist/app/assets/tt2-DTDvfOgc.js +0 -1
  585. package/dist/app/assets/twig-DxSF8gqH.js +0 -1
  586. package/dist/app/assets/typescript-Caebatmk.js +0 -1
  587. package/dist/app/assets/typoscript-B3uk1kES.js +0 -1
  588. package/dist/app/assets/unrealscript-ZNoSG8ji.js +0 -1
  589. package/dist/app/assets/uorazor-LekoNNOo.js +0 -1
  590. package/dist/app/assets/uri-B8YcIzOv.js +0 -1
  591. package/dist/app/assets/v-6rOne2a0.js +0 -1
  592. package/dist/app/assets/vala-CjEJEdsP.js +0 -1
  593. package/dist/app/assets/vbnet-DBPmBm7_.js +0 -1
  594. package/dist/app/assets/velocity-DOooMwL8.js +0 -1
  595. package/dist/app/assets/verilog-Cq0ZocvP.js +0 -1
  596. package/dist/app/assets/vhdl-Dxs_xidb.js +0 -1
  597. package/dist/app/assets/vim-BqsnXwB6.js +0 -1
  598. package/dist/app/assets/visual-basic-zAzjvaqP.js +0 -1
  599. package/dist/app/assets/warpscript-D9hbfr6_.js +0 -1
  600. package/dist/app/assets/wasm-C4TU9VDY.js +0 -1
  601. package/dist/app/assets/web-idl-DD5JcddQ.js +0 -1
  602. package/dist/app/assets/wiki-Des21yVK.js +0 -1
  603. package/dist/app/assets/wolfram-B7enpov1.js +0 -1
  604. package/dist/app/assets/wren-Rr8h-Ayu.js +0 -1
  605. package/dist/app/assets/xeora-EjcLXBhx.js +0 -1
  606. package/dist/app/assets/xml-doc-uaTxx6-m.js +0 -1
  607. package/dist/app/assets/xojo-CX6G8nhh.js +0 -1
  608. package/dist/app/assets/xquery-DvPb3Uw9.js +0 -1
  609. package/dist/app/assets/yaml-D-l_Y2hx.js +0 -1
  610. package/dist/app/assets/yang-KBoIIT4_.js +0 -1
  611. package/dist/app/assets/zig-_uNXp9cY.js +0 -1
package/dist/index.js CHANGED
@@ -1,6 +1,15 @@
1
1
  // src/components/chat.tsx
2
- import * as React20 from "react";
3
- import { ArrowDown, FileText as FileText2, Loader2 as Loader22, Pencil as Pencil3, RefreshCw as RefreshCw2, X as X2 } from "lucide-react";
2
+ import * as React22 from "react";
3
+ import {
4
+ ArrowDown,
5
+ FileText as FileText2,
6
+ ImageIcon,
7
+ Loader2 as Loader23,
8
+ Pencil as Pencil3,
9
+ Quote,
10
+ RefreshCw as RefreshCw2,
11
+ X as X3
12
+ } from "lucide-react";
4
13
 
5
14
  // src/lib/utils.ts
6
15
  import { clsx } from "clsx";
@@ -21,6 +30,64 @@ function createMessageId() {
21
30
  return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
22
31
  }
23
32
 
33
+ // src/lib/message.ts
34
+ import { isNil, omitBy } from "lodash-es";
35
+ var ASSISTANT_STREAM_IDLE_TO_THINKING_MS = 2e3;
36
+ function hasRenderableReasoning(reasoning) {
37
+ return Array.isArray(reasoning) && reasoning.some((item) => item.text?.trim());
38
+ }
39
+ function hasRenderableMessageContent(content) {
40
+ if (typeof content === "string") {
41
+ return content.trim().length > 0;
42
+ }
43
+ if (!Array.isArray(content) || content.length === 0) {
44
+ return false;
45
+ }
46
+ const items = content;
47
+ return items.some((item) => {
48
+ if (typeof item === "string") {
49
+ return item.trim().length > 0;
50
+ }
51
+ if (!item || typeof item !== "object") {
52
+ return false;
53
+ }
54
+ if (item.type === "text") {
55
+ return Boolean(item.text?.trim());
56
+ }
57
+ if (item.type === "reasoning") {
58
+ return Boolean(item.text?.trim());
59
+ }
60
+ return true;
61
+ });
62
+ }
63
+ function hasRenderableAssistantMessage(message) {
64
+ return hasRenderableMessageContent(message.content) || hasRenderableReasoning(message.reasoning);
65
+ }
66
+ function getAssistantStreamingStatus(message, isStreaming, options) {
67
+ if (!isStreaming) {
68
+ return null;
69
+ }
70
+ const now = options?.now ?? Date.now();
71
+ const lastStreamOutputAt = typeof message.lastStreamOutputAt === "number" ? message.lastStreamOutputAt : null;
72
+ const isIdle = lastStreamOutputAt !== null && now - lastStreamOutputAt >= ASSISTANT_STREAM_IDLE_TO_THINKING_MS;
73
+ if (message.status === "reasoning") {
74
+ return "thinking";
75
+ }
76
+ if (message.status === "answering") {
77
+ if (isIdle) {
78
+ return "thinking";
79
+ }
80
+ return "answering";
81
+ }
82
+ if (hasRenderableReasoning(message.reasoning)) {
83
+ return "thinking";
84
+ }
85
+ if (isIdle) {
86
+ return "thinking";
87
+ }
88
+ return "loading";
89
+ }
90
+
24
91
  // src/lib/scroll.ts
25
92
  var BOTTOM_FOLLOW_THRESHOLD_PX = 48;
26
93
  function getDistanceFromBottom(element) {
@@ -45,7 +112,29 @@ import {
45
112
  Client
46
113
  } from "@xpert-ai/xpert-sdk";
47
114
  import "@langchain/core/messages/tool";
48
- import { ChatMessageEventTypeEnum, ChatMessageTypeEnum } from "@xpert-ai/chatkit-types";
115
+ import {
116
+ ChatMessageEventTypeEnum,
117
+ ChatMessageTypeEnum
118
+ } from "@xpert-ai/chatkit-types";
119
+
120
+ // src/lib/api-config.ts
121
+ function hasConfiguredValue(value) {
122
+ return typeof value === "string" && value.trim().length > 0;
123
+ }
124
+ function getMissingApiConfigurationKind({
125
+ apiUrl,
126
+ clientSecret
127
+ }) {
128
+ const hasApiUrl = hasConfiguredValue(apiUrl);
129
+ const hasClientSecret = hasConfiguredValue(clientSecret);
130
+ if (hasApiUrl && hasClientSecret) {
131
+ return null;
132
+ }
133
+ if (!hasApiUrl && !hasClientSecret) {
134
+ return "apiUrlAndClientSecret";
135
+ }
136
+ return hasApiUrl ? "clientSecret" : "apiUrl";
137
+ }
49
138
 
50
139
  // src/lib/request-options.ts
51
140
  import {
@@ -129,8 +218,16 @@ function buildInjectedRequestOptions(input) {
129
218
  import { useContext, useEffect as useEffect2, useRef as useRef2 } from "react";
130
219
 
131
220
  // src/providers/ParentMessenger.tsx
132
- import { createContext, useCallback, useEffect, useMemo, useRef } from "react";
133
- import { STATE_VARIABLE_HUMAN as STATE_VARIABLE_HUMAN2 } from "@xpert-ai/chatkit-types";
221
+ import {
222
+ createContext,
223
+ useCallback,
224
+ useEffect,
225
+ useMemo,
226
+ useRef
227
+ } from "react";
228
+ import {
229
+ STATE_VARIABLE_HUMAN as STATE_VARIABLE_HUMAN2
230
+ } from "@xpert-ai/chatkit-types";
134
231
 
135
232
  // src/hooks/useStream.ts
136
233
  var streamRef = { current: null };
@@ -144,6 +241,302 @@ function useStreamManager() {
144
241
  };
145
242
  }
146
243
 
244
+ // src/lib/references.ts
245
+ function isObjectLike(value) {
246
+ return typeof value === "object" && value !== null && !Array.isArray(value);
247
+ }
248
+ function isNonEmptyString(value) {
249
+ return typeof value === "string" && value.trim().length > 0;
250
+ }
251
+ function isOptionalString(value) {
252
+ return value === void 0 || typeof value === "string";
253
+ }
254
+ function toOptionalString(value) {
255
+ return isNonEmptyString(value) ? value.trim() : void 0;
256
+ }
257
+ function toReferenceText(value) {
258
+ return typeof value === "string" && value.trim().length > 0 ? value : null;
259
+ }
260
+ function toLineNumber(value) {
261
+ if (typeof value === "number" && Number.isInteger(value) && value > 0) {
262
+ return value;
263
+ }
264
+ return null;
265
+ }
266
+ function isOptionalNumber(value) {
267
+ return value === void 0 || Number.isFinite(value);
268
+ }
269
+ function toOptionalNumber(value, options) {
270
+ const allowZero = options?.allowZero ?? false;
271
+ if (!Number.isFinite(value)) {
272
+ return void 0;
273
+ }
274
+ const numberValue = value;
275
+ if (numberValue > 0 || allowZero && numberValue === 0) {
276
+ return numberValue;
277
+ }
278
+ return void 0;
279
+ }
280
+ function hasImageReferenceLocator(candidate) {
281
+ return isNonEmptyString(candidate.fileId) || isNonEmptyString(candidate.url) || isNonEmptyString(candidate.name) || isNonEmptyString(candidate.label) || isNonEmptyString(candidate.text);
282
+ }
283
+ function isCodeReferenceCandidate(value) {
284
+ if (!isObjectLike(value)) {
285
+ return false;
286
+ }
287
+ const candidate = value;
288
+ return isNonEmptyString(candidate.path) && toLineNumber(candidate.startLine) !== null && toLineNumber(candidate.endLine) !== null && toReferenceText(candidate.text) !== null && isOptionalString(candidate.id) && isOptionalString(candidate.label) && isOptionalString(candidate.language) && isOptionalString(candidate.taskId);
289
+ }
290
+ function isQuoteReferenceCandidate(value) {
291
+ if (!isObjectLike(value)) {
292
+ return false;
293
+ }
294
+ const candidate = value;
295
+ return candidate.type === "quote" && toReferenceText(candidate.text) !== null && isOptionalString(candidate.id) && isOptionalString(candidate.label) && isOptionalString(candidate.messageId) && isOptionalString(candidate.source);
296
+ }
297
+ function isImageReferenceCandidate(value) {
298
+ if (!isObjectLike(value)) {
299
+ return false;
300
+ }
301
+ const candidate = value;
302
+ return candidate.type === "image" && isOptionalString(candidate.id) && isOptionalString(candidate.label) && isOptionalString(candidate.text) && isOptionalString(candidate.fileId) && isOptionalString(candidate.url) && isOptionalString(candidate.mimeType) && isOptionalString(candidate.name) && isOptionalNumber(candidate.size) && isOptionalNumber(candidate.width) && isOptionalNumber(candidate.height) && hasImageReferenceLocator(candidate);
303
+ }
304
+ function toCodeReference(candidate) {
305
+ return {
306
+ type: "code",
307
+ ...toOptionalString(candidate.id) ? { id: toOptionalString(candidate.id) } : {},
308
+ ...toOptionalString(candidate.label) ? { label: toOptionalString(candidate.label) } : {},
309
+ path: candidate.path.trim(),
310
+ startLine: candidate.startLine,
311
+ endLine: candidate.endLine,
312
+ text: candidate.text,
313
+ ...toOptionalString(candidate.language) ? { language: toOptionalString(candidate.language) } : {},
314
+ ...toOptionalString(candidate.taskId) ? { taskId: toOptionalString(candidate.taskId) } : {}
315
+ };
316
+ }
317
+ function toQuoteReference(candidate) {
318
+ return {
319
+ type: "quote",
320
+ ...toOptionalString(candidate.id) ? { id: toOptionalString(candidate.id) } : {},
321
+ ...toOptionalString(candidate.label) ? { label: toOptionalString(candidate.label) } : {},
322
+ text: candidate.text,
323
+ ...toOptionalString(candidate.messageId) ? { messageId: toOptionalString(candidate.messageId) } : {},
324
+ ...toOptionalString(candidate.source) ? { source: toOptionalString(candidate.source) } : {}
325
+ };
326
+ }
327
+ function toImageReference(candidate) {
328
+ const fileId = toOptionalString(candidate.fileId);
329
+ const url = toOptionalString(candidate.url);
330
+ const name = toOptionalString(candidate.name);
331
+ const label = toOptionalString(candidate.label);
332
+ const rawText = toReferenceText(candidate.text);
333
+ const text = rawText ?? name ?? label ?? "Pasted image";
334
+ return {
335
+ type: "image",
336
+ ...toOptionalString(candidate.id) ? { id: toOptionalString(candidate.id) } : {},
337
+ ...label ? { label } : {},
338
+ text,
339
+ ...fileId ? { fileId } : {},
340
+ ...url ? { url } : {},
341
+ ...toOptionalString(candidate.mimeType) ? { mimeType: toOptionalString(candidate.mimeType) } : {},
342
+ ...name ? { name } : {},
343
+ ...toOptionalNumber(candidate.size, { allowZero: true }) !== void 0 ? { size: toOptionalNumber(candidate.size, { allowZero: true }) } : {},
344
+ ...toOptionalNumber(candidate.width) !== void 0 ? { width: toOptionalNumber(candidate.width) } : {},
345
+ ...toOptionalNumber(candidate.height) !== void 0 ? { height: toOptionalNumber(candidate.height) } : {}
346
+ };
347
+ }
348
+ function isLegacyCodeReference(candidate) {
349
+ return candidate.type === void 0 && isNonEmptyString(candidate.path) && toLineNumber(candidate.startLine) !== null && toLineNumber(candidate.endLine) !== null && toReferenceText(candidate.text) !== null;
350
+ }
351
+ function normalizeReference(value) {
352
+ if (!isObjectLike(value)) {
353
+ return null;
354
+ }
355
+ const candidate = value;
356
+ const type = toOptionalString(candidate.type);
357
+ if (type === "code" && isCodeReferenceCandidate(candidate)) {
358
+ return toCodeReference(candidate);
359
+ }
360
+ if (isQuoteReferenceCandidate(candidate)) {
361
+ return toQuoteReference(candidate);
362
+ }
363
+ if (isImageReferenceCandidate(candidate)) {
364
+ return toImageReference(candidate);
365
+ }
366
+ if (type === void 0 && isLegacyCodeReference(candidate)) {
367
+ return toCodeReference(candidate);
368
+ }
369
+ return null;
370
+ }
371
+ function normalizeReferences(value) {
372
+ if (!Array.isArray(value)) {
373
+ return [];
374
+ }
375
+ return value.map((item) => normalizeReference(item)).filter((item) => item !== null);
376
+ }
377
+ function getCodeReferenceRange(reference) {
378
+ return reference.startLine === reference.endLine ? `${reference.startLine}` : `${reference.startLine}-${reference.endLine}`;
379
+ }
380
+ function getQuoteExcerpt(reference) {
381
+ const normalized = reference.text.replace(/\s+/g, " ").trim();
382
+ if (normalized.length <= 32) {
383
+ return normalized;
384
+ }
385
+ return `${normalized.slice(0, 29)}...`;
386
+ }
387
+ function getCodeReferenceLocation(reference) {
388
+ return `${reference.path}:${getCodeReferenceRange(reference)}`;
389
+ }
390
+ function formatReferenceSize(size2) {
391
+ if (size2 < 1024) {
392
+ return `${size2} B`;
393
+ }
394
+ if (size2 < 1024 * 1024) {
395
+ return `${(size2 / 1024).toFixed(size2 < 10 * 1024 ? 1 : 0)} KB`;
396
+ }
397
+ return `${(size2 / (1024 * 1024)).toFixed(size2 < 10 * 1024 * 1024 ? 1 : 0)} MB`;
398
+ }
399
+ function getImageReferenceDimensions(reference) {
400
+ if (!reference.width || !reference.height) {
401
+ return null;
402
+ }
403
+ return `${reference.width}x${reference.height}`;
404
+ }
405
+ function getImageReferenceMetaParts(reference) {
406
+ return [
407
+ reference.mimeType?.trim() || null,
408
+ getImageReferenceDimensions(reference),
409
+ typeof reference.size === "number" ? formatReferenceSize(reference.size) : null
410
+ ].filter((part) => Boolean(part));
411
+ }
412
+ function getReferenceKey(reference) {
413
+ if (reference.type === "image" && reference.fileId?.trim()) {
414
+ return `image:${reference.fileId.trim()}`;
415
+ }
416
+ if (reference.id && reference.id.trim()) {
417
+ return reference.id.trim();
418
+ }
419
+ if (reference.type === "code") {
420
+ return [
421
+ reference.type,
422
+ reference.path,
423
+ reference.startLine,
424
+ reference.endLine,
425
+ reference.text
426
+ ].join(":");
427
+ }
428
+ if (reference.type === "image") {
429
+ return [
430
+ reference.type,
431
+ reference.url ?? "",
432
+ reference.name ?? "",
433
+ reference.mimeType ?? "",
434
+ reference.size ?? "",
435
+ reference.width ?? "",
436
+ reference.height ?? "",
437
+ reference.text
438
+ ].join(":");
439
+ }
440
+ return [
441
+ reference.type,
442
+ reference.messageId ?? "",
443
+ reference.source ?? "",
444
+ reference.text
445
+ ].join(":");
446
+ }
447
+ function mergeReferences(current, incoming) {
448
+ const merged = [...current];
449
+ const seen = new Set(current.map(getReferenceKey));
450
+ incoming.forEach((reference) => {
451
+ const key = getReferenceKey(reference);
452
+ if (seen.has(key)) {
453
+ return;
454
+ }
455
+ seen.add(key);
456
+ merged.push(reference);
457
+ });
458
+ return merged;
459
+ }
460
+ function getReferenceLabel(reference) {
461
+ if (reference.label && reference.label.trim()) {
462
+ return reference.label.trim();
463
+ }
464
+ if (reference.type === "code") {
465
+ const segments = reference.path.split("/");
466
+ const fileName = segments[segments.length - 1] || reference.path;
467
+ return `${fileName} ${getCodeReferenceRange(reference)}`;
468
+ }
469
+ if (reference.type === "image") {
470
+ return reference.name?.trim() || "Pasted image";
471
+ }
472
+ if (reference.source && reference.source.trim()) {
473
+ return reference.source.trim();
474
+ }
475
+ return getQuoteExcerpt(reference);
476
+ }
477
+ function getReferenceMetaLine(reference) {
478
+ if (reference.type === "code") {
479
+ return getCodeReferenceLocation(reference);
480
+ }
481
+ if (reference.type === "image") {
482
+ const parts = getImageReferenceMetaParts(reference);
483
+ return parts.length ? parts.join(" \u2022 ") : null;
484
+ }
485
+ if (reference.source && reference.source.trim()) {
486
+ return getQuoteExcerpt(reference);
487
+ }
488
+ if (reference.messageId && reference.messageId.trim()) {
489
+ return `Message ${reference.messageId.trim()}`;
490
+ }
491
+ return null;
492
+ }
493
+ function getReferenceTitle(reference) {
494
+ if (reference.type === "code") {
495
+ return `${getCodeReferenceLocation(reference)}
496
+
497
+ ${reference.text}`;
498
+ }
499
+ if (reference.type === "image") {
500
+ const titleLines = [getReferenceLabel(reference)];
501
+ const metaLine = getReferenceMetaLine(reference);
502
+ const url = reference.url?.trim() && !reference.url.trim().startsWith("data:") ? reference.url.trim() : null;
503
+ if (metaLine) {
504
+ titleLines.push(metaLine);
505
+ }
506
+ if (url) {
507
+ titleLines.push(url);
508
+ }
509
+ if (reference.text.trim() && reference.text.trim() !== getReferenceLabel(reference)) {
510
+ titleLines.push("", reference.text.trim());
511
+ }
512
+ return titleLines.join("\n");
513
+ }
514
+ const header = reference.label?.trim() || reference.source?.trim() || "Quoted text";
515
+ return `${header}
516
+
517
+ ${reference.text}`;
518
+ }
519
+ function buildHumanMessageInputPayload(source) {
520
+ const references = normalizeReferences(source.references);
521
+ const nextReferenceComposition = source.referenceComposition ?? (references.length > 0 && typeof source.submittedInput !== "string" ? "compose" : void 0);
522
+ if (typeof source.submittedInput === "string") {
523
+ return {
524
+ input: source.submittedInput.trim(),
525
+ ...references.length > 0 ? { references } : {},
526
+ ...nextReferenceComposition ? { referenceComposition: nextReferenceComposition } : {}
527
+ };
528
+ }
529
+ const input = typeof source.content === "string" ? source.content.trim() : "";
530
+ if (!input && references.length === 0) {
531
+ return null;
532
+ }
533
+ return {
534
+ input,
535
+ ...references.length > 0 ? { references } : {},
536
+ ...nextReferenceComposition ? { referenceComposition: nextReferenceComposition } : {}
537
+ };
538
+ }
539
+
147
540
  // src/providers/ParentMessenger.tsx
148
541
  import { jsx } from "react/jsx-runtime";
149
542
  var handledSendUserMessageNonces = /* @__PURE__ */ new Set();
@@ -172,6 +565,10 @@ function ParentMessengerProvider({
172
565
  /* @__PURE__ */ new Map()
173
566
  );
174
567
  const onSetOptionsHandlersRef = useRef(/* @__PURE__ */ new Set());
568
+ const onSetComposerValueHandlersRef = useRef(
569
+ /* @__PURE__ */ new Set()
570
+ );
571
+ const onFocusComposerHandlersRef = useRef(/* @__PURE__ */ new Set());
175
572
  const latestOptionsRef = useRef(null);
176
573
  const isParentAvailable = useMemo(() => {
177
574
  return typeof window !== "undefined" && window.parent !== window;
@@ -185,6 +582,24 @@ function ParentMessengerProvider({
185
582
  onSetOptionsHandlersRef.current.delete(handler);
186
583
  };
187
584
  }, []);
585
+ const registerOnSetComposerValue = useCallback(
586
+ (handler) => {
587
+ onSetComposerValueHandlersRef.current.add(handler);
588
+ return () => {
589
+ onSetComposerValueHandlersRef.current.delete(handler);
590
+ };
591
+ },
592
+ []
593
+ );
594
+ const registerOnFocusComposer = useCallback(
595
+ (handler) => {
596
+ onFocusComposerHandlersRef.current.add(handler);
597
+ return () => {
598
+ onFocusComposerHandlersRef.current.delete(handler);
599
+ };
600
+ },
601
+ []
602
+ );
188
603
  useEffect(() => {
189
604
  if (!isParentAvailable) return;
190
605
  const sendResponse = (nonce, response, error) => {
@@ -205,7 +620,7 @@ function ParentMessengerProvider({
205
620
  }
206
621
  const payload = event.data;
207
622
  if (payload.__xpaiChatKit !== true) return;
208
- if (payload.type == "command" && payload.command === "onSendUserMessage") {
623
+ if (payload.type === "command" && payload.command === "onSendUserMessage") {
209
624
  const nonce = typeof payload.nonce === "string" ? payload.nonce : null;
210
625
  if (nonce) {
211
626
  if (handledSendUserMessageNonces.has(nonce)) return;
@@ -215,34 +630,53 @@ function ParentMessengerProvider({
215
630
  handledSendUserMessageEvents.add(event);
216
631
  }
217
632
  const params = payload.data;
218
- const prompt = (params.text ?? params.state?.[STATE_VARIABLE_HUMAN2]?.input ?? "").trim();
633
+ const prompt = typeof params.text === "string" ? params.text.trim() : typeof params.state?.[STATE_VARIABLE_HUMAN2]?.input === "string" ? params.state[STATE_VARIABLE_HUMAN2].input.trim() : "";
634
+ const references = normalizeReferences(
635
+ params.references ?? params.state?.[STATE_VARIABLE_HUMAN2]?.references
636
+ );
637
+ const referenceComposition = params.referenceComposition ?? params.state?.[STATE_VARIABLE_HUMAN2]?.referenceComposition;
638
+ const humanInput = buildHumanMessageInputPayload({
639
+ content: prompt,
640
+ references,
641
+ referenceComposition
642
+ });
643
+ if (!humanInput) {
644
+ if (payload.nonce) {
645
+ sendResponse(payload.nonce, { ok: true });
646
+ }
647
+ return;
648
+ }
219
649
  const newMessage = {
220
650
  id: createMessageId(),
221
651
  type: "human",
222
- content: prompt
652
+ content: prompt,
653
+ submittedInput: humanInput.input,
654
+ ...humanInput.referenceComposition ? { referenceComposition: humanInput.referenceComposition } : {},
655
+ ...references.length > 0 ? { references } : {}
223
656
  };
657
+ const stream = streamRef2.current;
658
+ const activeFollowUpMode = stream?.isLoading ? params.followUpMode && params.followUpMode !== "default" ? params.followUpMode : stream.followUpBehavior ?? "queue" : void 0;
224
659
  const requestOptions = buildInjectedRequestOptions({
225
660
  defaults: latestOptionsRef.current?.request,
226
661
  state: params.state,
227
- humanInput: {
228
- input: prompt
229
- }
662
+ humanInput
230
663
  });
231
- streamRef2.current?.submit(
664
+ stream?.submit(
232
665
  {
233
- input: {
234
- input: prompt
235
- },
666
+ input: humanInput,
236
667
  ...requestOptions.state ? { state: requestOptions.state } : {}
237
668
  },
238
669
  {
239
670
  newThread: params.newThread,
671
+ ...activeFollowUpMode ? { followUpMode: activeFollowUpMode } : {},
240
672
  ...requestOptions.context ? { context: requestOptions.context } : {},
241
673
  ...requestOptions.config ? { config: requestOptions.config } : {},
242
- optimisticValues: (prev) => {
243
- const prevMessages = prev?.messages ?? [];
244
- return { ...prev, messages: [...prevMessages, newMessage] };
245
- }
674
+ ...!activeFollowUpMode ? {
675
+ optimisticValues: (prev) => {
676
+ const prevMessages = prev?.messages ?? [];
677
+ return { ...prev, messages: [...prevMessages, newMessage] };
678
+ }
679
+ } : {}
246
680
  }
247
681
  );
248
682
  if (payload.nonce) {
@@ -250,7 +684,28 @@ function ParentMessengerProvider({
250
684
  }
251
685
  return;
252
686
  }
253
- if (payload.type == "command" && payload.command === "onSetOptions") {
687
+ if (payload.type === "command" && payload.command === "onSetComposerValue") {
688
+ const nextPayload = payload.data ?? null;
689
+ const normalizedPayload = nextPayload && Array.isArray(nextPayload.references) ? {
690
+ ...nextPayload,
691
+ references: normalizeReferences(nextPayload.references)
692
+ } : nextPayload;
693
+ void Promise.all(
694
+ [...onSetComposerValueHandlersRef.current].map(
695
+ (handler2) => Promise.resolve(handler2(normalizedPayload))
696
+ )
697
+ ).then(() => {
698
+ if (payload.nonce) {
699
+ sendResponse(payload.nonce, { ok: true });
700
+ }
701
+ }).catch((error) => {
702
+ if (payload.nonce) {
703
+ sendResponse(payload.nonce, void 0, error);
704
+ }
705
+ });
706
+ return;
707
+ }
708
+ if (payload.type === "command" && payload.command === "onSetOptions") {
254
709
  latestOptionsRef.current = payload.data ?? null;
255
710
  if (onSetOptionsHandlersRef.current.size > 0) {
256
711
  onSetOptionsHandlersRef.current.forEach((handler2) => {
@@ -262,16 +717,41 @@ function ParentMessengerProvider({
262
717
  }
263
718
  return;
264
719
  }
265
- if (payload.type == "command" && payload.command === "onSetThreadId") {
720
+ if (payload.type === "command" && payload.command === "onFocusComposer") {
721
+ void Promise.all(
722
+ [...onFocusComposerHandlersRef.current].map(
723
+ (handler2) => Promise.resolve(handler2())
724
+ )
725
+ ).then(() => {
726
+ if (payload.nonce) {
727
+ sendResponse(payload.nonce, { ok: true });
728
+ }
729
+ }).catch((error) => {
730
+ if (payload.nonce) {
731
+ sendResponse(payload.nonce, void 0, error);
732
+ }
733
+ });
734
+ return;
735
+ }
736
+ if (payload.type === "command" && payload.command === "onSetThreadId") {
266
737
  const data = payload.data;
267
738
  const nextThreadId = data?.threadId ?? null;
268
739
  const stream = streamRef2.current;
740
+ if (stream?.threadId === nextThreadId) {
741
+ if (payload.nonce) {
742
+ sendResponse(payload.nonce, { ok: true });
743
+ }
744
+ return;
745
+ }
269
746
  stream?.reset(nextThreadId, void 0, { suppressThreadChange: true });
270
747
  if (stream && nextThreadId) {
271
748
  stream.loadThread(nextThreadId).catch((err) => {
272
749
  console.warn("Failed to load thread messages", err);
273
750
  });
274
751
  }
752
+ if (payload.nonce) {
753
+ sendResponse(payload.nonce, { ok: true });
754
+ }
275
755
  return;
276
756
  }
277
757
  if (payload.type !== "response") return;
@@ -332,25 +812,55 @@ function ParentMessengerProvider({
332
812
  isParentAvailable,
333
813
  sendCommand,
334
814
  sendEvent,
335
- registerOnSetOptions
815
+ registerOnSetOptions,
816
+ registerOnSetComposerValue,
817
+ registerOnFocusComposer
336
818
  }),
337
- [isParentAvailable, sendCommand, sendEvent, registerOnSetOptions]
819
+ [
820
+ isParentAvailable,
821
+ sendCommand,
822
+ sendEvent,
823
+ registerOnSetOptions,
824
+ registerOnSetComposerValue,
825
+ registerOnFocusComposer
826
+ ]
338
827
  );
339
828
  return /* @__PURE__ */ jsx(ParentMessengerContext.Provider, { value, children });
340
829
  }
341
830
 
342
831
  // src/hooks/useParentMessenger.tsx
343
- function useParentMessenger({ onSetOptions } = {}) {
832
+ function useParentMessenger({
833
+ onSetOptions,
834
+ onSetComposerValue,
835
+ onFocusComposer
836
+ } = {}) {
344
837
  const context = useContext(ParentMessengerContext);
345
838
  if (!context) {
346
- throw new Error("useParentMessenger must be used within a ParentMessengerProvider");
839
+ throw new Error(
840
+ "useParentMessenger must be used within a ParentMessengerProvider"
841
+ );
347
842
  }
348
- const { registerOnSetOptions, ...messenger } = context;
843
+ const {
844
+ registerOnSetOptions,
845
+ registerOnSetComposerValue,
846
+ registerOnFocusComposer,
847
+ ...messenger
848
+ } = context;
349
849
  const onSetOptionsRef = useRef2(onSetOptions);
850
+ const onSetComposerValueRef = useRef2(onSetComposerValue);
851
+ const onFocusComposerRef = useRef2(onFocusComposer);
350
852
  useEffect2(() => {
351
853
  onSetOptionsRef.current = onSetOptions;
352
854
  }, [onSetOptions]);
855
+ useEffect2(() => {
856
+ onSetComposerValueRef.current = onSetComposerValue;
857
+ }, [onSetComposerValue]);
858
+ useEffect2(() => {
859
+ onFocusComposerRef.current = onFocusComposer;
860
+ }, [onFocusComposer]);
353
861
  const hasOnSetOptions = Boolean(onSetOptions);
862
+ const hasOnSetComposerValue = Boolean(onSetComposerValue);
863
+ const hasOnFocusComposer = Boolean(onFocusComposer);
354
864
  useEffect2(() => {
355
865
  if (!hasOnSetOptions) return;
356
866
  const handler = (options) => {
@@ -358,6 +868,20 @@ function useParentMessenger({ onSetOptions } = {}) {
358
868
  };
359
869
  return registerOnSetOptions(handler);
360
870
  }, [hasOnSetOptions, registerOnSetOptions]);
871
+ useEffect2(() => {
872
+ if (!hasOnSetComposerValue) return;
873
+ const handler = (payload) => {
874
+ onSetComposerValueRef.current?.(payload);
875
+ };
876
+ return registerOnSetComposerValue(handler);
877
+ }, [hasOnSetComposerValue, registerOnSetComposerValue]);
878
+ useEffect2(() => {
879
+ if (!hasOnFocusComposer) return;
880
+ const handler = () => {
881
+ onFocusComposerRef.current?.();
882
+ };
883
+ return registerOnFocusComposer(handler);
884
+ }, [hasOnFocusComposer, registerOnFocusComposer]);
361
885
  return messenger;
362
886
  }
363
887
 
@@ -391,6 +915,17 @@ function resolveUsedContextSize(options) {
391
915
  return normalizeContextUsageNumber(options.fallbackUsedTokens) ?? 0;
392
916
  }
393
917
 
918
+ // src/lib/follow-ups.ts
919
+ function getComposerFollowUpShortcutLabels(queueShortcutLabel) {
920
+ return {
921
+ steer: "Enter",
922
+ queue: queueShortcutLabel
923
+ };
924
+ }
925
+ function getBusyComposerShortcutFollowUpMode(useQueueShortcut) {
926
+ return useQueueShortcut ? "queue" : "steer";
927
+ }
928
+
394
929
  // src/providers/Stream.tsx
395
930
  import { jsx as jsx2 } from "react/jsx-runtime";
396
931
  var StreamContext = createContext2(void 0);
@@ -522,12 +1057,39 @@ var en_US_default = {
522
1057
  statusOnline: "Online",
523
1058
  missingConfigShort: "Missing ChatKit configuration.",
524
1059
  missingConfigDetail: "Missing ChatKit configuration. Check `VITE_XPERTAI_API_URL`, and the `clientSecret` prop.",
1060
+ missingApiUrlShort: "Missing ChatKit API URL.",
1061
+ missingApiUrlDetail: "Missing ChatKit API URL. Check `VITE_XPERTAI_API_URL` or `options.api.apiUrl`.",
1062
+ missingClientSecretShort: "Missing ChatKit client secret.",
1063
+ missingClientSecretDetail: "Missing ChatKit client secret. Check the `clientSecret` prop or `api.getClientSecret` integration.",
1064
+ missingApiUrlAndClientSecretShort: "Missing ChatKit API URL and client secret.",
1065
+ missingApiUrlAndClientSecretDetail: "Missing ChatKit API URL and client secret. Check `VITE_XPERTAI_API_URL`, `options.api.apiUrl`, and your client secret integration.",
525
1066
  loadingThread: "Loading thread...",
526
1067
  stop: "Stop",
527
1068
  send: "Send message",
1069
+ referencedContentOnly: "Referenced content",
1070
+ youLabel: "You",
528
1071
  scrollToBottom: "Scroll to bottom",
529
1072
  retryUpload: "Retry upload",
530
1073
  poweredBy: "Powered by Xpert AI",
1074
+ followUps: {
1075
+ label: "Follow-up behavior",
1076
+ settings: "Settings",
1077
+ idleHint: "Used when you send while a run is active.",
1078
+ activeHint: "This message will use the selected busy-run behavior.",
1079
+ pending: "Pending follow-ups",
1080
+ queue: "Queue",
1081
+ steer: "Steer",
1082
+ steerAction: "Steer",
1083
+ promoteToSteer: "Steer now",
1084
+ sendNow: "Send now",
1085
+ remove: "Remove pending follow-up",
1086
+ more: "More actions",
1087
+ edit: "Edit message",
1088
+ turnOffQueueing: "Turn off queueing",
1089
+ queueHint: "Starts after the current run finishes",
1090
+ manualQueueHint: "Ready to send as a new run",
1091
+ steerHint: "Injects after the current tool call"
1092
+ },
531
1093
  errors: {
532
1094
  loadMessages: "Failed to load thread messages",
533
1095
  createThread: "Failed to create thread",
@@ -558,13 +1120,24 @@ var en_US_default = {
558
1120
  },
559
1121
  composer: {
560
1122
  openMenu: "Open menu",
561
- addAttachment: "Add attachment"
1123
+ addAttachment: "Add attachment",
1124
+ removeReference: "Remove reference",
1125
+ quoteSelection: "Quote selection"
562
1126
  },
563
1127
  sheet: {
564
1128
  close: "Close"
565
1129
  },
566
1130
  markdown: {
567
- copy: "Copy"
1131
+ copy: "Copy",
1132
+ mermaid: {
1133
+ title: "Mermaid",
1134
+ diagram: "Diagram",
1135
+ code: "Code",
1136
+ download: "Download SVG",
1137
+ fullScreen: "Open full screen",
1138
+ rendering: "Rendering diagram",
1139
+ failed: "Failed to render diagram"
1140
+ }
568
1141
  },
569
1142
  thread: {
570
1143
  errorToast: "An error occurred. Please try again.",
@@ -573,7 +1146,10 @@ var en_US_default = {
573
1146
  },
574
1147
  message: {
575
1148
  answer: "Answer",
576
- reasoning: "Reasoning"
1149
+ reasoning: "Reasoning",
1150
+ loading: "Loading",
1151
+ thinking: "Thinking",
1152
+ answering: "Answering"
577
1153
  }
578
1154
  };
579
1155
 
@@ -585,12 +1161,39 @@ var zh_CN_default = {
585
1161
  statusOnline: "\u5728\u7EBF",
586
1162
  missingConfigShort: "\u7F3A\u5C11 ChatKit \u914D\u7F6E\u3002",
587
1163
  missingConfigDetail: "\u7F3A\u5C11 ChatKit \u914D\u7F6E\u3002\u8BF7\u68C0\u67E5 `VITE_XPERTAI_API_URL` \u548C `clientSecret` \u53C2\u6570\u3002",
1164
+ missingApiUrlShort: "\u7F3A\u5C11 ChatKit API URL\u3002",
1165
+ missingApiUrlDetail: "\u7F3A\u5C11 ChatKit API URL\u3002\u8BF7\u68C0\u67E5 `VITE_XPERTAI_API_URL` \u6216 `options.api.apiUrl`\u3002",
1166
+ missingClientSecretShort: "\u7F3A\u5C11 ChatKit client secret\u3002",
1167
+ missingClientSecretDetail: "\u7F3A\u5C11 ChatKit client secret\u3002\u8BF7\u68C0\u67E5 `clientSecret` \u53C2\u6570\u6216 `api.getClientSecret` \u96C6\u6210\u3002",
1168
+ missingApiUrlAndClientSecretShort: "\u7F3A\u5C11 ChatKit API URL \u548C client secret\u3002",
1169
+ missingApiUrlAndClientSecretDetail: "\u7F3A\u5C11 ChatKit API URL \u548C client secret\u3002\u8BF7\u68C0\u67E5 `VITE_XPERTAI_API_URL`\u3001`options.api.apiUrl` \u4EE5\u53CA client secret \u96C6\u6210\u3002",
588
1170
  loadingThread: "\u6B63\u5728\u52A0\u8F7D\u7EBF\u7A0B...",
589
1171
  stop: "\u505C\u6B62",
590
1172
  send: "\u53D1\u9001\u6D88\u606F",
1173
+ referencedContentOnly: "\u5DF2\u5F15\u7528\u5185\u5BB9",
1174
+ youLabel: "\u4F60",
591
1175
  scrollToBottom: "\u56DE\u5230\u5E95\u90E8",
592
1176
  retryUpload: "\u91CD\u65B0\u4E0A\u4F20",
593
1177
  poweredBy: "\u7531 Xpert AI \u9A71\u52A8",
1178
+ followUps: {
1179
+ label: "Follow-up \u6A21\u5F0F",
1180
+ settings: "\u8BBE\u7F6E",
1181
+ idleHint: "\u4EC5\u5728\u8FD0\u884C\u4E2D\u53D1\u9001\u6D88\u606F\u65F6\u751F\u6548\u3002",
1182
+ activeHint: "\u5F53\u524D\u6D88\u606F\u4F1A\u6309\u6240\u9009\u7684\u8FD0\u884C\u4E2D\u884C\u4E3A\u5904\u7406\u3002",
1183
+ pending: "\u5F85\u5904\u7406 Follow-up",
1184
+ queue: "\u6392\u961F",
1185
+ steer: "\u5F15\u5BFC",
1186
+ steerAction: "\u5F15\u5BFC",
1187
+ promoteToSteer: "\u8F6C\u4E3A\u5F15\u5BFC",
1188
+ sendNow: "\u7ACB\u5373\u53D1\u9001",
1189
+ remove: "\u79FB\u9664\u6B64\u5F85\u5904\u7406 Follow-up",
1190
+ more: "\u66F4\u591A\u64CD\u4F5C",
1191
+ edit: "\u7F16\u8F91\u6D88\u606F",
1192
+ turnOffQueueing: "\u5173\u95ED\u6392\u961F",
1193
+ queueHint: "\u5F53\u524D\u8FD0\u884C\u7ED3\u675F\u540E\u5F00\u542F\u4E0B\u4E00\u8F6E",
1194
+ manualQueueHint: "\u4FDD\u7559\u4E3A\u5F85\u53D1\u9001\uFF0C\u53EF\u624B\u52A8\u5F00\u542F\u65B0\u4E00\u8F6E",
1195
+ steerHint: "\u5F53\u524D\u5DE5\u5177\u8C03\u7528\u5B8C\u6210\u540E\u6CE8\u5165"
1196
+ },
594
1197
  errors: {
595
1198
  loadMessages: "\u52A0\u8F7D\u7EBF\u7A0B\u6D88\u606F\u5931\u8D25",
596
1199
  createThread: "\u521B\u5EFA\u7EBF\u7A0B\u5931\u8D25",
@@ -621,13 +1224,24 @@ var zh_CN_default = {
621
1224
  },
622
1225
  composer: {
623
1226
  openMenu: "\u6253\u5F00\u83DC\u5355",
624
- addAttachment: "\u6DFB\u52A0\u9644\u4EF6"
1227
+ addAttachment: "\u6DFB\u52A0\u9644\u4EF6",
1228
+ removeReference: "\u79FB\u9664\u5F15\u7528",
1229
+ quoteSelection: "\u5F15\u7528\u9009\u4E2D\u5185\u5BB9"
625
1230
  },
626
1231
  sheet: {
627
1232
  close: "\u5173\u95ED"
628
1233
  },
629
1234
  markdown: {
630
- copy: "\u590D\u5236"
1235
+ copy: "\u590D\u5236",
1236
+ mermaid: {
1237
+ title: "Mermaid",
1238
+ diagram: "\u56FE\u8868",
1239
+ code: "\u4EE3\u7801",
1240
+ download: "\u4E0B\u8F7D SVG",
1241
+ fullScreen: "\u5168\u5C4F\u67E5\u770B",
1242
+ rendering: "\u6B63\u5728\u6E32\u67D3\u56FE\u8868",
1243
+ failed: "\u56FE\u8868\u6E32\u67D3\u5931\u8D25"
1244
+ }
631
1245
  },
632
1246
  thread: {
633
1247
  errorToast: "\u53D1\u751F\u9519\u8BEF\uFF0C\u8BF7\u91CD\u8BD5\u3002",
@@ -636,7 +1250,10 @@ var zh_CN_default = {
636
1250
  },
637
1251
  message: {
638
1252
  answer: "\u56DE\u7B54",
639
- reasoning: "\u63A8\u7406"
1253
+ reasoning: "\u63A8\u7406",
1254
+ loading: "\u6B63\u5728\u52A0\u8F7D",
1255
+ thinking: "\u6B63\u5728\u601D\u8003",
1256
+ answering: "\u6B63\u5728\u751F\u6210"
640
1257
  }
641
1258
  };
642
1259
 
@@ -1157,18 +1774,86 @@ function ComposerMenu({
1157
1774
 
1158
1775
  // src/components/composer/SendButton.tsx
1159
1776
  import { ArrowUp, Square } from "lucide-react";
1160
- import { jsx as jsx7 } from "react/jsx-runtime";
1777
+
1778
+ // src/components/ui/tooltip.tsx
1779
+ import "react";
1780
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
1781
+ import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
1782
+ function TooltipProvider({
1783
+ delayDuration = 0,
1784
+ ...props
1785
+ }) {
1786
+ return /* @__PURE__ */ jsx7(
1787
+ TooltipPrimitive.Provider,
1788
+ {
1789
+ "data-slot": "tooltip-provider",
1790
+ delayDuration,
1791
+ ...props
1792
+ }
1793
+ );
1794
+ }
1795
+ function Tooltip({
1796
+ ...props
1797
+ }) {
1798
+ return /* @__PURE__ */ jsx7(TooltipProvider, { children: /* @__PURE__ */ jsx7(
1799
+ TooltipPrimitive.Root,
1800
+ {
1801
+ "data-slot": "tooltip",
1802
+ ...props
1803
+ }
1804
+ ) });
1805
+ }
1806
+ function TooltipTrigger({
1807
+ ...props
1808
+ }) {
1809
+ return /* @__PURE__ */ jsx7(
1810
+ TooltipPrimitive.Trigger,
1811
+ {
1812
+ "data-slot": "tooltip-trigger",
1813
+ ...props
1814
+ }
1815
+ );
1816
+ }
1817
+ function TooltipContent({
1818
+ className,
1819
+ sideOffset = 0,
1820
+ hideArrow = false,
1821
+ children,
1822
+ ...props
1823
+ }) {
1824
+ return /* @__PURE__ */ jsx7(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs2(
1825
+ TooltipPrimitive.Content,
1826
+ {
1827
+ "data-slot": "tooltip-content",
1828
+ sideOffset,
1829
+ className: cn(
1830
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit rounded-md px-3 py-1.5 text-xs text-balance",
1831
+ className
1832
+ ),
1833
+ ...props,
1834
+ children: [
1835
+ children,
1836
+ !hideArrow ? /* @__PURE__ */ jsx7(TooltipPrimitive.Arrow, { className: "bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" }) : null
1837
+ ]
1838
+ }
1839
+ ) });
1840
+ }
1841
+
1842
+ // src/components/composer/SendButton.tsx
1843
+ import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
1161
1844
  function SendButton({
1162
1845
  disabled = false,
1163
1846
  isLoading = false,
1847
+ showStop = isLoading,
1164
1848
  onStop,
1165
1849
  stopLabel = "Stop",
1166
- sendLabel = "Send"
1850
+ sendLabel = "Send",
1851
+ shortcuts
1167
1852
  }) {
1168
1853
  const { theme } = useTheme();
1169
1854
  const roundedClass = getRoundedClass(theme.radius);
1170
- if (isLoading) {
1171
- return /* @__PURE__ */ jsx7(
1855
+ if (showStop) {
1856
+ return /* @__PURE__ */ jsx8(
1172
1857
  "button",
1173
1858
  {
1174
1859
  type: "button",
@@ -1181,11 +1866,11 @@ function SendButton({
1181
1866
  "hover:scale-105 active:scale-95"
1182
1867
  ),
1183
1868
  "aria-label": stopLabel,
1184
- children: /* @__PURE__ */ jsx7(Square, { size: 14, fill: "currentColor", stroke: "currentColor", strokeWidth: 0 })
1869
+ children: /* @__PURE__ */ jsx8(Square, { size: 14, fill: "currentColor", stroke: "currentColor", strokeWidth: 0 })
1185
1870
  }
1186
1871
  );
1187
1872
  }
1188
- return /* @__PURE__ */ jsx7(
1873
+ const button = /* @__PURE__ */ jsx8(
1189
1874
  "button",
1190
1875
  {
1191
1876
  type: "submit",
@@ -1199,34 +1884,63 @@ function SendButton({
1199
1884
  "disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:scale-100"
1200
1885
  ),
1201
1886
  "aria-label": sendLabel,
1202
- children: /* @__PURE__ */ jsx7(ArrowUp, { size: 18, strokeWidth: 2.5 })
1887
+ children: /* @__PURE__ */ jsx8(ArrowUp, { size: 18, strokeWidth: 2.5 })
1203
1888
  }
1204
1889
  );
1890
+ if (!shortcuts?.length || disabled) {
1891
+ return button;
1892
+ }
1893
+ return /* @__PURE__ */ jsxs3(Tooltip, { children: [
1894
+ /* @__PURE__ */ jsx8(TooltipTrigger, { asChild: true, children: button }),
1895
+ /* @__PURE__ */ jsx8(
1896
+ TooltipContent,
1897
+ {
1898
+ side: "top",
1899
+ sideOffset: 10,
1900
+ hideArrow: true,
1901
+ className: cn(
1902
+ "min-w-36 border border-border/70 bg-background px-3 py-2 text-foreground shadow-lg",
1903
+ roundedClass
1904
+ ),
1905
+ children: /* @__PURE__ */ jsx8("div", { className: "space-y-1", children: shortcuts.map((shortcut) => /* @__PURE__ */ jsxs3(
1906
+ "div",
1907
+ {
1908
+ className: "flex items-center justify-between gap-4 text-sm",
1909
+ children: [
1910
+ /* @__PURE__ */ jsx8("span", { className: "font-medium", children: shortcut.label }),
1911
+ /* @__PURE__ */ jsx8("kbd", { className: "inline-flex min-w-16 items-center justify-center rounded-full bg-muted px-2.5 py-0.5 text-xs font-medium text-muted-foreground", children: shortcut.keys })
1912
+ ]
1913
+ },
1914
+ `${shortcut.label}-${shortcut.keys}`
1915
+ )) })
1916
+ }
1917
+ )
1918
+ ] });
1205
1919
  }
1206
1920
 
1207
1921
  // src/components/history/HistorySidebar.tsx
1208
- import * as React8 from "react";
1922
+ import * as React9 from "react";
1209
1923
  import { History, MessageSquare, PlusCircle, Trash2 } from "lucide-react";
1210
1924
 
1211
1925
  // src/components/ui/scroll-area.tsx
1212
- import * as React6 from "react";
1926
+ import * as React7 from "react";
1213
1927
  import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
1214
- import { jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
1215
- var ScrollArea = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs2(
1928
+ import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
1929
+ var ScrollArea = React7.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs4(
1216
1930
  ScrollAreaPrimitive.Root,
1217
1931
  {
1218
1932
  ref,
1219
1933
  className: cn("relative overflow-hidden", className),
1220
1934
  ...props,
1221
1935
  children: [
1222
- /* @__PURE__ */ jsx8(ScrollAreaPrimitive.Viewport, { className: "h-full w-full rounded-[inherit]", children }),
1223
- /* @__PURE__ */ jsx8(ScrollBar, {}),
1224
- /* @__PURE__ */ jsx8(ScrollAreaPrimitive.Corner, {})
1936
+ /* @__PURE__ */ jsx9(ScrollAreaPrimitive.Viewport, { className: "h-full w-full rounded-[inherit]", children }),
1937
+ /* @__PURE__ */ jsx9(ScrollBar, {}),
1938
+ /* @__PURE__ */ jsx9(ScrollAreaPrimitive.Corner, {})
1225
1939
  ]
1226
1940
  }
1227
1941
  ));
1228
1942
  ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
1229
- var ScrollBar = React6.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsx8(
1943
+ var ScrollBar = React7.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsx9(
1230
1944
  ScrollAreaPrimitive.ScrollAreaScrollbar,
1231
1945
  {
1232
1946
  ref,
@@ -1238,7 +1952,7 @@ var ScrollBar = React6.forwardRef(({ className, orientation = "vertical", ...pro
1238
1952
  className
1239
1953
  ),
1240
1954
  ...props,
1241
- children: /* @__PURE__ */ jsx8(ScrollAreaPrimitive.ScrollAreaThumb, { className: "relative flex-1 rounded-full bg-border" })
1955
+ children: /* @__PURE__ */ jsx9(ScrollAreaPrimitive.ScrollAreaThumb, { className: "relative flex-1 rounded-full bg-border" })
1242
1956
  }
1243
1957
  ));
1244
1958
  ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
@@ -1247,21 +1961,21 @@ ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
1247
1961
  import "react";
1248
1962
  import { X } from "lucide-react";
1249
1963
  import * as SheetPrimitive from "@radix-ui/react-dialog";
1250
- import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
1964
+ import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
1251
1965
  function Sheet({ ...props }) {
1252
- return /* @__PURE__ */ jsx9(SheetPrimitive.Root, { ...props });
1966
+ return /* @__PURE__ */ jsx10(SheetPrimitive.Root, { ...props });
1253
1967
  }
1254
1968
  function SheetTrigger({ ...props }) {
1255
- return /* @__PURE__ */ jsx9(SheetPrimitive.Trigger, { ...props });
1969
+ return /* @__PURE__ */ jsx10(SheetPrimitive.Trigger, { ...props });
1256
1970
  }
1257
1971
  function SheetPortal({ ...props }) {
1258
- return /* @__PURE__ */ jsx9(SheetPrimitive.Portal, { ...props });
1972
+ return /* @__PURE__ */ jsx10(SheetPrimitive.Portal, { ...props });
1259
1973
  }
1260
1974
  function SheetOverlay({
1261
1975
  className,
1262
1976
  ...props
1263
1977
  }) {
1264
- return /* @__PURE__ */ jsx9(
1978
+ return /* @__PURE__ */ jsx10(
1265
1979
  SheetPrimitive.Overlay,
1266
1980
  {
1267
1981
  className: cn(
@@ -1285,9 +1999,9 @@ function SheetContent({
1285
1999
  left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
1286
2000
  right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"
1287
2001
  };
1288
- return /* @__PURE__ */ jsxs3(SheetPortal, { children: [
1289
- /* @__PURE__ */ jsx9(SheetOverlay, {}),
1290
- /* @__PURE__ */ jsxs3(
2002
+ return /* @__PURE__ */ jsxs5(SheetPortal, { children: [
2003
+ /* @__PURE__ */ jsx10(SheetOverlay, {}),
2004
+ /* @__PURE__ */ jsxs5(
1291
2005
  SheetPrimitive.Content,
1292
2006
  {
1293
2007
  className: cn(
@@ -1298,9 +2012,9 @@ function SheetContent({
1298
2012
  ...props,
1299
2013
  children: [
1300
2014
  children,
1301
- /* @__PURE__ */ jsxs3(SheetPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary", children: [
1302
- /* @__PURE__ */ jsx9(X, { size: 16 }),
1303
- /* @__PURE__ */ jsx9("span", { className: "sr-only", children: t("sheet.close") })
2015
+ /* @__PURE__ */ jsxs5(SheetPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary", children: [
2016
+ /* @__PURE__ */ jsx10(X, { size: 16 }),
2017
+ /* @__PURE__ */ jsx10("span", { className: "sr-only", children: t("sheet.close") })
1304
2018
  ] })
1305
2019
  ]
1306
2020
  }
@@ -1311,7 +2025,7 @@ function SheetHeader({
1311
2025
  className,
1312
2026
  ...props
1313
2027
  }) {
1314
- return /* @__PURE__ */ jsx9(
2028
+ return /* @__PURE__ */ jsx10(
1315
2029
  "div",
1316
2030
  {
1317
2031
  className: cn(
@@ -1326,7 +2040,7 @@ function SheetTitle({
1326
2040
  className,
1327
2041
  ...props
1328
2042
  }) {
1329
- return /* @__PURE__ */ jsx9(
2043
+ return /* @__PURE__ */ jsx10(
1330
2044
  SheetPrimitive.Title,
1331
2045
  {
1332
2046
  className: cn("text-lg font-semibold text-foreground", className),
@@ -1336,7 +2050,7 @@ function SheetTitle({
1336
2050
  }
1337
2051
 
1338
2052
  // src/components/history/HistorySidebar.tsx
1339
- import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
2053
+ import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
1340
2054
  function HistorySidebar({
1341
2055
  threads = [],
1342
2056
  currentThreadId,
@@ -1347,7 +2061,7 @@ function HistorySidebar({
1347
2061
  disabled = false
1348
2062
  }) {
1349
2063
  const { t } = useChatkitTranslation();
1350
- const [open, setOpen] = React8.useState(false);
2064
+ const [open, setOpen] = React9.useState(false);
1351
2065
  const handleNewThread = () => {
1352
2066
  onNewThread?.();
1353
2067
  setOpen(false);
@@ -1356,8 +2070,8 @@ function HistorySidebar({
1356
2070
  onSelectThread?.(id);
1357
2071
  setOpen(false);
1358
2072
  };
1359
- return /* @__PURE__ */ jsxs4(Sheet, { open, onOpenChange: setOpen, children: [
1360
- /* @__PURE__ */ jsx10(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsxs4(
2073
+ return /* @__PURE__ */ jsxs6(Sheet, { open, onOpenChange: setOpen, children: [
2074
+ /* @__PURE__ */ jsx11(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
1361
2075
  Button,
1362
2076
  {
1363
2077
  variant: "ghost",
@@ -1365,26 +2079,26 @@ function HistorySidebar({
1365
2079
  disabled,
1366
2080
  className: "h-8 w-8 cursor-pointer",
1367
2081
  children: [
1368
- /* @__PURE__ */ jsx10(History, { size: 16 }),
1369
- /* @__PURE__ */ jsx10("span", { className: "sr-only", children: t("history.threadHistory") })
2082
+ /* @__PURE__ */ jsx11(History, { size: 16 }),
2083
+ /* @__PURE__ */ jsx11("span", { className: "sr-only", children: t("history.threadHistory") })
1370
2084
  ]
1371
2085
  }
1372
2086
  ) }),
1373
- /* @__PURE__ */ jsxs4(SheetContent, { side: "right", className: "w-80 p-0", children: [
1374
- /* @__PURE__ */ jsx10(SheetHeader, { className: "border-b p-4", children: /* @__PURE__ */ jsx10(SheetTitle, { children: t("history.title") }) }),
1375
- /* @__PURE__ */ jsx10("div", { className: "p-4", children: /* @__PURE__ */ jsxs4(
2087
+ /* @__PURE__ */ jsxs6(SheetContent, { side: "right", className: "w-80 p-0", children: [
2088
+ /* @__PURE__ */ jsx11(SheetHeader, { className: "border-b p-4", children: /* @__PURE__ */ jsx11(SheetTitle, { children: t("history.title") }) }),
2089
+ /* @__PURE__ */ jsx11("div", { className: "p-4", children: /* @__PURE__ */ jsxs6(
1376
2090
  Button,
1377
2091
  {
1378
2092
  onClick: handleNewThread,
1379
2093
  className: "w-full justify-start gap-2",
1380
2094
  variant: "secondary",
1381
2095
  children: [
1382
- /* @__PURE__ */ jsx10(PlusCircle, { size: 16 }),
2096
+ /* @__PURE__ */ jsx11(PlusCircle, { size: 16 }),
1383
2097
  t("history.newThread")
1384
2098
  ]
1385
2099
  }
1386
2100
  ) }),
1387
- /* @__PURE__ */ jsx10(ScrollArea, { className: "h-[calc(100vh-140px)]", children: /* @__PURE__ */ jsx10("div", { className: "px-4 pb-4", children: threads.length === 0 ? /* @__PURE__ */ jsx10("div", { className: "py-8 text-center text-sm text-muted-foreground", children: t("history.empty") }) : /* @__PURE__ */ jsx10("div", { className: "space-y-1", children: threads.map((thread) => /* @__PURE__ */ jsxs4(
2101
+ /* @__PURE__ */ jsx11(ScrollArea, { className: "h-[calc(100vh-140px)]", children: /* @__PURE__ */ jsx11("div", { className: "px-4 pb-4", children: threads.length === 0 ? /* @__PURE__ */ jsx11("div", { className: "py-8 text-center text-sm text-muted-foreground", children: t("history.empty") }) : /* @__PURE__ */ jsx11("div", { className: "space-y-1", children: threads.map((thread) => /* @__PURE__ */ jsxs6(
1388
2102
  "div",
1389
2103
  {
1390
2104
  className: cn(
@@ -1394,9 +2108,9 @@ function HistorySidebar({
1394
2108
  ),
1395
2109
  onClick: () => handleSelectThread(thread.id),
1396
2110
  children: [
1397
- /* @__PURE__ */ jsx10("span", { className: "text-muted-foreground", children: /* @__PURE__ */ jsx10(MessageSquare, { size: 16 }) }),
1398
- /* @__PURE__ */ jsx10("span", { className: "flex-1 truncate", children: thread.title }),
1399
- showDelete && onDeleteThread && /* @__PURE__ */ jsx10(
2111
+ /* @__PURE__ */ jsx11("span", { className: "text-muted-foreground", children: /* @__PURE__ */ jsx11(MessageSquare, { size: 16 }) }),
2112
+ /* @__PURE__ */ jsx11("span", { className: "flex-1 truncate", children: thread.title }),
2113
+ showDelete && onDeleteThread && /* @__PURE__ */ jsx11(
1400
2114
  "button",
1401
2115
  {
1402
2116
  type: "button",
@@ -1405,7 +2119,7 @@ function HistorySidebar({
1405
2119
  onDeleteThread(thread.id);
1406
2120
  },
1407
2121
  className: "opacity-0 group-hover:opacity-100 p-1 rounded hover:bg-destructive/10 hover:text-destructive transition-all",
1408
- children: /* @__PURE__ */ jsx10(Trash2, { size: 14 })
2122
+ children: /* @__PURE__ */ jsx11(Trash2, { size: 14 })
1409
2123
  }
1410
2124
  )
1411
2125
  ]
@@ -1416,31 +2130,334 @@ function HistorySidebar({
1416
2130
  ] });
1417
2131
  }
1418
2132
 
2133
+ // src/components/composer/pending-follow-ups.tsx
2134
+ import * as React10 from "react";
2135
+ import {
2136
+ CornerDownLeft,
2137
+ Ellipsis,
2138
+ Info,
2139
+ PencilLine,
2140
+ SlidersHorizontal as SlidersHorizontal2,
2141
+ Trash2 as Trash22
2142
+ } from "lucide-react";
2143
+ import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
2144
+ function getPendingFollowUpText(item, referencedContentFallback) {
2145
+ const text = item.request?.input?.input?.trim() ?? "";
2146
+ if (text) {
2147
+ return text;
2148
+ }
2149
+ const references = normalizeReferences(item.request?.input?.references);
2150
+ if (references.length === 0) {
2151
+ return referencedContentFallback;
2152
+ }
2153
+ const firstReferenceLabel = getReferenceLabel(references[0]);
2154
+ if (references.length === 1) {
2155
+ return firstReferenceLabel;
2156
+ }
2157
+ return `${firstReferenceLabel} +${references.length - 1}`;
2158
+ }
2159
+ function useRoundedClasses() {
2160
+ const { theme } = useTheme();
2161
+ return {
2162
+ top: theme.radius ? {
2163
+ pill: "rounded-t-full",
2164
+ round: "rounded-t-xl",
2165
+ soft: "rounded-t-lg",
2166
+ sharp: "rounded-t-none"
2167
+ }[theme.radius] : "rounded-t-lg",
2168
+ panel: getRoundedClass(theme.radius, "rounded-lg"),
2169
+ control: getRoundedClass(theme.radius, "rounded-md")
2170
+ };
2171
+ }
2172
+ function PendingFollowUps({
2173
+ items,
2174
+ isLoading,
2175
+ followUpBehavior,
2176
+ onBehaviorChange,
2177
+ onPromoteToSteer,
2178
+ canSendNow,
2179
+ onSendNow,
2180
+ onEdit,
2181
+ onRemove,
2182
+ className
2183
+ }) {
2184
+ const { t } = useChatkitTranslation();
2185
+ const rounded = useRoundedClasses();
2186
+ const referencedContentFallback = t("chat.referencedContentOnly");
2187
+ const [isSettingsOpen, setIsSettingsOpen] = React10.useState(false);
2188
+ const [openMenuId, setOpenMenuId] = React10.useState(null);
2189
+ React10.useEffect(() => {
2190
+ if (items.length === 0 && isSettingsOpen) {
2191
+ setIsSettingsOpen(false);
2192
+ }
2193
+ if (items.every((item) => item.id !== openMenuId)) {
2194
+ setOpenMenuId(null);
2195
+ }
2196
+ }, [isSettingsOpen, items, openMenuId]);
2197
+ if (items.length === 0) {
2198
+ return null;
2199
+ }
2200
+ return /* @__PURE__ */ jsx12(
2201
+ "div",
2202
+ {
2203
+ className: cn(
2204
+ "space-y-2 mx-2 p-2 border border-border border-b-0",
2205
+ rounded.top,
2206
+ className
2207
+ ),
2208
+ children: /* @__PURE__ */ jsxs7("div", { className: "space-y-1", children: [
2209
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between gap-3", children: [
2210
+ /* @__PURE__ */ jsx12("div", { className: "text-xs font-medium text-foreground", children: t("chat.followUps.pending") }),
2211
+ /* @__PURE__ */ jsxs7(Tooltip, { children: [
2212
+ /* @__PURE__ */ jsx12(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs7(
2213
+ "button",
2214
+ {
2215
+ type: "button",
2216
+ onClick: () => setIsSettingsOpen((prev) => !prev),
2217
+ className: cn(
2218
+ "inline-flex h-6 w-6 items-center justify-center transition-colors",
2219
+ isSettingsOpen ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/60 hover:text-foreground",
2220
+ rounded.control
2221
+ ),
2222
+ "aria-label": t("chat.followUps.settings"),
2223
+ "aria-expanded": isSettingsOpen,
2224
+ "aria-controls": "follow-ups-settings-panel",
2225
+ children: [
2226
+ /* @__PURE__ */ jsx12(SlidersHorizontal2, { className: "h-3.5 w-3.5" }),
2227
+ /* @__PURE__ */ jsx12("span", { className: "sr-only", children: t("chat.followUps.settings") })
2228
+ ]
2229
+ }
2230
+ ) }),
2231
+ /* @__PURE__ */ jsx12(TooltipContent, { side: "top", children: t("chat.followUps.settings") })
2232
+ ] })
2233
+ ] }),
2234
+ isSettingsOpen && /* @__PURE__ */ jsx12(
2235
+ "div",
2236
+ {
2237
+ id: "follow-ups-settings-panel",
2238
+ className: cn(
2239
+ "border border-border/70 bg-muted/20 px-3 py-2",
2240
+ rounded.panel
2241
+ ),
2242
+ children: /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between gap-3", children: [
2243
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0", children: [
2244
+ /* @__PURE__ */ jsx12("div", { className: "text-xs font-medium text-foreground", children: t("chat.followUps.label") }),
2245
+ /* @__PURE__ */ jsx12("div", { className: "text-[11px] text-muted-foreground", children: isLoading ? t("chat.followUps.activeHint") : t("chat.followUps.idleHint") })
2246
+ ] }),
2247
+ /* @__PURE__ */ jsx12(
2248
+ "div",
2249
+ {
2250
+ className: cn(
2251
+ "inline-flex shrink-0 border border-border bg-background p-1",
2252
+ rounded.control
2253
+ ),
2254
+ children: ["queue", "steer"].map((behavior) => /* @__PURE__ */ jsxs7(Tooltip, { children: [
2255
+ /* @__PURE__ */ jsx12(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx12(
2256
+ "button",
2257
+ {
2258
+ type: "button",
2259
+ onClick: () => {
2260
+ onBehaviorChange(behavior);
2261
+ setIsSettingsOpen(false);
2262
+ },
2263
+ className: cn(
2264
+ "px-3 py-1 text-xs font-medium transition-colors",
2265
+ rounded.control,
2266
+ followUpBehavior === behavior ? "bg-primary text-background" : "text-muted-foreground hover:text-foreground"
2267
+ ),
2268
+ children: behavior === "queue" ? t("chat.followUps.queue") : t("chat.followUps.steer")
2269
+ }
2270
+ ) }),
2271
+ /* @__PURE__ */ jsx12(TooltipContent, { side: "top", children: behavior === "queue" ? t("chat.followUps.queueHint") : t("chat.followUps.steerHint") })
2272
+ ] }, behavior))
2273
+ }
2274
+ )
2275
+ ] })
2276
+ }
2277
+ ),
2278
+ items.map((item) => {
2279
+ const canSendItemNow = item.mode === "queue" && canSendNow(item.id);
2280
+ return /* @__PURE__ */ jsx12(
2281
+ "div",
2282
+ {
2283
+ className: cn(
2284
+ "border border-border/50 bg-muted/15 px-2 py-1",
2285
+ rounded.panel
2286
+ ),
2287
+ children: /* @__PURE__ */ jsxs7("div", { className: "flex items-start gap-2.5", children: [
2288
+ /* @__PURE__ */ jsx12(CornerDownLeft, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
2289
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
2290
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-start gap-2", children: [
2291
+ /* @__PURE__ */ jsx12("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx12(
2292
+ "div",
2293
+ {
2294
+ className: "truncate text-[13px] leading-5 text-foreground",
2295
+ title: getPendingFollowUpText(
2296
+ item,
2297
+ referencedContentFallback
2298
+ ),
2299
+ children: getPendingFollowUpText(
2300
+ item,
2301
+ referencedContentFallback
2302
+ )
2303
+ }
2304
+ ) }),
2305
+ /* @__PURE__ */ jsxs7("div", { className: "flex shrink-0 items-center gap-1", children: [
2306
+ item.mode === "queue" && isLoading && /* @__PURE__ */ jsx12(
2307
+ "button",
2308
+ {
2309
+ type: "button",
2310
+ onClick: () => void onPromoteToSteer(item.id),
2311
+ className: cn(
2312
+ "inline-flex h-6 items-center border border-primary/20 bg-primary/5 px-2 text-[11px] font-medium text-primary transition-colors hover:bg-primary/10",
2313
+ rounded.control
2314
+ ),
2315
+ "aria-label": t("chat.followUps.steerAction"),
2316
+ title: t("chat.followUps.steerAction"),
2317
+ children: t("chat.followUps.steerAction")
2318
+ }
2319
+ ),
2320
+ canSendItemNow && /* @__PURE__ */ jsx12(
2321
+ "button",
2322
+ {
2323
+ type: "button",
2324
+ onClick: () => void onSendNow(item.id),
2325
+ className: cn(
2326
+ "inline-flex h-6 items-center border border-primary/20 bg-primary/5 px-2 text-[11px] font-medium text-primary transition-colors hover:bg-primary/10",
2327
+ rounded.control
2328
+ ),
2329
+ "aria-label": t("chat.followUps.sendNow"),
2330
+ title: t("chat.followUps.sendNow"),
2331
+ children: t("chat.followUps.sendNow")
2332
+ }
2333
+ ),
2334
+ item.mode === "queue" && /* @__PURE__ */ jsx12(
2335
+ "button",
2336
+ {
2337
+ type: "button",
2338
+ onClick: () => onRemove(item.id),
2339
+ className: cn(
2340
+ "inline-flex h-6 w-6 shrink-0 items-center justify-center text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
2341
+ rounded.control
2342
+ ),
2343
+ "aria-label": t("chat.followUps.remove"),
2344
+ title: t("chat.followUps.remove"),
2345
+ children: /* @__PURE__ */ jsx12(Trash22, { size: 13 })
2346
+ }
2347
+ ),
2348
+ item.mode === "queue" && /* @__PURE__ */ jsxs7(
2349
+ Popover,
2350
+ {
2351
+ open: openMenuId === item.id,
2352
+ onOpenChange: (open) => setOpenMenuId(open ? item.id : null),
2353
+ children: [
2354
+ /* @__PURE__ */ jsx12(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx12(
2355
+ "button",
2356
+ {
2357
+ type: "button",
2358
+ className: cn(
2359
+ "inline-flex h-6 w-6 shrink-0 items-center justify-center text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
2360
+ rounded.control
2361
+ ),
2362
+ "aria-label": t("chat.followUps.more"),
2363
+ title: t("chat.followUps.more"),
2364
+ children: /* @__PURE__ */ jsx12(Ellipsis, { size: 13 })
2365
+ }
2366
+ ) }),
2367
+ /* @__PURE__ */ jsx12(
2368
+ PopoverContent,
2369
+ {
2370
+ align: "end",
2371
+ side: "bottom",
2372
+ className: cn(
2373
+ "w-52 border-border/70 bg-background p-1.5",
2374
+ rounded.panel
2375
+ ),
2376
+ children: /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-1", children: [
2377
+ /* @__PURE__ */ jsxs7(
2378
+ "button",
2379
+ {
2380
+ type: "button",
2381
+ onClick: () => {
2382
+ setOpenMenuId(null);
2383
+ onEdit(item.id);
2384
+ },
2385
+ className: cn(
2386
+ "flex items-center gap-2 px-2 py-1.5 text-left text-sm text-foreground transition-colors hover:bg-muted",
2387
+ rounded.control
2388
+ ),
2389
+ children: [
2390
+ /* @__PURE__ */ jsx12(PencilLine, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
2391
+ /* @__PURE__ */ jsx12("span", { children: t("chat.followUps.edit") })
2392
+ ]
2393
+ }
2394
+ ),
2395
+ /* @__PURE__ */ jsxs7(
2396
+ "button",
2397
+ {
2398
+ type: "button",
2399
+ onClick: () => {
2400
+ setOpenMenuId(null);
2401
+ onBehaviorChange("steer");
2402
+ },
2403
+ className: cn(
2404
+ "flex items-center gap-2 px-2 py-1.5 text-left text-sm text-foreground transition-colors hover:bg-muted",
2405
+ rounded.control
2406
+ ),
2407
+ children: [
2408
+ /* @__PURE__ */ jsx12(CornerDownLeft, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
2409
+ /* @__PURE__ */ jsx12("span", { children: t("chat.followUps.turnOffQueueing") })
2410
+ ]
2411
+ }
2412
+ )
2413
+ ] })
2414
+ }
2415
+ )
2416
+ ]
2417
+ }
2418
+ )
2419
+ ] })
2420
+ ] }),
2421
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1.5 text-[10px] leading-4 text-muted-foreground", children: [
2422
+ /* @__PURE__ */ jsx12(Info, { className: "h-3 w-3 shrink-0" }),
2423
+ /* @__PURE__ */ jsx12("span", { className: "truncate", children: item.mode === "queue" ? canSendItemNow ? t("chat.followUps.manualQueueHint") : t("chat.followUps.queueHint") : t("chat.followUps.steerHint") })
2424
+ ] })
2425
+ ] })
2426
+ ] })
2427
+ },
2428
+ item.id
2429
+ );
2430
+ })
2431
+ ] })
2432
+ }
2433
+ );
2434
+ }
2435
+
1419
2436
  // src/components/thread/messages/ai.tsx
1420
- import * as React13 from "react";
1421
- import { ChevronDown, CheckCircle2, XCircle, Loader2 } from "lucide-react";
2437
+ import * as React15 from "react";
2438
+ import { ChevronDown, CheckCircle2, XCircle, Loader2 as Loader22 } from "lucide-react";
1422
2439
 
1423
2440
  // src/components/ui/badge.tsx
1424
- import * as React9 from "react";
1425
- import { jsx as jsx11 } from "react/jsx-runtime";
2441
+ import * as React11 from "react";
2442
+ import { jsx as jsx13 } from "react/jsx-runtime";
1426
2443
  var base = "inline-flex items-center rounded-full border border-transparent px-2.5 py-0.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ring-offset-background";
1427
2444
  var variants = {
1428
2445
  default: "bg-primary text-primary-foreground",
1429
2446
  secondary: "bg-secondary text-secondary-foreground",
1430
2447
  outline: "border-input text-foreground"
1431
2448
  };
1432
- var Badge = React9.forwardRef(
2449
+ var Badge = React11.forwardRef(
1433
2450
  ({ className, variant = "default", ...props }, ref) => {
1434
- return /* @__PURE__ */ jsx11("span", { ref, className: cn(base, variants[variant], className), ...props });
2451
+ return /* @__PURE__ */ jsx13("span", { ref, className: cn(base, variants[variant], className), ...props });
1435
2452
  }
1436
2453
  );
1437
2454
  Badge.displayName = "Badge";
1438
2455
 
1439
2456
  // src/components/ui/card.tsx
1440
- import * as React10 from "react";
1441
- import { jsx as jsx12 } from "react/jsx-runtime";
1442
- var Card = React10.forwardRef(
1443
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx12(
2457
+ import * as React12 from "react";
2458
+ import { jsx as jsx14 } from "react/jsx-runtime";
2459
+ var Card = React12.forwardRef(
2460
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx14(
1444
2461
  "div",
1445
2462
  {
1446
2463
  ref,
@@ -1453,50 +2470,50 @@ var Card = React10.forwardRef(
1453
2470
  )
1454
2471
  );
1455
2472
  Card.displayName = "Card";
1456
- var CardHeader = React10.forwardRef(
1457
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx12("div", { ref, className: cn("flex flex-col gap-1.5 px-6 pt-6", className), ...props })
2473
+ var CardHeader = React12.forwardRef(
2474
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx14("div", { ref, className: cn("flex flex-col gap-1.5 px-6 pt-6", className), ...props })
1458
2475
  );
1459
2476
  CardHeader.displayName = "CardHeader";
1460
- var CardTitle = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx12("h3", { ref, className: cn("text-lg font-semibold leading-tight", className), ...props }));
2477
+ var CardTitle = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx14("h3", { ref, className: cn("text-lg font-semibold leading-tight", className), ...props }));
1461
2478
  CardTitle.displayName = "CardTitle";
1462
- var CardDescription = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx12("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
2479
+ var CardDescription = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx14("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
1463
2480
  CardDescription.displayName = "CardDescription";
1464
- var CardContent = React10.forwardRef(
1465
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx12("div", { ref, className: cn("px-6 pb-6", className), ...props })
2481
+ var CardContent = React12.forwardRef(
2482
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx14("div", { ref, className: cn("px-6 pb-6", className), ...props })
1466
2483
  );
1467
2484
  CardContent.displayName = "CardContent";
1468
- var CardFooter = React10.forwardRef(
1469
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx12("div", { ref, className: cn("flex items-center px-6 pb-6", className), ...props })
2485
+ var CardFooter = React12.forwardRef(
2486
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx14("div", { ref, className: cn("flex items-center px-6 pb-6", className), ...props })
1470
2487
  );
1471
2488
  CardFooter.displayName = "CardFooter";
1472
- var CardAction = React10.forwardRef(
1473
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx12("div", { ref, className: cn("ml-auto flex items-center", className), ...props })
2489
+ var CardAction = React12.forwardRef(
2490
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx14("div", { ref, className: cn("ml-auto flex items-center", className), ...props })
1474
2491
  );
1475
2492
  CardAction.displayName = "CardAction";
1476
2493
 
1477
2494
  // src/components/ui/tabs.tsx
1478
- import * as React11 from "react";
1479
- import { jsx as jsx13 } from "react/jsx-runtime";
1480
- var TabsContext = React11.createContext(null);
2495
+ import * as React13 from "react";
2496
+ import { jsx as jsx15 } from "react/jsx-runtime";
2497
+ var TabsContext = React13.createContext(null);
1481
2498
  function Tabs({ className, defaultValue, value, onValueChange, ...props }) {
1482
- const [internalValue, setInternalValue] = React11.useState(defaultValue ?? "");
2499
+ const [internalValue, setInternalValue] = React13.useState(defaultValue ?? "");
1483
2500
  const activeValue = value ?? internalValue;
1484
- const setValue = React11.useCallback(
2501
+ const setValue = React13.useCallback(
1485
2502
  (nextValue) => {
1486
2503
  if (value === void 0) setInternalValue(nextValue);
1487
2504
  onValueChange?.(nextValue);
1488
2505
  },
1489
2506
  [onValueChange, value]
1490
2507
  );
1491
- return /* @__PURE__ */ jsx13(TabsContext.Provider, { value: { value: activeValue, setValue }, children: /* @__PURE__ */ jsx13("div", { className: cn("w-full", className), ...props }) });
2508
+ return /* @__PURE__ */ jsx15(TabsContext.Provider, { value: { value: activeValue, setValue }, children: /* @__PURE__ */ jsx15("div", { className: cn("w-full", className), ...props }) });
1492
2509
  }
1493
- var TabsList = React11.forwardRef(
1494
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
2510
+ var TabsList = React13.forwardRef(
2511
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx15(
1495
2512
  "div",
1496
2513
  {
1497
2514
  ref,
1498
2515
  className: cn(
1499
- "inline-flex h-11 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
2516
+ "inline-flex items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
1500
2517
  className
1501
2518
  ),
1502
2519
  role: "tablist",
@@ -1505,14 +2522,14 @@ var TabsList = React11.forwardRef(
1505
2522
  )
1506
2523
  );
1507
2524
  TabsList.displayName = "TabsList";
1508
- var TabsTrigger = React11.forwardRef(
2525
+ var TabsTrigger = React13.forwardRef(
1509
2526
  ({ className, value, onClick, ...props }, ref) => {
1510
- const context = React11.useContext(TabsContext);
2527
+ const context = React13.useContext(TabsContext);
1511
2528
  if (!context) {
1512
2529
  throw new Error("TabsTrigger must be used within Tabs");
1513
2530
  }
1514
2531
  const isActive = context.value === value;
1515
- return /* @__PURE__ */ jsx13(
2532
+ return /* @__PURE__ */ jsx15(
1516
2533
  "button",
1517
2534
  {
1518
2535
  ref,
@@ -1521,7 +2538,7 @@ var TabsTrigger = React11.forwardRef(
1521
2538
  "aria-selected": isActive,
1522
2539
  "data-state": isActive ? "active" : "inactive",
1523
2540
  className: cn(
1524
- "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-2 text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ring-offset-background disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
2541
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ring-offset-background disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
1525
2542
  className
1526
2543
  ),
1527
2544
  onClick: (event) => {
@@ -1534,14 +2551,14 @@ var TabsTrigger = React11.forwardRef(
1534
2551
  }
1535
2552
  );
1536
2553
  TabsTrigger.displayName = "TabsTrigger";
1537
- var TabsContent = React11.forwardRef(
2554
+ var TabsContent = React13.forwardRef(
1538
2555
  ({ className, value, ...props }, ref) => {
1539
- const context = React11.useContext(TabsContext);
2556
+ const context = React13.useContext(TabsContext);
1540
2557
  if (!context) {
1541
2558
  throw new Error("TabsContent must be used within Tabs");
1542
2559
  }
1543
2560
  if (context.value !== value) return null;
1544
- return /* @__PURE__ */ jsx13(
2561
+ return /* @__PURE__ */ jsx15(
1545
2562
  "div",
1546
2563
  {
1547
2564
  ref,
@@ -1564,10 +2581,11 @@ import rehypeKatex from "rehype-katex";
1564
2581
  import remarkMath from "remark-math";
1565
2582
  import {
1566
2583
  Children,
2584
+ isValidElement,
1567
2585
  memo,
1568
- useState as useState5
2586
+ useState as useState7
1569
2587
  } from "react";
1570
- import { CheckIcon, CopyIcon } from "lucide-react";
2588
+ import { CheckIcon as CheckIcon2, CopyIcon as CopyIcon2 } from "lucide-react";
1571
2589
 
1572
2590
  // src/components/thread/syntax-highlighter.tsx
1573
2591
  import { PrismAsyncLight as SyntaxHighlighterPrism } from "react-syntax-highlighter";
@@ -1575,7 +2593,7 @@ import tsx from "react-syntax-highlighter/dist/esm/languages/prism/tsx";
1575
2593
  import python from "react-syntax-highlighter/dist/esm/languages/prism/python";
1576
2594
  import { coldarkDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
1577
2595
  import "react";
1578
- import { jsx as jsx14 } from "react/jsx-runtime";
2596
+ import { jsx as jsx16 } from "react/jsx-runtime";
1579
2597
  SyntaxHighlighterPrism.registerLanguage("js", tsx);
1580
2598
  SyntaxHighlighterPrism.registerLanguage("jsx", tsx);
1581
2599
  SyntaxHighlighterPrism.registerLanguage("ts", tsx);
@@ -1586,7 +2604,7 @@ var SyntaxHighlighter = ({
1586
2604
  language,
1587
2605
  className
1588
2606
  }) => {
1589
- return /* @__PURE__ */ jsx14(
2607
+ return /* @__PURE__ */ jsx16(
1590
2608
  SyntaxHighlighterPrism,
1591
2609
  {
1592
2610
  language,
@@ -1603,77 +2621,27 @@ var SyntaxHighlighter = ({
1603
2621
  );
1604
2622
  };
1605
2623
 
1606
- // src/components/thread/tooltip-icon-button.tsx
1607
- import { forwardRef as forwardRef5 } from "react";
1608
-
1609
- // src/components/ui/tooltip.tsx
1610
- import "react";
1611
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
1612
- import { jsx as jsx15, jsxs as jsxs5 } from "react/jsx-runtime";
1613
- function TooltipProvider({
1614
- delayDuration = 0,
1615
- ...props
1616
- }) {
1617
- return /* @__PURE__ */ jsx15(
1618
- TooltipPrimitive.Provider,
1619
- {
1620
- "data-slot": "tooltip-provider",
1621
- delayDuration,
1622
- ...props
1623
- }
1624
- );
1625
- }
1626
- function Tooltip({
1627
- ...props
1628
- }) {
1629
- return /* @__PURE__ */ jsx15(TooltipProvider, { children: /* @__PURE__ */ jsx15(
1630
- TooltipPrimitive.Root,
1631
- {
1632
- "data-slot": "tooltip",
1633
- ...props
1634
- }
1635
- ) });
1636
- }
1637
- function TooltipTrigger({
1638
- ...props
1639
- }) {
1640
- return /* @__PURE__ */ jsx15(
1641
- TooltipPrimitive.Trigger,
1642
- {
1643
- "data-slot": "tooltip-trigger",
1644
- ...props
1645
- }
1646
- );
1647
- }
1648
- function TooltipContent({
1649
- className,
1650
- sideOffset = 0,
1651
- children,
1652
- ...props
1653
- }) {
1654
- return /* @__PURE__ */ jsx15(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs5(
1655
- TooltipPrimitive.Content,
1656
- {
1657
- "data-slot": "tooltip-content",
1658
- sideOffset,
1659
- className: cn(
1660
- "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit rounded-md px-3 py-1.5 text-xs text-balance",
1661
- className
1662
- ),
1663
- ...props,
1664
- children: [
1665
- children,
1666
- /* @__PURE__ */ jsx15(TooltipPrimitive.Arrow, { className: "bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
1667
- ]
1668
- }
1669
- ) });
1670
- }
2624
+ // src/components/thread/mermaid-block.tsx
2625
+ import * as Dialog from "@radix-ui/react-dialog";
2626
+ import mermaid from "mermaid";
2627
+ import {
2628
+ CheckIcon,
2629
+ Code2Icon,
2630
+ CopyIcon,
2631
+ DownloadIcon,
2632
+ ExpandIcon,
2633
+ Loader2,
2634
+ TriangleAlert,
2635
+ X as X2
2636
+ } from "lucide-react";
2637
+ import * as React14 from "react";
1671
2638
 
1672
2639
  // src/components/thread/tooltip-icon-button.tsx
1673
- import { jsx as jsx16, jsxs as jsxs6 } from "react/jsx-runtime";
2640
+ import { forwardRef as forwardRef5 } from "react";
2641
+ import { jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
1674
2642
  var TooltipIconButton = forwardRef5(({ children, tooltip, side = "bottom", className, ...rest }, ref) => {
1675
- return /* @__PURE__ */ jsx16(TooltipProvider, { children: /* @__PURE__ */ jsxs6(Tooltip, { children: [
1676
- /* @__PURE__ */ jsx16(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
2643
+ return /* @__PURE__ */ jsx17(TooltipProvider, { children: /* @__PURE__ */ jsxs8(Tooltip, { children: [
2644
+ /* @__PURE__ */ jsx17(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs8(
1677
2645
  Button,
1678
2646
  {
1679
2647
  variant: "ghost",
@@ -1683,28 +2651,519 @@ var TooltipIconButton = forwardRef5(({ children, tooltip, side = "bottom", class
1683
2651
  ref,
1684
2652
  children: [
1685
2653
  children,
1686
- /* @__PURE__ */ jsx16("span", { className: "sr-only", children: tooltip })
2654
+ /* @__PURE__ */ jsx17("span", { className: "sr-only", children: tooltip })
1687
2655
  ]
1688
2656
  }
1689
2657
  ) }),
1690
- /* @__PURE__ */ jsx16(TooltipContent, { side, children: tooltip })
2658
+ /* @__PURE__ */ jsx17(TooltipContent, { side, children: tooltip })
1691
2659
  ] }) });
1692
2660
  });
1693
2661
  TooltipIconButton.displayName = "TooltipIconButton";
1694
2662
 
2663
+ // src/components/thread/mermaid-block.tsx
2664
+ import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs9 } from "react/jsx-runtime";
2665
+ var HEX_COLOR_PATTERN = /^#([\da-f]{3,8})$/i;
2666
+ var MERMAID_DIRECTIVE_PATTERN = /%{2}{\s*(?:(\w+)\s*:|(\w+))\s*(?:(\w+)|((?:(?!}%{2}).|\r?\n)*))?\s*(?:}%{2})?/gi;
2667
+ var MERMAID_FRONTMATTER_PATTERN = /^-{3}\s*[\n\r](.*?)[\n\r]-{3}\s*[\n\r]+/s;
2668
+ var OKLCH_COLOR_PATTERN = /^oklch\((.+)\)$/i;
2669
+ var RGB_COLOR_PATTERN = /^rgba?\((.+)\)$/i;
2670
+ var MERMAID_SECURE_KEYS = [
2671
+ "fontFamily",
2672
+ "maxEdges",
2673
+ "maxTextSize",
2674
+ "securityLevel",
2675
+ "secure",
2676
+ "startOnLoad",
2677
+ "suppressErrorRendering",
2678
+ "theme",
2679
+ "themeVariables"
2680
+ ];
2681
+ function clamp(value, min, max) {
2682
+ return Math.min(max, Math.max(min, value));
2683
+ }
2684
+ function normalizeMermaidCode(code) {
2685
+ return code.replace(MERMAID_FRONTMATTER_PATTERN, "").replace(MERMAID_DIRECTIVE_PATTERN, "").trim();
2686
+ }
2687
+ function parseAlpha(value) {
2688
+ if (!value) return 1;
2689
+ const normalized = value.trim();
2690
+ if (!normalized) return 1;
2691
+ if (normalized.endsWith("%")) {
2692
+ return clamp(Number.parseFloat(normalized) / 100, 0, 1);
2693
+ }
2694
+ return clamp(Number.parseFloat(normalized), 0, 1);
2695
+ }
2696
+ function parseHexColor(value) {
2697
+ const match = value.trim().match(HEX_COLOR_PATTERN);
2698
+ if (!match) return null;
2699
+ const hex = match[1];
2700
+ if (hex.length === 3 || hex.length === 4) {
2701
+ const [r, g, b, a = "f"] = hex.split("");
2702
+ return {
2703
+ r: Number.parseInt(r + r, 16),
2704
+ g: Number.parseInt(g + g, 16),
2705
+ b: Number.parseInt(b + b, 16),
2706
+ a: Number.parseInt(a + a, 16) / 255
2707
+ };
2708
+ }
2709
+ if (hex.length === 6 || hex.length === 8) {
2710
+ const alphaHex = hex.length === 8 ? hex.slice(6, 8) : "ff";
2711
+ return {
2712
+ r: Number.parseInt(hex.slice(0, 2), 16),
2713
+ g: Number.parseInt(hex.slice(2, 4), 16),
2714
+ b: Number.parseInt(hex.slice(4, 6), 16),
2715
+ a: Number.parseInt(alphaHex, 16) / 255
2716
+ };
2717
+ }
2718
+ return null;
2719
+ }
2720
+ function parseRgbChannel(value) {
2721
+ const normalized = value.trim();
2722
+ if (normalized.endsWith("%")) {
2723
+ return clamp(Math.round(Number.parseFloat(normalized) / 100 * 255), 0, 255);
2724
+ }
2725
+ return clamp(Math.round(Number.parseFloat(normalized)), 0, 255);
2726
+ }
2727
+ function parseRgbColor(value) {
2728
+ const match = value.trim().match(RGB_COLOR_PATTERN);
2729
+ if (!match) return null;
2730
+ const parts = match[1].split(/[,\s/]+/).map((part) => part.trim()).filter(Boolean);
2731
+ if (parts.length < 3) return null;
2732
+ return {
2733
+ r: parseRgbChannel(parts[0]),
2734
+ g: parseRgbChannel(parts[1]),
2735
+ b: parseRgbChannel(parts[2]),
2736
+ a: parseAlpha(parts[3])
2737
+ };
2738
+ }
2739
+ function parseOklchLightness(value) {
2740
+ const normalized = value.trim();
2741
+ if (normalized.endsWith("%")) {
2742
+ return clamp(Number.parseFloat(normalized) / 100, 0, 1);
2743
+ }
2744
+ return clamp(Number.parseFloat(normalized), 0, 1);
2745
+ }
2746
+ function parseHue(value) {
2747
+ const normalized = value.trim().toLowerCase();
2748
+ const numeric = Number.parseFloat(normalized);
2749
+ if (Number.isNaN(numeric)) return 0;
2750
+ if (normalized.endsWith("turn")) return numeric * 360;
2751
+ if (normalized.endsWith("rad")) return numeric * (180 / Math.PI);
2752
+ if (normalized.endsWith("grad")) return numeric * 0.9;
2753
+ return numeric;
2754
+ }
2755
+ function linearToSrgb(linear) {
2756
+ if (linear <= 31308e-7) {
2757
+ return 12.92 * linear;
2758
+ }
2759
+ return 1.055 * Math.pow(linear, 1 / 2.4) - 0.055;
2760
+ }
2761
+ function parseOklchColor(value) {
2762
+ const match = value.trim().match(OKLCH_COLOR_PATTERN);
2763
+ if (!match) return null;
2764
+ const [base2, alphaSegment] = match[1].split("/");
2765
+ const parts = base2.trim().split(/\s+/).map((part) => part.trim()).filter(Boolean);
2766
+ if (parts.length < 3) return null;
2767
+ const lightness = parseOklchLightness(parts[0]);
2768
+ const chroma = Number.parseFloat(parts[1]);
2769
+ const hueRadians = parseHue(parts[2]) * Math.PI / 180;
2770
+ const alpha = parseAlpha(alphaSegment);
2771
+ const a = chroma * Math.cos(hueRadians);
2772
+ const b = chroma * Math.sin(hueRadians);
2773
+ const l_ = lightness + 0.3963377774 * a + 0.2158037573 * b;
2774
+ const m_ = lightness - 0.1055613458 * a - 0.0638541728 * b;
2775
+ const s_ = lightness - 0.0894841775 * a - 1.291485548 * b;
2776
+ const l = l_ * l_ * l_;
2777
+ const m = m_ * m_ * m_;
2778
+ const s = s_ * s_ * s_;
2779
+ const linearR = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
2780
+ const linearG = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
2781
+ const linearB = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;
2782
+ return {
2783
+ r: clamp(Math.round(linearToSrgb(linearR) * 255), 0, 255),
2784
+ g: clamp(Math.round(linearToSrgb(linearG) * 255), 0, 255),
2785
+ b: clamp(Math.round(linearToSrgb(linearB) * 255), 0, 255),
2786
+ a: alpha
2787
+ };
2788
+ }
2789
+ function parseCssColor(value) {
2790
+ const normalized = value.trim();
2791
+ if (!normalized) return null;
2792
+ return parseHexColor(normalized) ?? parseRgbColor(normalized) ?? parseOklchColor(normalized);
2793
+ }
2794
+ function compositeColor(foreground, background) {
2795
+ const alpha = foreground.a + background.a * (1 - foreground.a);
2796
+ if (alpha <= 0) {
2797
+ return { r: 0, g: 0, b: 0, a: 0 };
2798
+ }
2799
+ const r = (foreground.r * foreground.a + background.r * background.a * (1 - foreground.a)) / alpha;
2800
+ const g = (foreground.g * foreground.a + background.g * background.a * (1 - foreground.a)) / alpha;
2801
+ const b = (foreground.b * foreground.a + background.b * background.a * (1 - foreground.a)) / alpha;
2802
+ return {
2803
+ r: clamp(Math.round(r), 0, 255),
2804
+ g: clamp(Math.round(g), 0, 255),
2805
+ b: clamp(Math.round(b), 0, 255),
2806
+ a: clamp(alpha, 0, 1)
2807
+ };
2808
+ }
2809
+ function toHexChannel(value) {
2810
+ return value.toString(16).padStart(2, "0");
2811
+ }
2812
+ function rgbaToHex(value) {
2813
+ return `#${toHexChannel(value.r)}${toHexChannel(value.g)}${toHexChannel(value.b)}`;
2814
+ }
2815
+ function getFallbackPalette(isDarkMode) {
2816
+ if (isDarkMode) {
2817
+ return {
2818
+ background: "#171717",
2819
+ border: "#52525b",
2820
+ fontFamily: "Inter Variable, sans-serif",
2821
+ line: "#a1a1aa",
2822
+ surface: "#262626",
2823
+ surfaceAlt: "#3f3f46",
2824
+ text: "#fafafa"
2825
+ };
2826
+ }
2827
+ return {
2828
+ background: "#ffffff",
2829
+ border: "#e4e4e7",
2830
+ fontFamily: "Inter Variable, sans-serif",
2831
+ line: "#71717a",
2832
+ surface: "#ffffff",
2833
+ surfaceAlt: "#f4f4f5",
2834
+ text: "#18181b"
2835
+ };
2836
+ }
2837
+ function resolveColor(styles, property, fallback, background) {
2838
+ const parsed = parseCssColor(styles.getPropertyValue(property));
2839
+ if (!parsed) return fallback;
2840
+ if (parsed.a < 1 && background) {
2841
+ return rgbaToHex(compositeColor(parsed, background));
2842
+ }
2843
+ return rgbaToHex(parsed);
2844
+ }
2845
+ function resolvePalette(element, isDarkMode) {
2846
+ const fallback = getFallbackPalette(isDarkMode);
2847
+ const styles = window.getComputedStyle(element);
2848
+ const backgroundColor = parseCssColor(styles.getPropertyValue("--card")) ?? parseCssColor(styles.getPropertyValue("--background")) ?? parseCssColor(fallback.surface);
2849
+ return {
2850
+ background: resolveColor(styles, "--background", fallback.background, backgroundColor),
2851
+ border: resolveColor(styles, "--border", fallback.border, backgroundColor),
2852
+ fontFamily: styles.getPropertyValue("font-family").trim() || fallback.fontFamily,
2853
+ line: resolveColor(styles, "--muted-foreground", fallback.line, backgroundColor),
2854
+ surface: resolveColor(styles, "--card", fallback.surface, backgroundColor),
2855
+ surfaceAlt: resolveColor(styles, "--muted", fallback.surfaceAlt, backgroundColor),
2856
+ text: resolveColor(styles, "--foreground", fallback.text, backgroundColor)
2857
+ };
2858
+ }
2859
+ function buildThemeVariables(palette) {
2860
+ return {
2861
+ background: palette.background,
2862
+ clusterBkg: palette.surfaceAlt,
2863
+ clusterBorder: palette.border,
2864
+ edgeLabelBackground: palette.surface,
2865
+ fontFamily: palette.fontFamily,
2866
+ lineColor: palette.line,
2867
+ mainBkg: palette.surface,
2868
+ nodeBorder: palette.border,
2869
+ nodeTextColor: palette.text,
2870
+ primaryBorderColor: palette.border,
2871
+ primaryColor: palette.surfaceAlt,
2872
+ primaryTextColor: palette.text,
2873
+ secondaryBorderColor: palette.border,
2874
+ secondaryColor: palette.surface,
2875
+ secondaryTextColor: palette.text,
2876
+ tertiaryBorderColor: palette.border,
2877
+ tertiaryColor: palette.surface,
2878
+ tertiaryTextColor: palette.text,
2879
+ textColor: palette.text
2880
+ };
2881
+ }
2882
+ async function renderMermaidDiagram({
2883
+ code,
2884
+ host,
2885
+ id,
2886
+ palette
2887
+ }) {
2888
+ host.innerHTML = "";
2889
+ mermaid.initialize({
2890
+ flowchart: {
2891
+ htmlLabels: false,
2892
+ useMaxWidth: true
2893
+ },
2894
+ fontFamily: palette.fontFamily,
2895
+ secure: [...MERMAID_SECURE_KEYS],
2896
+ securityLevel: "strict",
2897
+ startOnLoad: false,
2898
+ theme: "base",
2899
+ themeVariables: buildThemeVariables(palette)
2900
+ });
2901
+ const { svg } = await mermaid.render(id, code, host);
2902
+ host.innerHTML = "";
2903
+ return svg;
2904
+ }
2905
+ function MermaidPreviewDialog({
2906
+ closeLabel,
2907
+ onOpenChange,
2908
+ open,
2909
+ svgMarkup,
2910
+ title
2911
+ }) {
2912
+ return /* @__PURE__ */ jsx18(Dialog.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs9(Dialog.Portal, { children: [
2913
+ /* @__PURE__ */ jsx18(Dialog.Overlay, { className: "fixed inset-0 z-50 bg-black/60 backdrop-blur-sm data-[state=closed]:animate-out data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" }),
2914
+ /* @__PURE__ */ jsxs9(Dialog.Content, { className: "fixed inset-[5vh] z-50 flex flex-col overflow-hidden rounded-3xl border border-border bg-background shadow-2xl outline-none data-[state=closed]:animate-out data-[state=open]:animate-in data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", children: [
2915
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between gap-4 border-b border-border px-5 py-4", children: [
2916
+ /* @__PURE__ */ jsx18(Dialog.Title, { className: "text-base font-semibold text-foreground", children: title }),
2917
+ /* @__PURE__ */ jsx18(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsxs9(
2918
+ "button",
2919
+ {
2920
+ type: "button",
2921
+ className: "inline-flex size-10 items-center justify-center rounded-full border border-border bg-card text-muted-foreground transition-colors hover:text-foreground",
2922
+ children: [
2923
+ /* @__PURE__ */ jsx18(X2, { className: "size-4" }),
2924
+ /* @__PURE__ */ jsx18("span", { className: "sr-only", children: closeLabel })
2925
+ ]
2926
+ }
2927
+ ) })
2928
+ ] }),
2929
+ /* @__PURE__ */ jsx18("div", { className: "flex-1 overflow-auto bg-card p-6", children: /* @__PURE__ */ jsx18(
2930
+ "div",
2931
+ {
2932
+ "data-slot": "mermaid-preview",
2933
+ className: "min-h-full rounded-[calc(var(--radius)+0.5rem)] border border-border bg-background p-6 [&_svg]:mx-auto [&_svg]:h-auto [&_svg]:max-w-none",
2934
+ dangerouslySetInnerHTML: { __html: svgMarkup }
2935
+ }
2936
+ ) })
2937
+ ] })
2938
+ ] }) });
2939
+ }
2940
+ function MermaidBlock({ code }) {
2941
+ const { t } = useChatkitTranslation();
2942
+ const { theme, isDarkMode } = useTheme();
2943
+ const containerRef = React14.useRef(null);
2944
+ const renderHostRef = React14.useRef(null);
2945
+ const renderSequenceRef = React14.useRef(0);
2946
+ const copyResetTimeoutRef = React14.useRef(null);
2947
+ const diagramId = React14.useId().replace(/:/g, "");
2948
+ const [activeTab, setActiveTab] = React14.useState("diagram");
2949
+ const [isCopied, setIsCopied] = React14.useState(false);
2950
+ const [isPreviewOpen, setIsPreviewOpen] = React14.useState(false);
2951
+ const [isRendering, setIsRendering] = React14.useState(true);
2952
+ const [renderError, setRenderError] = React14.useState(null);
2953
+ const [svgMarkup, setSvgMarkup] = React14.useState(null);
2954
+ const normalizedCode = React14.useMemo(() => normalizeMermaidCode(code), [code]);
2955
+ const clearCopyResetTimeout = React14.useCallback(() => {
2956
+ if (copyResetTimeoutRef.current === null) return;
2957
+ window.clearTimeout(copyResetTimeoutRef.current);
2958
+ copyResetTimeoutRef.current = null;
2959
+ }, []);
2960
+ React14.useEffect(() => {
2961
+ let isActive = true;
2962
+ async function runRender() {
2963
+ const container = containerRef.current;
2964
+ const renderHost = renderHostRef.current;
2965
+ if (!container || !renderHost) return;
2966
+ setIsRendering(true);
2967
+ setRenderError(null);
2968
+ try {
2969
+ renderSequenceRef.current += 1;
2970
+ const svg = await renderMermaidDiagram({
2971
+ code: normalizedCode,
2972
+ host: renderHost,
2973
+ id: `mermaid-${diagramId}-${renderSequenceRef.current}`,
2974
+ palette: resolvePalette(container, isDarkMode)
2975
+ });
2976
+ if (!isActive) return;
2977
+ setSvgMarkup(svg);
2978
+ } catch (error) {
2979
+ if (!isActive) return;
2980
+ setSvgMarkup(null);
2981
+ setRenderError(error instanceof Error ? error.message : "render_failed");
2982
+ setActiveTab((currentTab) => currentTab === "diagram" ? "code" : currentTab);
2983
+ } finally {
2984
+ if (isActive) {
2985
+ setIsRendering(false);
2986
+ renderHost.innerHTML = "";
2987
+ }
2988
+ }
2989
+ }
2990
+ void runRender();
2991
+ return () => {
2992
+ isActive = false;
2993
+ if (renderHostRef.current) {
2994
+ renderHostRef.current.innerHTML = "";
2995
+ }
2996
+ };
2997
+ }, [diagramId, isDarkMode, normalizedCode, theme]);
2998
+ React14.useEffect(() => {
2999
+ clearCopyResetTimeout();
3000
+ setIsCopied(false);
3001
+ }, [activeTab, clearCopyResetTimeout, code]);
3002
+ React14.useEffect(
3003
+ () => () => {
3004
+ clearCopyResetTimeout();
3005
+ },
3006
+ [clearCopyResetTimeout]
3007
+ );
3008
+ const handleDownload = React14.useCallback(() => {
3009
+ if (!svgMarkup) return;
3010
+ const blob = new Blob([svgMarkup], {
3011
+ type: "image/svg+xml;charset=utf-8"
3012
+ });
3013
+ const url = window.URL.createObjectURL(blob);
3014
+ const anchor = document.createElement("a");
3015
+ anchor.href = url;
3016
+ anchor.download = `mermaid-diagram-${diagramId}.svg`;
3017
+ document.body.append(anchor);
3018
+ anchor.click();
3019
+ anchor.remove();
3020
+ window.URL.revokeObjectURL(url);
3021
+ }, [diagramId, svgMarkup]);
3022
+ const handleCopyCode = React14.useCallback(() => {
3023
+ if (!code || isCopied) return;
3024
+ navigator.clipboard.writeText(code).then(() => {
3025
+ setIsCopied(true);
3026
+ clearCopyResetTimeout();
3027
+ copyResetTimeoutRef.current = window.setTimeout(() => {
3028
+ setIsCopied(false);
3029
+ copyResetTimeoutRef.current = null;
3030
+ }, 3e3);
3031
+ }).catch(() => {
3032
+ });
3033
+ }, [clearCopyResetTimeout, code, isCopied]);
3034
+ const hasRenderedDiagram = svgMarkup !== null && !renderError;
3035
+ const statusMessage = isRendering ? t("markdown.mermaid.rendering") : t("markdown.mermaid.failed");
3036
+ return /* @__PURE__ */ jsxs9(Fragment2, { children: [
3037
+ /* @__PURE__ */ jsx18(
3038
+ Tabs,
3039
+ {
3040
+ className: "w-full",
3041
+ onValueChange: (value) => setActiveTab(value),
3042
+ value: activeTab,
3043
+ children: /* @__PURE__ */ jsxs9(
3044
+ "div",
3045
+ {
3046
+ ref: containerRef,
3047
+ "data-slot": "mermaid-block",
3048
+ className: "relative overflow-hidden text-card-foreground",
3049
+ children: [
3050
+ /* @__PURE__ */ jsx18(
3051
+ "div",
3052
+ {
3053
+ ref: renderHostRef,
3054
+ "aria-hidden": "true",
3055
+ className: "pointer-events-none absolute inset-0 -z-10 overflow-hidden opacity-0",
3056
+ "data-slot": "mermaid-render-host"
3057
+ }
3058
+ ),
3059
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap items-center justify-between gap-3 px-4 py-3", children: [
3060
+ /* @__PURE__ */ jsxs9("div", { className: "flex min-w-0 items-center gap-3", children: [
3061
+ /* @__PURE__ */ jsx18("span", { className: "inline-flex size-9 shrink-0 items-center justify-center rounded-full bg-muted text-foreground", children: /* @__PURE__ */ jsx18(Code2Icon, { className: "size-4" }) }),
3062
+ /* @__PURE__ */ jsx18("span", { className: "truncate text-base font-semibold text-foreground", children: t("markdown.mermaid.title") })
3063
+ ] }),
3064
+ /* @__PURE__ */ jsxs9("div", { className: "flex shrink-0 items-center gap-2", children: [
3065
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1", children: [
3066
+ activeTab === "diagram" && hasRenderedDiagram ? /* @__PURE__ */ jsx18(
3067
+ TooltipIconButton,
3068
+ {
3069
+ onClick: handleDownload,
3070
+ tooltip: t("markdown.mermaid.download"),
3071
+ children: /* @__PURE__ */ jsx18(DownloadIcon, { className: "size-4" })
3072
+ }
3073
+ ) : null,
3074
+ activeTab === "diagram" && hasRenderedDiagram ? /* @__PURE__ */ jsx18(
3075
+ TooltipIconButton,
3076
+ {
3077
+ onClick: () => setIsPreviewOpen(true),
3078
+ tooltip: t("markdown.mermaid.fullScreen"),
3079
+ children: /* @__PURE__ */ jsx18(ExpandIcon, { className: "size-4" })
3080
+ }
3081
+ ) : null,
3082
+ activeTab === "code" ? /* @__PURE__ */ jsx18(
3083
+ TooltipIconButton,
3084
+ {
3085
+ onClick: handleCopyCode,
3086
+ tooltip: t("markdown.copy"),
3087
+ children: isCopied ? /* @__PURE__ */ jsx18(CheckIcon, { className: "size-4" }) : /* @__PURE__ */ jsx18(CopyIcon, { className: "size-4" })
3088
+ }
3089
+ ) : null
3090
+ ] }),
3091
+ /* @__PURE__ */ jsxs9(TabsList, { children: [
3092
+ /* @__PURE__ */ jsx18(TabsTrigger, { value: "diagram", children: t("markdown.mermaid.diagram") }),
3093
+ /* @__PURE__ */ jsx18(TabsTrigger, { value: "code", children: t("markdown.mermaid.code") })
3094
+ ] })
3095
+ ] })
3096
+ ] }),
3097
+ /* @__PURE__ */ jsxs9("div", { className: "border-t border-border pt-4", children: [
3098
+ renderError ? /* @__PURE__ */ jsx18("p", { role: "alert", className: "mb-4 text-sm font-medium text-destructive", children: t("markdown.mermaid.failed") }) : null,
3099
+ /* @__PURE__ */ jsx18(TabsContent, { value: "diagram", className: "mt-0 space-y-4", children: /* @__PURE__ */ jsx18(
3100
+ "div",
3101
+ {
3102
+ className: cn(
3103
+ "relative overflow-auto rounded-[calc(var(--radius)+0.5rem)] border border-border bg-background p-4",
3104
+ hasRenderedDiagram ? "[&_svg]:mx-auto [&_svg]:h-auto [&_svg]:w-full [&_svg]:max-w-none" : "min-h-[14rem]"
3105
+ ),
3106
+ children: hasRenderedDiagram ? /* @__PURE__ */ jsx18(
3107
+ "div",
3108
+ {
3109
+ "data-slot": "mermaid-diagram",
3110
+ dangerouslySetInnerHTML: { __html: svgMarkup }
3111
+ }
3112
+ ) : /* @__PURE__ */ jsxs9("div", { className: "flex min-h-[12rem] flex-col items-center justify-center gap-3 text-center text-muted-foreground", children: [
3113
+ isRendering ? /* @__PURE__ */ jsx18(Loader2, { className: "size-5 animate-spin" }) : /* @__PURE__ */ jsx18(TriangleAlert, { className: "size-5 text-destructive" }),
3114
+ /* @__PURE__ */ jsx18(
3115
+ "p",
3116
+ {
3117
+ className: cn("text-sm font-medium", !isRendering && "text-destructive"),
3118
+ role: renderError ? "alert" : void 0,
3119
+ children: statusMessage
3120
+ }
3121
+ )
3122
+ ] })
3123
+ }
3124
+ ) }),
3125
+ /* @__PURE__ */ jsx18(TabsContent, { value: "code", className: "mt-0", children: /* @__PURE__ */ jsx18(
3126
+ "pre",
3127
+ {
3128
+ "data-slot": "mermaid-code",
3129
+ className: "overflow-x-auto rounded-[calc(var(--radius)+0.5rem)] border border-border bg-zinc-950 px-4 py-4 text-sm text-zinc-50",
3130
+ children: /* @__PURE__ */ jsx18("code", { className: "block whitespace-pre font-mono", children: code })
3131
+ }
3132
+ ) })
3133
+ ] })
3134
+ ]
3135
+ }
3136
+ )
3137
+ }
3138
+ ),
3139
+ svgMarkup ? /* @__PURE__ */ jsx18(
3140
+ MermaidPreviewDialog,
3141
+ {
3142
+ closeLabel: t("sheet.close"),
3143
+ onOpenChange: setIsPreviewOpen,
3144
+ open: isPreviewOpen,
3145
+ svgMarkup,
3146
+ title: t("markdown.mermaid.title")
3147
+ }
3148
+ ) : null
3149
+ ] });
3150
+ }
3151
+
1695
3152
  // src/components/thread/markdown-text.tsx
1696
3153
  import "katex/dist/katex.min.css";
1697
- import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs7 } from "react/jsx-runtime";
3154
+ import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
1698
3155
  var getTextContent = (children) => Children.toArray(children).map((child) => {
1699
3156
  if (typeof child === "string" || typeof child === "number") {
1700
3157
  return String(child);
1701
3158
  }
1702
3159
  return "";
1703
3160
  }).join("");
3161
+ var isMermaidBlockChild = (child) => isValidElement(child) && child.type === MermaidBlock;
3162
+ var isMermaidCodeElement = (child) => isValidElement(child) && typeof child.props.className === "string" && child.props.className.includes("language-mermaid");
1704
3163
  var useCopyToClipboard = ({
1705
3164
  copiedDuration = 3e3
1706
3165
  } = {}) => {
1707
- const [isCopied, setIsCopied] = useState5(false);
3166
+ const [isCopied, setIsCopied] = useState7(false);
1708
3167
  const copyToClipboard = (value) => {
1709
3168
  if (!value) return;
1710
3169
  navigator.clipboard.writeText(value).then(() => {
@@ -1721,23 +3180,23 @@ var CodeHeader = ({ language, code }) => {
1721
3180
  if (!code || isCopied) return;
1722
3181
  copyToClipboard(code);
1723
3182
  };
1724
- return /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between gap-4 rounded-t-lg bg-zinc-900 px-4 py-2 text-sm font-semibold text-white", children: [
1725
- /* @__PURE__ */ jsx17("span", { className: "lowercase [&>span]:text-xs", children: language }),
1726
- /* @__PURE__ */ jsxs7(
3183
+ return /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between gap-4 rounded-t-lg bg-zinc-900 px-4 py-2 text-sm font-semibold text-white", children: [
3184
+ /* @__PURE__ */ jsx19("span", { className: "lowercase [&>span]:text-xs", children: language }),
3185
+ /* @__PURE__ */ jsxs10(
1727
3186
  TooltipIconButton,
1728
3187
  {
1729
3188
  tooltip: t("markdown.copy"),
1730
3189
  onClick: onCopy,
1731
3190
  children: [
1732
- !isCopied && /* @__PURE__ */ jsx17(CopyIcon, {}),
1733
- isCopied && /* @__PURE__ */ jsx17(CheckIcon, {})
3191
+ !isCopied && /* @__PURE__ */ jsx19(CopyIcon2, {}),
3192
+ isCopied && /* @__PURE__ */ jsx19(CheckIcon2, {})
1734
3193
  ]
1735
3194
  }
1736
3195
  )
1737
3196
  ] });
1738
3197
  };
1739
3198
  var defaultComponents = {
1740
- h1: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3199
+ h1: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1741
3200
  "h1",
1742
3201
  {
1743
3202
  className: cn(
@@ -1747,7 +3206,7 @@ var defaultComponents = {
1747
3206
  ...props
1748
3207
  }
1749
3208
  ),
1750
- h2: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3209
+ h2: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1751
3210
  "h2",
1752
3211
  {
1753
3212
  className: cn(
@@ -1757,7 +3216,7 @@ var defaultComponents = {
1757
3216
  ...props
1758
3217
  }
1759
3218
  ),
1760
- h3: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3219
+ h3: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1761
3220
  "h3",
1762
3221
  {
1763
3222
  className: cn(
@@ -1767,7 +3226,7 @@ var defaultComponents = {
1767
3226
  ...props
1768
3227
  }
1769
3228
  ),
1770
- h4: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3229
+ h4: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1771
3230
  "h4",
1772
3231
  {
1773
3232
  className: cn(
@@ -1777,7 +3236,7 @@ var defaultComponents = {
1777
3236
  ...props
1778
3237
  }
1779
3238
  ),
1780
- h5: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3239
+ h5: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1781
3240
  "h5",
1782
3241
  {
1783
3242
  className: cn(
@@ -1787,21 +3246,21 @@ var defaultComponents = {
1787
3246
  ...props
1788
3247
  }
1789
3248
  ),
1790
- h6: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3249
+ h6: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1791
3250
  "h6",
1792
3251
  {
1793
3252
  className: cn("my-4 font-semibold first:mt-0 last:mb-0", className),
1794
3253
  ...props
1795
3254
  }
1796
3255
  ),
1797
- p: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3256
+ p: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1798
3257
  "p",
1799
3258
  {
1800
3259
  className: cn("mt-5 mb-5 leading-7 first:mt-0 last:mb-0", className),
1801
3260
  ...props
1802
3261
  }
1803
3262
  ),
1804
- a: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3263
+ a: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1805
3264
  "a",
1806
3265
  {
1807
3266
  className: cn(
@@ -1817,7 +3276,7 @@ var defaultComponents = {
1817
3276
  className,
1818
3277
  node: _node,
1819
3278
  ...props
1820
- }) => /* @__PURE__ */ jsx17(
3279
+ }) => /* @__PURE__ */ jsx19(
1821
3280
  "blockquote",
1822
3281
  {
1823
3282
  className: cn(
@@ -1827,21 +3286,21 @@ var defaultComponents = {
1827
3286
  ...props
1828
3287
  }
1829
3288
  ),
1830
- ul: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3289
+ ul: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1831
3290
  "ul",
1832
3291
  {
1833
3292
  className: cn("my-5 list-outside list-disc pl-6 [&>li]:mt-2", className),
1834
3293
  ...props
1835
3294
  }
1836
3295
  ),
1837
- ol: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3296
+ ol: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1838
3297
  "ol",
1839
3298
  {
1840
3299
  className: cn("my-5 list-outside list-decimal pl-8 [&>li]:mt-2", className),
1841
3300
  ...props
1842
3301
  }
1843
3302
  ),
1844
- hr: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3303
+ hr: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1845
3304
  "hr",
1846
3305
  {
1847
3306
  className: cn("my-5 border-b", className),
@@ -1852,7 +3311,7 @@ var defaultComponents = {
1852
3311
  className,
1853
3312
  node: _node,
1854
3313
  ...props
1855
- }) => /* @__PURE__ */ jsx17(
3314
+ }) => /* @__PURE__ */ jsx19(
1856
3315
  "table",
1857
3316
  {
1858
3317
  className: cn(
@@ -1862,7 +3321,7 @@ var defaultComponents = {
1862
3321
  ...props
1863
3322
  }
1864
3323
  ),
1865
- th: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3324
+ th: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1866
3325
  "th",
1867
3326
  {
1868
3327
  className: cn(
@@ -1872,7 +3331,7 @@ var defaultComponents = {
1872
3331
  ...props
1873
3332
  }
1874
3333
  ),
1875
- td: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3334
+ td: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1876
3335
  "td",
1877
3336
  {
1878
3337
  className: cn(
@@ -1882,7 +3341,7 @@ var defaultComponents = {
1882
3341
  ...props
1883
3342
  }
1884
3343
  ),
1885
- tr: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3344
+ tr: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1886
3345
  "tr",
1887
3346
  {
1888
3347
  className: cn(
@@ -1892,21 +3351,21 @@ var defaultComponents = {
1892
3351
  ...props
1893
3352
  }
1894
3353
  ),
1895
- sup: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3354
+ sup: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx19(
1896
3355
  "sup",
1897
3356
  {
1898
3357
  className: cn("[&>a]:text-xs [&>a]:no-underline", className),
1899
3358
  ...props
1900
3359
  }
1901
3360
  ),
1902
- pre: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
3361
+ pre: ({ className, children, node: _node }) => Children.toArray(children).length === 1 && (isMermaidBlockChild(Children.toArray(children)[0]) || isMermaidCodeElement(Children.toArray(children)[0])) ? /* @__PURE__ */ jsx19(Fragment3, { children }) : /* @__PURE__ */ jsx19(
1903
3362
  "div",
1904
3363
  {
1905
3364
  className: cn(
1906
3365
  "max-w-4xl overflow-x-auto rounded-lg text-sm bg-black text-white dark:bg-zinc-800",
1907
3366
  className
1908
3367
  ),
1909
- ...props
3368
+ children
1910
3369
  }
1911
3370
  ),
1912
3371
  code: ({
@@ -1915,21 +3374,24 @@ var defaultComponents = {
1915
3374
  node: _node,
1916
3375
  ...props
1917
3376
  }) => {
1918
- const match = /language-(\w+)/.exec(className || "");
3377
+ const match = /language-([\w-]+)/.exec(className || "");
1919
3378
  const code = getTextContent(children);
1920
3379
  const isBlockCode = code.includes("\n");
1921
3380
  if (match) {
1922
3381
  const language = match[1];
1923
3382
  const normalizedCode = code.replace(/\n$/, "");
1924
- return /* @__PURE__ */ jsxs7(Fragment2, { children: [
1925
- /* @__PURE__ */ jsx17(
3383
+ if (language === "mermaid") {
3384
+ return /* @__PURE__ */ jsx19(MermaidBlock, { code: normalizedCode });
3385
+ }
3386
+ return /* @__PURE__ */ jsxs10(Fragment3, { children: [
3387
+ /* @__PURE__ */ jsx19(
1926
3388
  CodeHeader,
1927
3389
  {
1928
3390
  language,
1929
3391
  code: normalizedCode
1930
3392
  }
1931
3393
  ),
1932
- /* @__PURE__ */ jsx17(
3394
+ /* @__PURE__ */ jsx19(
1933
3395
  SyntaxHighlighter,
1934
3396
  {
1935
3397
  language,
@@ -1940,7 +3402,7 @@ var defaultComponents = {
1940
3402
  ] });
1941
3403
  }
1942
3404
  if (isBlockCode) {
1943
- return /* @__PURE__ */ jsx17(
3405
+ return /* @__PURE__ */ jsx19(
1944
3406
  "code",
1945
3407
  {
1946
3408
  className: cn(
@@ -1952,7 +3414,7 @@ var defaultComponents = {
1952
3414
  }
1953
3415
  );
1954
3416
  }
1955
- return /* @__PURE__ */ jsx17(
3417
+ return /* @__PURE__ */ jsx19(
1956
3418
  "code",
1957
3419
  {
1958
3420
  className: cn(
@@ -1966,7 +3428,7 @@ var defaultComponents = {
1966
3428
  }
1967
3429
  };
1968
3430
  var MarkdownTextImpl = ({ children }) => {
1969
- return /* @__PURE__ */ jsx17("div", { className: "markdown-content", children: /* @__PURE__ */ jsx17(
3431
+ return /* @__PURE__ */ jsx19("div", { className: "markdown-content", children: /* @__PURE__ */ jsx19(
1970
3432
  ReactMarkdown,
1971
3433
  {
1972
3434
  remarkPlugins: [remarkGfm, remarkMath],
@@ -1980,18 +3442,18 @@ var MarkdownText = memo(MarkdownTextImpl);
1980
3442
 
1981
3443
  // src/components/thread/messages/widget.tsx
1982
3444
  import { SurfaceRenderer } from "@xpert-ai/a2ui-react";
1983
- import { jsx as jsx18 } from "react/jsx-runtime";
3445
+ import { jsx as jsx20 } from "react/jsx-runtime";
1984
3446
  function WidgetMessage({ messageId, data }) {
1985
3447
  const widgets = Array.isArray(data.widgets) ? data.widgets : [];
1986
3448
  if (widgets.length === 0) return null;
1987
3449
  const baseSurfaceId = `widget-${messageId}`;
1988
- return /* @__PURE__ */ jsx18("div", { className: "space-y-3", children: widgets.map((widget, index) => {
3450
+ return /* @__PURE__ */ jsx20("div", { className: "space-y-3", children: widgets.map((widget, index) => {
1989
3451
  const config = widget?.config;
1990
3452
  if (!config || typeof config !== "object") {
1991
3453
  return null;
1992
3454
  }
1993
3455
  const surfaceId = widgets.length > 1 ? `${baseSurfaceId}-${index}` : baseSurfaceId;
1994
- return /* @__PURE__ */ jsx18(
3456
+ return /* @__PURE__ */ jsx20(
1995
3457
  SurfaceRenderer,
1996
3458
  {
1997
3459
  surfaceId,
@@ -2003,7 +3465,7 @@ function WidgetMessage({ messageId, data }) {
2003
3465
  }
2004
3466
 
2005
3467
  // src/components/thread/messages/ai.tsx
2006
- import { jsx as jsx19, jsxs as jsxs8 } from "react/jsx-runtime";
3468
+ import { jsx as jsx21, jsxs as jsxs11 } from "react/jsx-runtime";
2007
3469
  function isTextContent(content) {
2008
3470
  return content.type === "text";
2009
3471
  }
@@ -2027,7 +3489,7 @@ var statusConfig = {
2027
3489
  },
2028
3490
  running: {
2029
3491
  iconClass: "border-blue-500 text-blue-700",
2030
- icon: Loader2
3492
+ icon: Loader22
2031
3493
  }
2032
3494
  };
2033
3495
  function isWidgetComponent(content) {
@@ -2044,14 +3506,17 @@ function safeJson(value) {
2044
3506
  return String(value);
2045
3507
  }
2046
3508
  }
3509
+ function formatDisplayValue(value) {
3510
+ return typeof value === "string" ? value : safeJson(value);
3511
+ }
2047
3512
  function ReasoningBlock({ reasoning }) {
2048
3513
  const blocks = reasoning.filter((item) => item.text?.trim());
2049
3514
  if (blocks.length === 0) return null;
2050
- return /* @__PURE__ */ jsx19("div", { className: "space-y-2", children: blocks.map((item, index) => /* @__PURE__ */ jsx19(
3515
+ return /* @__PURE__ */ jsx21("div", { className: "space-y-2", children: blocks.map((item, index) => /* @__PURE__ */ jsx21(
2051
3516
  "div",
2052
3517
  {
2053
3518
  className: "rounded-lg border bg-muted/40 p-3 text-xs text-muted-foreground",
2054
- children: /* @__PURE__ */ jsx19("p", { className: "whitespace-pre-wrap wrap-break-word leading-relaxed", children: item.text })
3519
+ children: /* @__PURE__ */ jsx21("p", { className: "whitespace-pre-wrap wrap-break-word leading-relaxed", children: item.text })
2055
3520
  },
2056
3521
  item.id ?? `reasoning-${index}`
2057
3522
  )) });
@@ -2059,27 +3524,27 @@ function ReasoningBlock({ reasoning }) {
2059
3524
  function ImageBlock({ content }) {
2060
3525
  const imageUrl = typeof content.image_url === "string" ? content.image_url : typeof content.image_url?.url === "string" ? content.image_url.url : null;
2061
3526
  if (!imageUrl) {
2062
- return /* @__PURE__ */ jsxs8(Card, { children: [
2063
- /* @__PURE__ */ jsx19(CardHeader, { className: "space-y-1", children: /* @__PURE__ */ jsx19(CardTitle, { className: "text-sm", children: "Image" }) }),
2064
- /* @__PURE__ */ jsx19(CardContent, { className: "text-xs text-muted-foreground", children: safeJson(content) })
3527
+ return /* @__PURE__ */ jsxs11(Card, { children: [
3528
+ /* @__PURE__ */ jsx21(CardHeader, { className: "space-y-1", children: /* @__PURE__ */ jsx21(CardTitle, { className: "text-sm", children: "Image" }) }),
3529
+ /* @__PURE__ */ jsx21(CardContent, { className: "text-xs text-muted-foreground", children: safeJson(content) })
2065
3530
  ] });
2066
3531
  }
2067
- return /* @__PURE__ */ jsx19("figure", { className: "overflow-hidden rounded-lg border bg-background", children: /* @__PURE__ */ jsx19("img", { src: imageUrl, alt: "Assistant output", className: "h-auto w-full object-cover" }) });
3532
+ return /* @__PURE__ */ jsx21("figure", { className: "overflow-hidden rounded-lg border bg-background", children: /* @__PURE__ */ jsx21("img", { src: imageUrl, alt: "Assistant output", className: "h-auto w-full object-cover" }) });
2068
3533
  }
2069
3534
  function MemoryBlock({ content }) {
2070
- return /* @__PURE__ */ jsxs8(Card, { children: [
2071
- /* @__PURE__ */ jsxs8(CardHeader, { className: "flex flex-row items-center justify-between gap-2", children: [
2072
- /* @__PURE__ */ jsx19(CardTitle, { className: "text-sm", children: "Memory" }),
2073
- /* @__PURE__ */ jsx19(Badge, { variant: "secondary", children: "Memory" })
3535
+ return /* @__PURE__ */ jsxs11(Card, { children: [
3536
+ /* @__PURE__ */ jsxs11(CardHeader, { className: "flex flex-row items-center justify-between gap-2", children: [
3537
+ /* @__PURE__ */ jsx21(CardTitle, { className: "text-sm", children: "Memory" }),
3538
+ /* @__PURE__ */ jsx21(Badge, { variant: "secondary", children: "Memory" })
2074
3539
  ] }),
2075
- /* @__PURE__ */ jsx19(CardContent, { className: "text-xs text-muted-foreground", children: /* @__PURE__ */ jsx19("pre", { className: "whitespace-pre-wrap wrap-break-word", children: safeJson(content.data ?? []) }) })
3540
+ /* @__PURE__ */ jsx21(CardContent, { className: "text-xs text-muted-foreground", children: /* @__PURE__ */ jsx21("pre", { className: "whitespace-pre-wrap wrap-break-word", children: safeJson(content.data ?? []) }) })
2076
3541
  ] });
2077
3542
  }
2078
3543
  function ComponentBlock({ content }) {
2079
- const [isExpanded, setIsExpanded] = React13.useState(false);
2080
- const contentRef = React13.useRef(null);
2081
- const shouldAutoScrollRef = React13.useRef(true);
2082
- const previousScrollTopRef = React13.useRef(0);
3544
+ const [isExpanded, setIsExpanded] = React15.useState(false);
3545
+ const contentRef = React15.useRef(null);
3546
+ const shouldAutoScrollRef = React15.useRef(true);
3547
+ const previousScrollTopRef = React15.useRef(0);
2083
3548
  const data = content.data ?? {};
2084
3549
  const category = data.category ?? "Component";
2085
3550
  const title = data.tool && category === "Tool" ? data.tool : data.title ?? data.type ?? "Component";
@@ -2087,12 +3552,12 @@ function ComponentBlock({ content }) {
2087
3552
  const message = data.message ?? null;
2088
3553
  const output = data.output ?? null;
2089
3554
  const error = data.error ?? null;
2090
- const fallback = message ?? output ?? safeJson(data.data ?? data);
3555
+ const fallback = message ?? output ?? data.data ?? data;
2091
3556
  const hasOutput = message !== null || output !== null;
2092
- React13.useEffect(() => {
3557
+ React15.useEffect(() => {
2093
3558
  if (status === "running" && output !== null) setIsExpanded(true);
2094
3559
  }, [status, output]);
2095
- React13.useEffect(() => {
3560
+ React15.useEffect(() => {
2096
3561
  const element = contentRef.current;
2097
3562
  if (!element) return;
2098
3563
  previousScrollTopRef.current = element.scrollTop;
@@ -2112,7 +3577,7 @@ function ComponentBlock({ content }) {
2112
3577
  element.removeEventListener("scroll", updateAutoScrollState);
2113
3578
  };
2114
3579
  }, [isExpanded]);
2115
- React13.useEffect(() => {
3580
+ React15.useEffect(() => {
2116
3581
  if (status !== "running") {
2117
3582
  shouldAutoScrollRef.current = true;
2118
3583
  return;
@@ -2125,20 +3590,20 @@ function ComponentBlock({ content }) {
2125
3590
  }, [isExpanded, output, status]);
2126
3591
  const config = status ? statusConfig[status] : null;
2127
3592
  const StatusIcon = config?.icon;
2128
- return /* @__PURE__ */ jsxs8(Card, { children: [
2129
- /* @__PURE__ */ jsxs8(CardHeader, { className: "flex flex-row items-center justify-between gap-2 px-2 py-1 cursor-pointer", onClick: () => setIsExpanded(!isExpanded), children: [
2130
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-1 flex-1 min-w-0", children: [
2131
- status && StatusIcon && /* @__PURE__ */ jsx19(StatusIcon, { className: cn("h-4 w-4", config?.iconClass, status === "running" && "animate-spin") }),
2132
- /* @__PURE__ */ jsx19(CardTitle, { className: "text-sm truncate", children: title })
3593
+ return /* @__PURE__ */ jsxs11(Card, { children: [
3594
+ /* @__PURE__ */ jsxs11(CardHeader, { className: "flex flex-row items-center justify-between gap-2 px-2 py-1 cursor-pointer", onClick: () => setIsExpanded(!isExpanded), children: [
3595
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center space-x-1 flex-1 min-w-0", children: [
3596
+ status && StatusIcon && /* @__PURE__ */ jsx21(StatusIcon, { className: cn("h-4 w-4", config?.iconClass, status === "running" && "animate-spin") }),
3597
+ /* @__PURE__ */ jsx21(CardTitle, { className: "text-sm truncate", children: title })
2133
3598
  ] }),
2134
- /* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap items-center gap-2 shrink-0", children: [
2135
- /* @__PURE__ */ jsx19(Badge, { variant: "secondary", className: "rounded-lg px-1.5", children: category }),
2136
- /* @__PURE__ */ jsx19(
3599
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap items-center gap-2 shrink-0", children: [
3600
+ /* @__PURE__ */ jsx21(Badge, { variant: "secondary", className: "rounded-lg px-1.5", children: category }),
3601
+ /* @__PURE__ */ jsx21(
2137
3602
  "button",
2138
3603
  {
2139
3604
  className: "text-muted-foreground hover:text-foreground transition-colors",
2140
3605
  "aria-label": isExpanded ? "Collapse" : "Expand",
2141
- children: /* @__PURE__ */ jsx19(
3606
+ children: /* @__PURE__ */ jsx21(
2142
3607
  ChevronDown,
2143
3608
  {
2144
3609
  className: cn("h-4 w-4 transition-transform", isExpanded && "rotate-180")
@@ -2148,89 +3613,128 @@ function ComponentBlock({ content }) {
2148
3613
  )
2149
3614
  ] })
2150
3615
  ] }),
2151
- isExpanded && /* @__PURE__ */ jsxs8(CardContent, { ref: contentRef, className: "text-xs text-muted-foreground max-h-60 overflow-auto", children: [
2152
- data.input && /* @__PURE__ */ jsx19("pre", { className: "whitespace-pre-wrap wrap-break-word", children: JSON.stringify(data.input, null, 2) }),
2153
- error ? /* @__PURE__ */ jsx19("pre", { className: "whitespace-pre-wrap wrap-break-word text-destructive", children: typeof error === "string" ? error : safeJson(error) }) : hasOutput && /* @__PURE__ */ jsx19("pre", { className: "whitespace-pre-wrap wrap-break-word", children: fallback })
3616
+ isExpanded && /* @__PURE__ */ jsxs11(CardContent, { ref: contentRef, className: "text-xs text-muted-foreground max-h-60 overflow-auto", children: [
3617
+ data.input && /* @__PURE__ */ jsx21("pre", { className: "whitespace-pre-wrap wrap-break-word", children: formatDisplayValue(data.input) }),
3618
+ error ? /* @__PURE__ */ jsx21("pre", { className: "whitespace-pre-wrap wrap-break-word text-destructive", children: formatDisplayValue(error) }) : hasOutput && /* @__PURE__ */ jsx21("pre", { className: "whitespace-pre-wrap wrap-break-word", children: formatDisplayValue(fallback) })
2154
3619
  ] })
2155
3620
  ] });
2156
3621
  }
2157
3622
  function UnknownBlock({ content }) {
2158
- return /* @__PURE__ */ jsxs8(Card, { children: [
2159
- /* @__PURE__ */ jsxs8(CardHeader, { className: "flex flex-row items-center justify-between gap-2", children: [
2160
- /* @__PURE__ */ jsx19(CardTitle, { className: "text-sm", children: "Assistant Content" }),
2161
- /* @__PURE__ */ jsx19(Badge, { variant: "outline", children: content.type ?? "unknown" })
3623
+ return /* @__PURE__ */ jsxs11(Card, { children: [
3624
+ /* @__PURE__ */ jsxs11(CardHeader, { className: "flex flex-row items-center justify-between gap-2", children: [
3625
+ /* @__PURE__ */ jsx21(CardTitle, { className: "text-sm", children: "Assistant Content" }),
3626
+ /* @__PURE__ */ jsx21(Badge, { variant: "outline", children: content.type ?? "unknown" })
2162
3627
  ] }),
2163
- /* @__PURE__ */ jsx19(CardContent, { className: "text-xs text-muted-foreground", children: /* @__PURE__ */ jsx19("pre", { className: "whitespace-pre-wrap break-words", children: safeJson(content) }) })
3628
+ /* @__PURE__ */ jsx21(CardContent, { className: "text-xs text-muted-foreground", children: /* @__PURE__ */ jsx21("pre", { className: "whitespace-pre-wrap break-words", children: safeJson(content) }) })
2164
3629
  ] });
2165
3630
  }
2166
3631
  function renderContentItem(content, index, messageId) {
2167
3632
  if (typeof content === "string") {
2168
- return /* @__PURE__ */ jsxs8("div", { children: [
2169
- /* @__PURE__ */ jsx19(MarkdownText, { children: content }),
3633
+ return /* @__PURE__ */ jsxs11("div", { children: [
3634
+ /* @__PURE__ */ jsx21(MarkdownText, { children: content }),
2170
3635
  ";"
2171
3636
  ] }, `text-${index}`);
2172
3637
  }
2173
3638
  if (isTextContent(content)) {
2174
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(MarkdownText, { children: content.text }) }, content.id ?? `text-${index}`);
3639
+ return /* @__PURE__ */ jsx21("div", { children: /* @__PURE__ */ jsx21(MarkdownText, { children: content.text }) }, content.id ?? `text-${index}`);
2175
3640
  }
2176
3641
  if (isReasoningContent(content)) {
2177
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(ReasoningBlock, { reasoning: [content] }) }, content.id ?? `reasoning-${index}`);
3642
+ return /* @__PURE__ */ jsx21("div", { children: /* @__PURE__ */ jsx21(ReasoningBlock, { reasoning: [content] }) }, content.id ?? `reasoning-${index}`);
2178
3643
  }
2179
3644
  if (isImageContent(content)) {
2180
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(ImageBlock, { content }) }, content.id ?? `image-${index}`);
3645
+ return /* @__PURE__ */ jsx21("div", { children: /* @__PURE__ */ jsx21(ImageBlock, { content }) }, content.id ?? `image-${index}`);
2181
3646
  }
2182
3647
  if (isComponentContent(content)) {
2183
3648
  if (isWidgetComponent(content)) {
2184
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(WidgetMessage, { messageId, data: content.data }) }, content.id ?? `widget-${index}`);
3649
+ return /* @__PURE__ */ jsx21("div", { children: /* @__PURE__ */ jsx21(WidgetMessage, { messageId, data: content.data }) }, content.id ?? `widget-${index}`);
2185
3650
  }
2186
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(ComponentBlock, { content }) }, content.id ?? `component-${index}`);
3651
+ return /* @__PURE__ */ jsx21("div", { children: /* @__PURE__ */ jsx21(ComponentBlock, { content }) }, content.id ?? `component-${index}`);
2187
3652
  }
2188
3653
  if (isMemoryContent(content)) {
2189
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(MemoryBlock, { content }) }, content.id ?? `memory-${index}`);
3654
+ return /* @__PURE__ */ jsx21("div", { children: /* @__PURE__ */ jsx21(MemoryBlock, { content }) }, content.id ?? `memory-${index}`);
2190
3655
  }
2191
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(UnknownBlock, { content }) }, content.id ?? `unknown-${index}`);
3656
+ return /* @__PURE__ */ jsx21("div", { children: /* @__PURE__ */ jsx21(UnknownBlock, { content }) }, content.id ?? `unknown-${index}`);
2192
3657
  }
2193
3658
  function renderContent(content, messageId) {
2194
3659
  if (typeof content === "string") {
2195
3660
  if (!content.trim()) return null;
2196
- return /* @__PURE__ */ jsx19(MarkdownText, { children: content });
3661
+ return /* @__PURE__ */ jsx21(MarkdownText, { children: content });
2197
3662
  }
2198
3663
  if (!Array.isArray(content) || content.length === 0) return null;
2199
- return /* @__PURE__ */ jsx19("div", { className: "space-y-3", children: content.map((item, index) => renderContentItem(item, index, messageId)) });
3664
+ return /* @__PURE__ */ jsx21("div", { className: "space-y-3", children: content.map((item, index) => renderContentItem(item, index, messageId)) });
2200
3665
  }
2201
- function AssistantMessage({ message, className, isStreaming = false }) {
3666
+ function AssistantStreamingIndicator({
3667
+ status,
3668
+ className
3669
+ }) {
2202
3670
  const { t } = useChatkitTranslation();
2203
- const content = message.content;
2204
- const hasContent = content != null && !(typeof content === "string" && content.trim() === "" || Array.isArray(message.content) && message.content.length === 0);
2205
- const hasReasoning = Array.isArray(message.reasoning) && message.reasoning.some((item) => item.text?.trim());
3671
+ const labelMap = {
3672
+ loading: t("message.loading"),
3673
+ thinking: t("message.thinking"),
3674
+ answering: t("message.answering")
3675
+ };
3676
+ return /* @__PURE__ */ jsxs11("div", { className: cn("flex items-center gap-2 text-xs text-muted-foreground", className), children: [
3677
+ status === "loading" && /* @__PURE__ */ jsx21(Loader22, { className: "h-3.5 w-3.5 animate-spin" }),
3678
+ status === "thinking" && /* @__PURE__ */ jsxs11("div", { className: "flex items-end gap-1", "aria-hidden": "true", children: [
3679
+ /* @__PURE__ */ jsx21("span", { className: "h-1.5 w-1.5 rounded-full bg-current animate-bounce [animation-delay:-0.3s]" }),
3680
+ /* @__PURE__ */ jsx21("span", { className: "h-1.5 w-1.5 rounded-full bg-current animate-bounce [animation-delay:-0.15s]" }),
3681
+ /* @__PURE__ */ jsx21("span", { className: "h-1.5 w-1.5 rounded-full bg-current animate-bounce" })
3682
+ ] }),
3683
+ status === "answering" && /* @__PURE__ */ jsxs11("div", { className: "flex items-end gap-1", "aria-hidden": "true", children: [
3684
+ /* @__PURE__ */ jsx21("span", { className: "h-2 w-0.5 rounded-full bg-current animate-pulse [animation-delay:-0.25s]" }),
3685
+ /* @__PURE__ */ jsx21("span", { className: "h-3 w-0.5 rounded-full bg-current animate-pulse [animation-delay:-0.1s]" }),
3686
+ /* @__PURE__ */ jsx21("span", { className: "h-2.5 w-0.5 rounded-full bg-current animate-pulse" })
3687
+ ] }),
3688
+ /* @__PURE__ */ jsx21("span", { children: labelMap[status] })
3689
+ ] });
3690
+ }
3691
+ function AssistantMessage({
3692
+ message,
3693
+ className,
3694
+ isStreaming = false,
3695
+ streamingStatus
3696
+ }) {
3697
+ const { t } = useChatkitTranslation();
3698
+ const hasContent = hasRenderableMessageContent(message.content);
3699
+ const hasReasoning = hasRenderableReasoning(message.reasoning);
3700
+ const resolvedStreamingStatus = streamingStatus ?? getAssistantStreamingStatus(message, isStreaming);
2206
3701
  const answerNode = renderContent(message.content, message.id);
2207
- const reasoningNode = hasReasoning ? /* @__PURE__ */ jsx19(ReasoningBlock, { reasoning: message.reasoning ?? [] }) : null;
2208
- if (!hasContent && !hasReasoning) return null;
3702
+ const reasoningNode = hasReasoning ? /* @__PURE__ */ jsx21(ReasoningBlock, { reasoning: message.reasoning ?? [] }) : null;
3703
+ if (!hasRenderableAssistantMessage(message) && !resolvedStreamingStatus) return null;
2209
3704
  const streamingClass = isStreaming ? "streaming-active" : "";
3705
+ if (!hasRenderableAssistantMessage(message) && resolvedStreamingStatus) {
3706
+ return /* @__PURE__ */ jsx21("div", { className: cn("space-y-3", streamingClass, className), children: /* @__PURE__ */ jsx21(AssistantStreamingIndicator, { status: resolvedStreamingStatus }) });
3707
+ }
2210
3708
  if (hasContent && hasReasoning) {
2211
- return /* @__PURE__ */ jsx19("div", { className: cn("space-y-3", streamingClass, className), children: /* @__PURE__ */ jsxs8(
2212
- Tabs,
2213
- {
2214
- defaultValue: message.status === "reasoning" ? "reasoning" : "answer",
2215
- className: "w-full",
2216
- children: [
2217
- /* @__PURE__ */ jsxs8(TabsList, { className: "h-9", children: [
2218
- /* @__PURE__ */ jsx19(TabsTrigger, { value: "answer", children: t("message.answer") }),
2219
- /* @__PURE__ */ jsx19(TabsTrigger, { value: "reasoning", children: t("message.reasoning") })
2220
- ] }),
2221
- /* @__PURE__ */ jsx19(TabsContent, { value: "answer", className: "space-y-3", children: answerNode }),
2222
- /* @__PURE__ */ jsx19(TabsContent, { value: "reasoning", className: "space-y-3", children: reasoningNode })
2223
- ]
2224
- }
2225
- ) });
3709
+ return /* @__PURE__ */ jsxs11("div", { className: cn("space-y-3", streamingClass, className), children: [
3710
+ /* @__PURE__ */ jsxs11(
3711
+ Tabs,
3712
+ {
3713
+ defaultValue: message.status === "reasoning" ? "reasoning" : "answer",
3714
+ className: "w-full",
3715
+ children: [
3716
+ /* @__PURE__ */ jsxs11(TabsList, { className: "", children: [
3717
+ /* @__PURE__ */ jsx21(TabsTrigger, { value: "answer", children: t("message.answer") }),
3718
+ /* @__PURE__ */ jsx21(TabsTrigger, { value: "reasoning", children: t("message.reasoning") })
3719
+ ] }),
3720
+ /* @__PURE__ */ jsx21(TabsContent, { value: "answer", className: "space-y-3", children: answerNode }),
3721
+ /* @__PURE__ */ jsx21(TabsContent, { value: "reasoning", className: "space-y-3", children: reasoningNode })
3722
+ ]
3723
+ }
3724
+ ),
3725
+ resolvedStreamingStatus ? /* @__PURE__ */ jsx21(AssistantStreamingIndicator, { status: resolvedStreamingStatus }) : null
3726
+ ] });
2226
3727
  }
2227
- return /* @__PURE__ */ jsx19("div", { className: cn("space-y-3", streamingClass, className), children: hasReasoning ? reasoningNode : answerNode });
3728
+ return /* @__PURE__ */ jsxs11("div", { className: cn("space-y-3", streamingClass, className), children: [
3729
+ hasReasoning ? reasoningNode : answerNode,
3730
+ resolvedStreamingStatus ? /* @__PURE__ */ jsx21(AssistantStreamingIndicator, { status: resolvedStreamingStatus }) : null
3731
+ ] });
2228
3732
  }
2229
3733
 
2230
3734
  // src/components/thread/MessageActions.tsx
2231
- import * as React14 from "react";
3735
+ import * as React16 from "react";
2232
3736
  import { Check, Copy, RefreshCw } from "lucide-react";
2233
- import { jsx as jsx20, jsxs as jsxs9 } from "react/jsx-runtime";
3737
+ import { jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
2234
3738
  function MessageActions({
2235
3739
  content,
2236
3740
  isAssistant = false,
@@ -2239,7 +3743,7 @@ function MessageActions({
2239
3743
  className
2240
3744
  }) {
2241
3745
  const { t } = useChatkitTranslation();
2242
- const [copied, setCopied] = React14.useState(false);
3746
+ const [copied, setCopied] = React16.useState(false);
2243
3747
  const handleCopy = async () => {
2244
3748
  try {
2245
3749
  await navigator.clipboard.writeText(content);
@@ -2252,7 +3756,7 @@ function MessageActions({
2252
3756
  if (isStreaming) {
2253
3757
  return null;
2254
3758
  }
2255
- return /* @__PURE__ */ jsxs9(
3759
+ return /* @__PURE__ */ jsxs12(
2256
3760
  "div",
2257
3761
  {
2258
3762
  className: cn(
@@ -2260,7 +3764,7 @@ function MessageActions({
2260
3764
  className
2261
3765
  ),
2262
3766
  children: [
2263
- /* @__PURE__ */ jsx20(
3767
+ /* @__PURE__ */ jsx22(
2264
3768
  "button",
2265
3769
  {
2266
3770
  type: "button",
@@ -2270,17 +3774,17 @@ function MessageActions({
2270
3774
  copied && "text-green-500"
2271
3775
  ),
2272
3776
  title: copied ? t("messageActions.copied") : t("messageActions.copy"),
2273
- children: copied ? /* @__PURE__ */ jsx20(Check, { size: 14 }) : /* @__PURE__ */ jsx20(Copy, { size: 14 })
3777
+ children: copied ? /* @__PURE__ */ jsx22(Check, { size: 14 }) : /* @__PURE__ */ jsx22(Copy, { size: 14 })
2274
3778
  }
2275
3779
  ),
2276
- isAssistant && onRetry && /* @__PURE__ */ jsx20(
3780
+ isAssistant && onRetry && /* @__PURE__ */ jsx22(
2277
3781
  "button",
2278
3782
  {
2279
3783
  type: "button",
2280
3784
  onClick: onRetry,
2281
3785
  className: "p-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
2282
3786
  title: t("messageActions.regenerate"),
2283
- children: /* @__PURE__ */ jsx20(RefreshCw, { size: 14 })
3787
+ children: /* @__PURE__ */ jsx22(RefreshCw, { size: 14 })
2284
3788
  }
2285
3789
  )
2286
3790
  ]
@@ -2301,18 +3805,18 @@ import {
2301
3805
  Sparkles as Sparkles2,
2302
3806
  Zap
2303
3807
  } from "lucide-react";
2304
- import { jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
3808
+ import { jsx as jsx23, jsxs as jsxs13 } from "react/jsx-runtime";
2305
3809
  function getIconComponent2(icon) {
2306
3810
  const iconMap = {
2307
- "circle-question": /* @__PURE__ */ jsx21(HelpCircle, { size: 20 }),
2308
- "lightbulb": /* @__PURE__ */ jsx21(Lightbulb2, { size: 20 }),
2309
- "sparkle": /* @__PURE__ */ jsx21(Sparkles2, { size: 20 }),
2310
- "write": /* @__PURE__ */ jsx21(Pencil2, { size: 20 }),
2311
- "search": /* @__PURE__ */ jsx21(Search2, { size: 20 }),
2312
- "globe": /* @__PURE__ */ jsx21(Globe2, { size: 20 }),
2313
- "book-open": /* @__PURE__ */ jsx21(BookOpen, { size: 20 }),
2314
- "compass": /* @__PURE__ */ jsx21(Compass, { size: 20 }),
2315
- "bolt": /* @__PURE__ */ jsx21(Zap, { size: 20 })
3811
+ "circle-question": /* @__PURE__ */ jsx23(HelpCircle, { size: 20 }),
3812
+ "lightbulb": /* @__PURE__ */ jsx23(Lightbulb2, { size: 20 }),
3813
+ "sparkle": /* @__PURE__ */ jsx23(Sparkles2, { size: 20 }),
3814
+ "write": /* @__PURE__ */ jsx23(Pencil2, { size: 20 }),
3815
+ "search": /* @__PURE__ */ jsx23(Search2, { size: 20 }),
3816
+ "globe": /* @__PURE__ */ jsx23(Globe2, { size: 20 }),
3817
+ "book-open": /* @__PURE__ */ jsx23(BookOpen, { size: 20 }),
3818
+ "compass": /* @__PURE__ */ jsx23(Compass, { size: 20 }),
3819
+ "bolt": /* @__PURE__ */ jsx23(Zap, { size: 20 })
2316
3820
  };
2317
3821
  return icon ? iconMap[icon] || iconMap["sparkle"] : iconMap["sparkle"];
2318
3822
  }
@@ -2320,9 +3824,9 @@ function StartScreen({ startScreen, onPromptClick, className }) {
2320
3824
  const { t } = useChatkitTranslation();
2321
3825
  const greeting = startScreen?.greeting ?? t("startScreen.greeting");
2322
3826
  const prompts = startScreen?.prompts ?? [];
2323
- return /* @__PURE__ */ jsxs10("div", { className: cn("flex flex-col items-center justify-center py-12 px-4", className), children: [
2324
- /* @__PURE__ */ jsx21("div", { className: "mb-8 text-center", children: /* @__PURE__ */ jsx21("h2", { className: "text-2xl font-semibold text-foreground mb-2", children: greeting }) }),
2325
- prompts.length > 0 && /* @__PURE__ */ jsx21("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsx21("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: prompts.map((item, index) => /* @__PURE__ */ jsxs10(
3827
+ return /* @__PURE__ */ jsxs13("div", { className: cn("flex flex-col items-center justify-center py-12 px-4", className), children: [
3828
+ /* @__PURE__ */ jsx23("div", { className: "mb-8 text-center", children: /* @__PURE__ */ jsx23("h2", { className: "text-2xl font-semibold text-foreground mb-2", children: greeting }) }),
3829
+ prompts.length > 0 && /* @__PURE__ */ jsx23("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsx23("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: prompts.map((item, index) => /* @__PURE__ */ jsxs13(
2326
3830
  "button",
2327
3831
  {
2328
3832
  type: "button",
@@ -2333,8 +3837,8 @@ function StartScreen({ startScreen, onPromptClick, className }) {
2333
3837
  "focus:outline-none focus:ring-2 focus:ring-primary/20"
2334
3838
  ),
2335
3839
  children: [
2336
- /* @__PURE__ */ jsx21("span", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary", children: getIconComponent2(item.icon) }),
2337
- /* @__PURE__ */ jsx21("span", { className: "text-sm font-medium text-foreground", children: item.label })
3840
+ /* @__PURE__ */ jsx23("span", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary", children: getIconComponent2(item.icon) }),
3841
+ /* @__PURE__ */ jsx23("span", { className: "text-sm font-medium text-foreground", children: item.label })
2338
3842
  ]
2339
3843
  },
2340
3844
  `prompt-${index}`
@@ -2346,10 +3850,10 @@ function StartScreen({ startScreen, onPromptClick, className }) {
2346
3850
  import "react";
2347
3851
 
2348
3852
  // src/components/ui/avatar.tsx
2349
- import * as React16 from "react";
3853
+ import * as React18 from "react";
2350
3854
  import * as AvatarPrimitive from "@radix-ui/react-avatar";
2351
- import { jsx as jsx22 } from "react/jsx-runtime";
2352
- var Avatar = React16.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
3855
+ import { jsx as jsx24 } from "react/jsx-runtime";
3856
+ var Avatar = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
2353
3857
  AvatarPrimitive.Root,
2354
3858
  {
2355
3859
  ref,
@@ -2361,7 +3865,7 @@ var Avatar = React16.forwardRef(({ className, ...props }, ref) => /* @__PURE__ *
2361
3865
  }
2362
3866
  ));
2363
3867
  Avatar.displayName = AvatarPrimitive.Root.displayName;
2364
- var AvatarImage = React16.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
3868
+ var AvatarImage = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
2365
3869
  AvatarPrimitive.Image,
2366
3870
  {
2367
3871
  ref,
@@ -2370,7 +3874,7 @@ var AvatarImage = React16.forwardRef(({ className, ...props }, ref) => /* @__PUR
2370
3874
  }
2371
3875
  ));
2372
3876
  AvatarImage.displayName = AvatarPrimitive.Image.displayName;
2373
- var AvatarFallback = React16.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
3877
+ var AvatarFallback = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
2374
3878
  AvatarPrimitive.Fallback,
2375
3879
  {
2376
3880
  ref,
@@ -2384,7 +3888,7 @@ var AvatarFallback = React16.forwardRef(({ className, ...props }, ref) => /* @__
2384
3888
  AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
2385
3889
 
2386
3890
  // src/components/ui/chatkit-avatar.tsx
2387
- import { jsx as jsx23, jsxs as jsxs11 } from "react/jsx-runtime";
3891
+ import { jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
2388
3892
  function asRecord(value) {
2389
3893
  return value && typeof value === "object" ? value : null;
2390
3894
  }
@@ -2457,21 +3961,21 @@ function ChatkitAvatar({
2457
3961
  const fallbackStyle = {
2458
3962
  ...avatar?.background ? { background: avatar.background } : {}
2459
3963
  };
2460
- return /* @__PURE__ */ jsxs11(Avatar, { className: cn(roundedClass, className), style, ...props, children: [
2461
- avatar?.url ? /* @__PURE__ */ jsx23(AvatarImage, { className: imageClassName, src: avatar.url, alt: label }) : null,
2462
- /* @__PURE__ */ jsx23(
3964
+ return /* @__PURE__ */ jsxs14(Avatar, { className: cn(roundedClass, className), style, ...props, children: [
3965
+ avatar?.url ? /* @__PURE__ */ jsx25(AvatarImage, { className: imageClassName, src: avatar.url, alt: label }) : null,
3966
+ /* @__PURE__ */ jsx25(
2463
3967
  AvatarFallback,
2464
3968
  {
2465
3969
  className: cn(roundedClass, "text-sm font-medium text-foreground", fallbackClassName),
2466
3970
  style: fallbackStyle,
2467
- children: emojiCharacter ? /* @__PURE__ */ jsx23("span", { className: "text-[1.1em] leading-none", style: emojiStyle, children: emojiCharacter }) : fallbackText
3971
+ children: emojiCharacter ? /* @__PURE__ */ jsx25("span", { className: "text-[1.1em] leading-none", style: emojiStyle, children: emojiCharacter }) : fallbackText
2468
3972
  }
2469
3973
  )
2470
3974
  ] });
2471
3975
  }
2472
3976
 
2473
3977
  // src/hooks/useThreads.ts
2474
- import * as React18 from "react";
3978
+ import * as React20 from "react";
2475
3979
  var DEFAULT_LIMIT = 50;
2476
3980
  var getThreadTitle = (threadRecord) => {
2477
3981
  const title = threadRecord.title?.trim();
@@ -2509,16 +4013,16 @@ function useThreads(limit = DEFAULT_LIMIT) {
2509
4013
  isReady,
2510
4014
  isLoading: isStreamLoading
2511
4015
  } = useStreamContext();
2512
- const [threadRecords, setThreadRecords] = React18.useState([]);
2513
- const [isLoading, setIsLoading] = React18.useState(false);
2514
- const [error, setError] = React18.useState(null);
2515
- const upsertThreadRecord = React18.useCallback((threadRecord) => {
4016
+ const [threadRecords, setThreadRecords] = React20.useState([]);
4017
+ const [isLoading, setIsLoading] = React20.useState(false);
4018
+ const [error, setError] = React20.useState(null);
4019
+ const upsertThreadRecord = React20.useCallback((threadRecord) => {
2516
4020
  setThreadRecords((prev) => {
2517
4021
  const next = prev.filter((item) => item.id !== threadRecord.id);
2518
4022
  return sortThreadRecords([threadRecord, ...next]);
2519
4023
  });
2520
4024
  }, []);
2521
- const refreshThreads = React18.useCallback(async () => {
4025
+ const refreshThreads = React20.useCallback(async () => {
2522
4026
  setIsLoading(true);
2523
4027
  setError(null);
2524
4028
  try {
@@ -2534,7 +4038,7 @@ function useThreads(limit = DEFAULT_LIMIT) {
2534
4038
  setIsLoading(false);
2535
4039
  }
2536
4040
  }, [client, limit, assistantId]);
2537
- const createThread = React18.useCallback(
4041
+ const createThread = React20.useCallback(
2538
4042
  async (input) => {
2539
4043
  setError(null);
2540
4044
  const payload = {};
@@ -2548,7 +4052,7 @@ function useThreads(limit = DEFAULT_LIMIT) {
2548
4052
  },
2549
4053
  [client, upsertThreadRecord]
2550
4054
  );
2551
- const updateThread = React18.useCallback(
4055
+ const updateThread = React20.useCallback(
2552
4056
  async (recordId, payload) => {
2553
4057
  setError(null);
2554
4058
  const updated = await client.conversations.update(recordId, payload);
@@ -2557,7 +4061,7 @@ function useThreads(limit = DEFAULT_LIMIT) {
2557
4061
  },
2558
4062
  [client, upsertThreadRecord]
2559
4063
  );
2560
- const deleteThread = React18.useCallback(
4064
+ const deleteThread = React20.useCallback(
2561
4065
  async (recordId) => {
2562
4066
  setError(null);
2563
4067
  await client.conversations.delete(recordId);
@@ -2565,23 +4069,24 @@ function useThreads(limit = DEFAULT_LIMIT) {
2565
4069
  },
2566
4070
  [client]
2567
4071
  );
2568
- React18.useEffect(() => {
4072
+ React20.useEffect(() => {
2569
4073
  if (!isReady) return;
2570
4074
  void refreshThreads();
2571
4075
  }, [refreshThreads, isReady]);
2572
- React18.useEffect(() => {
4076
+ React20.useEffect(() => {
2573
4077
  if (!threadId || !isStreamLoading) return;
2574
4078
  const now = (/* @__PURE__ */ new Date()).toISOString();
4079
+ const busyStatus = "busy";
2575
4080
  setThreadRecords((prev) => {
2576
4081
  let changed = false;
2577
4082
  const next = prev.map((item) => {
2578
4083
  const isCurrentThread = item.threadId === threadId || item.id === threadId;
2579
4084
  if (!isCurrentThread) return item;
2580
- if (item.status === "busy" && !item.error) return item;
4085
+ if (item.status === busyStatus && !item.error) return item;
2581
4086
  changed = true;
2582
4087
  return {
2583
4088
  ...item,
2584
- status: "busy",
4089
+ status: busyStatus,
2585
4090
  error: void 0,
2586
4091
  updatedAt: now
2587
4092
  };
@@ -2589,7 +4094,7 @@ function useThreads(limit = DEFAULT_LIMIT) {
2589
4094
  return changed ? sortThreadRecords(next) : prev;
2590
4095
  });
2591
4096
  }, [threadId, isStreamLoading]);
2592
- React18.useEffect(() => {
4097
+ React20.useEffect(() => {
2593
4098
  if (!isReady || !threadId || isStreamLoading) return;
2594
4099
  let cancelled = false;
2595
4100
  void client.conversations.search({ where: { threadId }, limit: 1 }).then((result) => {
@@ -2603,7 +4108,7 @@ function useThreads(limit = DEFAULT_LIMIT) {
2603
4108
  cancelled = true;
2604
4109
  };
2605
4110
  }, [client, threadId, upsertThreadRecord, isReady, isStreamLoading]);
2606
- const threads = React18.useMemo(
4111
+ const threads = React20.useMemo(
2607
4112
  () => threadRecords.map((threadRecord) => toThreadItem(threadRecord)),
2608
4113
  [threadRecords]
2609
4114
  );
@@ -2620,18 +4125,18 @@ function useThreads(limit = DEFAULT_LIMIT) {
2620
4125
  }
2621
4126
 
2622
4127
  // src/components/thread/context-usage-indicator.tsx
2623
- import * as React19 from "react";
4128
+ import * as React21 from "react";
2624
4129
 
2625
4130
  // src/components/ui/progress-circle.tsx
2626
- import { jsx as jsx24, jsxs as jsxs12 } from "react/jsx-runtime";
2627
- function clamp(input, a, b) {
4131
+ import { jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
4132
+ function clamp2(input, a, b) {
2628
4133
  return Math.max(Math.min(input, Math.max(a, b)), Math.min(a, b));
2629
4134
  }
2630
4135
  var size = 24;
2631
4136
  var strokeWidth = 4;
2632
4137
  var total = 100;
2633
4138
  var ProgressCircle = ({ value, className, ...restSvgProps }) => {
2634
- const normalizedValue = clamp(value, 0, total);
4139
+ const normalizedValue = clamp2(value, 0, total);
2635
4140
  const radius = (size - strokeWidth) / 2;
2636
4141
  const circumference = 2 * Math.PI * radius;
2637
4142
  const progress = normalizedValue / total * circumference;
@@ -2646,7 +4151,7 @@ var ProgressCircle = ({ value, className, ...restSvgProps }) => {
2646
4151
  return (
2647
4152
  // biome-ignore lint/a11y/useFocusableInteractive: false positive (progress + progressbar are not focusable interactives)
2648
4153
  // biome-ignore lint/nursery/useAriaPropsSupportedByRole: biome rule at odds with mdn docs (presumed nursary bug with rule)
2649
- /* @__PURE__ */ jsxs12(
4154
+ /* @__PURE__ */ jsxs15(
2650
4155
  "svg",
2651
4156
  {
2652
4157
  role: "progressbar",
@@ -2657,8 +4162,8 @@ var ProgressCircle = ({ value, className, ...restSvgProps }) => {
2657
4162
  "aria-valuemax": 100,
2658
4163
  ...restSvgProps,
2659
4164
  children: [
2660
- /* @__PURE__ */ jsx24("circle", { ...commonParams, className: "stroke-current/25" }),
2661
- /* @__PURE__ */ jsx24(
4165
+ /* @__PURE__ */ jsx26("circle", { ...commonParams, className: "stroke-current/25" }),
4166
+ /* @__PURE__ */ jsx26(
2662
4167
  "circle",
2663
4168
  {
2664
4169
  ...commonParams,
@@ -2677,7 +4182,7 @@ var ProgressCircle = ({ value, className, ...restSvgProps }) => {
2677
4182
  };
2678
4183
 
2679
4184
  // src/components/thread/context-usage-indicator.tsx
2680
- import { jsx as jsx25, jsxs as jsxs13 } from "react/jsx-runtime";
4185
+ import { jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
2681
4186
  var kNumberFormatter = new Intl.NumberFormat("en-US", {
2682
4187
  minimumFractionDigits: 0,
2683
4188
  maximumFractionDigits: 1
@@ -2710,20 +4215,20 @@ function ContextUsageIndicator({
2710
4215
  }) {
2711
4216
  const { t } = useChatkitTranslation();
2712
4217
  const stream = useStreamContext();
2713
- const [maxContextSize, setMaxContextSize] = React19.useState(null);
2714
- const [usedContextSize, setUsedContextSize] = React19.useState(null);
2715
- const [assistantAgentKey, setAssistantAgentKey] = React19.useState(null);
2716
- const latestRealtimeUsageRef = React19.useRef({
4218
+ const [maxContextSize, setMaxContextSize] = React21.useState(null);
4219
+ const [usedContextSize, setUsedContextSize] = React21.useState(null);
4220
+ const [assistantAgentKey, setAssistantAgentKey] = React21.useState(null);
4221
+ const latestRealtimeUsageRef = React21.useRef({
2717
4222
  threadId: null,
2718
4223
  agentKey: null,
2719
4224
  usedTokens: null
2720
4225
  });
2721
- const realtimeUsage = React19.useMemo(
4226
+ const realtimeUsage = React21.useMemo(
2722
4227
  () => getThreadContextUsage(stream.contextUsageByAgentKey, assistantAgentKey),
2723
4228
  [assistantAgentKey, stream.contextUsageByAgentKey]
2724
4229
  );
2725
4230
  const realtimeUsedContextSize = getThreadContextUsageTotalTokens(realtimeUsage);
2726
- React19.useEffect(() => {
4231
+ React21.useEffect(() => {
2727
4232
  if (!stream.client || !stream.assistantId) {
2728
4233
  setMaxContextSize(null);
2729
4234
  setAssistantAgentKey(null);
@@ -2743,18 +4248,18 @@ function ContextUsageIndicator({
2743
4248
  cancelled = true;
2744
4249
  };
2745
4250
  }, [stream.client, stream.assistantId]);
2746
- React19.useEffect(() => {
4251
+ React21.useEffect(() => {
2747
4252
  latestRealtimeUsageRef.current = {
2748
4253
  threadId: stream.threadId ?? null,
2749
4254
  agentKey: assistantAgentKey,
2750
4255
  usedTokens: realtimeUsedContextSize
2751
4256
  };
2752
4257
  }, [assistantAgentKey, realtimeUsedContextSize, stream.threadId]);
2753
- React19.useEffect(() => {
4258
+ React21.useEffect(() => {
2754
4259
  if (realtimeUsedContextSize == null) return;
2755
4260
  setUsedContextSize(realtimeUsedContextSize);
2756
4261
  }, [realtimeUsedContextSize]);
2757
- React19.useEffect(() => {
4262
+ React21.useEffect(() => {
2758
4263
  if (!stream.client) {
2759
4264
  setUsedContextSize(null);
2760
4265
  return;
@@ -2819,8 +4324,8 @@ function ContextUsageIndicator({
2819
4324
  });
2820
4325
  const usageLabelWithSuffix = usageLabel.endsWith(":") ? usageLabel : `${usageLabel}:`;
2821
4326
  const progressClassName = percent >= 90 ? "text-destructive" : percent >= 75 ? "text-amber-500" : "text-primary dark:text-zinc-300";
2822
- return /* @__PURE__ */ jsxs13(Tooltip, { children: [
2823
- /* @__PURE__ */ jsx25(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(
4327
+ return /* @__PURE__ */ jsxs16(Tooltip, { children: [
4328
+ /* @__PURE__ */ jsx27(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx27(
2824
4329
  "button",
2825
4330
  {
2826
4331
  type: "button",
@@ -2829,20 +4334,73 @@ function ContextUsageIndicator({
2829
4334
  className
2830
4335
  ),
2831
4336
  "aria-label": `${usageLabelWithSuffix} ${usageFullLabel}. ${usageTokensLabel}`,
2832
- children: /* @__PURE__ */ jsx25(ProgressCircle, { value: percent, className: cn("size-3.5", progressClassName) })
4337
+ children: /* @__PURE__ */ jsx27(ProgressCircle, { value: percent, className: cn("size-3.5", progressClassName) })
2833
4338
  }
2834
4339
  ) }),
2835
- /* @__PURE__ */ jsxs13(TooltipContent, { side: "top", sideOffset: 6, className: "space-y-0.5 px-3 py-2 text-center", children: [
2836
- /* @__PURE__ */ jsx25("div", { className: "text-primary-foreground/70", children: usageLabelWithSuffix }),
2837
- /* @__PURE__ */ jsx25("div", { className: "font-medium text-primary-foreground/80", children: usageFullLabel }),
2838
- /* @__PURE__ */ jsx25("div", { className: "text-sm font-semibold", children: usageTokensLabel })
4340
+ /* @__PURE__ */ jsxs16(TooltipContent, { side: "top", sideOffset: 6, className: "space-y-0.5 px-3 py-2 text-center", children: [
4341
+ /* @__PURE__ */ jsx27("div", { className: "text-primary-foreground/70", children: usageLabelWithSuffix }),
4342
+ /* @__PURE__ */ jsx27("div", { className: "font-medium text-primary-foreground/80", children: usageFullLabel }),
4343
+ /* @__PURE__ */ jsx27("div", { className: "text-sm font-semibold", children: usageTokensLabel })
2839
4344
  ] })
2840
4345
  ] });
2841
4346
  }
2842
4347
 
2843
4348
  // src/components/chat.tsx
2844
- import { Fragment as Fragment3, jsx as jsx26, jsxs as jsxs14 } from "react/jsx-runtime";
4349
+ import { Fragment as Fragment4, jsx as jsx28, jsxs as jsxs17 } from "react/jsx-runtime";
2845
4350
  var defaultApiUrl2 = import.meta.env.VITE_XPERTAI_API_URL;
4351
+ var COMPOSER_INPUT_MAX_HEIGHT = 128;
4352
+ var LONG_TEXT_REFERENCE_THRESHOLD = 5e3;
4353
+ async function readImageDimensions(file) {
4354
+ if (typeof window === "undefined" || typeof URL === "undefined") {
4355
+ return {};
4356
+ }
4357
+ return new Promise((resolve) => {
4358
+ const objectUrl = URL.createObjectURL(file);
4359
+ const image = new window.Image();
4360
+ const cleanup = () => {
4361
+ URL.revokeObjectURL(objectUrl);
4362
+ };
4363
+ image.onload = () => {
4364
+ resolve({
4365
+ width: image.naturalWidth || void 0,
4366
+ height: image.naturalHeight || void 0
4367
+ });
4368
+ cleanup();
4369
+ };
4370
+ image.onerror = () => {
4371
+ resolve({});
4372
+ cleanup();
4373
+ };
4374
+ image.src = objectUrl;
4375
+ });
4376
+ }
4377
+ function getStorageFileUrl(file) {
4378
+ return file.url ?? file.fileUrl ?? file.thumbUrl;
4379
+ }
4380
+ function buildPastedImageReference(file, storageFile, dimensions) {
4381
+ const name = storageFile.originalName?.trim() || file.name.trim() || "Pasted image";
4382
+ const mimeType = storageFile.mimetype?.trim() || file.type.trim() || "image/*";
4383
+ const size2 = storageFile.size ?? file.size;
4384
+ const width = dimensions?.width;
4385
+ const height = dimensions?.height;
4386
+ const metaParts = [
4387
+ mimeType,
4388
+ width && height ? `${width}x${height}` : null,
4389
+ typeof size2 === "number" ? `${size2} bytes` : null
4390
+ ].filter((part) => Boolean(part));
4391
+ return {
4392
+ type: "image",
4393
+ id: storageFile.id,
4394
+ fileId: storageFile.id,
4395
+ url: getStorageFileUrl(storageFile),
4396
+ mimeType,
4397
+ name,
4398
+ ...typeof size2 === "number" ? { size: size2 } : {},
4399
+ ...width ? { width } : {},
4400
+ ...height ? { height } : {},
4401
+ text: `Pasted image${metaParts.length ? ` (${metaParts.join(", ")})` : ""}: ${name}`
4402
+ };
4403
+ }
2846
4404
  function formatMessageContent(content) {
2847
4405
  if (typeof content === "string") {
2848
4406
  return content;
@@ -2864,6 +4422,81 @@ function formatMessageContent(content) {
2864
4422
  }
2865
4423
  return "";
2866
4424
  }
4425
+ function getClosestQuoteContainer(node) {
4426
+ if (!node) {
4427
+ return null;
4428
+ }
4429
+ const element = node instanceof HTMLElement ? node : node instanceof Text ? node.parentElement : null;
4430
+ return element?.closest("[data-quote-message-id]") ?? null;
4431
+ }
4432
+ function ReferenceChip({
4433
+ reference,
4434
+ variant,
4435
+ onRemove,
4436
+ removeLabel
4437
+ }) {
4438
+ const metaLine = getReferenceMetaLine(reference);
4439
+ const isComposer = variant === "composer";
4440
+ const Icon = reference.type === "quote" ? Quote : reference.type === "image" ? ImageIcon : FileText2;
4441
+ return /* @__PURE__ */ jsxs17(
4442
+ "div",
4443
+ {
4444
+ className: cn(
4445
+ "flex items-start gap-2 rounded-md px-2 py-1",
4446
+ isComposer ? "bg-muted text-foreground" : "bg-primary-foreground/20"
4447
+ ),
4448
+ title: getReferenceTitle(reference),
4449
+ children: [
4450
+ /* @__PURE__ */ jsx28(
4451
+ Icon,
4452
+ {
4453
+ size: isComposer ? 14 : 12,
4454
+ className: cn(
4455
+ "mt-0.5 shrink-0",
4456
+ isComposer ? "text-muted-foreground" : "text-primary-foreground/80"
4457
+ )
4458
+ }
4459
+ ),
4460
+ /* @__PURE__ */ jsxs17("div", { className: "min-w-0 flex-1", children: [
4461
+ /* @__PURE__ */ jsx28(
4462
+ "div",
4463
+ {
4464
+ className: cn(
4465
+ "truncate whitespace-pre-wrap",
4466
+ isComposer ? "text-sm" : "text-xs font-medium"
4467
+ ),
4468
+ children: getReferenceLabel(reference)
4469
+ }
4470
+ ),
4471
+ metaLine && /* @__PURE__ */ jsx28(
4472
+ "div",
4473
+ {
4474
+ className: cn(
4475
+ "truncate whitespace-pre-wrap",
4476
+ isComposer ? "text-xs text-muted-foreground" : "text-[10px] text-primary-foreground/75"
4477
+ ),
4478
+ children: metaLine
4479
+ }
4480
+ )
4481
+ ] }),
4482
+ onRemove && removeLabel && /* @__PURE__ */ jsx28(
4483
+ "button",
4484
+ {
4485
+ type: "button",
4486
+ onClick: onRemove,
4487
+ className: cn(
4488
+ "ml-1 rounded-full p-0.5",
4489
+ isComposer ? "hover:bg-muted-foreground/20" : "hover:bg-primary-foreground/20"
4490
+ ),
4491
+ title: removeLabel,
4492
+ "aria-label": removeLabel,
4493
+ children: /* @__PURE__ */ jsx28(X3, { size: 12 })
4494
+ }
4495
+ )
4496
+ ]
4497
+ }
4498
+ );
4499
+ }
2867
4500
  function Chat({
2868
4501
  className,
2869
4502
  options,
@@ -2880,17 +4513,21 @@ function Chat({
2880
4513
  const apiUrl = options?.api?.apiUrl || defaultApiUrl2;
2881
4514
  const { setStream } = useStreamManager();
2882
4515
  const stream = useStreamContext();
2883
- const [isHistoryLoading, setIsHistoryLoading] = React20.useState(false);
2884
- const [historyError, setHistoryError] = React20.useState(null);
2885
- const [assistantName, setAssistantName] = React20.useState(null);
2886
- const [assistantAvatar, setAssistantAvatar] = React20.useState(null);
4516
+ const { theme } = useTheme();
4517
+ const [isHistoryLoading, setIsHistoryLoading] = React22.useState(false);
4518
+ const [historyError, setHistoryError] = React22.useState(null);
4519
+ const [assistantName, setAssistantName] = React22.useState(null);
4520
+ const [assistantAvatar, setAssistantAvatar] = React22.useState(null);
2887
4521
  const LOADING_DOTS_MIN_DURATION = 800;
2888
- const [showLoadingDots, setShowLoadingDots] = React20.useState(false);
2889
- const loadingStartTimeRef = React20.useRef(null);
2890
- React20.useEffect(() => {
4522
+ const STREAMING_STATUS_REFRESH_MS = 250;
4523
+ const [showLoadingDots, setShowLoadingDots] = React22.useState(false);
4524
+ const [streamingNow, setStreamingNow] = React22.useState(() => Date.now());
4525
+ const loadingStartTimeRef = React22.useRef(null);
4526
+ const lastStreamOutputAtRef = React22.useRef(null);
4527
+ React22.useEffect(() => {
2891
4528
  setStream(stream);
2892
4529
  }, [setStream, stream]);
2893
- React20.useEffect(() => {
4530
+ React22.useEffect(() => {
2894
4531
  if (stream.isLoading) {
2895
4532
  if (!loadingStartTimeRef.current) {
2896
4533
  loadingStartTimeRef.current = Date.now();
@@ -2913,67 +4550,181 @@ function Chat({
2913
4550
  }
2914
4551
  }
2915
4552
  }, [stream.isLoading]);
2916
- const [draft, setDraft] = React20.useState("");
2917
- const [selectedTool, setSelectedTool] = React20.useState(null);
2918
- const [attachments, setAttachments] = React20.useState([]);
2919
- const [isAtBottom, setIsAtBottom] = React20.useState(true);
2920
- const [hasUpdatesBelow, setHasUpdatesBelow] = React20.useState(false);
4553
+ React22.useEffect(() => {
4554
+ if (!stream.isLoading) {
4555
+ lastStreamOutputAtRef.current = null;
4556
+ setStreamingNow(Date.now());
4557
+ return;
4558
+ }
4559
+ const now = Date.now();
4560
+ lastStreamOutputAtRef.current = now;
4561
+ setStreamingNow(now);
4562
+ }, [stream.messages, stream.isLoading]);
4563
+ React22.useEffect(() => {
4564
+ if (!stream.isLoading) {
4565
+ return;
4566
+ }
4567
+ const timer = window.setInterval(() => {
4568
+ setStreamingNow(Date.now());
4569
+ }, STREAMING_STATUS_REFRESH_MS);
4570
+ return () => window.clearInterval(timer);
4571
+ }, [stream.isLoading]);
4572
+ const [draft, setDraft] = React22.useState("");
4573
+ const [selectedTool, setSelectedTool] = React22.useState(
4574
+ null
4575
+ );
4576
+ const [attachments, setAttachments] = React22.useState([]);
4577
+ const [references, setReferences] = React22.useState([]);
4578
+ const [isUploadingReferenceImages, setIsUploadingReferenceImages] = React22.useState(false);
4579
+ const [quoteSelection, setQuoteSelection] = React22.useState(null);
4580
+ const [isAtBottom, setIsAtBottom] = React22.useState(true);
4581
+ const [hasUpdatesBelow, setHasUpdatesBelow] = React22.useState(false);
2921
4582
  const {
2922
4583
  threads,
2923
4584
  deleteThread,
2924
4585
  refreshThreads,
2925
4586
  isLoading: isThreadsLoading
2926
4587
  } = useThreads();
2927
- const viewportRef = React20.useRef(null);
2928
- const fileInputRef = React20.useRef(null);
2929
- const shouldAutoScrollRef = React20.useRef(true);
2930
- const forceFollowRef = React20.useRef(false);
2931
- const previousMessageCountRef = React20.useRef(0);
2932
- const previousScrollTopRef = React20.useRef(0);
2933
- const autoScrollFrameRef = React20.useRef(null);
2934
- const isPointerDownRef = React20.useRef(false);
2935
- const lastTouchYRef = React20.useRef(null);
4588
+ const viewportRef = React22.useRef(null);
4589
+ const fileInputRef = React22.useRef(null);
4590
+ const composerInputRef = React22.useRef(null);
4591
+ const shouldAutoScrollRef = React22.useRef(true);
4592
+ const forceFollowRef = React22.useRef(false);
4593
+ const previousMessageCountRef = React22.useRef(0);
4594
+ const previousScrollTopRef = React22.useRef(0);
4595
+ const autoScrollFrameRef = React22.useRef(null);
4596
+ const isPointerDownRef = React22.useRef(false);
4597
+ const lastTouchYRef = React22.useRef(null);
2936
4598
  const resolvedTitle = title ?? t("chat.title");
2937
4599
  const resolvedPlaceholder = placeholder ?? t("chat.placeholder");
2938
4600
  const inputPlaceholder = selectedTool?.placeholderOverride ?? composer?.placeholder ?? resolvedPlaceholder;
2939
- const messages = React20.useMemo(() => stream.messages ?? [], [stream.messages]);
4601
+ const messages = React22.useMemo(
4602
+ () => stream.messages ?? [],
4603
+ [stream.messages]
4604
+ );
2940
4605
  const trimmedDraft = draft.trim();
2941
- const cancelPendingAutoScroll = React20.useCallback(() => {
4606
+ const hasReferences = references.length > 0;
4607
+ const pendingFollowUps = React22.useMemo(
4608
+ () => [...stream.pendingFollowUps ?? []].sort(
4609
+ (a, b) => a.createdAt - b.createdAt
4610
+ ),
4611
+ [stream.pendingFollowUps]
4612
+ );
4613
+ const clearQuoteSelection = React22.useCallback(() => {
4614
+ setQuoteSelection(null);
4615
+ }, []);
4616
+ useParentMessenger({
4617
+ onSetComposerValue: React22.useCallback(
4618
+ (payload) => {
4619
+ if (!payload) {
4620
+ return;
4621
+ }
4622
+ if (typeof payload.text === "string") {
4623
+ setDraft(payload.text);
4624
+ }
4625
+ if (Array.isArray(payload.references)) {
4626
+ const nextReferences = normalizeReferences(payload.references);
4627
+ setReferences(
4628
+ (previous) => payload.appendReferences ? mergeReferences(previous, nextReferences) : nextReferences
4629
+ );
4630
+ }
4631
+ if (payload.selectedToolId !== void 0) {
4632
+ const nextTool = payload.selectedToolId === null ? null : (composer?.tools ?? []).find(
4633
+ (tool) => tool.id === payload.selectedToolId
4634
+ ) ?? null;
4635
+ setSelectedTool(nextTool);
4636
+ }
4637
+ },
4638
+ [composer?.tools]
4639
+ ),
4640
+ onFocusComposer: React22.useCallback(() => {
4641
+ composerInputRef.current?.focus();
4642
+ }, [])
4643
+ });
4644
+ const syncQuoteSelection = React22.useCallback(() => {
4645
+ if (typeof window === "undefined") {
4646
+ clearQuoteSelection();
4647
+ return;
4648
+ }
4649
+ const selection = window.getSelection();
4650
+ if (!selection || selection.isCollapsed || selection.rangeCount === 0) {
4651
+ clearQuoteSelection();
4652
+ return;
4653
+ }
4654
+ const text = selection.toString().trim();
4655
+ if (!text) {
4656
+ clearQuoteSelection();
4657
+ return;
4658
+ }
4659
+ const anchorContainer = getClosestQuoteContainer(selection.anchorNode);
4660
+ const focusContainer = getClosestQuoteContainer(selection.focusNode);
4661
+ if (!anchorContainer || !focusContainer || anchorContainer !== focusContainer || !viewportRef.current?.contains(anchorContainer)) {
4662
+ clearQuoteSelection();
4663
+ return;
4664
+ }
4665
+ const range = selection.getRangeAt(0);
4666
+ const rect = range.getBoundingClientRect();
4667
+ if (rect.width === 0 && rect.height === 0) {
4668
+ clearQuoteSelection();
4669
+ return;
4670
+ }
4671
+ const top = rect.bottom + 8 > window.innerHeight - 48 ? Math.max(12, rect.top - 44) : rect.bottom + 8;
4672
+ const left = Math.min(
4673
+ Math.max(24, rect.left + rect.width / 2),
4674
+ window.innerWidth - 24
4675
+ );
4676
+ const source = anchorContainer.dataset.quoteSource?.trim() || void 0;
4677
+ const messageId = anchorContainer.dataset.quoteMessageId?.trim() || void 0;
4678
+ setQuoteSelection({
4679
+ reference: {
4680
+ type: "quote",
4681
+ text,
4682
+ ...messageId ? { messageId } : {},
4683
+ ...source ? { source, label: source } : {}
4684
+ },
4685
+ top,
4686
+ left
4687
+ });
4688
+ }, [clearQuoteSelection]);
4689
+ const cancelPendingAutoScroll = React22.useCallback(() => {
2942
4690
  if (autoScrollFrameRef.current !== null) {
2943
4691
  cancelAnimationFrame(autoScrollFrameRef.current);
2944
4692
  autoScrollFrameRef.current = null;
2945
4693
  }
2946
4694
  }, []);
2947
- const disableAutoFollow = React20.useCallback(() => {
4695
+ const disableAutoFollow = React22.useCallback(() => {
2948
4696
  forceFollowRef.current = false;
2949
4697
  shouldAutoScrollRef.current = false;
2950
4698
  cancelPendingAutoScroll();
2951
4699
  }, [cancelPendingAutoScroll]);
2952
- const enableAutoFollow = React20.useCallback(() => {
4700
+ const enableAutoFollow = React22.useCallback(() => {
2953
4701
  forceFollowRef.current = true;
2954
4702
  shouldAutoScrollRef.current = true;
2955
4703
  setHasUpdatesBelow(false);
2956
4704
  }, []);
2957
- const scrollToBottom = React20.useCallback((smooth = false, force = false) => {
2958
- if (force) {
2959
- enableAutoFollow();
2960
- }
2961
- cancelPendingAutoScroll();
2962
- autoScrollFrameRef.current = requestAnimationFrame(() => {
2963
- autoScrollFrameRef.current = null;
2964
- const viewport = viewportRef.current;
2965
- if (viewport) {
2966
- if (!force && !shouldAutoScrollRef.current) {
2967
- return;
2968
- }
2969
- viewport.scrollTo({
2970
- top: viewport.scrollHeight,
2971
- behavior: smooth ? "smooth" : "instant"
2972
- });
4705
+ const scrollToBottom = React22.useCallback(
4706
+ (smooth = false, force = false) => {
4707
+ if (force) {
4708
+ enableAutoFollow();
2973
4709
  }
2974
- });
2975
- }, [cancelPendingAutoScroll, enableAutoFollow]);
2976
- React20.useEffect(() => {
4710
+ cancelPendingAutoScroll();
4711
+ autoScrollFrameRef.current = requestAnimationFrame(() => {
4712
+ autoScrollFrameRef.current = null;
4713
+ const viewport = viewportRef.current;
4714
+ if (viewport) {
4715
+ if (!force && !shouldAutoScrollRef.current) {
4716
+ return;
4717
+ }
4718
+ viewport.scrollTo({
4719
+ top: viewport.scrollHeight,
4720
+ behavior: smooth ? "smooth" : "instant"
4721
+ });
4722
+ }
4723
+ });
4724
+ },
4725
+ [cancelPendingAutoScroll, enableAutoFollow]
4726
+ );
4727
+ React22.useEffect(() => {
2977
4728
  const viewport = viewportRef.current;
2978
4729
  if (!viewport) return;
2979
4730
  previousScrollTopRef.current = viewport.scrollTop;
@@ -3025,13 +4776,23 @@ function Chat({
3025
4776
  };
3026
4777
  updateAutoScrollState();
3027
4778
  viewport.addEventListener("wheel", handleWheel, { passive: true });
3028
- viewport.addEventListener("pointerdown", handlePointerDown, { passive: true });
3029
- viewport.addEventListener("scroll", updateAutoScrollState, { passive: true });
3030
- viewport.addEventListener("touchstart", handleTouchStart, { passive: true });
4779
+ viewport.addEventListener("pointerdown", handlePointerDown, {
4780
+ passive: true
4781
+ });
4782
+ viewport.addEventListener("scroll", updateAutoScrollState, {
4783
+ passive: true
4784
+ });
4785
+ viewport.addEventListener("touchstart", handleTouchStart, {
4786
+ passive: true
4787
+ });
3031
4788
  viewport.addEventListener("touchmove", handleTouchMove, { passive: true });
3032
4789
  viewport.addEventListener("touchend", handleTouchEnd, { passive: true });
3033
- window.addEventListener("pointerup", stopPointerTracking, { passive: true });
3034
- window.addEventListener("pointercancel", stopPointerTracking, { passive: true });
4790
+ window.addEventListener("pointerup", stopPointerTracking, {
4791
+ passive: true
4792
+ });
4793
+ window.addEventListener("pointercancel", stopPointerTracking, {
4794
+ passive: true
4795
+ });
3035
4796
  return () => {
3036
4797
  cancelPendingAutoScroll();
3037
4798
  viewport.removeEventListener("wheel", handleWheel);
@@ -3044,14 +4805,14 @@ function Chat({
3044
4805
  window.removeEventListener("pointercancel", stopPointerTracking);
3045
4806
  };
3046
4807
  }, [cancelPendingAutoScroll, disableAutoFollow]);
3047
- React20.useEffect(() => {
4808
+ React22.useEffect(() => {
3048
4809
  shouldAutoScrollRef.current = true;
3049
4810
  forceFollowRef.current = false;
3050
4811
  previousScrollTopRef.current = 0;
3051
4812
  setIsAtBottom(true);
3052
4813
  setHasUpdatesBelow(false);
3053
4814
  }, [stream.threadId]);
3054
- React20.useEffect(() => {
4815
+ React22.useEffect(() => {
3055
4816
  const messageCountChanged = messages.length !== previousMessageCountRef.current;
3056
4817
  previousMessageCountRef.current = messages.length;
3057
4818
  if (!shouldAutoScrollRef.current) {
@@ -3065,16 +4826,85 @@ function Chat({
3065
4826
  }
3066
4827
  }, [stream.isLoading, messages, scrollToBottom]);
3067
4828
  const effectiveClientSecret = stream.apiKey?.trim() ? stream.apiKey : clientSecret;
3068
- const hasApiKey = Boolean(effectiveClientSecret.trim());
3069
- const missingConfig = !apiUrl || !hasApiKey;
4829
+ const missingConfigKind = getMissingApiConfigurationKind({
4830
+ apiUrl,
4831
+ clientSecret: effectiveClientSecret
4832
+ });
4833
+ const missingConfig = Boolean(missingConfigKind);
4834
+ const missingConfigShortMessage = React22.useMemo(() => {
4835
+ switch (missingConfigKind) {
4836
+ case "apiUrl":
4837
+ return t("chat.missingApiUrlShort");
4838
+ case "clientSecret":
4839
+ return t("chat.missingClientSecretShort");
4840
+ case "apiUrlAndClientSecret":
4841
+ return t("chat.missingApiUrlAndClientSecretShort");
4842
+ default:
4843
+ return t("chat.missingConfigShort");
4844
+ }
4845
+ }, [missingConfigKind, t]);
4846
+ const missingConfigDetailMessage = React22.useMemo(() => {
4847
+ switch (missingConfigKind) {
4848
+ case "apiUrl":
4849
+ return t("chat.missingApiUrlDetail");
4850
+ case "clientSecret":
4851
+ return t("chat.missingClientSecretDetail");
4852
+ case "apiUrlAndClientSecret":
4853
+ return t("chat.missingApiUrlAndClientSecretDetail");
4854
+ default:
4855
+ return t("chat.missingConfigDetail");
4856
+ }
4857
+ }, [missingConfigKind, t]);
3070
4858
  const showMissingConfig = !isClientSecretInitializing && missingConfig;
3071
4859
  const hasUploadingFiles = attachments.some((a) => a.status === "uploading");
3072
- const isSendDisabled = !trimmedDraft || stream.isLoading || missingConfig || isHistoryLoading || hasUploadingFiles;
3073
- React20.useEffect(() => {
4860
+ const isSendDisabled = !trimmedDraft && !hasReferences || missingConfig || isHistoryLoading || hasUploadingFiles || isUploadingReferenceImages;
4861
+ const resizeComposerInput = React22.useCallback(() => {
4862
+ const textarea = composerInputRef.current;
4863
+ if (!textarea) {
4864
+ return;
4865
+ }
4866
+ textarea.style.height = "auto";
4867
+ const nextHeight = Math.min(
4868
+ textarea.scrollHeight,
4869
+ COMPOSER_INPUT_MAX_HEIGHT
4870
+ );
4871
+ textarea.style.height = `${nextHeight}px`;
4872
+ textarea.style.overflowY = textarea.scrollHeight > COMPOSER_INPUT_MAX_HEIGHT ? "auto" : "hidden";
4873
+ }, []);
4874
+ React22.useEffect(() => {
4875
+ resizeComposerInput();
4876
+ }, [draft, resizeComposerInput]);
4877
+ React22.useEffect(() => {
4878
+ document.addEventListener("selectionchange", syncQuoteSelection);
4879
+ return () => {
4880
+ document.removeEventListener("selectionchange", syncQuoteSelection);
4881
+ };
4882
+ }, [syncQuoteSelection]);
4883
+ React22.useEffect(() => {
4884
+ const viewport = viewportRef.current;
4885
+ if (!viewport) {
4886
+ return;
4887
+ }
4888
+ const handleViewportScroll = () => {
4889
+ clearQuoteSelection();
4890
+ };
4891
+ viewport.addEventListener("scroll", handleViewportScroll, {
4892
+ passive: true
4893
+ });
4894
+ window.addEventListener("resize", handleViewportScroll, { passive: true });
4895
+ return () => {
4896
+ viewport.removeEventListener("scroll", handleViewportScroll);
4897
+ window.removeEventListener("resize", handleViewportScroll);
4898
+ };
4899
+ }, [clearQuoteSelection]);
4900
+ React22.useEffect(() => {
4901
+ clearQuoteSelection();
4902
+ }, [messages.length, stream.threadId, clearQuoteSelection]);
4903
+ React22.useEffect(() => {
3074
4904
  if (missingConfig) return;
3075
4905
  void refreshThreads();
3076
4906
  }, [missingConfig, refreshThreads]);
3077
- React20.useEffect(() => {
4907
+ React22.useEffect(() => {
3078
4908
  if (missingConfig || !stream.client || !stream.assistantId) {
3079
4909
  setAssistantName(null);
3080
4910
  setAssistantAvatar(null);
@@ -3105,80 +4935,275 @@ function Chat({
3105
4935
  mimetype: a.storageFile?.mimetype ?? a.file.type,
3106
4936
  size: a.storageFile?.size ?? a.file.size
3107
4937
  }));
4938
+ const submitDraft = React22.useCallback(
4939
+ (followUpOverride) => {
4940
+ if (isSendDisabled) return;
4941
+ const filesToSend = uploadedFiles.length > 0 ? [...uploadedFiles] : void 0;
4942
+ const referencesToSend = references.length > 0 ? [...references] : void 0;
4943
+ const nextFollowUpMode = stream.isLoading ? followUpOverride ?? stream.followUpBehavior : void 0;
4944
+ const humanInput = buildHumanMessageInputPayload({
4945
+ content: trimmedDraft,
4946
+ references: referencesToSend
4947
+ });
4948
+ if (!humanInput) {
4949
+ return;
4950
+ }
4951
+ const displayContent = trimmedDraft || (referencesToSend ? t("chat.referencedContentOnly") : "");
4952
+ const newMessage = {
4953
+ id: createMessageId(),
4954
+ type: "human",
4955
+ content: displayContent,
4956
+ submittedInput: humanInput.input,
4957
+ ...humanInput.referenceComposition ? { referenceComposition: humanInput.referenceComposition } : {},
4958
+ ...filesToSend ? { attachments: filesToSend } : {},
4959
+ ...referencesToSend ? { references: referencesToSend } : {}
4960
+ };
4961
+ setDraft("");
4962
+ const inputPayload = {
4963
+ ...humanInput
4964
+ };
4965
+ if (filesToSend) {
4966
+ inputPayload.files = filesToSend;
4967
+ }
4968
+ const requestOptions = buildInjectedRequestOptions({
4969
+ defaults: options?.request,
4970
+ humanInput: inputPayload
4971
+ });
4972
+ stream.submit(
4973
+ {
4974
+ input: inputPayload,
4975
+ ...requestOptions.state ? { state: requestOptions.state } : {}
4976
+ },
4977
+ {
4978
+ ...nextFollowUpMode ? { followUpMode: nextFollowUpMode } : {},
4979
+ ...requestOptions.context ? { context: requestOptions.context } : {},
4980
+ ...requestOptions.config ? { config: requestOptions.config } : {},
4981
+ ...!nextFollowUpMode ? {
4982
+ optimisticValues: (prev) => {
4983
+ const prevMessages = prev?.messages ?? [];
4984
+ return { ...prev, messages: [...prevMessages, newMessage] };
4985
+ }
4986
+ } : {}
4987
+ }
4988
+ );
4989
+ scrollToBottom(true, true);
4990
+ if (selectedTool && !selectedTool.pinned) {
4991
+ setSelectedTool(null);
4992
+ }
4993
+ setAttachments([]);
4994
+ setReferences([]);
4995
+ },
4996
+ [
4997
+ isSendDisabled,
4998
+ options?.request,
4999
+ references,
5000
+ scrollToBottom,
5001
+ selectedTool,
5002
+ stream,
5003
+ trimmedDraft,
5004
+ uploadedFiles,
5005
+ t
5006
+ ]
5007
+ );
3108
5008
  const handleSubmit = (event) => {
3109
5009
  event.preventDefault();
3110
- if (isSendDisabled) return;
3111
- const filesToSend = uploadedFiles.length > 0 ? [...uploadedFiles] : void 0;
3112
- const newMessage = {
3113
- id: createMessageId(),
3114
- type: "human",
3115
- content: trimmedDraft,
3116
- ...filesToSend ? { attachments: filesToSend } : {}
3117
- };
3118
- setDraft("");
3119
- const inputPayload = {
3120
- input: trimmedDraft
3121
- };
3122
- if (filesToSend) {
3123
- inputPayload.files = filesToSend;
3124
- }
3125
- const requestOptions = buildInjectedRequestOptions({
3126
- defaults: options?.request,
3127
- humanInput: inputPayload
3128
- });
3129
- stream.submit(
3130
- {
3131
- input: inputPayload,
3132
- ...requestOptions.state ? { state: requestOptions.state } : {}
3133
- },
3134
- {
3135
- ...requestOptions.context ? { context: requestOptions.context } : {},
3136
- ...requestOptions.config ? { config: requestOptions.config } : {},
3137
- optimisticValues: (prev) => {
3138
- const prevMessages = prev?.messages ?? [];
3139
- return { ...prev, messages: [...prevMessages, newMessage] };
3140
- }
5010
+ submitDraft();
5011
+ };
5012
+ const handleEditPendingFollowUp = React22.useCallback(
5013
+ (id) => {
5014
+ const item = pendingFollowUps.find(
5015
+ (entry) => entry.id === id && entry.mode === "queue"
5016
+ );
5017
+ if (!item) {
5018
+ return;
3141
5019
  }
5020
+ const text = item.request?.input?.input?.trim() ?? "";
5021
+ const nextReferences = normalizeReferences(
5022
+ item.request?.input?.references
5023
+ );
5024
+ stream.removePendingFollowUp(id);
5025
+ setDraft(text);
5026
+ setReferences(nextReferences);
5027
+ requestAnimationFrame(() => {
5028
+ const input = composerInputRef.current;
5029
+ if (!input) {
5030
+ return;
5031
+ }
5032
+ input.focus();
5033
+ const position = text.length;
5034
+ input.setSelectionRange(position, position);
5035
+ });
5036
+ },
5037
+ [pendingFollowUps, stream]
5038
+ );
5039
+ const handleQuoteSelection = React22.useCallback(() => {
5040
+ if (!quoteSelection) {
5041
+ return;
5042
+ }
5043
+ setReferences(
5044
+ (previous) => mergeReferences(previous, [quoteSelection.reference])
3142
5045
  );
3143
- scrollToBottom(true, true);
3144
- if (selectedTool && !selectedTool.pinned) {
3145
- setSelectedTool(null);
5046
+ clearQuoteSelection();
5047
+ if (typeof window !== "undefined") {
5048
+ window.getSelection()?.removeAllRanges();
3146
5049
  }
3147
- setAttachments([]);
3148
- };
5050
+ composerInputRef.current?.focus();
5051
+ }, [clearQuoteSelection, quoteSelection]);
3149
5052
  const handleAttachmentClick = () => {
3150
5053
  fileInputRef.current?.click();
3151
5054
  };
3152
- const uploadFile = React20.useCallback(async (localId, file) => {
3153
- try {
3154
- const result = await stream.client.contexts.uploadFile(file);
3155
- setAttachments(
3156
- (prev) => prev.map(
3157
- (item) => item.localId === localId ? { ...item, status: "success", storageFile: result } : item
3158
- )
5055
+ const uploadContextFile = React22.useCallback(
5056
+ (file) => stream.client.contexts.uploadFile(file),
5057
+ [stream.client]
5058
+ );
5059
+ const handleComposerKeyDown = (event) => {
5060
+ if (event.key !== "Enter") {
5061
+ return;
5062
+ }
5063
+ if (event.shiftKey) {
5064
+ return;
5065
+ }
5066
+ if (event.nativeEvent.isComposing) {
5067
+ return;
5068
+ }
5069
+ event.preventDefault();
5070
+ if (isSendDisabled) {
5071
+ return;
5072
+ }
5073
+ if (stream.isLoading) {
5074
+ submitDraft(
5075
+ getBusyComposerShortcutFollowUpMode(event.metaKey || event.ctrlKey)
5076
+ );
5077
+ return;
5078
+ }
5079
+ submitDraft();
5080
+ };
5081
+ const handleComposerPaste = React22.useCallback(
5082
+ (event) => {
5083
+ const clipboardData = event.clipboardData;
5084
+ if (!clipboardData) {
5085
+ return;
5086
+ }
5087
+ const imageFiles = Array.from(clipboardData.items).filter(
5088
+ (item) => item.kind === "file" && item.type.startsWith("image/")
5089
+ ).map((item) => item.getAsFile()).filter((item) => Boolean(item));
5090
+ if (imageFiles.length > 0) {
5091
+ event.preventDefault();
5092
+ const maxCount = composer?.attachments?.maxCount ?? 10;
5093
+ const maxSize = composer?.attachments?.maxSize ?? 100 * 1024 * 1024;
5094
+ const currentImageReferenceCount = references.filter(
5095
+ (reference) => reference.type === "image"
5096
+ ).length;
5097
+ const availableSlots = Math.max(
5098
+ 0,
5099
+ maxCount - currentImageReferenceCount
5100
+ );
5101
+ const nextFiles = imageFiles.filter((file) => file.size <= maxSize).slice(0, availableSlots);
5102
+ if (nextFiles.length === 0) {
5103
+ return;
5104
+ }
5105
+ setIsUploadingReferenceImages(true);
5106
+ void Promise.allSettled(
5107
+ nextFiles.map(async (file) => {
5108
+ const [dimensions, storageFile] = await Promise.all([
5109
+ readImageDimensions(file),
5110
+ uploadContextFile(file)
5111
+ ]);
5112
+ return buildPastedImageReference(file, storageFile, dimensions);
5113
+ })
5114
+ ).then((results) => {
5115
+ const nextReferences = results.filter(
5116
+ (result) => result.status === "fulfilled"
5117
+ ).map((result) => result.value);
5118
+ if (nextReferences.length > 0) {
5119
+ setReferences(
5120
+ (previous) => mergeReferences(previous, nextReferences)
5121
+ );
5122
+ composerInputRef.current?.focus();
5123
+ }
5124
+ results.filter(
5125
+ (result) => result.status === "rejected"
5126
+ ).forEach((result) => {
5127
+ console.warn(
5128
+ "[Chat] Failed to upload pasted image reference:",
5129
+ result.reason
5130
+ );
5131
+ });
5132
+ }).finally(() => {
5133
+ setIsUploadingReferenceImages(false);
5134
+ });
5135
+ return;
5136
+ }
5137
+ const pastedText = clipboardData.getData("text/plain");
5138
+ if (pastedText.trim().length <= LONG_TEXT_REFERENCE_THRESHOLD) {
5139
+ return;
5140
+ }
5141
+ event.preventDefault();
5142
+ setReferences(
5143
+ (previous) => mergeReferences(previous, [
5144
+ {
5145
+ type: "quote",
5146
+ source: "Pasted text",
5147
+ text: pastedText
5148
+ }
5149
+ ])
3159
5150
  );
3160
- } catch (error) {
5151
+ composerInputRef.current?.focus();
5152
+ },
5153
+ [
5154
+ composer?.attachments?.maxCount,
5155
+ composer?.attachments?.maxSize,
5156
+ references,
5157
+ uploadContextFile
5158
+ ]
5159
+ );
5160
+ const alternateFollowUpShortcutLabel = React22.useMemo(() => {
5161
+ if (typeof navigator === "undefined") {
5162
+ return "\u2318Enter";
5163
+ }
5164
+ const platform = navigator.platform || navigator.userAgent;
5165
+ return /Mac|iPhone|iPad|iPod/i.test(platform) ? "\u2318Enter" : "Ctrl+Enter";
5166
+ }, []);
5167
+ const followUpShortcutLabels = React22.useMemo(
5168
+ () => getComposerFollowUpShortcutLabels(alternateFollowUpShortcutLabel),
5169
+ [alternateFollowUpShortcutLabel]
5170
+ );
5171
+ const uploadFile = React22.useCallback(
5172
+ async (localId, file) => {
5173
+ try {
5174
+ const result = await uploadContextFile(file);
5175
+ setAttachments(
5176
+ (prev) => prev.map(
5177
+ (item) => item.localId === localId ? { ...item, status: "success", storageFile: result } : item
5178
+ )
5179
+ );
5180
+ } catch (error) {
5181
+ setAttachments(
5182
+ (prev) => prev.map(
5183
+ (item) => item.localId === localId ? {
5184
+ ...item,
5185
+ status: "error",
5186
+ error: error instanceof Error ? error.message : "Upload failed"
5187
+ } : item
5188
+ )
5189
+ );
5190
+ }
5191
+ },
5192
+ [uploadContextFile]
5193
+ );
5194
+ const handleRetryUpload = React22.useCallback(
5195
+ (localId) => {
5196
+ const attachment = attachments.find((a) => a.localId === localId);
5197
+ if (!attachment || attachment.status !== "error") return;
3161
5198
  setAttachments(
3162
5199
  (prev) => prev.map(
3163
- (item) => item.localId === localId ? {
3164
- ...item,
3165
- status: "error",
3166
- error: error instanceof Error ? error.message : "Upload failed"
3167
- } : item
5200
+ (item) => item.localId === localId ? { ...item, status: "uploading", error: void 0 } : item
3168
5201
  )
3169
5202
  );
3170
- }
3171
- }, [stream.client]);
3172
- const handleRetryUpload = React20.useCallback((localId) => {
3173
- const attachment = attachments.find((a) => a.localId === localId);
3174
- if (!attachment || attachment.status !== "error") return;
3175
- setAttachments(
3176
- (prev) => prev.map(
3177
- (item) => item.localId === localId ? { ...item, status: "uploading", error: void 0 } : item
3178
- )
3179
- );
3180
- void uploadFile(localId, attachment.file);
3181
- }, [attachments, uploadFile]);
5203
+ void uploadFile(localId, attachment.file);
5204
+ },
5205
+ [attachments, uploadFile]
5206
+ );
3182
5207
  const handleFileChange = (event) => {
3183
5208
  const files = event.target.files;
3184
5209
  if (!files || files.length === 0) return;
@@ -3212,12 +5237,15 @@ function Chat({
3212
5237
  if (!attachment) return;
3213
5238
  if (attachment.status === "success" && attachment.storageFile?.id) {
3214
5239
  try {
3215
- await fetch(`${stream.apiUrl}/contexts/file/${attachment.storageFile.id}`, {
3216
- method: "DELETE",
3217
- headers: {
3218
- "Authorization": `Bearer ${effectiveClientSecret}`
5240
+ await fetch(
5241
+ `${stream.apiUrl}/contexts/file/${attachment.storageFile.id}`,
5242
+ {
5243
+ method: "DELETE",
5244
+ headers: {
5245
+ Authorization: `Bearer ${effectiveClientSecret}`
5246
+ }
3219
5247
  }
3220
- });
5248
+ );
3221
5249
  } catch {
3222
5250
  }
3223
5251
  }
@@ -3227,27 +5255,31 @@ function Chat({
3227
5255
  setSelectedTool((prev) => prev?.id === tool.id ? null : tool);
3228
5256
  };
3229
5257
  const handlePromptClick = (prompt) => {
3230
- if (missingConfig || stream.isLoading || isHistoryLoading) return;
5258
+ if (missingConfig || isHistoryLoading) return;
3231
5259
  const newMessage = {
3232
5260
  id: createMessageId(),
3233
5261
  type: "human",
3234
5262
  content: prompt
3235
5263
  };
5264
+ const nextFollowUpMode = stream.isLoading ? stream.followUpBehavior : void 0;
3236
5265
  stream.submit(
3237
5266
  { input: { input: prompt } },
3238
5267
  {
3239
- optimisticValues: (prev) => {
3240
- const prevMessages = prev?.messages ?? [];
3241
- return { ...prev, messages: [...prevMessages, newMessage] };
3242
- }
5268
+ ...nextFollowUpMode ? { followUpMode: nextFollowUpMode } : {},
5269
+ ...!nextFollowUpMode ? {
5270
+ optimisticValues: (prev) => {
5271
+ const prevMessages = prev?.messages ?? [];
5272
+ return { ...prev, messages: [...prevMessages, newMessage] };
5273
+ }
5274
+ } : {}
3243
5275
  }
3244
5276
  );
3245
5277
  scrollToBottom(true, true);
3246
5278
  };
3247
- const loadConversationMessages = React20.useCallback(
5279
+ const loadConversationMessages = React22.useCallback(
3248
5280
  async (recordId) => {
3249
5281
  if (missingConfig) {
3250
- setHistoryError(t("chat.missingConfigShort"));
5282
+ setHistoryError(missingConfigShortMessage);
3251
5283
  return;
3252
5284
  }
3253
5285
  setHistoryError(null);
@@ -3263,7 +5295,7 @@ function Chat({
3263
5295
  setIsHistoryLoading(false);
3264
5296
  }
3265
5297
  },
3266
- [missingConfig, stream, t]
5298
+ [missingConfig, missingConfigShortMessage, stream, t]
3267
5299
  );
3268
5300
  const handleNewThread = async () => {
3269
5301
  if (missingConfig || isHistoryLoading) return;
@@ -3306,12 +5338,16 @@ function Chat({
3306
5338
  };
3307
5339
  const handleRetry = (messageIndex) => {
3308
5340
  const messagesUpToIndex = messages.slice(0, messageIndex);
3309
- const lastHumanMessage = [...messagesUpToIndex].reverse().find(
3310
- (m) => String(m.type) === "human"
3311
- );
3312
- if (lastHumanMessage && typeof lastHumanMessage.content === "string") {
5341
+ const lastHumanMessage = [...messagesUpToIndex].reverse().find((m) => String(m.type) === "human");
5342
+ const humanInput = buildHumanMessageInputPayload({
5343
+ content: lastHumanMessage && typeof lastHumanMessage.content === "string" ? lastHumanMessage.content : "",
5344
+ submittedInput: lastHumanMessage?.submittedInput,
5345
+ references: lastHumanMessage?.references,
5346
+ referenceComposition: lastHumanMessage?.referenceComposition
5347
+ });
5348
+ if (humanInput) {
3313
5349
  stream.submit(
3314
- { input: { input: lastHumanMessage.content } },
5350
+ { input: humanInput },
3315
5351
  {
3316
5352
  optimisticValues: (prev) => {
3317
5353
  const prevMessages = prev?.messages ?? [];
@@ -3326,18 +5362,18 @@ function Chat({
3326
5362
  }
3327
5363
  };
3328
5364
  const acceptMimes = composer?.attachments?.accept ? Object.entries(composer.attachments.accept).map(([mime, exts]) => [mime, ...exts.map((e) => `.${e}`)].join(",")).join(",") : void 0;
3329
- const currentThread = React20.useMemo(
5365
+ const currentThread = React22.useMemo(
3330
5366
  () => threads.find((item) => item.id === stream.threadId),
3331
5367
  [threads, stream.threadId]
3332
5368
  );
3333
5369
  const errorMessage = stream.error instanceof Error ? stream.error.message : void 0;
3334
- const threadErrorMessage = React20.useMemo(() => {
5370
+ const threadErrorMessage = React22.useMemo(() => {
3335
5371
  if (currentThread?.status !== "error") return void 0;
3336
5372
  const message = currentThread.error?.trim();
3337
5373
  return message || t("thread.errorToast");
3338
5374
  }, [currentThread, t]);
3339
5375
  const assistantTitle = assistantName || resolvedTitle;
3340
- return /* @__PURE__ */ jsxs14(
5376
+ return /* @__PURE__ */ jsxs17(
3341
5377
  "div",
3342
5378
  {
3343
5379
  ref: viewportRef,
@@ -3346,10 +5382,10 @@ function Chat({
3346
5382
  className
3347
5383
  ),
3348
5384
  children: [
3349
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between border-b p-2 sticky top-0 z-10 bg-background", children: [
3350
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-3 overflow-hidden", children: [
3351
- /* @__PURE__ */ jsxs14("div", { className: "relative shrink-0", children: [
3352
- /* @__PURE__ */ jsx26(
5385
+ /* @__PURE__ */ jsxs17("div", { className: "flex items-center justify-between border-b p-2 sticky top-0 z-10 bg-background", children: [
5386
+ /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-3 overflow-hidden", children: [
5387
+ /* @__PURE__ */ jsxs17("div", { className: "relative shrink-0", children: [
5388
+ /* @__PURE__ */ jsx28(
3353
5389
  ChatkitAvatar,
3354
5390
  {
3355
5391
  avatar: assistantAvatar,
@@ -3357,15 +5393,22 @@ function Chat({
3357
5393
  label: assistantTitle
3358
5394
  }
3359
5395
  ),
3360
- /* @__PURE__ */ jsx26("span", { className: "absolute bottom-0 right-0 h-2.5 w-2.5 rounded-full border-2 border-background bg-green-500" })
5396
+ /* @__PURE__ */ jsx28("span", { className: "absolute bottom-0 right-0 h-2.5 w-2.5 rounded-full border-2 border-background bg-green-500" })
3361
5397
  ] }),
3362
- /* @__PURE__ */ jsxs14("div", { className: "truncate", children: [
3363
- /* @__PURE__ */ jsx26("h2", { className: "text-lg font-semibold truncate", title: assistantTitle, children: assistantTitle }),
3364
- /* @__PURE__ */ jsx26("p", { className: "text-xs text-muted-foreground", children: t("chat.statusOnline") })
5398
+ /* @__PURE__ */ jsxs17("div", { className: "truncate", children: [
5399
+ /* @__PURE__ */ jsx28(
5400
+ "h2",
5401
+ {
5402
+ className: "text-lg font-semibold truncate",
5403
+ title: assistantTitle,
5404
+ children: assistantTitle
5405
+ }
5406
+ ),
5407
+ /* @__PURE__ */ jsx28("p", { className: "text-xs text-muted-foreground", children: t("chat.statusOnline") })
3365
5408
  ] })
3366
5409
  ] }),
3367
- history?.enabled !== false && /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1", children: [
3368
- /* @__PURE__ */ jsx26(
5410
+ history?.enabled !== false && /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-1", children: [
5411
+ /* @__PURE__ */ jsx28(
3369
5412
  "button",
3370
5413
  {
3371
5414
  type: "button",
@@ -3378,10 +5421,10 @@ function Chat({
3378
5421
  "disabled:opacity-50 disabled:cursor-not-allowed"
3379
5422
  ),
3380
5423
  title: t("history.newThread"),
3381
- children: /* @__PURE__ */ jsx26(Pencil3, { size: 16 })
5424
+ children: /* @__PURE__ */ jsx28(Pencil3, { size: 16 })
3382
5425
  }
3383
5426
  ),
3384
- /* @__PURE__ */ jsx26(
5427
+ /* @__PURE__ */ jsx28(
3385
5428
  HistorySidebar,
3386
5429
  {
3387
5430
  threads,
@@ -3395,23 +5438,45 @@ function Chat({
3395
5438
  )
3396
5439
  ] })
3397
5440
  ] }),
3398
- /* @__PURE__ */ jsxs14("div", { className: "flex-1 p-4", children: [
3399
- errorMessage && /* @__PURE__ */ jsx26("div", { className: "mb-4 rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: errorMessage }),
3400
- historyError && /* @__PURE__ */ jsx26("div", { className: "mb-4 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900", children: historyError }),
3401
- showMissingConfig && /* @__PURE__ */ jsx26("div", { className: "mb-4 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900", children: t("chat.missingConfigDetail") }),
3402
- isHistoryLoading && /* @__PURE__ */ jsx26("div", { className: "mb-4 rounded-lg border border-muted px-3 py-2 text-sm text-muted-foreground", children: t("chat.loadingThread") }),
3403
- messages.length === 0 ? /* @__PURE__ */ jsx26(
5441
+ /* @__PURE__ */ jsxs17("div", { className: "flex-1 p-4", children: [
5442
+ errorMessage && /* @__PURE__ */ jsx28("div", { className: "mb-4 rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: errorMessage }),
5443
+ historyError && /* @__PURE__ */ jsx28("div", { className: "mb-4 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900", children: historyError }),
5444
+ showMissingConfig && /* @__PURE__ */ jsx28("div", { className: "mb-4 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900", children: missingConfigDetailMessage }),
5445
+ isHistoryLoading && /* @__PURE__ */ jsx28("div", { className: "mb-4 rounded-lg border border-muted px-3 py-2 text-sm text-muted-foreground", children: t("chat.loadingThread") }),
5446
+ messages.length === 0 ? /* @__PURE__ */ jsx28(
3404
5447
  StartScreen,
3405
5448
  {
3406
5449
  startScreen,
3407
5450
  onPromptClick: handlePromptClick
3408
5451
  }
3409
- ) : /* @__PURE__ */ jsxs14("div", { className: "space-y-4", children: [
5452
+ ) : /* @__PURE__ */ jsxs17("div", { className: "space-y-4", children: [
3410
5453
  messages.map((message, index) => {
3411
5454
  const messageType = String(message.type);
3412
5455
  const isAssistantMessage = messageType === "assistant" || messageType === "ai";
5456
+ const isStreamingMessage = stream.isLoading && index === messages.length - 1;
5457
+ const streamingStatus = isAssistantMessage ? getAssistantStreamingStatus(
5458
+ {
5459
+ ...message,
5460
+ lastStreamOutputAt: lastStreamOutputAtRef.current
5461
+ },
5462
+ isStreamingMessage,
5463
+ { now: streamingNow }
5464
+ ) : null;
5465
+ if (isAssistantMessage && !hasRenderableAssistantMessage(message) && !streamingStatus) {
5466
+ return null;
5467
+ }
3413
5468
  const messageContent = typeof message.content === "string" ? message.content : Array.isArray(message.content) ? message.content.map((part) => formatMessageContent(part)).join("") : formatMessageContent(message.content);
3414
- return /* @__PURE__ */ jsx26(
5469
+ const hasPlainRenderableContent = messageContent.trim().length > 0;
5470
+ const humanMessage = message;
5471
+ const humanReferences = humanMessage.references ?? [];
5472
+ const humanAttachments = humanMessage.attachments ?? [];
5473
+ const hasHumanAttachments = message.type === "human" && humanAttachments.length > 0;
5474
+ const canQuoteMessage = message.type === "human" || isAssistantMessage;
5475
+ const quoteSource = message.type === "human" ? t("chat.youLabel") : assistantTitle;
5476
+ if (!isAssistantMessage && !hasPlainRenderableContent && !hasHumanAttachments && humanReferences.length === 0) {
5477
+ return null;
5478
+ }
5479
+ return /* @__PURE__ */ jsx28(
3415
5480
  "div",
3416
5481
  {
3417
5482
  className: cn(
@@ -3419,53 +5484,66 @@ function Chat({
3419
5484
  message.type === "human" ? "justify-end" : "justify-start -ml-1"
3420
5485
  // AI messages: slightly closer to left
3421
5486
  ),
3422
- children: /* @__PURE__ */ jsxs14("div", { className: "flex flex-col px-3 overflow-hidden", children: [
3423
- /* @__PURE__ */ jsx26(
5487
+ children: /* @__PURE__ */ jsxs17("div", { className: "flex flex-col px-3 overflow-hidden", children: [
5488
+ /* @__PURE__ */ jsx28(
3424
5489
  "div",
3425
5490
  {
5491
+ ...canQuoteMessage ? {
5492
+ "data-quote-message-id": message.id,
5493
+ "data-quote-source": quoteSource
5494
+ } : {},
3426
5495
  className: cn(
3427
5496
  "max-w-full rounded-2xl",
3428
5497
  message.type === "human" ? "bg-primary text-primary-foreground px-4 py-2.5" : message.type === "system" ? "bg-muted text-muted-foreground text-xs px-4 py-2.5" : "py-1 text-chat-foreground"
3429
5498
  // AI messages: use chat-specific foreground color
3430
5499
  ),
3431
- children: isAssistantMessage ? /* @__PURE__ */ jsx26(
5500
+ children: isAssistantMessage ? /* @__PURE__ */ jsx28(
3432
5501
  AssistantMessage,
3433
5502
  {
3434
5503
  message: {
3435
5504
  ...message,
3436
5505
  type: "assistant"
3437
5506
  },
3438
- isStreaming: stream.isLoading && index === messages.length - 1
5507
+ isStreaming: isStreamingMessage,
5508
+ streamingStatus
3439
5509
  }
3440
- ) : /* @__PURE__ */ jsxs14(Fragment3, { children: [
3441
- message.type === "human" && message.attachments?.length > 0 && /* @__PURE__ */ jsx26("div", { className: "flex flex-wrap gap-1.5 mb-2", children: message.attachments.map((file, fileIndex) => /* @__PURE__ */ jsxs14(
5510
+ ) : /* @__PURE__ */ jsxs17(Fragment4, { children: [
5511
+ message.type === "human" && humanReferences.length > 0 && /* @__PURE__ */ jsx28("div", { className: "mb-2 flex flex-wrap gap-1.5", children: humanReferences.map((reference) => /* @__PURE__ */ jsx28(
5512
+ ReferenceChip,
5513
+ {
5514
+ reference,
5515
+ variant: "message"
5516
+ },
5517
+ getReferenceKey(reference)
5518
+ )) }),
5519
+ message.type === "human" && humanAttachments.length > 0 && /* @__PURE__ */ jsx28("div", { className: "flex flex-wrap gap-1.5 mb-2", children: humanAttachments.map((file, fileIndex) => /* @__PURE__ */ jsxs17(
3442
5520
  "div",
3443
5521
  {
3444
5522
  className: "flex items-center gap-1.5 rounded-md bg-primary-foreground/20 px-2 py-1 text-xs",
3445
5523
  children: [
3446
- /* @__PURE__ */ jsx26(FileText2, { size: 12 }),
3447
- /* @__PURE__ */ jsx26("span", { className: "max-w-[100px] truncate", children: file.originalName })
5524
+ /* @__PURE__ */ jsx28(FileText2, { size: 12 }),
5525
+ /* @__PURE__ */ jsx28("span", { className: "max-w-[100px] truncate", children: file.originalName })
3448
5526
  ]
3449
5527
  },
3450
5528
  fileIndex
3451
5529
  )) }),
3452
- Array.isArray(message.content) ? message.content.map((part, partIndex) => /* @__PURE__ */ jsx26(
5530
+ Array.isArray(message.content) ? message.content.map((part, partIndex) => /* @__PURE__ */ jsx28(
3453
5531
  "p",
3454
5532
  {
3455
5533
  className: "wrap-break-word text-sm leading-relaxed",
3456
5534
  children: formatMessageContent(part)
3457
5535
  },
3458
5536
  `${part.type}-${partIndex}`
3459
- )) : /* @__PURE__ */ jsx26("span", { className: "wrap-break-word text-sm leading-relaxed", children: formatMessageContent(message.content) })
5537
+ )) : /* @__PURE__ */ jsx28("span", { className: "wrap-break-word text-sm leading-relaxed", children: formatMessageContent(message.content) })
3460
5538
  ] })
3461
5539
  }
3462
5540
  ),
3463
- /* @__PURE__ */ jsx26(
5541
+ /* @__PURE__ */ jsx28(
3464
5542
  MessageActions,
3465
5543
  {
3466
5544
  content: messageContent,
3467
5545
  isAssistant: isAssistantMessage,
3468
- isStreaming: stream.isLoading && index === messages.length - 1,
5546
+ isStreaming: isStreamingMessage,
3469
5547
  onRetry: isAssistantMessage && !stream.isLoading && index === messages.length - 1 ? () => handleRetry(index) : void 0
3470
5548
  }
3471
5549
  )
@@ -3478,18 +5556,34 @@ function Chat({
3478
5556
  const lastMessage = messages[messages.length - 1];
3479
5557
  const lastMessageType = lastMessage ? String(lastMessage.type) : "";
3480
5558
  const isLastMessageFromAI = lastMessageType === "ai" || lastMessageType === "assistant";
3481
- const lastMsgContent = lastMessage?.content;
3482
- const hasSubstantialContent = isLastMessageFromAI && (typeof lastMsgContent === "string" && lastMsgContent.length > 10 || Array.isArray(lastMsgContent) && lastMsgContent.length > 0);
3483
- if (hasSubstantialContent) return null;
3484
- return /* @__PURE__ */ jsx26("div", { className: "flex justify-start gap-3 -ml-2", children: /* @__PURE__ */ jsx26("div", { className: "max-w-full rounded-2xl py-2.5", children: /* @__PURE__ */ jsxs14("div", { className: "flex gap-1.5", children: [
3485
- /* @__PURE__ */ jsx26("div", { className: "h-2 w-2 animate-bounce rounded-full bg-muted-foreground/60 [animation-delay:-0.3s]" }),
3486
- /* @__PURE__ */ jsx26("div", { className: "h-2 w-2 animate-bounce rounded-full bg-muted-foreground/60 [animation-delay:-0.15s]" }),
3487
- /* @__PURE__ */ jsx26("div", { className: "h-2 w-2 animate-bounce rounded-full bg-muted-foreground/60" })
3488
- ] }) }) });
5559
+ const lastAssistantStatus = isLastMessageFromAI ? getAssistantStreamingStatus(
5560
+ {
5561
+ ...lastMessage,
5562
+ lastStreamOutputAt: lastStreamOutputAtRef.current
5563
+ },
5564
+ stream.isLoading,
5565
+ { now: streamingNow }
5566
+ ) : null;
5567
+ if (lastAssistantStatus) return null;
5568
+ const fallbackStreamingStatus = getAssistantStreamingStatus(
5569
+ {
5570
+ status: void 0,
5571
+ reasoning: void 0,
5572
+ lastStreamOutputAt: lastStreamOutputAtRef.current
5573
+ },
5574
+ stream.isLoading,
5575
+ { now: streamingNow }
5576
+ );
5577
+ return /* @__PURE__ */ jsx28("div", { className: "flex justify-start gap-3 -ml-2", children: /* @__PURE__ */ jsx28("div", { className: "max-w-full rounded-2xl py-2.5", children: /* @__PURE__ */ jsx28(
5578
+ AssistantStreamingIndicator,
5579
+ {
5580
+ status: fallbackStreamingStatus ?? "loading"
5581
+ }
5582
+ ) }) });
3489
5583
  })()
3490
5584
  ] })
3491
5585
  ] }),
3492
- !isAtBottom && messages.length > 0 && /* @__PURE__ */ jsx26("div", { className: "sticky bottom-20 z-20 flex justify-center px-4 pointer-events-none", children: /* @__PURE__ */ jsx26(
5586
+ !isAtBottom && messages.length > 0 && /* @__PURE__ */ jsx28("div", { className: "sticky bottom-20 z-20 flex justify-center px-4 pointer-events-none", children: /* @__PURE__ */ jsx28(
3493
5587
  Button,
3494
5588
  {
3495
5589
  type: "button",
@@ -3502,12 +5596,40 @@ function Chat({
3502
5596
  onClick: () => scrollToBottom(true, true),
3503
5597
  "aria-label": t("chat.scrollToBottom"),
3504
5598
  title: t("chat.scrollToBottom"),
3505
- children: /* @__PURE__ */ jsx26(ArrowDown, { size: 16 })
5599
+ children: /* @__PURE__ */ jsx28(ArrowDown, { size: 16 })
3506
5600
  }
3507
5601
  ) }),
3508
- /* @__PURE__ */ jsxs14("div", { className: "p-2 sticky bottom-0 z-10 bg-background", children: [
3509
- threadErrorMessage && /* @__PURE__ */ jsx26("div", { className: "mb-3 rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: threadErrorMessage }),
3510
- /* @__PURE__ */ jsx26(
5602
+ quoteSelection && /* @__PURE__ */ jsx28(
5603
+ "div",
5604
+ {
5605
+ className: "pointer-events-none fixed z-50",
5606
+ style: {
5607
+ top: `${quoteSelection.top}px`,
5608
+ left: `${quoteSelection.left}px`,
5609
+ transform: "translateX(-50%)"
5610
+ },
5611
+ children: /* @__PURE__ */ jsxs17(
5612
+ Button,
5613
+ {
5614
+ type: "button",
5615
+ size: "sm",
5616
+ variant: "secondary",
5617
+ className: "pointer-events-auto shadow-lg",
5618
+ onMouseDown: (event) => event.preventDefault(),
5619
+ onClick: handleQuoteSelection,
5620
+ "aria-label": t("composer.quoteSelection"),
5621
+ title: t("composer.quoteSelection"),
5622
+ children: [
5623
+ /* @__PURE__ */ jsx28(Quote, { size: 14 }),
5624
+ t("composer.quoteSelection")
5625
+ ]
5626
+ }
5627
+ )
5628
+ }
5629
+ ),
5630
+ /* @__PURE__ */ jsxs17("div", { className: "p-2 sticky bottom-0 z-10 bg-background", children: [
5631
+ threadErrorMessage && /* @__PURE__ */ jsx28("div", { className: "mb-3 rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive overflow-auto", children: threadErrorMessage }),
5632
+ /* @__PURE__ */ jsx28(
3511
5633
  "input",
3512
5634
  {
3513
5635
  ref: fileInputRef,
@@ -3518,7 +5640,7 @@ function Chat({
3518
5640
  className: "hidden"
3519
5641
  }
3520
5642
  ),
3521
- attachments.length > 0 && /* @__PURE__ */ jsx26("div", { className: "mb-3 flex flex-wrap gap-2", children: attachments.map((item) => /* @__PURE__ */ jsxs14(
5643
+ attachments.length > 0 && /* @__PURE__ */ jsx28("div", { className: "mb-3 flex flex-wrap gap-2", children: attachments.map((item) => /* @__PURE__ */ jsxs17(
3522
5644
  "div",
3523
5645
  {
3524
5646
  className: cn(
@@ -3526,24 +5648,36 @@ function Chat({
3526
5648
  item.status === "error" ? "bg-destructive/10 border border-destructive/30" : "bg-muted"
3527
5649
  ),
3528
5650
  children: [
3529
- item.status === "uploading" && /* @__PURE__ */ jsx26(Loader22, { size: 14, className: "animate-spin text-muted-foreground" }),
3530
- item.status === "success" && /* @__PURE__ */ jsx26(FileText2, { size: 14, className: "text-muted-foreground" }),
3531
- item.status === "error" && /* @__PURE__ */ jsx26(FileText2, { size: 14, className: "text-destructive" }),
3532
- /* @__PURE__ */ jsx26("span", { className: cn(
3533
- "max-w-30 truncate",
3534
- item.status === "error" && "text-destructive"
3535
- ), children: item.file.name }),
3536
- item.status === "error" && /* @__PURE__ */ jsx26(
5651
+ item.status === "uploading" && /* @__PURE__ */ jsx28(
5652
+ Loader23,
5653
+ {
5654
+ size: 14,
5655
+ className: "animate-spin text-muted-foreground"
5656
+ }
5657
+ ),
5658
+ item.status === "success" && /* @__PURE__ */ jsx28(FileText2, { size: 14, className: "text-muted-foreground" }),
5659
+ item.status === "error" && /* @__PURE__ */ jsx28(FileText2, { size: 14, className: "text-destructive" }),
5660
+ /* @__PURE__ */ jsx28(
5661
+ "span",
5662
+ {
5663
+ className: cn(
5664
+ "max-w-30 truncate",
5665
+ item.status === "error" && "text-destructive"
5666
+ ),
5667
+ children: item.file.name
5668
+ }
5669
+ ),
5670
+ item.status === "error" && /* @__PURE__ */ jsx28(
3537
5671
  "button",
3538
5672
  {
3539
5673
  type: "button",
3540
5674
  onClick: () => handleRetryUpload(item.localId),
3541
5675
  className: "ml-1 rounded-full p-0.5 text-destructive hover:bg-destructive/20",
3542
5676
  title: t("chat.retryUpload"),
3543
- children: /* @__PURE__ */ jsx26(RefreshCw2, { size: 12 })
5677
+ children: /* @__PURE__ */ jsx28(RefreshCw2, { size: 12 })
3544
5678
  }
3545
5679
  ),
3546
- /* @__PURE__ */ jsx26(
5680
+ /* @__PURE__ */ jsx28(
3547
5681
  "button",
3548
5682
  {
3549
5683
  type: "button",
@@ -3552,76 +5686,118 @@ function Chat({
3552
5686
  "ml-1 rounded-full p-0.5",
3553
5687
  item.status === "error" ? "text-destructive hover:bg-destructive/20" : "hover:bg-muted-foreground/20"
3554
5688
  ),
3555
- children: /* @__PURE__ */ jsx26(X2, { size: 12 })
5689
+ children: /* @__PURE__ */ jsx28(X3, { size: 12 })
3556
5690
  }
3557
5691
  )
3558
5692
  ]
3559
5693
  },
3560
5694
  item.localId
3561
5695
  )) }),
3562
- selectedTool && /* @__PURE__ */ jsxs14("div", { className: "mb-2 flex items-center gap-2", children: [
3563
- /* @__PURE__ */ jsx26("span", { className: "rounded-full bg-primary/10 px-2 py-0.5 text-xs font-medium text-primary", children: selectedTool.shortLabel ?? selectedTool.label }),
3564
- /* @__PURE__ */ jsx26(
5696
+ references.length > 0 && /* @__PURE__ */ jsx28("div", { className: "mb-3 flex flex-wrap gap-2", children: references.map((reference) => /* @__PURE__ */ jsx28(
5697
+ ReferenceChip,
5698
+ {
5699
+ reference,
5700
+ variant: "composer",
5701
+ onRemove: () => setReferences(
5702
+ (previous) => previous.filter(
5703
+ (item) => getReferenceKey(item) !== getReferenceKey(reference)
5704
+ )
5705
+ ),
5706
+ removeLabel: t("composer.removeReference")
5707
+ },
5708
+ getReferenceKey(reference)
5709
+ )) }),
5710
+ selectedTool && /* @__PURE__ */ jsxs17("div", { className: "mb-2 flex items-center gap-2", children: [
5711
+ /* @__PURE__ */ jsx28("span", { className: "rounded-full bg-primary/10 px-2 py-0.5 text-xs font-medium text-primary", children: selectedTool.shortLabel ?? selectedTool.label }),
5712
+ /* @__PURE__ */ jsx28(
3565
5713
  "button",
3566
5714
  {
3567
5715
  type: "button",
3568
5716
  onClick: () => setSelectedTool(null),
3569
5717
  className: "rounded-full p-0.5 text-muted-foreground hover:bg-muted",
3570
- children: /* @__PURE__ */ jsx26(X2, { size: 12 })
5718
+ children: /* @__PURE__ */ jsx28(X3, { size: 12 })
3571
5719
  }
3572
5720
  )
3573
5721
  ] }),
3574
- /* @__PURE__ */ jsx26("form", { className: "flex items-center", onSubmit: handleSubmit, children: /* @__PURE__ */ jsxs14(
5722
+ /* @__PURE__ */ jsx28(
5723
+ PendingFollowUps,
5724
+ {
5725
+ items: pendingFollowUps,
5726
+ isLoading: stream.isLoading,
5727
+ followUpBehavior: stream.followUpBehavior,
5728
+ onBehaviorChange: stream.setFollowUpBehavior,
5729
+ onPromoteToSteer: (id) => stream.promotePendingFollowUpToSteer(id),
5730
+ canSendNow: stream.canSendPendingFollowUpNow,
5731
+ onSendNow: (id) => stream.sendPendingFollowUpNow(id),
5732
+ onEdit: handleEditPendingFollowUp,
5733
+ onRemove: stream.removePendingFollowUp
5734
+ }
5735
+ ),
5736
+ /* @__PURE__ */ jsx28("form", { className: "flex items-end", onSubmit: handleSubmit, children: /* @__PURE__ */ jsxs17(
3575
5737
  "div",
3576
5738
  {
3577
5739
  className: cn(
3578
- "flex flex-1 items-center gap-1 rounded-xl",
5740
+ "flex flex-1 items-end gap-1 rounded-xl",
3579
5741
  "bg-background border border-border shadow-sm",
3580
5742
  "pl-1.5 pr-1.5 py-1",
3581
5743
  "focus-within:border-muted-foreground/30 focus-within:shadow-md",
3582
- "transition-shadow duration-200"
5744
+ "transition-shadow duration-200",
5745
+ getRoundedClass(theme.radius)
3583
5746
  ),
3584
5747
  children: [
3585
- /* @__PURE__ */ jsx26(
5748
+ /* @__PURE__ */ jsx28(
3586
5749
  ComposerMenu,
3587
5750
  {
3588
5751
  composer,
3589
5752
  onAttachmentClick: handleAttachmentClick,
3590
5753
  onToolSelect: handleToolSelect,
3591
5754
  selectedTool,
3592
- disabled: stream.isLoading || missingConfig || isHistoryLoading
5755
+ disabled: missingConfig || isHistoryLoading
3593
5756
  }
3594
5757
  ),
3595
- /* @__PURE__ */ jsx26(
3596
- "input",
5758
+ /* @__PURE__ */ jsx28(
5759
+ "textarea",
3597
5760
  {
3598
- type: "text",
5761
+ ref: composerInputRef,
3599
5762
  value: draft,
3600
5763
  onChange: (event) => setDraft(event.target.value),
5764
+ onPaste: handleComposerPaste,
5765
+ onKeyDown: handleComposerKeyDown,
5766
+ rows: 1,
3601
5767
  placeholder: inputPlaceholder,
3602
- disabled: stream.isLoading || missingConfig || isHistoryLoading,
5768
+ disabled: missingConfig || isHistoryLoading,
3603
5769
  className: cn(
3604
- "flex-1 bg-transparent text-sm text-foreground outline-none pr-2",
5770
+ "min-h-8 max-h-32 flex-1 resize-none bg-transparent py-1 pr-2 text-sm leading-5 text-foreground outline-none",
3605
5771
  "placeholder:text-muted-foreground",
3606
5772
  "disabled:cursor-not-allowed disabled:opacity-50"
3607
- ),
3608
- autoComplete: "off"
5773
+ )
3609
5774
  }
3610
5775
  ),
3611
- /* @__PURE__ */ jsx26(
5776
+ /* @__PURE__ */ jsx28(
3612
5777
  SendButton,
3613
5778
  {
3614
5779
  disabled: isSendDisabled,
3615
5780
  isLoading: stream.isLoading,
5781
+ showStop: stream.isLoading && !trimmedDraft,
3616
5782
  onStop: () => stream.stop(),
3617
5783
  stopLabel: t("chat.stop"),
3618
- sendLabel: t("chat.send")
5784
+ sendLabel: t("chat.send"),
5785
+ shortcuts: stream.isLoading && trimmedDraft ? [
5786
+ {
5787
+ label: t("chat.followUps.steer"),
5788
+ keys: followUpShortcutLabels.steer
5789
+ },
5790
+ {
5791
+ label: t("chat.followUps.queue"),
5792
+ keys: followUpShortcutLabels.queue
5793
+ }
5794
+ ] : void 0
3619
5795
  }
3620
5796
  )
3621
5797
  ]
3622
5798
  }
3623
5799
  ) }),
3624
- disclaimer?.text && /* @__PURE__ */ jsx26(
5800
+ disclaimer?.text && /* @__PURE__ */ jsx28(
3625
5801
  "p",
3626
5802
  {
3627
5803
  className: cn(
@@ -3631,9 +5807,9 @@ function Chat({
3631
5807
  children: disclaimer.text
3632
5808
  }
3633
5809
  ),
3634
- /* @__PURE__ */ jsxs14("div", { className: "mt-2 flex items-center justify-center gap-2 text-xs text-muted-foreground", children: [
3635
- /* @__PURE__ */ jsx26("span", { children: t("chat.poweredBy") }),
3636
- /* @__PURE__ */ jsx26(ContextUsageIndicator, { className: "absolute right-4" })
5810
+ /* @__PURE__ */ jsxs17("div", { className: "mt-2 flex items-center justify-center gap-2 text-xs text-muted-foreground", children: [
5811
+ /* @__PURE__ */ jsx28("span", { children: t("chat.poweredBy") }),
5812
+ /* @__PURE__ */ jsx28(ContextUsageIndicator, { className: "absolute right-4" })
3637
5813
  ] })
3638
5814
  ] })
3639
5815
  ]
@@ -3642,11 +5818,11 @@ function Chat({
3642
5818
  }
3643
5819
 
3644
5820
  // src/components/ui/input.tsx
3645
- import * as React21 from "react";
3646
- import { jsx as jsx27 } from "react/jsx-runtime";
3647
- var Input = React21.forwardRef(
5821
+ import * as React23 from "react";
5822
+ import { jsx as jsx29 } from "react/jsx-runtime";
5823
+ var Input = React23.forwardRef(
3648
5824
  ({ className, type, ...props }, ref) => {
3649
- return /* @__PURE__ */ jsx27(
5825
+ return /* @__PURE__ */ jsx29(
3650
5826
  "input",
3651
5827
  {
3652
5828
  ref,
@@ -3663,10 +5839,10 @@ var Input = React21.forwardRef(
3663
5839
  Input.displayName = "Input";
3664
5840
 
3665
5841
  // src/components/ui/separator.tsx
3666
- import * as React22 from "react";
3667
- import { jsx as jsx28 } from "react/jsx-runtime";
3668
- var Separator = React22.forwardRef(
3669
- ({ className, orientation = "horizontal", ...props }, ref) => /* @__PURE__ */ jsx28(
5842
+ import * as React24 from "react";
5843
+ import { jsx as jsx30 } from "react/jsx-runtime";
5844
+ var Separator = React24.forwardRef(
5845
+ ({ className, orientation = "horizontal", ...props }, ref) => /* @__PURE__ */ jsx30(
3670
5846
  "div",
3671
5847
  {
3672
5848
  ref,