@xpert-ai/chatkit-ui 0.0.20 → 0.1.0

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 (284) hide show
  1. package/dist/app/assets/{abap-CabZ0vYL.js → abap-DMqO-Um8.js} +1 -1
  2. package/dist/app/assets/{abnf-CPoubvVG.js → abnf-CBYpoE1H.js} +1 -1
  3. package/dist/app/assets/{actionscript-CL1BPQFv.js → actionscript-ieE-wJMz.js} +1 -1
  4. package/dist/app/assets/{ada-BOt55oS4.js → ada-0-3Dx7g-.js} +1 -1
  5. package/dist/app/assets/{agda-DKyUkxie.js → agda-uvq9b4Kv.js} +1 -1
  6. package/dist/app/assets/{al-Jnhqb7P-.js → al-BmajJCAx.js} +1 -1
  7. package/dist/app/assets/{antlr4-BeT3YbbK.js → antlr4-DnRRgAfR.js} +1 -1
  8. package/dist/app/assets/{apacheconf-Ck_DRZXY.js → apacheconf-BWoRK3Q3.js} +1 -1
  9. package/dist/app/assets/{apex-CPjbO0O4.js → apex-u3cbevj3.js} +1 -1
  10. package/dist/app/assets/{apl-Ccs4_jOU.js → apl-Cifc7IZj.js} +1 -1
  11. package/dist/app/assets/{applescript-C6i7vo8F.js → applescript-CpHbiQqz.js} +1 -1
  12. package/dist/app/assets/{aql-D3ZWY-VL.js → aql-C_VCCvUl.js} +1 -1
  13. package/dist/app/assets/{arduino-xTj3TTXg.js → arduino-CSAc4iDr.js} +1 -1
  14. package/dist/app/assets/{arff-BOuVccGR.js → arff-B8hSQDyJ.js} +1 -1
  15. package/dist/app/assets/{asciidoc-BmShvnn0.js → asciidoc-Guc1Uqnw.js} +1 -1
  16. package/dist/app/assets/{asm6502-6FWPK68i.js → asm6502-CxPqNdV6.js} +1 -1
  17. package/dist/app/assets/{asmatmel-KLAd82QV.js → asmatmel-C76CHB5e.js} +1 -1
  18. package/dist/app/assets/{aspnet-vZiSZd1y.js → aspnet-BQFc33QF.js} +1 -1
  19. package/dist/app/assets/{autohotkey-tcBDP1b7.js → autohotkey-uQeN2mix.js} +1 -1
  20. package/dist/app/assets/{autoit-Bwt0tLM_.js → autoit-Bmy0PsAQ.js} +1 -1
  21. package/dist/app/assets/{avisynth-Bzz43Lfu.js → avisynth-BvuIlb62.js} +1 -1
  22. package/dist/app/assets/{avro-idl-Bt9aSyrD.js → avro-idl-DWeVWQR3.js} +1 -1
  23. package/dist/app/assets/{bash-BloO3C-T.js → bash-HypWaeXO.js} +1 -1
  24. package/dist/app/assets/{basic-B-OOkRrw.js → basic-B4YxRCle.js} +1 -1
  25. package/dist/app/assets/{batch-aOUu2msA.js → batch-B1yKhArW.js} +1 -1
  26. package/dist/app/assets/{bbcode-C4D8vm8O.js → bbcode-BIDNxh7c.js} +1 -1
  27. package/dist/app/assets/{bicep-BtBByAYv.js → bicep-DkupOIs7.js} +1 -1
  28. package/dist/app/assets/{birb-BKXLouTf.js → birb-Jo6NYQYX.js} +1 -1
  29. package/dist/app/assets/{bison-CniuHJJN.js → bison-BjPiLxuX.js} +1 -1
  30. package/dist/app/assets/{bnf-CGcuZYv2.js → bnf-BjygHCSE.js} +1 -1
  31. package/dist/app/assets/{brainfuck-C9dlh056.js → brainfuck-CsnLnGPx.js} +1 -1
  32. package/dist/app/assets/{brightscript-nhHFw9_4.js → brightscript-CwmmyoHc.js} +1 -1
  33. package/dist/app/assets/{bro-BTsReVOc.js → bro-BNKXu22N.js} +1 -1
  34. package/dist/app/assets/{bsl-CmOTwcFR.js → bsl-DOwsbsXU.js} +1 -1
  35. package/dist/app/assets/{c-Yjfq4oES.js → c-DyedRTs7.js} +1 -1
  36. package/dist/app/assets/{cfscript-DGhYlgJ7.js → cfscript-DCpmh-J_.js} +1 -1
  37. package/dist/app/assets/{chaiscript-CpP8bBSU.js → chaiscript-DRaisf-4.js} +1 -1
  38. package/dist/app/assets/{cil-CZ7j4pcz.js → cil-C5bobqND.js} +1 -1
  39. package/dist/app/assets/{clike-D581thF2.js → clike-CvmXR497.js} +1 -1
  40. package/dist/app/assets/{clojure-AXVmar0o.js → clojure-BH_u6xTK.js} +1 -1
  41. package/dist/app/assets/{cmake-BozSSfax.js → cmake-CZruZSdT.js} +1 -1
  42. package/dist/app/assets/{cobol-OciN9vwY.js → cobol-qc5xAkcg.js} +1 -1
  43. package/dist/app/assets/{coffeescript-B9yMzVL5.js → coffeescript-DGM4CLoq.js} +1 -1
  44. package/dist/app/assets/{concurnas-DeQIM64O.js → concurnas-DFyZRxPp.js} +1 -1
  45. package/dist/app/assets/{coq-CicPksao.js → coq-DbZe2f_H.js} +1 -1
  46. package/dist/app/assets/{core-BIcqXTaK.js → core-BWUnDrKt.js} +1 -1
  47. package/dist/app/assets/{cpp-DKQF7403.js → cpp-CidpRyAJ.js} +1 -1
  48. package/dist/app/assets/{crystal-Bcau7QFZ.js → crystal-DZE9-h5D.js} +1 -1
  49. package/dist/app/assets/{csharp-BYghYpTl.js → csharp-Cf2K5CJJ.js} +1 -1
  50. package/dist/app/assets/{cshtml-BIxIGrsH.js → cshtml-DRjf7C5F.js} +1 -1
  51. package/dist/app/assets/{csp-CzDOD-m1.js → csp-dEoRcP0N.js} +1 -1
  52. package/dist/app/assets/{css-CPRwU6oY.js → css-BWUfAyau.js} +1 -1
  53. package/dist/app/assets/{css-extras-C28yWYxN.js → css-extras-pPY_Crez.js} +1 -1
  54. package/dist/app/assets/{csv-D8IAZwKO.js → csv-DdkqZn4I.js} +1 -1
  55. package/dist/app/assets/{cypher-0hMRBt8D.js → cypher-BXQbix41.js} +1 -1
  56. package/dist/app/assets/{d-B5PQgXXo.js → d-BctgRQp0.js} +1 -1
  57. package/dist/app/assets/{dart-CvCyf8me.js → dart-DuiikcDB.js} +1 -1
  58. package/dist/app/assets/{dataweave-Izl0xtz9.js → dataweave-ClZ_D-Ju.js} +1 -1
  59. package/dist/app/assets/{dax-D-bGAkbS.js → dax-DXNfCTH9.js} +1 -1
  60. package/dist/app/assets/{dhall-DXIOSM5Q.js → dhall-Cbz5hfMr.js} +1 -1
  61. package/dist/app/assets/{diff-BE-xKdIi.js → diff-bify6WLh.js} +1 -1
  62. package/dist/app/assets/{django-DxEZdkeU.js → django-5DdvW3LZ.js} +1 -1
  63. package/dist/app/assets/{dns-zone-file-D406E4S7.js → dns-zone-file-DIIW7lsW.js} +1 -1
  64. package/dist/app/assets/{docker-BZkb2U00.js → docker-BxIMVoJD.js} +1 -1
  65. package/dist/app/assets/{dot-BGJNVmx1.js → dot-DLEHPnum.js} +1 -1
  66. package/dist/app/assets/{ebnf-_PEATas2.js → ebnf-DHWaG3pk.js} +1 -1
  67. package/dist/app/assets/{editorconfig-C1UuLwJC.js → editorconfig-D2gTUSqU.js} +1 -1
  68. package/dist/app/assets/{eiffel-PzXVtlzf.js → eiffel-C3dcM2dq.js} +1 -1
  69. package/dist/app/assets/{ejs-707c0691.js → ejs-0qd3jtKi.js} +1 -1
  70. package/dist/app/assets/{elixir-Bd3zWMjP.js → elixir-BbBaHIGe.js} +1 -1
  71. package/dist/app/assets/{elm-DvEDEOdK.js → elm-KJmeOU7e.js} +1 -1
  72. package/dist/app/assets/{erb-B6lZT1P9.js → erb-BncgAY0M.js} +1 -1
  73. package/dist/app/assets/{erlang-BwhqRmQk.js → erlang-DS2SHYdK.js} +1 -1
  74. package/dist/app/assets/{etlua-Bkg93PrU.js → etlua-CvdrPEPO.js} +1 -1
  75. package/dist/app/assets/{excel-formula-BD0I0dyD.js → excel-formula-BSj1zROW.js} +1 -1
  76. package/dist/app/assets/{factor-CiQgOsxY.js → factor-DAbcpTN7.js} +1 -1
  77. package/dist/app/assets/{false-DlJ-f_Rc.js → false-CI895JmG.js} +1 -1
  78. package/dist/app/assets/{firestore-security-rules-CxrEhPSm.js → firestore-security-rules-CJ33YIQv.js} +1 -1
  79. package/dist/app/assets/{flow-DOjTBDi4.js → flow-a2eNz08o.js} +1 -1
  80. package/dist/app/assets/{fortran-D6uA-pWI.js → fortran-Bt9e6qJa.js} +1 -1
  81. package/dist/app/assets/{fsharp-CFL1DcvT.js → fsharp-Y0Qf2U16.js} +1 -1
  82. package/dist/app/assets/{ftl-DzWZwecM.js → ftl-D-TrqPet.js} +1 -1
  83. package/dist/app/assets/{gap-DatQeRFY.js → gap-CP5bMoJx.js} +1 -1
  84. package/dist/app/assets/{gcode-5FSxboIT.js → gcode-DQNcGCou.js} +1 -1
  85. package/dist/app/assets/{gdscript-Dz-OC8bG.js → gdscript-Bxt6W-z5.js} +1 -1
  86. package/dist/app/assets/{gedcom-BS0539Ys.js → gedcom-Cqgp4wkt.js} +1 -1
  87. package/dist/app/assets/{gherkin-BJKrWYAT.js → gherkin-D7pNUe8Z.js} +1 -1
  88. package/dist/app/assets/{git-DCjIevVw.js → git-C4ec-8cM.js} +1 -1
  89. package/dist/app/assets/{glsl-toSXKJrw.js → glsl-8sVKxech.js} +1 -1
  90. package/dist/app/assets/{gml-DODsSWU7.js → gml-TuwFoFK6.js} +1 -1
  91. package/dist/app/assets/{gn-CzmtMWMm.js → gn-BwHrmBhU.js} +1 -1
  92. package/dist/app/assets/{go-module-BbcV-9oG.js → go-module-cqolzX_W.js} +1 -1
  93. package/dist/app/assets/{go-BCQUEKVv.js → go-vGJJNlGP.js} +1 -1
  94. package/dist/app/assets/{graphql-C_KxCYJO.js → graphql-Do6Lisgl.js} +1 -1
  95. package/dist/app/assets/{groovy-Cj97iKYK.js → groovy--87wZh42.js} +1 -1
  96. package/dist/app/assets/{haml-tLXJGYDb.js → haml-vhodueeI.js} +1 -1
  97. package/dist/app/assets/{handlebars-DIdVe3xN.js → handlebars-CNLRaZ5R.js} +1 -1
  98. package/dist/app/assets/{haskell-DPqw5u4H.js → haskell-BWTsCqP4.js} +1 -1
  99. package/dist/app/assets/{haxe-AsnHNCIR.js → haxe-CSb0SWYW.js} +1 -1
  100. package/dist/app/assets/{hcl-C6aoWR34.js → hcl-ftOASTH-.js} +1 -1
  101. package/dist/app/assets/{hlsl-B2hhU30-.js → hlsl-BnaGHwDi.js} +1 -1
  102. package/dist/app/assets/{hoon-Bs-KhWO3.js → hoon-wyj1oNzn.js} +1 -1
  103. package/dist/app/assets/{hpkp-C-J4O-Mp.js → hpkp-Broim0YQ.js} +1 -1
  104. package/dist/app/assets/{hsts-BNFEkSnm.js → hsts-BSMt-Rhs.js} +1 -1
  105. package/dist/app/assets/{http-D7UlQANy.js → http-yK1zPe9M.js} +1 -1
  106. package/dist/app/assets/{ichigojam-B01TJ8BA.js → ichigojam-Bpzuxs1S.js} +1 -1
  107. package/dist/app/assets/{icon-Ca_ghvQd.js → icon-DjPW0ImK.js} +1 -1
  108. package/dist/app/assets/{icu-message-format-CkcsJ0ML.js → icu-message-format-CTS86FWW.js} +1 -1
  109. package/dist/app/assets/{idris-BApVxI9a.js → idris-DkPie8bu.js} +1 -1
  110. package/dist/app/assets/{iecst-CXLR8sGn.js → iecst-CG1KmB8U.js} +1 -1
  111. package/dist/app/assets/{ignore-7LzAeAFj.js → ignore-D9eho3CQ.js} +1 -1
  112. package/dist/app/assets/{index-BUg2yVDW.js → index-4J46qBCc.js} +105 -99
  113. package/dist/app/assets/{index-om2E9pNd.css → index-DTn9OjqV.css} +1 -1
  114. package/dist/app/assets/{inform7-CtnRN-Iq.js → inform7-DD1mc6Wh.js} +1 -1
  115. package/dist/app/assets/{ini-Cjpl6yTL.js → ini-Db6U4nBT.js} +1 -1
  116. package/dist/app/assets/{io-C6W_EboY.js → io-BRkH6hzB.js} +1 -1
  117. package/dist/app/assets/{j-BOBDun2W.js → j-CD22iLrA.js} +1 -1
  118. package/dist/app/assets/{java-CNwVyXY2.js → java-DvhwWZfy.js} +1 -1
  119. package/dist/app/assets/{javadoc-DS6hxu7_.js → javadoc-Ecoxhe_9.js} +1 -1
  120. package/dist/app/assets/{javadoclike-J6YT11JS.js → javadoclike-Realhpv4.js} +1 -1
  121. package/dist/app/assets/{javascript-IbEfuVSB.js → javascript-BBd1k8wl.js} +1 -1
  122. package/dist/app/assets/{javastacktrace-DjxwGV26.js → javastacktrace-C8QW0vuU.js} +1 -1
  123. package/dist/app/assets/{jexl-TLHmHaQ5.js → jexl-CT2UXrnH.js} +1 -1
  124. package/dist/app/assets/{jolie-CLk71kur.js → jolie-qtyDXXST.js} +1 -1
  125. package/dist/app/assets/{jq-DZKnIQZM.js → jq-CNJQULTZ.js} +1 -1
  126. package/dist/app/assets/{js-extras-CJab09ti.js → js-extras-DwIZLd4T.js} +1 -1
  127. package/dist/app/assets/{js-templates-CQGqrHhi.js → js-templates-glA_Un9b.js} +1 -1
  128. package/dist/app/assets/{jsdoc--ymvl4aq.js → jsdoc-BsXlBBjy.js} +1 -1
  129. package/dist/app/assets/{json-D9b-V85G.js → json-BC3xmMOU.js} +1 -1
  130. package/dist/app/assets/{json5-LgA47n7A.js → json5-CiePGcB9.js} +1 -1
  131. package/dist/app/assets/{jsonp-Cvwp3f8M.js → jsonp-B9HJmhak.js} +1 -1
  132. package/dist/app/assets/{jsstacktrace-z8t2H6h6.js → jsstacktrace-3xS0eyZd.js} +1 -1
  133. package/dist/app/assets/{jsx-B71LrwNd.js → jsx-B5kMqxBm.js} +1 -1
  134. package/dist/app/assets/{julia-DCATdxwO.js → julia-B5Udq0EY.js} +1 -1
  135. package/dist/app/assets/{keepalived-DVYYbgrL.js → keepalived-CI0hMS1b.js} +1 -1
  136. package/dist/app/assets/{keyman-DLyOXnhf.js → keyman-BCtXwe5i.js} +1 -1
  137. package/dist/app/assets/{kotlin-CYoDfyDA.js → kotlin-B3l0V1Fn.js} +1 -1
  138. package/dist/app/assets/{kumir-CPWiEvmL.js → kumir-BmC_PBOp.js} +1 -1
  139. package/dist/app/assets/{kusto-BkfRYk0W.js → kusto-B0p1ppsT.js} +1 -1
  140. package/dist/app/assets/{latex-BEjZ0ppC.js → latex-CHwNDYz_.js} +1 -1
  141. package/dist/app/assets/{latte-DaZOqdGV.js → latte-DihAtCCl.js} +1 -1
  142. package/dist/app/assets/{less-BmKsj1gN.js → less-BLGkFSp1.js} +1 -1
  143. package/dist/app/assets/{lilypond-mmng28aJ.js → lilypond-CCsAc8Nl.js} +1 -1
  144. package/dist/app/assets/{liquid-BuuJO6_6.js → liquid-jBSQx5I5.js} +1 -1
  145. package/dist/app/assets/{lisp-DnffFM5N.js → lisp-CgzQXnYE.js} +1 -1
  146. package/dist/app/assets/{livescript-BSsr00Wr.js → livescript-u96H-zdx.js} +1 -1
  147. package/dist/app/assets/{llvm-37YjcHN5.js → llvm-WmVcvcNM.js} +1 -1
  148. package/dist/app/assets/{log-D3l5N3To.js → log-990P-Rch.js} +1 -1
  149. package/dist/app/assets/{lolcode-C0Q2M_6s.js → lolcode-DdFIjfxs.js} +1 -1
  150. package/dist/app/assets/{lua-DcLwN4Tg.js → lua-GkhnMu0T.js} +1 -1
  151. package/dist/app/assets/{magma-CK0Amip9.js → magma-wajb6K9F.js} +1 -1
  152. package/dist/app/assets/{makefile-CtpS-RoO.js → makefile-CGHjuGaS.js} +1 -1
  153. package/dist/app/assets/{markdown-BNK3F4ql.js → markdown-BFWQ31vs.js} +1 -1
  154. package/dist/app/assets/{markup-C9GIL65H.js → markup-1ihI0X17.js} +1 -1
  155. package/dist/app/assets/{markup-templating-Du1J3ADP.js → markup-templating-DblqKZLi.js} +1 -1
  156. package/dist/app/assets/{matlab-DEM6O1Ul.js → matlab-CPqo7ZUC.js} +1 -1
  157. package/dist/app/assets/{maxscript-DMvqa3gf.js → maxscript-CTgVjA7o.js} +1 -1
  158. package/dist/app/assets/{mel-C8DBIw1g.js → mel-Cxah6vYr.js} +1 -1
  159. package/dist/app/assets/{mermaid-CVko6NSq.js → mermaid-BAgJSsZ7.js} +1 -1
  160. package/dist/app/assets/{mizar-CwYm3_It.js → mizar-BL3spn8_.js} +1 -1
  161. package/dist/app/assets/{mongodb-DRqGwjq6.js → mongodb-DXzP7tR0.js} +1 -1
  162. package/dist/app/assets/{monkey-BxiKe6Nr.js → monkey-anPtBsfj.js} +1 -1
  163. package/dist/app/assets/{moonscript-CJyt1xoM.js → moonscript-Y_tcmLfW.js} +1 -1
  164. package/dist/app/assets/{n1ql-BBmjIGEU.js → n1ql-B7NGFYRY.js} +1 -1
  165. package/dist/app/assets/{n4js-ByKsJMJL.js → n4js-zh8URwWB.js} +1 -1
  166. package/dist/app/assets/{nand2tetris-hdl-BTSXj71h.js → nand2tetris-hdl-CDUtzUHw.js} +1 -1
  167. package/dist/app/assets/{naniscript-C4jykFVF.js → naniscript-CjJGU6C6.js} +1 -1
  168. package/dist/app/assets/{nasm-DPA0eXtX.js → nasm-D6biC9Vr.js} +1 -1
  169. package/dist/app/assets/{neon-upN4Ak64.js → neon-C3Z0pCuH.js} +1 -1
  170. package/dist/app/assets/{nevod-CdttHB8F.js → nevod-BT4Ivkzb.js} +1 -1
  171. package/dist/app/assets/{nginx-DI1fsQ3j.js → nginx-vHHTRs1B.js} +1 -1
  172. package/dist/app/assets/{nim-D7kc_mK9.js → nim-Jk1NOWk0.js} +1 -1
  173. package/dist/app/assets/{nix-BUG5ppr9.js → nix-CEkA_w3B.js} +1 -1
  174. package/dist/app/assets/{nsis-BnXhmmxO.js → nsis-Du9w_Qb8.js} +1 -1
  175. package/dist/app/assets/{objectivec-Bu4dOfb9.js → objectivec-BciYUGRR.js} +1 -1
  176. package/dist/app/assets/{ocaml-aT7VVPiL.js → ocaml-CpZ_M4DP.js} +1 -1
  177. package/dist/app/assets/{opencl-BzyWcYkI.js → opencl-C-4M-Mvx.js} +1 -1
  178. package/dist/app/assets/{openqasm-b2yFBJdq.js → openqasm-CilZXlSe.js} +1 -1
  179. package/dist/app/assets/{oz-D46TtIuw.js → oz-DluYJ10T.js} +1 -1
  180. package/dist/app/assets/{parigp-BAJyhdut.js → parigp-BlIaVN51.js} +1 -1
  181. package/dist/app/assets/{parser-B-ALvauC.js → parser-BZVTYRp4.js} +1 -1
  182. package/dist/app/assets/{pascal-B0ap4FDW.js → pascal-CMz_wkC0.js} +1 -1
  183. package/dist/app/assets/{pascaligo-ChOneu9-.js → pascaligo-DLQY1QwY.js} +1 -1
  184. package/dist/app/assets/{pcaxis-DTAmxHgs.js → pcaxis-C-5nzMDp.js} +1 -1
  185. package/dist/app/assets/{peoplecode-dQfUy8zn.js → peoplecode-BhTicHl8.js} +1 -1
  186. package/dist/app/assets/{perl-CYk00e1Q.js → perl-BArlZZ8M.js} +1 -1
  187. package/dist/app/assets/{php-DvSqFnSN.js → php-C6zNUOf5.js} +1 -1
  188. package/dist/app/assets/{php-extras-BFjUbIU6.js → php-extras-DD5Glhrz.js} +1 -1
  189. package/dist/app/assets/{phpdoc-Di7rKCNL.js → phpdoc-Buj0qa-9.js} +1 -1
  190. package/dist/app/assets/{plsql-dX0-BKqD.js → plsql-o2-C-Ezr.js} +1 -1
  191. package/dist/app/assets/{powerquery-3xq4KaAs.js → powerquery-Cl0Dbp57.js} +1 -1
  192. package/dist/app/assets/{powershell-BbXooszO.js → powershell-BVFtl1FS.js} +1 -1
  193. package/dist/app/assets/{processing-GWbfNCzH.js → processing-BHJTqgxZ.js} +1 -1
  194. package/dist/app/assets/{prolog-Tb2TbunJ.js → prolog-C9gykhtA.js} +1 -1
  195. package/dist/app/assets/{promql-QS8vHhL7.js → promql-TzYBDR1F.js} +1 -1
  196. package/dist/app/assets/{properties-BJ8AWlqX.js → properties-Bi8GxxCM.js} +1 -1
  197. package/dist/app/assets/{protobuf-De-puAg3.js → protobuf-s08U24Jk.js} +1 -1
  198. package/dist/app/assets/{psl-hZft3C8K.js → psl-By228u9L.js} +1 -1
  199. package/dist/app/assets/{pug-BcYHdk-i.js → pug-CahxgaMR.js} +1 -1
  200. package/dist/app/assets/{puppet-BWbqDQJD.js → puppet-BAY6TBQY.js} +1 -1
  201. package/dist/app/assets/{pure-Bz2pjTxR.js → pure-IA8ihD9R.js} +1 -1
  202. package/dist/app/assets/{purebasic-BlO48lYx.js → purebasic-B6joY-ZH.js} +1 -1
  203. package/dist/app/assets/{purescript-BxSMm2Br.js → purescript-DczXEj8E.js} +1 -1
  204. package/dist/app/assets/{q-DDUTW9aK.js → q-CEXq_tpX.js} +1 -1
  205. package/dist/app/assets/{qml-DisOV-LV.js → qml-ND31CBLa.js} +1 -1
  206. package/dist/app/assets/{qore-FNRP4gBF.js → qore-DAjVLL2F.js} +1 -1
  207. package/dist/app/assets/{qsharp-DhtMV0oO.js → qsharp-jccBvH6Y.js} +1 -1
  208. package/dist/app/assets/{r-CyiuHjNN.js → r-pv5Xhvsd.js} +1 -1
  209. package/dist/app/assets/{racket-DFgoSckH.js → racket-xRigDwdL.js} +1 -1
  210. package/dist/app/assets/{reason-HhYbY7K3.js → reason-DnAP7dec.js} +1 -1
  211. package/dist/app/assets/{regex-jU5TpvM-.js → regex-Dwkma1bN.js} +1 -1
  212. package/dist/app/assets/{rego-BCjDPrQO.js → rego-3dHPz-ut.js} +1 -1
  213. package/dist/app/assets/{renpy-BTSgQi2v.js → renpy-Czxc7hu0.js} +1 -1
  214. package/dist/app/assets/{rest-BLcZ4e-5.js → rest-BP_JQ_AG.js} +1 -1
  215. package/dist/app/assets/{rip-SltRJnuI.js → rip-Nredd5kD.js} +1 -1
  216. package/dist/app/assets/{roboconf-B-GZm2Oe.js → roboconf-CkR4ACer.js} +1 -1
  217. package/dist/app/assets/{robotframework-BOt8S6cX.js → robotframework-CYYV7JaP.js} +1 -1
  218. package/dist/app/assets/{ruby-CVfYH0zM.js → ruby-EA_sSyU6.js} +1 -1
  219. package/dist/app/assets/{rust-B6mEp4Sj.js → rust-BM2hEYJt.js} +1 -1
  220. package/dist/app/assets/{sas-DvEI8RJ0.js → sas-jaxOWx-0.js} +1 -1
  221. package/dist/app/assets/{sass-Cv25Jxqq.js → sass-pkiTdYnF.js} +1 -1
  222. package/dist/app/assets/{scala-CyqNr7Uv.js → scala-lTsQiijh.js} +1 -1
  223. package/dist/app/assets/{scheme-ji0XoXLf.js → scheme-DkPZYA1o.js} +1 -1
  224. package/dist/app/assets/{scss-B7_0neO_.js → scss-DZjxUgqE.js} +1 -1
  225. package/dist/app/assets/{shell-session-CqZEoMQD.js → shell-session-CKXJ0a90.js} +1 -1
  226. package/dist/app/assets/{smali-DKSzZYkI.js → smali-DVWpHHAX.js} +1 -1
  227. package/dist/app/assets/{smalltalk-BOA4piuq.js → smalltalk-ChiRh9QF.js} +1 -1
  228. package/dist/app/assets/{smarty-Du99BSgN.js → smarty-C4i7AVoC.js} +1 -1
  229. package/dist/app/assets/{sml-BJedIA4B.js → sml-v9dKzil3.js} +1 -1
  230. package/dist/app/assets/{solidity-DidQwG5Z.js → solidity-DaxM8K8t.js} +1 -1
  231. package/dist/app/assets/{solution-file-Bx0d9qN8.js → solution-file-Ch7ajMI6.js} +1 -1
  232. package/dist/app/assets/{soy-BBLv3Cfa.js → soy-CHeWJZPl.js} +1 -1
  233. package/dist/app/assets/{sparql-Da5WZKbL.js → sparql-f56EhPSR.js} +1 -1
  234. package/dist/app/assets/{splunk-spl-DbJKl8So.js → splunk-spl-CNX2IshN.js} +1 -1
  235. package/dist/app/assets/{sqf-CYrx0jxf.js → sqf-B9Z5kTgF.js} +1 -1
  236. package/dist/app/assets/{sql-Gv-aOlOf.js → sql-PZTLdUd4.js} +1 -1
  237. package/dist/app/assets/{squirrel-FpIGPPw4.js → squirrel-_QTHEJtD.js} +1 -1
  238. package/dist/app/assets/{stan-Dq001Nrk.js → stan-y02QaMQQ.js} +1 -1
  239. package/dist/app/assets/{stylus-aatfgWwe.js → stylus-CGYq1GKp.js} +1 -1
  240. package/dist/app/assets/{swift-pn7VW95d.js → swift-BBMLpv3H.js} +1 -1
  241. package/dist/app/assets/{systemd-9capsVJ6.js → systemd-CD7Dfv8Y.js} +1 -1
  242. package/dist/app/assets/{t4-cs-CKXcczci.js → t4-cs-BtxQixNP.js} +1 -1
  243. package/dist/app/assets/{t4-templating-1wTayb8u.js → t4-templating-BX2jWZwS.js} +1 -1
  244. package/dist/app/assets/{t4-vb-B_O7wBow.js → t4-vb-CX3AQUVf.js} +1 -1
  245. package/dist/app/assets/{tap-D-TV5_gQ.js → tap-BRBB20R0.js} +1 -1
  246. package/dist/app/assets/{tcl-BaVob1Om.js → tcl-CWrqc_vL.js} +1 -1
  247. package/dist/app/assets/{textile-COMk-HmI.js → textile-EJMS8IJv.js} +1 -1
  248. package/dist/app/assets/{toml-D9NJpArC.js → toml-DLWr0_Sd.js} +1 -1
  249. package/dist/app/assets/{tremor-rCNHwdQL.js → tremor-D0DGH64h.js} +1 -1
  250. package/dist/app/assets/{tt2-DTDvfOgc.js → tt2-CaSD1IpZ.js} +1 -1
  251. package/dist/app/assets/{turtle-D8pkqXh1.js → turtle-BtZWKoZ_.js} +1 -1
  252. package/dist/app/assets/{twig-DxSF8gqH.js → twig-BQ0AWwu3.js} +1 -1
  253. package/dist/app/assets/{typescript-Caebatmk.js → typescript-sByRs_H7.js} +1 -1
  254. package/dist/app/assets/{typoscript-B3uk1kES.js → typoscript-Bs3x5DVu.js} +1 -1
  255. package/dist/app/assets/{unrealscript-ZNoSG8ji.js → unrealscript-BPk-JGuX.js} +1 -1
  256. package/dist/app/assets/{uorazor-LekoNNOo.js → uorazor-Dxr1B729.js} +1 -1
  257. package/dist/app/assets/{uri-B8YcIzOv.js → uri-B18d7fGy.js} +1 -1
  258. package/dist/app/assets/{v-6rOne2a0.js → v-B-4se_c_.js} +1 -1
  259. package/dist/app/assets/{vala-CjEJEdsP.js → vala-CZJMpckw.js} +1 -1
  260. package/dist/app/assets/{vbnet-DBPmBm7_.js → vbnet-Bon1nLZm.js} +1 -1
  261. package/dist/app/assets/{velocity-DOooMwL8.js → velocity-Ck8gHF4B.js} +1 -1
  262. package/dist/app/assets/{verilog-Cq0ZocvP.js → verilog-zADKtd-6.js} +1 -1
  263. package/dist/app/assets/{vhdl-Dxs_xidb.js → vhdl-Ce3jhJNh.js} +1 -1
  264. package/dist/app/assets/{vim-BqsnXwB6.js → vim-CwgyIdo-.js} +1 -1
  265. package/dist/app/assets/{visual-basic-zAzjvaqP.js → visual-basic-BWQC7pBF.js} +1 -1
  266. package/dist/app/assets/{warpscript-D9hbfr6_.js → warpscript-CVp7w3zz.js} +1 -1
  267. package/dist/app/assets/{wasm-C4TU9VDY.js → wasm-yPowz3sM.js} +1 -1
  268. package/dist/app/assets/{web-idl-DD5JcddQ.js → web-idl-BkghLEob.js} +1 -1
  269. package/dist/app/assets/{wiki-Des21yVK.js → wiki-TBH4TnLK.js} +1 -1
  270. package/dist/app/assets/{wolfram-B7enpov1.js → wolfram-BmgF1AlB.js} +1 -1
  271. package/dist/app/assets/{wren-Rr8h-Ayu.js → wren-CJ8nrMy_.js} +1 -1
  272. package/dist/app/assets/{xeora-EjcLXBhx.js → xeora-N6_5XQpC.js} +1 -1
  273. package/dist/app/assets/{xml-doc-uaTxx6-m.js → xml-doc-GBGxTNFc.js} +1 -1
  274. package/dist/app/assets/{xojo-CX6G8nhh.js → xojo-CmpAfzYO.js} +1 -1
  275. package/dist/app/assets/{xquery-DvPb3Uw9.js → xquery-BA22D3yp.js} +1 -1
  276. package/dist/app/assets/{yaml-D-l_Y2hx.js → yaml-CDGmAMpu.js} +1 -1
  277. package/dist/app/assets/{yang-KBoIIT4_.js → yang-rFKIXOjI.js} +1 -1
  278. package/dist/app/assets/{zig-_uNXp9cY.js → zig-rH4Tzjve.js} +1 -1
  279. package/dist/app/index.html +2 -2
  280. package/dist/index.cjs +1891 -582
  281. package/dist/index.d.cts +17 -3
  282. package/dist/index.d.ts +17 -3
  283. package/dist/index.js +1926 -591
  284. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -1,6 +1,14 @@
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 React21 from "react";
3
+ import {
4
+ ArrowDown,
5
+ FileText as FileText2,
6
+ Loader2 as Loader22,
7
+ Pencil as Pencil3,
8
+ Quote,
9
+ RefreshCw as RefreshCw2,
10
+ X as X2
11
+ } from "lucide-react";
4
12
 
5
13
  // src/lib/utils.ts
6
14
  import { clsx } from "clsx";
@@ -21,6 +29,64 @@ function createMessageId() {
21
29
  return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
22
30
  }
23
31
 
32
+ // src/lib/message.ts
33
+ import { isNil, omitBy } from "lodash-es";
34
+ var ASSISTANT_STREAM_IDLE_TO_THINKING_MS = 2e3;
35
+ function hasRenderableReasoning(reasoning) {
36
+ return Array.isArray(reasoning) && reasoning.some((item) => item.text?.trim());
37
+ }
38
+ function hasRenderableMessageContent(content) {
39
+ if (typeof content === "string") {
40
+ return content.trim().length > 0;
41
+ }
42
+ if (!Array.isArray(content) || content.length === 0) {
43
+ return false;
44
+ }
45
+ const items = content;
46
+ return items.some((item) => {
47
+ if (typeof item === "string") {
48
+ return item.trim().length > 0;
49
+ }
50
+ if (!item || typeof item !== "object") {
51
+ return false;
52
+ }
53
+ if (item.type === "text") {
54
+ return Boolean(item.text?.trim());
55
+ }
56
+ if (item.type === "reasoning") {
57
+ return Boolean(item.text?.trim());
58
+ }
59
+ return true;
60
+ });
61
+ }
62
+ function hasRenderableAssistantMessage(message) {
63
+ return hasRenderableMessageContent(message.content) || hasRenderableReasoning(message.reasoning);
64
+ }
65
+ function getAssistantStreamingStatus(message, isStreaming, options) {
66
+ if (!isStreaming) {
67
+ return null;
68
+ }
69
+ const now = options?.now ?? Date.now();
70
+ const lastStreamOutputAt = typeof message.lastStreamOutputAt === "number" ? message.lastStreamOutputAt : null;
71
+ const isIdle = lastStreamOutputAt !== null && now - lastStreamOutputAt >= ASSISTANT_STREAM_IDLE_TO_THINKING_MS;
72
+ if (message.status === "reasoning") {
73
+ return "thinking";
74
+ }
75
+ if (message.status === "answering") {
76
+ if (isIdle) {
77
+ return "thinking";
78
+ }
79
+ return "answering";
80
+ }
81
+ if (hasRenderableReasoning(message.reasoning)) {
82
+ return "thinking";
83
+ }
84
+ if (isIdle) {
85
+ return "thinking";
86
+ }
87
+ return "loading";
88
+ }
89
+
24
90
  // src/lib/scroll.ts
25
91
  var BOTTOM_FOLLOW_THRESHOLD_PX = 48;
26
92
  function getDistanceFromBottom(element) {
@@ -45,7 +111,29 @@ import {
45
111
  Client
46
112
  } from "@xpert-ai/xpert-sdk";
47
113
  import "@langchain/core/messages/tool";
48
- import { ChatMessageEventTypeEnum, ChatMessageTypeEnum } from "@xpert-ai/chatkit-types";
114
+ import {
115
+ ChatMessageEventTypeEnum,
116
+ ChatMessageTypeEnum
117
+ } from "@xpert-ai/chatkit-types";
118
+
119
+ // src/lib/api-config.ts
120
+ function hasConfiguredValue(value) {
121
+ return typeof value === "string" && value.trim().length > 0;
122
+ }
123
+ function getMissingApiConfigurationKind({
124
+ apiUrl,
125
+ clientSecret
126
+ }) {
127
+ const hasApiUrl = hasConfiguredValue(apiUrl);
128
+ const hasClientSecret = hasConfiguredValue(clientSecret);
129
+ if (hasApiUrl && hasClientSecret) {
130
+ return null;
131
+ }
132
+ if (!hasApiUrl && !hasClientSecret) {
133
+ return "apiUrlAndClientSecret";
134
+ }
135
+ return hasApiUrl ? "clientSecret" : "apiUrl";
136
+ }
49
137
 
50
138
  // src/lib/request-options.ts
51
139
  import {
@@ -129,8 +217,16 @@ function buildInjectedRequestOptions(input) {
129
217
  import { useContext, useEffect as useEffect2, useRef as useRef2 } from "react";
130
218
 
131
219
  // 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";
220
+ import {
221
+ createContext,
222
+ useCallback,
223
+ useEffect,
224
+ useMemo,
225
+ useRef
226
+ } from "react";
227
+ import {
228
+ STATE_VARIABLE_HUMAN as STATE_VARIABLE_HUMAN2
229
+ } from "@xpert-ai/chatkit-types";
134
230
 
135
231
  // src/hooks/useStream.ts
136
232
  var streamRef = { current: null };
@@ -144,6 +240,189 @@ function useStreamManager() {
144
240
  };
145
241
  }
146
242
 
243
+ // src/lib/references.ts
244
+ function isObjectLike(value) {
245
+ return typeof value === "object" && value !== null && !Array.isArray(value);
246
+ }
247
+ function isNonEmptyString(value) {
248
+ return typeof value === "string" && value.trim().length > 0;
249
+ }
250
+ function toOptionalString(value) {
251
+ return isNonEmptyString(value) ? value.trim() : void 0;
252
+ }
253
+ function toReferenceText(value) {
254
+ return typeof value === "string" && value.trim().length > 0 ? value : null;
255
+ }
256
+ function toLineNumber(value) {
257
+ if (typeof value === "number" && Number.isInteger(value) && value > 0) {
258
+ return value;
259
+ }
260
+ return null;
261
+ }
262
+ function normalizeCodeReference(candidate) {
263
+ const path = toOptionalString(candidate.path);
264
+ const text = toReferenceText(candidate.text);
265
+ const startLine = toLineNumber(candidate.startLine);
266
+ const endLine = toLineNumber(candidate.endLine);
267
+ if (!path || !text || startLine === null || endLine === null) {
268
+ return null;
269
+ }
270
+ return {
271
+ type: "code",
272
+ ...toOptionalString(candidate.id) ? { id: toOptionalString(candidate.id) } : {},
273
+ ...toOptionalString(candidate.label) ? { label: toOptionalString(candidate.label) } : {},
274
+ path,
275
+ startLine,
276
+ endLine,
277
+ text,
278
+ ...toOptionalString(candidate.language) ? { language: toOptionalString(candidate.language) } : {},
279
+ ...toOptionalString(candidate.taskId) ? { taskId: toOptionalString(candidate.taskId) } : {}
280
+ };
281
+ }
282
+ function normalizeQuoteReference(candidate) {
283
+ const text = toReferenceText(candidate.text);
284
+ if (!text) {
285
+ return null;
286
+ }
287
+ return {
288
+ type: "quote",
289
+ ...toOptionalString(candidate.id) ? { id: toOptionalString(candidate.id) } : {},
290
+ ...toOptionalString(candidate.label) ? { label: toOptionalString(candidate.label) } : {},
291
+ text,
292
+ ...toOptionalString(candidate.messageId) ? { messageId: toOptionalString(candidate.messageId) } : {},
293
+ ...toOptionalString(candidate.source) ? { source: toOptionalString(candidate.source) } : {}
294
+ };
295
+ }
296
+ function isLegacyCodeReference(candidate) {
297
+ return isNonEmptyString(candidate.path) && toLineNumber(candidate.startLine) !== null && toLineNumber(candidate.endLine) !== null && toReferenceText(candidate.text) !== null;
298
+ }
299
+ function normalizeReference(value) {
300
+ if (!isObjectLike(value)) {
301
+ return null;
302
+ }
303
+ const candidate = value;
304
+ const type = toOptionalString(candidate.type);
305
+ if (type === "code") {
306
+ return normalizeCodeReference(candidate);
307
+ }
308
+ if (type === "quote") {
309
+ return normalizeQuoteReference(candidate);
310
+ }
311
+ if (type === void 0 && isLegacyCodeReference(candidate)) {
312
+ return normalizeCodeReference(candidate);
313
+ }
314
+ return null;
315
+ }
316
+ function normalizeReferences(value) {
317
+ if (!Array.isArray(value)) {
318
+ return [];
319
+ }
320
+ return value.map((item) => normalizeReference(item)).filter((item) => item !== null);
321
+ }
322
+ function getCodeReferenceRange(reference) {
323
+ return reference.startLine === reference.endLine ? `${reference.startLine}` : `${reference.startLine}-${reference.endLine}`;
324
+ }
325
+ function getQuoteExcerpt(reference) {
326
+ const normalized = reference.text.replace(/\s+/g, " ").trim();
327
+ if (normalized.length <= 32) {
328
+ return normalized;
329
+ }
330
+ return `${normalized.slice(0, 29)}...`;
331
+ }
332
+ function getCodeReferenceLocation(reference) {
333
+ return `${reference.path}:${getCodeReferenceRange(reference)}`;
334
+ }
335
+ function getReferenceKey(reference) {
336
+ if (reference.id && reference.id.trim()) {
337
+ return reference.id.trim();
338
+ }
339
+ if (reference.type === "code") {
340
+ return [
341
+ reference.type,
342
+ reference.path,
343
+ reference.startLine,
344
+ reference.endLine,
345
+ reference.text
346
+ ].join(":");
347
+ }
348
+ return [
349
+ reference.type,
350
+ reference.messageId ?? "",
351
+ reference.source ?? "",
352
+ reference.text
353
+ ].join(":");
354
+ }
355
+ function mergeReferences(current, incoming) {
356
+ const merged = [...current];
357
+ const seen = new Set(current.map(getReferenceKey));
358
+ incoming.forEach((reference) => {
359
+ const key = getReferenceKey(reference);
360
+ if (seen.has(key)) {
361
+ return;
362
+ }
363
+ seen.add(key);
364
+ merged.push(reference);
365
+ });
366
+ return merged;
367
+ }
368
+ function getReferenceLabel(reference) {
369
+ if (reference.label && reference.label.trim()) {
370
+ return reference.label.trim();
371
+ }
372
+ if (reference.type === "code") {
373
+ const segments = reference.path.split("/");
374
+ const fileName = segments[segments.length - 1] || reference.path;
375
+ return `${fileName} ${getCodeReferenceRange(reference)}`;
376
+ }
377
+ if (reference.source && reference.source.trim()) {
378
+ return reference.source.trim();
379
+ }
380
+ return getQuoteExcerpt(reference);
381
+ }
382
+ function getReferenceMetaLine(reference) {
383
+ if (reference.type === "code") {
384
+ return getCodeReferenceLocation(reference);
385
+ }
386
+ if (reference.source && reference.source.trim()) {
387
+ return getQuoteExcerpt(reference);
388
+ }
389
+ if (reference.messageId && reference.messageId.trim()) {
390
+ return `Message ${reference.messageId.trim()}`;
391
+ }
392
+ return null;
393
+ }
394
+ function getReferenceTitle(reference) {
395
+ if (reference.type === "code") {
396
+ return `${getCodeReferenceLocation(reference)}
397
+
398
+ ${reference.text}`;
399
+ }
400
+ const header = reference.label?.trim() || reference.source?.trim() || "Quoted text";
401
+ return `${header}
402
+
403
+ ${reference.text}`;
404
+ }
405
+ function buildHumanMessageInputPayload(source) {
406
+ const references = normalizeReferences(source.references);
407
+ const nextReferenceComposition = source.referenceComposition ?? (references.length > 0 && typeof source.submittedInput !== "string" ? "compose" : void 0);
408
+ if (typeof source.submittedInput === "string") {
409
+ return {
410
+ input: source.submittedInput.trim(),
411
+ ...references.length > 0 ? { references } : {},
412
+ ...nextReferenceComposition ? { referenceComposition: nextReferenceComposition } : {}
413
+ };
414
+ }
415
+ const input = typeof source.content === "string" ? source.content.trim() : "";
416
+ if (!input && references.length === 0) {
417
+ return null;
418
+ }
419
+ return {
420
+ input,
421
+ ...references.length > 0 ? { references } : {},
422
+ ...nextReferenceComposition ? { referenceComposition: nextReferenceComposition } : {}
423
+ };
424
+ }
425
+
147
426
  // src/providers/ParentMessenger.tsx
148
427
  import { jsx } from "react/jsx-runtime";
149
428
  var handledSendUserMessageNonces = /* @__PURE__ */ new Set();
@@ -172,6 +451,10 @@ function ParentMessengerProvider({
172
451
  /* @__PURE__ */ new Map()
173
452
  );
174
453
  const onSetOptionsHandlersRef = useRef(/* @__PURE__ */ new Set());
454
+ const onSetComposerValueHandlersRef = useRef(
455
+ /* @__PURE__ */ new Set()
456
+ );
457
+ const onFocusComposerHandlersRef = useRef(/* @__PURE__ */ new Set());
175
458
  const latestOptionsRef = useRef(null);
176
459
  const isParentAvailable = useMemo(() => {
177
460
  return typeof window !== "undefined" && window.parent !== window;
@@ -185,6 +468,24 @@ function ParentMessengerProvider({
185
468
  onSetOptionsHandlersRef.current.delete(handler);
186
469
  };
187
470
  }, []);
471
+ const registerOnSetComposerValue = useCallback(
472
+ (handler) => {
473
+ onSetComposerValueHandlersRef.current.add(handler);
474
+ return () => {
475
+ onSetComposerValueHandlersRef.current.delete(handler);
476
+ };
477
+ },
478
+ []
479
+ );
480
+ const registerOnFocusComposer = useCallback(
481
+ (handler) => {
482
+ onFocusComposerHandlersRef.current.add(handler);
483
+ return () => {
484
+ onFocusComposerHandlersRef.current.delete(handler);
485
+ };
486
+ },
487
+ []
488
+ );
188
489
  useEffect(() => {
189
490
  if (!isParentAvailable) return;
190
491
  const sendResponse = (nonce, response, error) => {
@@ -205,7 +506,7 @@ function ParentMessengerProvider({
205
506
  }
206
507
  const payload = event.data;
207
508
  if (payload.__xpaiChatKit !== true) return;
208
- if (payload.type == "command" && payload.command === "onSendUserMessage") {
509
+ if (payload.type === "command" && payload.command === "onSendUserMessage") {
209
510
  const nonce = typeof payload.nonce === "string" ? payload.nonce : null;
210
511
  if (nonce) {
211
512
  if (handledSendUserMessageNonces.has(nonce)) return;
@@ -215,34 +516,53 @@ function ParentMessengerProvider({
215
516
  handledSendUserMessageEvents.add(event);
216
517
  }
217
518
  const params = payload.data;
218
- const prompt = (params.text ?? params.state?.[STATE_VARIABLE_HUMAN2]?.input ?? "").trim();
519
+ const prompt = typeof params.text === "string" ? params.text.trim() : typeof params.state?.[STATE_VARIABLE_HUMAN2]?.input === "string" ? params.state[STATE_VARIABLE_HUMAN2].input.trim() : "";
520
+ const references = normalizeReferences(
521
+ params.references ?? params.state?.[STATE_VARIABLE_HUMAN2]?.references
522
+ );
523
+ const referenceComposition = params.referenceComposition ?? params.state?.[STATE_VARIABLE_HUMAN2]?.referenceComposition;
524
+ const humanInput = buildHumanMessageInputPayload({
525
+ content: prompt,
526
+ references,
527
+ referenceComposition
528
+ });
529
+ if (!humanInput) {
530
+ if (payload.nonce) {
531
+ sendResponse(payload.nonce, { ok: true });
532
+ }
533
+ return;
534
+ }
219
535
  const newMessage = {
220
536
  id: createMessageId(),
221
537
  type: "human",
222
- content: prompt
538
+ content: prompt,
539
+ submittedInput: humanInput.input,
540
+ ...humanInput.referenceComposition ? { referenceComposition: humanInput.referenceComposition } : {},
541
+ ...references.length > 0 ? { references } : {}
223
542
  };
543
+ const stream = streamRef2.current;
544
+ const activeFollowUpMode = stream?.isLoading ? params.followUpMode && params.followUpMode !== "default" ? params.followUpMode : stream.followUpBehavior ?? "queue" : void 0;
224
545
  const requestOptions = buildInjectedRequestOptions({
225
546
  defaults: latestOptionsRef.current?.request,
226
547
  state: params.state,
227
- humanInput: {
228
- input: prompt
229
- }
548
+ humanInput
230
549
  });
231
- streamRef2.current?.submit(
550
+ stream?.submit(
232
551
  {
233
- input: {
234
- input: prompt
235
- },
552
+ input: humanInput,
236
553
  ...requestOptions.state ? { state: requestOptions.state } : {}
237
554
  },
238
555
  {
239
556
  newThread: params.newThread,
557
+ ...activeFollowUpMode ? { followUpMode: activeFollowUpMode } : {},
240
558
  ...requestOptions.context ? { context: requestOptions.context } : {},
241
559
  ...requestOptions.config ? { config: requestOptions.config } : {},
242
- optimisticValues: (prev) => {
243
- const prevMessages = prev?.messages ?? [];
244
- return { ...prev, messages: [...prevMessages, newMessage] };
245
- }
560
+ ...!activeFollowUpMode ? {
561
+ optimisticValues: (prev) => {
562
+ const prevMessages = prev?.messages ?? [];
563
+ return { ...prev, messages: [...prevMessages, newMessage] };
564
+ }
565
+ } : {}
246
566
  }
247
567
  );
248
568
  if (payload.nonce) {
@@ -250,7 +570,28 @@ function ParentMessengerProvider({
250
570
  }
251
571
  return;
252
572
  }
253
- if (payload.type == "command" && payload.command === "onSetOptions") {
573
+ if (payload.type === "command" && payload.command === "onSetComposerValue") {
574
+ const nextPayload = payload.data ?? null;
575
+ const normalizedPayload = nextPayload && Array.isArray(nextPayload.references) ? {
576
+ ...nextPayload,
577
+ references: normalizeReferences(nextPayload.references)
578
+ } : nextPayload;
579
+ void Promise.all(
580
+ [...onSetComposerValueHandlersRef.current].map(
581
+ (handler2) => Promise.resolve(handler2(normalizedPayload))
582
+ )
583
+ ).then(() => {
584
+ if (payload.nonce) {
585
+ sendResponse(payload.nonce, { ok: true });
586
+ }
587
+ }).catch((error) => {
588
+ if (payload.nonce) {
589
+ sendResponse(payload.nonce, void 0, error);
590
+ }
591
+ });
592
+ return;
593
+ }
594
+ if (payload.type === "command" && payload.command === "onSetOptions") {
254
595
  latestOptionsRef.current = payload.data ?? null;
255
596
  if (onSetOptionsHandlersRef.current.size > 0) {
256
597
  onSetOptionsHandlersRef.current.forEach((handler2) => {
@@ -262,16 +603,41 @@ function ParentMessengerProvider({
262
603
  }
263
604
  return;
264
605
  }
265
- if (payload.type == "command" && payload.command === "onSetThreadId") {
606
+ if (payload.type === "command" && payload.command === "onFocusComposer") {
607
+ void Promise.all(
608
+ [...onFocusComposerHandlersRef.current].map(
609
+ (handler2) => Promise.resolve(handler2())
610
+ )
611
+ ).then(() => {
612
+ if (payload.nonce) {
613
+ sendResponse(payload.nonce, { ok: true });
614
+ }
615
+ }).catch((error) => {
616
+ if (payload.nonce) {
617
+ sendResponse(payload.nonce, void 0, error);
618
+ }
619
+ });
620
+ return;
621
+ }
622
+ if (payload.type === "command" && payload.command === "onSetThreadId") {
266
623
  const data = payload.data;
267
624
  const nextThreadId = data?.threadId ?? null;
268
625
  const stream = streamRef2.current;
626
+ if (stream?.threadId === nextThreadId) {
627
+ if (payload.nonce) {
628
+ sendResponse(payload.nonce, { ok: true });
629
+ }
630
+ return;
631
+ }
269
632
  stream?.reset(nextThreadId, void 0, { suppressThreadChange: true });
270
633
  if (stream && nextThreadId) {
271
634
  stream.loadThread(nextThreadId).catch((err) => {
272
635
  console.warn("Failed to load thread messages", err);
273
636
  });
274
637
  }
638
+ if (payload.nonce) {
639
+ sendResponse(payload.nonce, { ok: true });
640
+ }
275
641
  return;
276
642
  }
277
643
  if (payload.type !== "response") return;
@@ -332,25 +698,55 @@ function ParentMessengerProvider({
332
698
  isParentAvailable,
333
699
  sendCommand,
334
700
  sendEvent,
335
- registerOnSetOptions
701
+ registerOnSetOptions,
702
+ registerOnSetComposerValue,
703
+ registerOnFocusComposer
336
704
  }),
337
- [isParentAvailable, sendCommand, sendEvent, registerOnSetOptions]
705
+ [
706
+ isParentAvailable,
707
+ sendCommand,
708
+ sendEvent,
709
+ registerOnSetOptions,
710
+ registerOnSetComposerValue,
711
+ registerOnFocusComposer
712
+ ]
338
713
  );
339
714
  return /* @__PURE__ */ jsx(ParentMessengerContext.Provider, { value, children });
340
715
  }
341
716
 
342
717
  // src/hooks/useParentMessenger.tsx
343
- function useParentMessenger({ onSetOptions } = {}) {
718
+ function useParentMessenger({
719
+ onSetOptions,
720
+ onSetComposerValue,
721
+ onFocusComposer
722
+ } = {}) {
344
723
  const context = useContext(ParentMessengerContext);
345
724
  if (!context) {
346
- throw new Error("useParentMessenger must be used within a ParentMessengerProvider");
725
+ throw new Error(
726
+ "useParentMessenger must be used within a ParentMessengerProvider"
727
+ );
347
728
  }
348
- const { registerOnSetOptions, ...messenger } = context;
729
+ const {
730
+ registerOnSetOptions,
731
+ registerOnSetComposerValue,
732
+ registerOnFocusComposer,
733
+ ...messenger
734
+ } = context;
349
735
  const onSetOptionsRef = useRef2(onSetOptions);
736
+ const onSetComposerValueRef = useRef2(onSetComposerValue);
737
+ const onFocusComposerRef = useRef2(onFocusComposer);
350
738
  useEffect2(() => {
351
739
  onSetOptionsRef.current = onSetOptions;
352
740
  }, [onSetOptions]);
741
+ useEffect2(() => {
742
+ onSetComposerValueRef.current = onSetComposerValue;
743
+ }, [onSetComposerValue]);
744
+ useEffect2(() => {
745
+ onFocusComposerRef.current = onFocusComposer;
746
+ }, [onFocusComposer]);
353
747
  const hasOnSetOptions = Boolean(onSetOptions);
748
+ const hasOnSetComposerValue = Boolean(onSetComposerValue);
749
+ const hasOnFocusComposer = Boolean(onFocusComposer);
354
750
  useEffect2(() => {
355
751
  if (!hasOnSetOptions) return;
356
752
  const handler = (options) => {
@@ -358,6 +754,20 @@ function useParentMessenger({ onSetOptions } = {}) {
358
754
  };
359
755
  return registerOnSetOptions(handler);
360
756
  }, [hasOnSetOptions, registerOnSetOptions]);
757
+ useEffect2(() => {
758
+ if (!hasOnSetComposerValue) return;
759
+ const handler = (payload) => {
760
+ onSetComposerValueRef.current?.(payload);
761
+ };
762
+ return registerOnSetComposerValue(handler);
763
+ }, [hasOnSetComposerValue, registerOnSetComposerValue]);
764
+ useEffect2(() => {
765
+ if (!hasOnFocusComposer) return;
766
+ const handler = () => {
767
+ onFocusComposerRef.current?.();
768
+ };
769
+ return registerOnFocusComposer(handler);
770
+ }, [hasOnFocusComposer, registerOnFocusComposer]);
361
771
  return messenger;
362
772
  }
363
773
 
@@ -522,12 +932,39 @@ var en_US_default = {
522
932
  statusOnline: "Online",
523
933
  missingConfigShort: "Missing ChatKit configuration.",
524
934
  missingConfigDetail: "Missing ChatKit configuration. Check `VITE_XPERTAI_API_URL`, and the `clientSecret` prop.",
935
+ missingApiUrlShort: "Missing ChatKit API URL.",
936
+ missingApiUrlDetail: "Missing ChatKit API URL. Check `VITE_XPERTAI_API_URL` or `options.api.apiUrl`.",
937
+ missingClientSecretShort: "Missing ChatKit client secret.",
938
+ missingClientSecretDetail: "Missing ChatKit client secret. Check the `clientSecret` prop or `api.getClientSecret` integration.",
939
+ missingApiUrlAndClientSecretShort: "Missing ChatKit API URL and client secret.",
940
+ missingApiUrlAndClientSecretDetail: "Missing ChatKit API URL and client secret. Check `VITE_XPERTAI_API_URL`, `options.api.apiUrl`, and your client secret integration.",
525
941
  loadingThread: "Loading thread...",
526
942
  stop: "Stop",
527
943
  send: "Send message",
944
+ referencedContentOnly: "Referenced content",
945
+ youLabel: "You",
528
946
  scrollToBottom: "Scroll to bottom",
529
947
  retryUpload: "Retry upload",
530
948
  poweredBy: "Powered by Xpert AI",
949
+ followUps: {
950
+ label: "Follow-up behavior",
951
+ settings: "Settings",
952
+ idleHint: "Used when you send while a run is active.",
953
+ activeHint: "This message will use the selected busy-run behavior.",
954
+ pending: "Pending follow-ups",
955
+ queue: "Queue",
956
+ steer: "Steer",
957
+ steerAction: "Steer",
958
+ promoteToSteer: "Steer now",
959
+ sendNow: "Send now",
960
+ remove: "Remove pending follow-up",
961
+ more: "More actions",
962
+ edit: "Edit message",
963
+ turnOffQueueing: "Turn off queueing",
964
+ queueHint: "Starts after the current run finishes",
965
+ manualQueueHint: "Ready to send as a new run",
966
+ steerHint: "Injects after the current tool call"
967
+ },
531
968
  errors: {
532
969
  loadMessages: "Failed to load thread messages",
533
970
  createThread: "Failed to create thread",
@@ -558,7 +995,9 @@ var en_US_default = {
558
995
  },
559
996
  composer: {
560
997
  openMenu: "Open menu",
561
- addAttachment: "Add attachment"
998
+ addAttachment: "Add attachment",
999
+ removeReference: "Remove reference",
1000
+ quoteSelection: "Quote selection"
562
1001
  },
563
1002
  sheet: {
564
1003
  close: "Close"
@@ -573,7 +1012,10 @@ var en_US_default = {
573
1012
  },
574
1013
  message: {
575
1014
  answer: "Answer",
576
- reasoning: "Reasoning"
1015
+ reasoning: "Reasoning",
1016
+ loading: "Loading",
1017
+ thinking: "Thinking",
1018
+ answering: "Answering"
577
1019
  }
578
1020
  };
579
1021
 
@@ -585,12 +1027,39 @@ var zh_CN_default = {
585
1027
  statusOnline: "\u5728\u7EBF",
586
1028
  missingConfigShort: "\u7F3A\u5C11 ChatKit \u914D\u7F6E\u3002",
587
1029
  missingConfigDetail: "\u7F3A\u5C11 ChatKit \u914D\u7F6E\u3002\u8BF7\u68C0\u67E5 `VITE_XPERTAI_API_URL` \u548C `clientSecret` \u53C2\u6570\u3002",
1030
+ missingApiUrlShort: "\u7F3A\u5C11 ChatKit API URL\u3002",
1031
+ missingApiUrlDetail: "\u7F3A\u5C11 ChatKit API URL\u3002\u8BF7\u68C0\u67E5 `VITE_XPERTAI_API_URL` \u6216 `options.api.apiUrl`\u3002",
1032
+ missingClientSecretShort: "\u7F3A\u5C11 ChatKit client secret\u3002",
1033
+ missingClientSecretDetail: "\u7F3A\u5C11 ChatKit client secret\u3002\u8BF7\u68C0\u67E5 `clientSecret` \u53C2\u6570\u6216 `api.getClientSecret` \u96C6\u6210\u3002",
1034
+ missingApiUrlAndClientSecretShort: "\u7F3A\u5C11 ChatKit API URL \u548C client secret\u3002",
1035
+ 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
1036
  loadingThread: "\u6B63\u5728\u52A0\u8F7D\u7EBF\u7A0B...",
589
1037
  stop: "\u505C\u6B62",
590
1038
  send: "\u53D1\u9001\u6D88\u606F",
1039
+ referencedContentOnly: "\u5DF2\u5F15\u7528\u5185\u5BB9",
1040
+ youLabel: "\u4F60",
591
1041
  scrollToBottom: "\u56DE\u5230\u5E95\u90E8",
592
1042
  retryUpload: "\u91CD\u65B0\u4E0A\u4F20",
593
1043
  poweredBy: "\u7531 Xpert AI \u9A71\u52A8",
1044
+ followUps: {
1045
+ label: "Follow-up \u6A21\u5F0F",
1046
+ settings: "\u8BBE\u7F6E",
1047
+ idleHint: "\u4EC5\u5728\u8FD0\u884C\u4E2D\u53D1\u9001\u6D88\u606F\u65F6\u751F\u6548\u3002",
1048
+ activeHint: "\u5F53\u524D\u6D88\u606F\u4F1A\u6309\u6240\u9009\u7684\u8FD0\u884C\u4E2D\u884C\u4E3A\u5904\u7406\u3002",
1049
+ pending: "\u5F85\u5904\u7406 Follow-up",
1050
+ queue: "\u6392\u961F",
1051
+ steer: "\u5F15\u5BFC",
1052
+ steerAction: "Steer",
1053
+ promoteToSteer: "\u8F6C\u4E3A\u5F15\u5BFC",
1054
+ sendNow: "\u7ACB\u5373\u53D1\u9001",
1055
+ remove: "\u79FB\u9664\u6B64\u5F85\u5904\u7406 Follow-up",
1056
+ more: "\u66F4\u591A\u64CD\u4F5C",
1057
+ edit: "\u7F16\u8F91\u6D88\u606F",
1058
+ turnOffQueueing: "\u5173\u95ED\u6392\u961F",
1059
+ queueHint: "\u5F53\u524D\u8FD0\u884C\u7ED3\u675F\u540E\u5F00\u542F\u4E0B\u4E00\u8F6E",
1060
+ manualQueueHint: "\u4FDD\u7559\u4E3A\u5F85\u53D1\u9001\uFF0C\u53EF\u624B\u52A8\u5F00\u542F\u65B0\u4E00\u8F6E",
1061
+ steerHint: "\u5F53\u524D\u5DE5\u5177\u8C03\u7528\u5B8C\u6210\u540E\u6CE8\u5165"
1062
+ },
594
1063
  errors: {
595
1064
  loadMessages: "\u52A0\u8F7D\u7EBF\u7A0B\u6D88\u606F\u5931\u8D25",
596
1065
  createThread: "\u521B\u5EFA\u7EBF\u7A0B\u5931\u8D25",
@@ -621,7 +1090,9 @@ var zh_CN_default = {
621
1090
  },
622
1091
  composer: {
623
1092
  openMenu: "\u6253\u5F00\u83DC\u5355",
624
- addAttachment: "\u6DFB\u52A0\u9644\u4EF6"
1093
+ addAttachment: "\u6DFB\u52A0\u9644\u4EF6",
1094
+ removeReference: "\u79FB\u9664\u5F15\u7528",
1095
+ quoteSelection: "\u5F15\u7528\u9009\u4E2D\u5185\u5BB9"
625
1096
  },
626
1097
  sheet: {
627
1098
  close: "\u5173\u95ED"
@@ -636,7 +1107,10 @@ var zh_CN_default = {
636
1107
  },
637
1108
  message: {
638
1109
  answer: "\u56DE\u7B54",
639
- reasoning: "\u63A8\u7406"
1110
+ reasoning: "\u63A8\u7406",
1111
+ loading: "\u6B63\u5728\u52A0\u8F7D",
1112
+ thinking: "\u6B63\u5728\u601D\u8003",
1113
+ answering: "\u6B63\u5728\u751F\u6210"
640
1114
  }
641
1115
  };
642
1116
 
@@ -1161,13 +1635,14 @@ import { jsx as jsx7 } from "react/jsx-runtime";
1161
1635
  function SendButton({
1162
1636
  disabled = false,
1163
1637
  isLoading = false,
1638
+ showStop = isLoading,
1164
1639
  onStop,
1165
1640
  stopLabel = "Stop",
1166
1641
  sendLabel = "Send"
1167
1642
  }) {
1168
1643
  const { theme } = useTheme();
1169
1644
  const roundedClass = getRoundedClass(theme.radius);
1170
- if (isLoading) {
1645
+ if (showStop) {
1171
1646
  return /* @__PURE__ */ jsx7(
1172
1647
  "button",
1173
1648
  {
@@ -1416,103 +1891,471 @@ function HistorySidebar({
1416
1891
  ] });
1417
1892
  }
1418
1893
 
1419
- // src/components/thread/messages/ai.tsx
1420
- import * as React13 from "react";
1421
- import { ChevronDown, CheckCircle2, XCircle, Loader2 } from "lucide-react";
1422
-
1423
- // src/components/ui/badge.tsx
1424
- import * as React9 from "react";
1425
- import { jsx as jsx11 } from "react/jsx-runtime";
1426
- 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
- var variants = {
1428
- default: "bg-primary text-primary-foreground",
1429
- secondary: "bg-secondary text-secondary-foreground",
1430
- outline: "border-input text-foreground"
1431
- };
1432
- var Badge = React9.forwardRef(
1433
- ({ className, variant = "default", ...props }, ref) => {
1434
- return /* @__PURE__ */ jsx11("span", { ref, className: cn(base, variants[variant], className), ...props });
1435
- }
1436
- );
1437
- Badge.displayName = "Badge";
1438
-
1439
- // src/components/ui/card.tsx
1894
+ // src/components/composer/pending-follow-ups.tsx
1440
1895
  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(
1444
- "div",
1896
+ import {
1897
+ CornerDownLeft,
1898
+ Ellipsis,
1899
+ Info,
1900
+ PencilLine,
1901
+ SlidersHorizontal as SlidersHorizontal2,
1902
+ Trash2 as Trash22
1903
+ } from "lucide-react";
1904
+
1905
+ // src/components/ui/tooltip.tsx
1906
+ import "react";
1907
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
1908
+ import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
1909
+ function TooltipProvider({
1910
+ delayDuration = 0,
1911
+ ...props
1912
+ }) {
1913
+ return /* @__PURE__ */ jsx11(
1914
+ TooltipPrimitive.Provider,
1445
1915
  {
1446
- ref,
1447
- className: cn(
1448
- "rounded-xl border bg-background/80 text-foreground shadow-[0_14px_40px_-30px_rgba(15,23,42,0.5)] backdrop-blur",
1449
- className
1450
- ),
1916
+ "data-slot": "tooltip-provider",
1917
+ delayDuration,
1451
1918
  ...props
1452
1919
  }
1453
- )
1454
- );
1455
- 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 })
1458
- );
1459
- 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 }));
1461
- CardTitle.displayName = "CardTitle";
1462
- var CardDescription = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx12("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
1463
- CardDescription.displayName = "CardDescription";
1464
- var CardContent = React10.forwardRef(
1465
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx12("div", { ref, className: cn("px-6 pb-6", className), ...props })
1466
- );
1467
- 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 })
1470
- );
1471
- 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 })
1474
- );
1475
- CardAction.displayName = "CardAction";
1476
-
1477
- // 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);
1481
- function Tabs({ className, defaultValue, value, onValueChange, ...props }) {
1482
- const [internalValue, setInternalValue] = React11.useState(defaultValue ?? "");
1483
- const activeValue = value ?? internalValue;
1484
- const setValue = React11.useCallback(
1485
- (nextValue) => {
1486
- if (value === void 0) setInternalValue(nextValue);
1487
- onValueChange?.(nextValue);
1488
- },
1489
- [onValueChange, value]
1490
1920
  );
1491
- return /* @__PURE__ */ jsx13(TabsContext.Provider, { value: { value: activeValue, setValue }, children: /* @__PURE__ */ jsx13("div", { className: cn("w-full", className), ...props }) });
1492
1921
  }
1493
- var TabsList = React11.forwardRef(
1494
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
1495
- "div",
1922
+ function Tooltip({
1923
+ ...props
1924
+ }) {
1925
+ return /* @__PURE__ */ jsx11(TooltipProvider, { children: /* @__PURE__ */ jsx11(
1926
+ TooltipPrimitive.Root,
1496
1927
  {
1497
- ref,
1928
+ "data-slot": "tooltip",
1929
+ ...props
1930
+ }
1931
+ ) });
1932
+ }
1933
+ function TooltipTrigger({
1934
+ ...props
1935
+ }) {
1936
+ return /* @__PURE__ */ jsx11(
1937
+ TooltipPrimitive.Trigger,
1938
+ {
1939
+ "data-slot": "tooltip-trigger",
1940
+ ...props
1941
+ }
1942
+ );
1943
+ }
1944
+ function TooltipContent({
1945
+ className,
1946
+ sideOffset = 0,
1947
+ children,
1948
+ ...props
1949
+ }) {
1950
+ return /* @__PURE__ */ jsx11(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs5(
1951
+ TooltipPrimitive.Content,
1952
+ {
1953
+ "data-slot": "tooltip-content",
1954
+ sideOffset,
1498
1955
  className: cn(
1499
- "inline-flex h-11 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
1956
+ "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",
1500
1957
  className
1501
1958
  ),
1502
- role: "tablist",
1503
- ...props
1504
- }
1505
- )
1506
- );
1507
- TabsList.displayName = "TabsList";
1508
- var TabsTrigger = React11.forwardRef(
1509
- ({ className, value, onClick, ...props }, ref) => {
1510
- const context = React11.useContext(TabsContext);
1511
- if (!context) {
1512
- throw new Error("TabsTrigger must be used within Tabs");
1959
+ ...props,
1960
+ children: [
1961
+ children,
1962
+ /* @__PURE__ */ jsx11(TooltipPrimitive.Arrow, { className: "bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
1963
+ ]
1513
1964
  }
1514
- const isActive = context.value === value;
1515
- return /* @__PURE__ */ jsx13(
1965
+ ) });
1966
+ }
1967
+
1968
+ // src/components/composer/pending-follow-ups.tsx
1969
+ import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
1970
+ function getPendingFollowUpText(item, referencedContentFallback) {
1971
+ const text = item.request?.input?.input?.trim() ?? "";
1972
+ if (text) {
1973
+ return text;
1974
+ }
1975
+ const references = normalizeReferences(item.request?.input?.references);
1976
+ if (references.length === 0) {
1977
+ return referencedContentFallback;
1978
+ }
1979
+ const firstReferenceLabel = getReferenceLabel(references[0]);
1980
+ if (references.length === 1) {
1981
+ return firstReferenceLabel;
1982
+ }
1983
+ return `${firstReferenceLabel} +${references.length - 1}`;
1984
+ }
1985
+ function useRoundedClasses() {
1986
+ const { theme } = useTheme();
1987
+ return {
1988
+ top: theme.radius ? {
1989
+ pill: "rounded-t-full",
1990
+ round: "rounded-t-xl",
1991
+ soft: "rounded-t-lg",
1992
+ sharp: "rounded-t-none"
1993
+ }[theme.radius] : "rounded-t-lg",
1994
+ panel: getRoundedClass(theme.radius, "rounded-lg"),
1995
+ control: getRoundedClass(theme.radius, "rounded-md")
1996
+ };
1997
+ }
1998
+ function PendingFollowUps({
1999
+ items,
2000
+ isLoading,
2001
+ followUpBehavior,
2002
+ onBehaviorChange,
2003
+ onPromoteToSteer,
2004
+ canSendNow,
2005
+ onSendNow,
2006
+ onEdit,
2007
+ onRemove,
2008
+ className
2009
+ }) {
2010
+ const { t } = useChatkitTranslation();
2011
+ const rounded = useRoundedClasses();
2012
+ const referencedContentFallback = t("chat.referencedContentOnly");
2013
+ const [isSettingsOpen, setIsSettingsOpen] = React10.useState(false);
2014
+ const [openMenuId, setOpenMenuId] = React10.useState(null);
2015
+ React10.useEffect(() => {
2016
+ if (items.length === 0 && isSettingsOpen) {
2017
+ setIsSettingsOpen(false);
2018
+ }
2019
+ if (items.every((item) => item.id !== openMenuId)) {
2020
+ setOpenMenuId(null);
2021
+ }
2022
+ }, [isSettingsOpen, items, openMenuId]);
2023
+ if (items.length === 0) {
2024
+ return null;
2025
+ }
2026
+ return /* @__PURE__ */ jsx12(
2027
+ "div",
2028
+ {
2029
+ className: cn(
2030
+ "space-y-2 mx-2 p-2 border border-border border-b-0",
2031
+ rounded.top,
2032
+ className
2033
+ ),
2034
+ children: /* @__PURE__ */ jsxs6("div", { className: "space-y-1", children: [
2035
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-3", children: [
2036
+ /* @__PURE__ */ jsx12("div", { className: "text-xs font-medium text-foreground", children: t("chat.followUps.pending") }),
2037
+ /* @__PURE__ */ jsxs6(Tooltip, { children: [
2038
+ /* @__PURE__ */ jsx12(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
2039
+ "button",
2040
+ {
2041
+ type: "button",
2042
+ onClick: () => setIsSettingsOpen((prev) => !prev),
2043
+ className: cn(
2044
+ "inline-flex h-6 w-6 items-center justify-center transition-colors",
2045
+ isSettingsOpen ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/60 hover:text-foreground",
2046
+ rounded.control
2047
+ ),
2048
+ "aria-label": t("chat.followUps.settings"),
2049
+ "aria-expanded": isSettingsOpen,
2050
+ "aria-controls": "follow-ups-settings-panel",
2051
+ children: [
2052
+ /* @__PURE__ */ jsx12(SlidersHorizontal2, { className: "h-3.5 w-3.5" }),
2053
+ /* @__PURE__ */ jsx12("span", { className: "sr-only", children: t("chat.followUps.settings") })
2054
+ ]
2055
+ }
2056
+ ) }),
2057
+ /* @__PURE__ */ jsx12(TooltipContent, { side: "top", children: t("chat.followUps.settings") })
2058
+ ] })
2059
+ ] }),
2060
+ isSettingsOpen && /* @__PURE__ */ jsx12(
2061
+ "div",
2062
+ {
2063
+ id: "follow-ups-settings-panel",
2064
+ className: cn(
2065
+ "border border-border/70 bg-muted/20 px-3 py-2",
2066
+ rounded.panel
2067
+ ),
2068
+ children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-3", children: [
2069
+ /* @__PURE__ */ jsxs6("div", { className: "min-w-0", children: [
2070
+ /* @__PURE__ */ jsx12("div", { className: "text-xs font-medium text-foreground", children: t("chat.followUps.label") }),
2071
+ /* @__PURE__ */ jsx12("div", { className: "text-[11px] text-muted-foreground", children: isLoading ? t("chat.followUps.activeHint") : t("chat.followUps.idleHint") })
2072
+ ] }),
2073
+ /* @__PURE__ */ jsx12(
2074
+ "div",
2075
+ {
2076
+ className: cn(
2077
+ "inline-flex shrink-0 border border-border bg-background p-1",
2078
+ rounded.control
2079
+ ),
2080
+ children: ["queue", "steer"].map((behavior) => /* @__PURE__ */ jsxs6(Tooltip, { children: [
2081
+ /* @__PURE__ */ jsx12(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx12(
2082
+ "button",
2083
+ {
2084
+ type: "button",
2085
+ onClick: () => {
2086
+ onBehaviorChange(behavior);
2087
+ setIsSettingsOpen(false);
2088
+ },
2089
+ className: cn(
2090
+ "px-3 py-1 text-xs font-medium transition-colors",
2091
+ rounded.control,
2092
+ followUpBehavior === behavior ? "bg-primary text-background" : "text-muted-foreground hover:text-foreground"
2093
+ ),
2094
+ children: behavior === "queue" ? t("chat.followUps.queue") : t("chat.followUps.steer")
2095
+ }
2096
+ ) }),
2097
+ /* @__PURE__ */ jsx12(TooltipContent, { side: "top", children: behavior === "queue" ? t("chat.followUps.queueHint") : t("chat.followUps.steerHint") })
2098
+ ] }, behavior))
2099
+ }
2100
+ )
2101
+ ] })
2102
+ }
2103
+ ),
2104
+ items.map((item) => {
2105
+ const canSendItemNow = item.mode === "queue" && canSendNow(item.id);
2106
+ return /* @__PURE__ */ jsx12(
2107
+ "div",
2108
+ {
2109
+ className: cn(
2110
+ "border border-border/50 bg-muted/15 px-2 py-1",
2111
+ rounded.panel
2112
+ ),
2113
+ children: /* @__PURE__ */ jsxs6("div", { className: "flex items-start gap-2.5", children: [
2114
+ /* @__PURE__ */ jsx12(CornerDownLeft, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
2115
+ /* @__PURE__ */ jsxs6("div", { className: "min-w-0 flex-1", children: [
2116
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-start gap-2", children: [
2117
+ /* @__PURE__ */ jsx12("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx12(
2118
+ "div",
2119
+ {
2120
+ className: "truncate text-[13px] leading-5 text-foreground",
2121
+ title: getPendingFollowUpText(
2122
+ item,
2123
+ referencedContentFallback
2124
+ ),
2125
+ children: getPendingFollowUpText(
2126
+ item,
2127
+ referencedContentFallback
2128
+ )
2129
+ }
2130
+ ) }),
2131
+ /* @__PURE__ */ jsxs6("div", { className: "flex shrink-0 items-center gap-1", children: [
2132
+ item.mode === "queue" && isLoading && /* @__PURE__ */ jsx12(
2133
+ "button",
2134
+ {
2135
+ type: "button",
2136
+ onClick: () => void onPromoteToSteer(item.id),
2137
+ className: cn(
2138
+ "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",
2139
+ rounded.control
2140
+ ),
2141
+ "aria-label": t("chat.followUps.steerAction"),
2142
+ title: t("chat.followUps.steerAction"),
2143
+ children: t("chat.followUps.steerAction")
2144
+ }
2145
+ ),
2146
+ canSendItemNow && /* @__PURE__ */ jsx12(
2147
+ "button",
2148
+ {
2149
+ type: "button",
2150
+ onClick: () => void onSendNow(item.id),
2151
+ className: cn(
2152
+ "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",
2153
+ rounded.control
2154
+ ),
2155
+ "aria-label": t("chat.followUps.sendNow"),
2156
+ title: t("chat.followUps.sendNow"),
2157
+ children: t("chat.followUps.sendNow")
2158
+ }
2159
+ ),
2160
+ item.mode === "queue" && /* @__PURE__ */ jsx12(
2161
+ "button",
2162
+ {
2163
+ type: "button",
2164
+ onClick: () => onRemove(item.id),
2165
+ className: cn(
2166
+ "inline-flex h-6 w-6 shrink-0 items-center justify-center text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
2167
+ rounded.control
2168
+ ),
2169
+ "aria-label": t("chat.followUps.remove"),
2170
+ title: t("chat.followUps.remove"),
2171
+ children: /* @__PURE__ */ jsx12(Trash22, { size: 13 })
2172
+ }
2173
+ ),
2174
+ item.mode === "queue" && /* @__PURE__ */ jsxs6(
2175
+ Popover,
2176
+ {
2177
+ open: openMenuId === item.id,
2178
+ onOpenChange: (open) => setOpenMenuId(open ? item.id : null),
2179
+ children: [
2180
+ /* @__PURE__ */ jsx12(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx12(
2181
+ "button",
2182
+ {
2183
+ type: "button",
2184
+ className: cn(
2185
+ "inline-flex h-6 w-6 shrink-0 items-center justify-center text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
2186
+ rounded.control
2187
+ ),
2188
+ "aria-label": t("chat.followUps.more"),
2189
+ title: t("chat.followUps.more"),
2190
+ children: /* @__PURE__ */ jsx12(Ellipsis, { size: 13 })
2191
+ }
2192
+ ) }),
2193
+ /* @__PURE__ */ jsx12(
2194
+ PopoverContent,
2195
+ {
2196
+ align: "end",
2197
+ side: "bottom",
2198
+ className: cn(
2199
+ "w-52 border-border/70 bg-background p-1.5",
2200
+ rounded.panel
2201
+ ),
2202
+ children: /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-1", children: [
2203
+ /* @__PURE__ */ jsxs6(
2204
+ "button",
2205
+ {
2206
+ type: "button",
2207
+ onClick: () => {
2208
+ setOpenMenuId(null);
2209
+ onEdit(item.id);
2210
+ },
2211
+ className: cn(
2212
+ "flex items-center gap-2 px-2 py-1.5 text-left text-sm text-foreground transition-colors hover:bg-muted",
2213
+ rounded.control
2214
+ ),
2215
+ children: [
2216
+ /* @__PURE__ */ jsx12(PencilLine, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
2217
+ /* @__PURE__ */ jsx12("span", { children: t("chat.followUps.edit") })
2218
+ ]
2219
+ }
2220
+ ),
2221
+ /* @__PURE__ */ jsxs6(
2222
+ "button",
2223
+ {
2224
+ type: "button",
2225
+ onClick: () => {
2226
+ setOpenMenuId(null);
2227
+ onBehaviorChange("steer");
2228
+ },
2229
+ className: cn(
2230
+ "flex items-center gap-2 px-2 py-1.5 text-left text-sm text-foreground transition-colors hover:bg-muted",
2231
+ rounded.control
2232
+ ),
2233
+ children: [
2234
+ /* @__PURE__ */ jsx12(CornerDownLeft, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
2235
+ /* @__PURE__ */ jsx12("span", { children: t("chat.followUps.turnOffQueueing") })
2236
+ ]
2237
+ }
2238
+ )
2239
+ ] })
2240
+ }
2241
+ )
2242
+ ]
2243
+ }
2244
+ )
2245
+ ] })
2246
+ ] }),
2247
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1.5 text-[10px] leading-4 text-muted-foreground", children: [
2248
+ /* @__PURE__ */ jsx12(Info, { className: "h-3 w-3 shrink-0" }),
2249
+ /* @__PURE__ */ jsx12("span", { className: "truncate", children: item.mode === "queue" ? canSendItemNow ? t("chat.followUps.manualQueueHint") : t("chat.followUps.queueHint") : t("chat.followUps.steerHint") })
2250
+ ] })
2251
+ ] })
2252
+ ] })
2253
+ },
2254
+ item.id
2255
+ );
2256
+ })
2257
+ ] })
2258
+ }
2259
+ );
2260
+ }
2261
+
2262
+ // src/components/thread/messages/ai.tsx
2263
+ import * as React14 from "react";
2264
+ import { ChevronDown, CheckCircle2, XCircle, Loader2 } from "lucide-react";
2265
+
2266
+ // src/components/ui/badge.tsx
2267
+ import * as React11 from "react";
2268
+ import { jsx as jsx13 } from "react/jsx-runtime";
2269
+ 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";
2270
+ var variants = {
2271
+ default: "bg-primary text-primary-foreground",
2272
+ secondary: "bg-secondary text-secondary-foreground",
2273
+ outline: "border-input text-foreground"
2274
+ };
2275
+ var Badge = React11.forwardRef(
2276
+ ({ className, variant = "default", ...props }, ref) => {
2277
+ return /* @__PURE__ */ jsx13("span", { ref, className: cn(base, variants[variant], className), ...props });
2278
+ }
2279
+ );
2280
+ Badge.displayName = "Badge";
2281
+
2282
+ // src/components/ui/card.tsx
2283
+ import * as React12 from "react";
2284
+ import { jsx as jsx14 } from "react/jsx-runtime";
2285
+ var Card = React12.forwardRef(
2286
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx14(
2287
+ "div",
2288
+ {
2289
+ ref,
2290
+ className: cn(
2291
+ "rounded-xl border bg-background/80 text-foreground shadow-[0_14px_40px_-30px_rgba(15,23,42,0.5)] backdrop-blur",
2292
+ className
2293
+ ),
2294
+ ...props
2295
+ }
2296
+ )
2297
+ );
2298
+ Card.displayName = "Card";
2299
+ var CardHeader = React12.forwardRef(
2300
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx14("div", { ref, className: cn("flex flex-col gap-1.5 px-6 pt-6", className), ...props })
2301
+ );
2302
+ CardHeader.displayName = "CardHeader";
2303
+ var CardTitle = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx14("h3", { ref, className: cn("text-lg font-semibold leading-tight", className), ...props }));
2304
+ CardTitle.displayName = "CardTitle";
2305
+ var CardDescription = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx14("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
2306
+ CardDescription.displayName = "CardDescription";
2307
+ var CardContent = React12.forwardRef(
2308
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx14("div", { ref, className: cn("px-6 pb-6", className), ...props })
2309
+ );
2310
+ CardContent.displayName = "CardContent";
2311
+ var CardFooter = React12.forwardRef(
2312
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx14("div", { ref, className: cn("flex items-center px-6 pb-6", className), ...props })
2313
+ );
2314
+ CardFooter.displayName = "CardFooter";
2315
+ var CardAction = React12.forwardRef(
2316
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx14("div", { ref, className: cn("ml-auto flex items-center", className), ...props })
2317
+ );
2318
+ CardAction.displayName = "CardAction";
2319
+
2320
+ // src/components/ui/tabs.tsx
2321
+ import * as React13 from "react";
2322
+ import { jsx as jsx15 } from "react/jsx-runtime";
2323
+ var TabsContext = React13.createContext(null);
2324
+ function Tabs({ className, defaultValue, value, onValueChange, ...props }) {
2325
+ const [internalValue, setInternalValue] = React13.useState(defaultValue ?? "");
2326
+ const activeValue = value ?? internalValue;
2327
+ const setValue = React13.useCallback(
2328
+ (nextValue) => {
2329
+ if (value === void 0) setInternalValue(nextValue);
2330
+ onValueChange?.(nextValue);
2331
+ },
2332
+ [onValueChange, value]
2333
+ );
2334
+ return /* @__PURE__ */ jsx15(TabsContext.Provider, { value: { value: activeValue, setValue }, children: /* @__PURE__ */ jsx15("div", { className: cn("w-full", className), ...props }) });
2335
+ }
2336
+ var TabsList = React13.forwardRef(
2337
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx15(
2338
+ "div",
2339
+ {
2340
+ ref,
2341
+ className: cn(
2342
+ "inline-flex h-11 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
2343
+ className
2344
+ ),
2345
+ role: "tablist",
2346
+ ...props
2347
+ }
2348
+ )
2349
+ );
2350
+ TabsList.displayName = "TabsList";
2351
+ var TabsTrigger = React13.forwardRef(
2352
+ ({ className, value, onClick, ...props }, ref) => {
2353
+ const context = React13.useContext(TabsContext);
2354
+ if (!context) {
2355
+ throw new Error("TabsTrigger must be used within Tabs");
2356
+ }
2357
+ const isActive = context.value === value;
2358
+ return /* @__PURE__ */ jsx15(
1516
2359
  "button",
1517
2360
  {
1518
2361
  ref,
@@ -1534,14 +2377,14 @@ var TabsTrigger = React11.forwardRef(
1534
2377
  }
1535
2378
  );
1536
2379
  TabsTrigger.displayName = "TabsTrigger";
1537
- var TabsContent = React11.forwardRef(
2380
+ var TabsContent = React13.forwardRef(
1538
2381
  ({ className, value, ...props }, ref) => {
1539
- const context = React11.useContext(TabsContext);
2382
+ const context = React13.useContext(TabsContext);
1540
2383
  if (!context) {
1541
2384
  throw new Error("TabsContent must be used within Tabs");
1542
2385
  }
1543
2386
  if (context.value !== value) return null;
1544
- return /* @__PURE__ */ jsx13(
2387
+ return /* @__PURE__ */ jsx15(
1545
2388
  "div",
1546
2389
  {
1547
2390
  ref,
@@ -1565,7 +2408,7 @@ import remarkMath from "remark-math";
1565
2408
  import {
1566
2409
  Children,
1567
2410
  memo,
1568
- useState as useState5
2411
+ useState as useState6
1569
2412
  } from "react";
1570
2413
  import { CheckIcon, CopyIcon } from "lucide-react";
1571
2414
 
@@ -1575,7 +2418,7 @@ import tsx from "react-syntax-highlighter/dist/esm/languages/prism/tsx";
1575
2418
  import python from "react-syntax-highlighter/dist/esm/languages/prism/python";
1576
2419
  import { coldarkDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
1577
2420
  import "react";
1578
- import { jsx as jsx14 } from "react/jsx-runtime";
2421
+ import { jsx as jsx16 } from "react/jsx-runtime";
1579
2422
  SyntaxHighlighterPrism.registerLanguage("js", tsx);
1580
2423
  SyntaxHighlighterPrism.registerLanguage("jsx", tsx);
1581
2424
  SyntaxHighlighterPrism.registerLanguage("ts", tsx);
@@ -1586,7 +2429,7 @@ var SyntaxHighlighter = ({
1586
2429
  language,
1587
2430
  className
1588
2431
  }) => {
1589
- return /* @__PURE__ */ jsx14(
2432
+ return /* @__PURE__ */ jsx16(
1590
2433
  SyntaxHighlighterPrism,
1591
2434
  {
1592
2435
  language,
@@ -1605,75 +2448,10 @@ var SyntaxHighlighter = ({
1605
2448
 
1606
2449
  // src/components/thread/tooltip-icon-button.tsx
1607
2450
  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
- }
1671
-
1672
- // src/components/thread/tooltip-icon-button.tsx
1673
- import { jsx as jsx16, jsxs as jsxs6 } from "react/jsx-runtime";
2451
+ import { jsx as jsx17, jsxs as jsxs7 } from "react/jsx-runtime";
1674
2452
  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(
2453
+ return /* @__PURE__ */ jsx17(TooltipProvider, { children: /* @__PURE__ */ jsxs7(Tooltip, { children: [
2454
+ /* @__PURE__ */ jsx17(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs7(
1677
2455
  Button,
1678
2456
  {
1679
2457
  variant: "ghost",
@@ -1683,18 +2461,18 @@ var TooltipIconButton = forwardRef5(({ children, tooltip, side = "bottom", class
1683
2461
  ref,
1684
2462
  children: [
1685
2463
  children,
1686
- /* @__PURE__ */ jsx16("span", { className: "sr-only", children: tooltip })
2464
+ /* @__PURE__ */ jsx17("span", { className: "sr-only", children: tooltip })
1687
2465
  ]
1688
2466
  }
1689
2467
  ) }),
1690
- /* @__PURE__ */ jsx16(TooltipContent, { side, children: tooltip })
2468
+ /* @__PURE__ */ jsx17(TooltipContent, { side, children: tooltip })
1691
2469
  ] }) });
1692
2470
  });
1693
2471
  TooltipIconButton.displayName = "TooltipIconButton";
1694
2472
 
1695
2473
  // src/components/thread/markdown-text.tsx
1696
2474
  import "katex/dist/katex.min.css";
1697
- import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs7 } from "react/jsx-runtime";
2475
+ import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs8 } from "react/jsx-runtime";
1698
2476
  var getTextContent = (children) => Children.toArray(children).map((child) => {
1699
2477
  if (typeof child === "string" || typeof child === "number") {
1700
2478
  return String(child);
@@ -1704,7 +2482,7 @@ var getTextContent = (children) => Children.toArray(children).map((child) => {
1704
2482
  var useCopyToClipboard = ({
1705
2483
  copiedDuration = 3e3
1706
2484
  } = {}) => {
1707
- const [isCopied, setIsCopied] = useState5(false);
2485
+ const [isCopied, setIsCopied] = useState6(false);
1708
2486
  const copyToClipboard = (value) => {
1709
2487
  if (!value) return;
1710
2488
  navigator.clipboard.writeText(value).then(() => {
@@ -1721,23 +2499,23 @@ var CodeHeader = ({ language, code }) => {
1721
2499
  if (!code || isCopied) return;
1722
2500
  copyToClipboard(code);
1723
2501
  };
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(
2502
+ return /* @__PURE__ */ jsxs8("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: [
2503
+ /* @__PURE__ */ jsx18("span", { className: "lowercase [&>span]:text-xs", children: language }),
2504
+ /* @__PURE__ */ jsxs8(
1727
2505
  TooltipIconButton,
1728
2506
  {
1729
2507
  tooltip: t("markdown.copy"),
1730
2508
  onClick: onCopy,
1731
2509
  children: [
1732
- !isCopied && /* @__PURE__ */ jsx17(CopyIcon, {}),
1733
- isCopied && /* @__PURE__ */ jsx17(CheckIcon, {})
2510
+ !isCopied && /* @__PURE__ */ jsx18(CopyIcon, {}),
2511
+ isCopied && /* @__PURE__ */ jsx18(CheckIcon, {})
1734
2512
  ]
1735
2513
  }
1736
2514
  )
1737
2515
  ] });
1738
2516
  };
1739
2517
  var defaultComponents = {
1740
- h1: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2518
+ h1: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1741
2519
  "h1",
1742
2520
  {
1743
2521
  className: cn(
@@ -1747,7 +2525,7 @@ var defaultComponents = {
1747
2525
  ...props
1748
2526
  }
1749
2527
  ),
1750
- h2: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2528
+ h2: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1751
2529
  "h2",
1752
2530
  {
1753
2531
  className: cn(
@@ -1757,7 +2535,7 @@ var defaultComponents = {
1757
2535
  ...props
1758
2536
  }
1759
2537
  ),
1760
- h3: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2538
+ h3: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1761
2539
  "h3",
1762
2540
  {
1763
2541
  className: cn(
@@ -1767,7 +2545,7 @@ var defaultComponents = {
1767
2545
  ...props
1768
2546
  }
1769
2547
  ),
1770
- h4: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2548
+ h4: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1771
2549
  "h4",
1772
2550
  {
1773
2551
  className: cn(
@@ -1777,7 +2555,7 @@ var defaultComponents = {
1777
2555
  ...props
1778
2556
  }
1779
2557
  ),
1780
- h5: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2558
+ h5: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1781
2559
  "h5",
1782
2560
  {
1783
2561
  className: cn(
@@ -1787,21 +2565,21 @@ var defaultComponents = {
1787
2565
  ...props
1788
2566
  }
1789
2567
  ),
1790
- h6: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2568
+ h6: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1791
2569
  "h6",
1792
2570
  {
1793
2571
  className: cn("my-4 font-semibold first:mt-0 last:mb-0", className),
1794
2572
  ...props
1795
2573
  }
1796
2574
  ),
1797
- p: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2575
+ p: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1798
2576
  "p",
1799
2577
  {
1800
2578
  className: cn("mt-5 mb-5 leading-7 first:mt-0 last:mb-0", className),
1801
2579
  ...props
1802
2580
  }
1803
2581
  ),
1804
- a: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2582
+ a: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1805
2583
  "a",
1806
2584
  {
1807
2585
  className: cn(
@@ -1817,7 +2595,7 @@ var defaultComponents = {
1817
2595
  className,
1818
2596
  node: _node,
1819
2597
  ...props
1820
- }) => /* @__PURE__ */ jsx17(
2598
+ }) => /* @__PURE__ */ jsx18(
1821
2599
  "blockquote",
1822
2600
  {
1823
2601
  className: cn(
@@ -1827,21 +2605,21 @@ var defaultComponents = {
1827
2605
  ...props
1828
2606
  }
1829
2607
  ),
1830
- ul: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2608
+ ul: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1831
2609
  "ul",
1832
2610
  {
1833
2611
  className: cn("my-5 list-outside list-disc pl-6 [&>li]:mt-2", className),
1834
2612
  ...props
1835
2613
  }
1836
2614
  ),
1837
- ol: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2615
+ ol: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1838
2616
  "ol",
1839
2617
  {
1840
2618
  className: cn("my-5 list-outside list-decimal pl-8 [&>li]:mt-2", className),
1841
2619
  ...props
1842
2620
  }
1843
2621
  ),
1844
- hr: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2622
+ hr: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1845
2623
  "hr",
1846
2624
  {
1847
2625
  className: cn("my-5 border-b", className),
@@ -1852,7 +2630,7 @@ var defaultComponents = {
1852
2630
  className,
1853
2631
  node: _node,
1854
2632
  ...props
1855
- }) => /* @__PURE__ */ jsx17(
2633
+ }) => /* @__PURE__ */ jsx18(
1856
2634
  "table",
1857
2635
  {
1858
2636
  className: cn(
@@ -1862,7 +2640,7 @@ var defaultComponents = {
1862
2640
  ...props
1863
2641
  }
1864
2642
  ),
1865
- th: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2643
+ th: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1866
2644
  "th",
1867
2645
  {
1868
2646
  className: cn(
@@ -1872,7 +2650,7 @@ var defaultComponents = {
1872
2650
  ...props
1873
2651
  }
1874
2652
  ),
1875
- td: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2653
+ td: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1876
2654
  "td",
1877
2655
  {
1878
2656
  className: cn(
@@ -1882,7 +2660,7 @@ var defaultComponents = {
1882
2660
  ...props
1883
2661
  }
1884
2662
  ),
1885
- tr: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2663
+ tr: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1886
2664
  "tr",
1887
2665
  {
1888
2666
  className: cn(
@@ -1892,14 +2670,14 @@ var defaultComponents = {
1892
2670
  ...props
1893
2671
  }
1894
2672
  ),
1895
- sup: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2673
+ sup: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1896
2674
  "sup",
1897
2675
  {
1898
2676
  className: cn("[&>a]:text-xs [&>a]:no-underline", className),
1899
2677
  ...props
1900
2678
  }
1901
2679
  ),
1902
- pre: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx17(
2680
+ pre: ({ className, node: _node, ...props }) => /* @__PURE__ */ jsx18(
1903
2681
  "div",
1904
2682
  {
1905
2683
  className: cn(
@@ -1921,15 +2699,15 @@ var defaultComponents = {
1921
2699
  if (match) {
1922
2700
  const language = match[1];
1923
2701
  const normalizedCode = code.replace(/\n$/, "");
1924
- return /* @__PURE__ */ jsxs7(Fragment2, { children: [
1925
- /* @__PURE__ */ jsx17(
2702
+ return /* @__PURE__ */ jsxs8(Fragment2, { children: [
2703
+ /* @__PURE__ */ jsx18(
1926
2704
  CodeHeader,
1927
2705
  {
1928
2706
  language,
1929
2707
  code: normalizedCode
1930
2708
  }
1931
2709
  ),
1932
- /* @__PURE__ */ jsx17(
2710
+ /* @__PURE__ */ jsx18(
1933
2711
  SyntaxHighlighter,
1934
2712
  {
1935
2713
  language,
@@ -1940,7 +2718,7 @@ var defaultComponents = {
1940
2718
  ] });
1941
2719
  }
1942
2720
  if (isBlockCode) {
1943
- return /* @__PURE__ */ jsx17(
2721
+ return /* @__PURE__ */ jsx18(
1944
2722
  "code",
1945
2723
  {
1946
2724
  className: cn(
@@ -1952,7 +2730,7 @@ var defaultComponents = {
1952
2730
  }
1953
2731
  );
1954
2732
  }
1955
- return /* @__PURE__ */ jsx17(
2733
+ return /* @__PURE__ */ jsx18(
1956
2734
  "code",
1957
2735
  {
1958
2736
  className: cn(
@@ -1966,7 +2744,7 @@ var defaultComponents = {
1966
2744
  }
1967
2745
  };
1968
2746
  var MarkdownTextImpl = ({ children }) => {
1969
- return /* @__PURE__ */ jsx17("div", { className: "markdown-content", children: /* @__PURE__ */ jsx17(
2747
+ return /* @__PURE__ */ jsx18("div", { className: "markdown-content", children: /* @__PURE__ */ jsx18(
1970
2748
  ReactMarkdown,
1971
2749
  {
1972
2750
  remarkPlugins: [remarkGfm, remarkMath],
@@ -1980,18 +2758,18 @@ var MarkdownText = memo(MarkdownTextImpl);
1980
2758
 
1981
2759
  // src/components/thread/messages/widget.tsx
1982
2760
  import { SurfaceRenderer } from "@xpert-ai/a2ui-react";
1983
- import { jsx as jsx18 } from "react/jsx-runtime";
2761
+ import { jsx as jsx19 } from "react/jsx-runtime";
1984
2762
  function WidgetMessage({ messageId, data }) {
1985
2763
  const widgets = Array.isArray(data.widgets) ? data.widgets : [];
1986
2764
  if (widgets.length === 0) return null;
1987
2765
  const baseSurfaceId = `widget-${messageId}`;
1988
- return /* @__PURE__ */ jsx18("div", { className: "space-y-3", children: widgets.map((widget, index) => {
2766
+ return /* @__PURE__ */ jsx19("div", { className: "space-y-3", children: widgets.map((widget, index) => {
1989
2767
  const config = widget?.config;
1990
2768
  if (!config || typeof config !== "object") {
1991
2769
  return null;
1992
2770
  }
1993
2771
  const surfaceId = widgets.length > 1 ? `${baseSurfaceId}-${index}` : baseSurfaceId;
1994
- return /* @__PURE__ */ jsx18(
2772
+ return /* @__PURE__ */ jsx19(
1995
2773
  SurfaceRenderer,
1996
2774
  {
1997
2775
  surfaceId,
@@ -2003,7 +2781,7 @@ function WidgetMessage({ messageId, data }) {
2003
2781
  }
2004
2782
 
2005
2783
  // src/components/thread/messages/ai.tsx
2006
- import { jsx as jsx19, jsxs as jsxs8 } from "react/jsx-runtime";
2784
+ import { jsx as jsx20, jsxs as jsxs9 } from "react/jsx-runtime";
2007
2785
  function isTextContent(content) {
2008
2786
  return content.type === "text";
2009
2787
  }
@@ -2047,11 +2825,11 @@ function safeJson(value) {
2047
2825
  function ReasoningBlock({ reasoning }) {
2048
2826
  const blocks = reasoning.filter((item) => item.text?.trim());
2049
2827
  if (blocks.length === 0) return null;
2050
- return /* @__PURE__ */ jsx19("div", { className: "space-y-2", children: blocks.map((item, index) => /* @__PURE__ */ jsx19(
2828
+ return /* @__PURE__ */ jsx20("div", { className: "space-y-2", children: blocks.map((item, index) => /* @__PURE__ */ jsx20(
2051
2829
  "div",
2052
2830
  {
2053
2831
  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 })
2832
+ children: /* @__PURE__ */ jsx20("p", { className: "whitespace-pre-wrap wrap-break-word leading-relaxed", children: item.text })
2055
2833
  },
2056
2834
  item.id ?? `reasoning-${index}`
2057
2835
  )) });
@@ -2059,27 +2837,27 @@ function ReasoningBlock({ reasoning }) {
2059
2837
  function ImageBlock({ content }) {
2060
2838
  const imageUrl = typeof content.image_url === "string" ? content.image_url : typeof content.image_url?.url === "string" ? content.image_url.url : null;
2061
2839
  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) })
2840
+ return /* @__PURE__ */ jsxs9(Card, { children: [
2841
+ /* @__PURE__ */ jsx20(CardHeader, { className: "space-y-1", children: /* @__PURE__ */ jsx20(CardTitle, { className: "text-sm", children: "Image" }) }),
2842
+ /* @__PURE__ */ jsx20(CardContent, { className: "text-xs text-muted-foreground", children: safeJson(content) })
2065
2843
  ] });
2066
2844
  }
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" }) });
2845
+ return /* @__PURE__ */ jsx20("figure", { className: "overflow-hidden rounded-lg border bg-background", children: /* @__PURE__ */ jsx20("img", { src: imageUrl, alt: "Assistant output", className: "h-auto w-full object-cover" }) });
2068
2846
  }
2069
2847
  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" })
2848
+ return /* @__PURE__ */ jsxs9(Card, { children: [
2849
+ /* @__PURE__ */ jsxs9(CardHeader, { className: "flex flex-row items-center justify-between gap-2", children: [
2850
+ /* @__PURE__ */ jsx20(CardTitle, { className: "text-sm", children: "Memory" }),
2851
+ /* @__PURE__ */ jsx20(Badge, { variant: "secondary", children: "Memory" })
2074
2852
  ] }),
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 ?? []) }) })
2853
+ /* @__PURE__ */ jsx20(CardContent, { className: "text-xs text-muted-foreground", children: /* @__PURE__ */ jsx20("pre", { className: "whitespace-pre-wrap wrap-break-word", children: safeJson(content.data ?? []) }) })
2076
2854
  ] });
2077
2855
  }
2078
2856
  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);
2857
+ const [isExpanded, setIsExpanded] = React14.useState(false);
2858
+ const contentRef = React14.useRef(null);
2859
+ const shouldAutoScrollRef = React14.useRef(true);
2860
+ const previousScrollTopRef = React14.useRef(0);
2083
2861
  const data = content.data ?? {};
2084
2862
  const category = data.category ?? "Component";
2085
2863
  const title = data.tool && category === "Tool" ? data.tool : data.title ?? data.type ?? "Component";
@@ -2089,10 +2867,10 @@ function ComponentBlock({ content }) {
2089
2867
  const error = data.error ?? null;
2090
2868
  const fallback = message ?? output ?? safeJson(data.data ?? data);
2091
2869
  const hasOutput = message !== null || output !== null;
2092
- React13.useEffect(() => {
2870
+ React14.useEffect(() => {
2093
2871
  if (status === "running" && output !== null) setIsExpanded(true);
2094
2872
  }, [status, output]);
2095
- React13.useEffect(() => {
2873
+ React14.useEffect(() => {
2096
2874
  const element = contentRef.current;
2097
2875
  if (!element) return;
2098
2876
  previousScrollTopRef.current = element.scrollTop;
@@ -2112,7 +2890,7 @@ function ComponentBlock({ content }) {
2112
2890
  element.removeEventListener("scroll", updateAutoScrollState);
2113
2891
  };
2114
2892
  }, [isExpanded]);
2115
- React13.useEffect(() => {
2893
+ React14.useEffect(() => {
2116
2894
  if (status !== "running") {
2117
2895
  shouldAutoScrollRef.current = true;
2118
2896
  return;
@@ -2125,20 +2903,20 @@ function ComponentBlock({ content }) {
2125
2903
  }, [isExpanded, output, status]);
2126
2904
  const config = status ? statusConfig[status] : null;
2127
2905
  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 })
2906
+ return /* @__PURE__ */ jsxs9(Card, { children: [
2907
+ /* @__PURE__ */ jsxs9(CardHeader, { className: "flex flex-row items-center justify-between gap-2 px-2 py-1 cursor-pointer", onClick: () => setIsExpanded(!isExpanded), children: [
2908
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center space-x-1 flex-1 min-w-0", children: [
2909
+ status && StatusIcon && /* @__PURE__ */ jsx20(StatusIcon, { className: cn("h-4 w-4", config?.iconClass, status === "running" && "animate-spin") }),
2910
+ /* @__PURE__ */ jsx20(CardTitle, { className: "text-sm truncate", children: title })
2133
2911
  ] }),
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(
2912
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap items-center gap-2 shrink-0", children: [
2913
+ /* @__PURE__ */ jsx20(Badge, { variant: "secondary", className: "rounded-lg px-1.5", children: category }),
2914
+ /* @__PURE__ */ jsx20(
2137
2915
  "button",
2138
2916
  {
2139
2917
  className: "text-muted-foreground hover:text-foreground transition-colors",
2140
2918
  "aria-label": isExpanded ? "Collapse" : "Expand",
2141
- children: /* @__PURE__ */ jsx19(
2919
+ children: /* @__PURE__ */ jsx20(
2142
2920
  ChevronDown,
2143
2921
  {
2144
2922
  className: cn("h-4 w-4 transition-transform", isExpanded && "rotate-180")
@@ -2148,89 +2926,128 @@ function ComponentBlock({ content }) {
2148
2926
  )
2149
2927
  ] })
2150
2928
  ] }),
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 })
2929
+ isExpanded && /* @__PURE__ */ jsxs9(CardContent, { ref: contentRef, className: "text-xs text-muted-foreground max-h-60 overflow-auto", children: [
2930
+ data.input && /* @__PURE__ */ jsx20("pre", { className: "whitespace-pre-wrap wrap-break-word", children: JSON.stringify(data.input, null, 2) }),
2931
+ error ? /* @__PURE__ */ jsx20("pre", { className: "whitespace-pre-wrap wrap-break-word text-destructive", children: typeof error === "string" ? error : safeJson(error) }) : hasOutput && /* @__PURE__ */ jsx20("pre", { className: "whitespace-pre-wrap wrap-break-word", children: fallback })
2154
2932
  ] })
2155
2933
  ] });
2156
2934
  }
2157
2935
  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" })
2936
+ return /* @__PURE__ */ jsxs9(Card, { children: [
2937
+ /* @__PURE__ */ jsxs9(CardHeader, { className: "flex flex-row items-center justify-between gap-2", children: [
2938
+ /* @__PURE__ */ jsx20(CardTitle, { className: "text-sm", children: "Assistant Content" }),
2939
+ /* @__PURE__ */ jsx20(Badge, { variant: "outline", children: content.type ?? "unknown" })
2162
2940
  ] }),
2163
- /* @__PURE__ */ jsx19(CardContent, { className: "text-xs text-muted-foreground", children: /* @__PURE__ */ jsx19("pre", { className: "whitespace-pre-wrap break-words", children: safeJson(content) }) })
2941
+ /* @__PURE__ */ jsx20(CardContent, { className: "text-xs text-muted-foreground", children: /* @__PURE__ */ jsx20("pre", { className: "whitespace-pre-wrap break-words", children: safeJson(content) }) })
2164
2942
  ] });
2165
2943
  }
2166
2944
  function renderContentItem(content, index, messageId) {
2167
2945
  if (typeof content === "string") {
2168
- return /* @__PURE__ */ jsxs8("div", { children: [
2169
- /* @__PURE__ */ jsx19(MarkdownText, { children: content }),
2946
+ return /* @__PURE__ */ jsxs9("div", { children: [
2947
+ /* @__PURE__ */ jsx20(MarkdownText, { children: content }),
2170
2948
  ";"
2171
2949
  ] }, `text-${index}`);
2172
2950
  }
2173
2951
  if (isTextContent(content)) {
2174
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(MarkdownText, { children: content.text }) }, content.id ?? `text-${index}`);
2952
+ return /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(MarkdownText, { children: content.text }) }, content.id ?? `text-${index}`);
2175
2953
  }
2176
2954
  if (isReasoningContent(content)) {
2177
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(ReasoningBlock, { reasoning: [content] }) }, content.id ?? `reasoning-${index}`);
2955
+ return /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(ReasoningBlock, { reasoning: [content] }) }, content.id ?? `reasoning-${index}`);
2178
2956
  }
2179
2957
  if (isImageContent(content)) {
2180
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(ImageBlock, { content }) }, content.id ?? `image-${index}`);
2958
+ return /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(ImageBlock, { content }) }, content.id ?? `image-${index}`);
2181
2959
  }
2182
2960
  if (isComponentContent(content)) {
2183
2961
  if (isWidgetComponent(content)) {
2184
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(WidgetMessage, { messageId, data: content.data }) }, content.id ?? `widget-${index}`);
2962
+ return /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(WidgetMessage, { messageId, data: content.data }) }, content.id ?? `widget-${index}`);
2185
2963
  }
2186
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(ComponentBlock, { content }) }, content.id ?? `component-${index}`);
2964
+ return /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(ComponentBlock, { content }) }, content.id ?? `component-${index}`);
2187
2965
  }
2188
2966
  if (isMemoryContent(content)) {
2189
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(MemoryBlock, { content }) }, content.id ?? `memory-${index}`);
2967
+ return /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(MemoryBlock, { content }) }, content.id ?? `memory-${index}`);
2190
2968
  }
2191
- return /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(UnknownBlock, { content }) }, content.id ?? `unknown-${index}`);
2969
+ return /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(UnknownBlock, { content }) }, content.id ?? `unknown-${index}`);
2192
2970
  }
2193
2971
  function renderContent(content, messageId) {
2194
2972
  if (typeof content === "string") {
2195
2973
  if (!content.trim()) return null;
2196
- return /* @__PURE__ */ jsx19(MarkdownText, { children: content });
2974
+ return /* @__PURE__ */ jsx20(MarkdownText, { children: content });
2197
2975
  }
2198
2976
  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)) });
2977
+ return /* @__PURE__ */ jsx20("div", { className: "space-y-3", children: content.map((item, index) => renderContentItem(item, index, messageId)) });
2200
2978
  }
2201
- function AssistantMessage({ message, className, isStreaming = false }) {
2979
+ function AssistantStreamingIndicator({
2980
+ status,
2981
+ className
2982
+ }) {
2202
2983
  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());
2984
+ const labelMap = {
2985
+ loading: t("message.loading"),
2986
+ thinking: t("message.thinking"),
2987
+ answering: t("message.answering")
2988
+ };
2989
+ return /* @__PURE__ */ jsxs9("div", { className: cn("flex items-center gap-2 text-xs text-muted-foreground", className), children: [
2990
+ status === "loading" && /* @__PURE__ */ jsx20(Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
2991
+ status === "thinking" && /* @__PURE__ */ jsxs9("div", { className: "flex items-end gap-1", "aria-hidden": "true", children: [
2992
+ /* @__PURE__ */ jsx20("span", { className: "h-1.5 w-1.5 rounded-full bg-current animate-bounce [animation-delay:-0.3s]" }),
2993
+ /* @__PURE__ */ jsx20("span", { className: "h-1.5 w-1.5 rounded-full bg-current animate-bounce [animation-delay:-0.15s]" }),
2994
+ /* @__PURE__ */ jsx20("span", { className: "h-1.5 w-1.5 rounded-full bg-current animate-bounce" })
2995
+ ] }),
2996
+ status === "answering" && /* @__PURE__ */ jsxs9("div", { className: "flex items-end gap-1", "aria-hidden": "true", children: [
2997
+ /* @__PURE__ */ jsx20("span", { className: "h-2 w-0.5 rounded-full bg-current animate-pulse [animation-delay:-0.25s]" }),
2998
+ /* @__PURE__ */ jsx20("span", { className: "h-3 w-0.5 rounded-full bg-current animate-pulse [animation-delay:-0.1s]" }),
2999
+ /* @__PURE__ */ jsx20("span", { className: "h-2.5 w-0.5 rounded-full bg-current animate-pulse" })
3000
+ ] }),
3001
+ /* @__PURE__ */ jsx20("span", { children: labelMap[status] })
3002
+ ] });
3003
+ }
3004
+ function AssistantMessage({
3005
+ message,
3006
+ className,
3007
+ isStreaming = false,
3008
+ streamingStatus
3009
+ }) {
3010
+ const { t } = useChatkitTranslation();
3011
+ const hasContent = hasRenderableMessageContent(message.content);
3012
+ const hasReasoning = hasRenderableReasoning(message.reasoning);
3013
+ const resolvedStreamingStatus = streamingStatus ?? getAssistantStreamingStatus(message, isStreaming);
2206
3014
  const answerNode = renderContent(message.content, message.id);
2207
- const reasoningNode = hasReasoning ? /* @__PURE__ */ jsx19(ReasoningBlock, { reasoning: message.reasoning ?? [] }) : null;
2208
- if (!hasContent && !hasReasoning) return null;
3015
+ const reasoningNode = hasReasoning ? /* @__PURE__ */ jsx20(ReasoningBlock, { reasoning: message.reasoning ?? [] }) : null;
3016
+ if (!hasRenderableAssistantMessage(message) && !resolvedStreamingStatus) return null;
2209
3017
  const streamingClass = isStreaming ? "streaming-active" : "";
3018
+ if (!hasRenderableAssistantMessage(message) && resolvedStreamingStatus) {
3019
+ return /* @__PURE__ */ jsx20("div", { className: cn("space-y-3", streamingClass, className), children: /* @__PURE__ */ jsx20(AssistantStreamingIndicator, { status: resolvedStreamingStatus }) });
3020
+ }
2210
3021
  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
- ) });
3022
+ return /* @__PURE__ */ jsxs9("div", { className: cn("space-y-3", streamingClass, className), children: [
3023
+ /* @__PURE__ */ jsxs9(
3024
+ Tabs,
3025
+ {
3026
+ defaultValue: message.status === "reasoning" ? "reasoning" : "answer",
3027
+ className: "w-full",
3028
+ children: [
3029
+ /* @__PURE__ */ jsxs9(TabsList, { className: "h-9", children: [
3030
+ /* @__PURE__ */ jsx20(TabsTrigger, { value: "answer", children: t("message.answer") }),
3031
+ /* @__PURE__ */ jsx20(TabsTrigger, { value: "reasoning", children: t("message.reasoning") })
3032
+ ] }),
3033
+ /* @__PURE__ */ jsx20(TabsContent, { value: "answer", className: "space-y-3", children: answerNode }),
3034
+ /* @__PURE__ */ jsx20(TabsContent, { value: "reasoning", className: "space-y-3", children: reasoningNode })
3035
+ ]
3036
+ }
3037
+ ),
3038
+ resolvedStreamingStatus ? /* @__PURE__ */ jsx20(AssistantStreamingIndicator, { status: resolvedStreamingStatus }) : null
3039
+ ] });
2226
3040
  }
2227
- return /* @__PURE__ */ jsx19("div", { className: cn("space-y-3", streamingClass, className), children: hasReasoning ? reasoningNode : answerNode });
3041
+ return /* @__PURE__ */ jsxs9("div", { className: cn("space-y-3", streamingClass, className), children: [
3042
+ hasReasoning ? reasoningNode : answerNode,
3043
+ resolvedStreamingStatus ? /* @__PURE__ */ jsx20(AssistantStreamingIndicator, { status: resolvedStreamingStatus }) : null
3044
+ ] });
2228
3045
  }
2229
3046
 
2230
3047
  // src/components/thread/MessageActions.tsx
2231
- import * as React14 from "react";
3048
+ import * as React15 from "react";
2232
3049
  import { Check, Copy, RefreshCw } from "lucide-react";
2233
- import { jsx as jsx20, jsxs as jsxs9 } from "react/jsx-runtime";
3050
+ import { jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
2234
3051
  function MessageActions({
2235
3052
  content,
2236
3053
  isAssistant = false,
@@ -2239,7 +3056,7 @@ function MessageActions({
2239
3056
  className
2240
3057
  }) {
2241
3058
  const { t } = useChatkitTranslation();
2242
- const [copied, setCopied] = React14.useState(false);
3059
+ const [copied, setCopied] = React15.useState(false);
2243
3060
  const handleCopy = async () => {
2244
3061
  try {
2245
3062
  await navigator.clipboard.writeText(content);
@@ -2252,7 +3069,7 @@ function MessageActions({
2252
3069
  if (isStreaming) {
2253
3070
  return null;
2254
3071
  }
2255
- return /* @__PURE__ */ jsxs9(
3072
+ return /* @__PURE__ */ jsxs10(
2256
3073
  "div",
2257
3074
  {
2258
3075
  className: cn(
@@ -2260,7 +3077,7 @@ function MessageActions({
2260
3077
  className
2261
3078
  ),
2262
3079
  children: [
2263
- /* @__PURE__ */ jsx20(
3080
+ /* @__PURE__ */ jsx21(
2264
3081
  "button",
2265
3082
  {
2266
3083
  type: "button",
@@ -2270,17 +3087,17 @@ function MessageActions({
2270
3087
  copied && "text-green-500"
2271
3088
  ),
2272
3089
  title: copied ? t("messageActions.copied") : t("messageActions.copy"),
2273
- children: copied ? /* @__PURE__ */ jsx20(Check, { size: 14 }) : /* @__PURE__ */ jsx20(Copy, { size: 14 })
3090
+ children: copied ? /* @__PURE__ */ jsx21(Check, { size: 14 }) : /* @__PURE__ */ jsx21(Copy, { size: 14 })
2274
3091
  }
2275
3092
  ),
2276
- isAssistant && onRetry && /* @__PURE__ */ jsx20(
3093
+ isAssistant && onRetry && /* @__PURE__ */ jsx21(
2277
3094
  "button",
2278
3095
  {
2279
3096
  type: "button",
2280
3097
  onClick: onRetry,
2281
3098
  className: "p-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
2282
3099
  title: t("messageActions.regenerate"),
2283
- children: /* @__PURE__ */ jsx20(RefreshCw, { size: 14 })
3100
+ children: /* @__PURE__ */ jsx21(RefreshCw, { size: 14 })
2284
3101
  }
2285
3102
  )
2286
3103
  ]
@@ -2301,18 +3118,18 @@ import {
2301
3118
  Sparkles as Sparkles2,
2302
3119
  Zap
2303
3120
  } from "lucide-react";
2304
- import { jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
3121
+ import { jsx as jsx22, jsxs as jsxs11 } from "react/jsx-runtime";
2305
3122
  function getIconComponent2(icon) {
2306
3123
  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 })
3124
+ "circle-question": /* @__PURE__ */ jsx22(HelpCircle, { size: 20 }),
3125
+ "lightbulb": /* @__PURE__ */ jsx22(Lightbulb2, { size: 20 }),
3126
+ "sparkle": /* @__PURE__ */ jsx22(Sparkles2, { size: 20 }),
3127
+ "write": /* @__PURE__ */ jsx22(Pencil2, { size: 20 }),
3128
+ "search": /* @__PURE__ */ jsx22(Search2, { size: 20 }),
3129
+ "globe": /* @__PURE__ */ jsx22(Globe2, { size: 20 }),
3130
+ "book-open": /* @__PURE__ */ jsx22(BookOpen, { size: 20 }),
3131
+ "compass": /* @__PURE__ */ jsx22(Compass, { size: 20 }),
3132
+ "bolt": /* @__PURE__ */ jsx22(Zap, { size: 20 })
2316
3133
  };
2317
3134
  return icon ? iconMap[icon] || iconMap["sparkle"] : iconMap["sparkle"];
2318
3135
  }
@@ -2320,9 +3137,9 @@ function StartScreen({ startScreen, onPromptClick, className }) {
2320
3137
  const { t } = useChatkitTranslation();
2321
3138
  const greeting = startScreen?.greeting ?? t("startScreen.greeting");
2322
3139
  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(
3140
+ return /* @__PURE__ */ jsxs11("div", { className: cn("flex flex-col items-center justify-center py-12 px-4", className), children: [
3141
+ /* @__PURE__ */ jsx22("div", { className: "mb-8 text-center", children: /* @__PURE__ */ jsx22("h2", { className: "text-2xl font-semibold text-foreground mb-2", children: greeting }) }),
3142
+ prompts.length > 0 && /* @__PURE__ */ jsx22("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsx22("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: prompts.map((item, index) => /* @__PURE__ */ jsxs11(
2326
3143
  "button",
2327
3144
  {
2328
3145
  type: "button",
@@ -2333,8 +3150,8 @@ function StartScreen({ startScreen, onPromptClick, className }) {
2333
3150
  "focus:outline-none focus:ring-2 focus:ring-primary/20"
2334
3151
  ),
2335
3152
  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 })
3153
+ /* @__PURE__ */ jsx22("span", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary", children: getIconComponent2(item.icon) }),
3154
+ /* @__PURE__ */ jsx22("span", { className: "text-sm font-medium text-foreground", children: item.label })
2338
3155
  ]
2339
3156
  },
2340
3157
  `prompt-${index}`
@@ -2346,10 +3163,10 @@ function StartScreen({ startScreen, onPromptClick, className }) {
2346
3163
  import "react";
2347
3164
 
2348
3165
  // src/components/ui/avatar.tsx
2349
- import * as React16 from "react";
3166
+ import * as React17 from "react";
2350
3167
  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(
3168
+ import { jsx as jsx23 } from "react/jsx-runtime";
3169
+ var Avatar = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
2353
3170
  AvatarPrimitive.Root,
2354
3171
  {
2355
3172
  ref,
@@ -2361,7 +3178,7 @@ var Avatar = React16.forwardRef(({ className, ...props }, ref) => /* @__PURE__ *
2361
3178
  }
2362
3179
  ));
2363
3180
  Avatar.displayName = AvatarPrimitive.Root.displayName;
2364
- var AvatarImage = React16.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
3181
+ var AvatarImage = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
2365
3182
  AvatarPrimitive.Image,
2366
3183
  {
2367
3184
  ref,
@@ -2370,7 +3187,7 @@ var AvatarImage = React16.forwardRef(({ className, ...props }, ref) => /* @__PUR
2370
3187
  }
2371
3188
  ));
2372
3189
  AvatarImage.displayName = AvatarPrimitive.Image.displayName;
2373
- var AvatarFallback = React16.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
3190
+ var AvatarFallback = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
2374
3191
  AvatarPrimitive.Fallback,
2375
3192
  {
2376
3193
  ref,
@@ -2384,7 +3201,7 @@ var AvatarFallback = React16.forwardRef(({ className, ...props }, ref) => /* @__
2384
3201
  AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
2385
3202
 
2386
3203
  // src/components/ui/chatkit-avatar.tsx
2387
- import { jsx as jsx23, jsxs as jsxs11 } from "react/jsx-runtime";
3204
+ import { jsx as jsx24, jsxs as jsxs12 } from "react/jsx-runtime";
2388
3205
  function asRecord(value) {
2389
3206
  return value && typeof value === "object" ? value : null;
2390
3207
  }
@@ -2457,21 +3274,21 @@ function ChatkitAvatar({
2457
3274
  const fallbackStyle = {
2458
3275
  ...avatar?.background ? { background: avatar.background } : {}
2459
3276
  };
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(
3277
+ return /* @__PURE__ */ jsxs12(Avatar, { className: cn(roundedClass, className), style, ...props, children: [
3278
+ avatar?.url ? /* @__PURE__ */ jsx24(AvatarImage, { className: imageClassName, src: avatar.url, alt: label }) : null,
3279
+ /* @__PURE__ */ jsx24(
2463
3280
  AvatarFallback,
2464
3281
  {
2465
3282
  className: cn(roundedClass, "text-sm font-medium text-foreground", fallbackClassName),
2466
3283
  style: fallbackStyle,
2467
- children: emojiCharacter ? /* @__PURE__ */ jsx23("span", { className: "text-[1.1em] leading-none", style: emojiStyle, children: emojiCharacter }) : fallbackText
3284
+ children: emojiCharacter ? /* @__PURE__ */ jsx24("span", { className: "text-[1.1em] leading-none", style: emojiStyle, children: emojiCharacter }) : fallbackText
2468
3285
  }
2469
3286
  )
2470
3287
  ] });
2471
3288
  }
2472
3289
 
2473
3290
  // src/hooks/useThreads.ts
2474
- import * as React18 from "react";
3291
+ import * as React19 from "react";
2475
3292
  var DEFAULT_LIMIT = 50;
2476
3293
  var getThreadTitle = (threadRecord) => {
2477
3294
  const title = threadRecord.title?.trim();
@@ -2509,16 +3326,16 @@ function useThreads(limit = DEFAULT_LIMIT) {
2509
3326
  isReady,
2510
3327
  isLoading: isStreamLoading
2511
3328
  } = 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) => {
3329
+ const [threadRecords, setThreadRecords] = React19.useState([]);
3330
+ const [isLoading, setIsLoading] = React19.useState(false);
3331
+ const [error, setError] = React19.useState(null);
3332
+ const upsertThreadRecord = React19.useCallback((threadRecord) => {
2516
3333
  setThreadRecords((prev) => {
2517
3334
  const next = prev.filter((item) => item.id !== threadRecord.id);
2518
3335
  return sortThreadRecords([threadRecord, ...next]);
2519
3336
  });
2520
3337
  }, []);
2521
- const refreshThreads = React18.useCallback(async () => {
3338
+ const refreshThreads = React19.useCallback(async () => {
2522
3339
  setIsLoading(true);
2523
3340
  setError(null);
2524
3341
  try {
@@ -2534,7 +3351,7 @@ function useThreads(limit = DEFAULT_LIMIT) {
2534
3351
  setIsLoading(false);
2535
3352
  }
2536
3353
  }, [client, limit, assistantId]);
2537
- const createThread = React18.useCallback(
3354
+ const createThread = React19.useCallback(
2538
3355
  async (input) => {
2539
3356
  setError(null);
2540
3357
  const payload = {};
@@ -2548,7 +3365,7 @@ function useThreads(limit = DEFAULT_LIMIT) {
2548
3365
  },
2549
3366
  [client, upsertThreadRecord]
2550
3367
  );
2551
- const updateThread = React18.useCallback(
3368
+ const updateThread = React19.useCallback(
2552
3369
  async (recordId, payload) => {
2553
3370
  setError(null);
2554
3371
  const updated = await client.conversations.update(recordId, payload);
@@ -2557,7 +3374,7 @@ function useThreads(limit = DEFAULT_LIMIT) {
2557
3374
  },
2558
3375
  [client, upsertThreadRecord]
2559
3376
  );
2560
- const deleteThread = React18.useCallback(
3377
+ const deleteThread = React19.useCallback(
2561
3378
  async (recordId) => {
2562
3379
  setError(null);
2563
3380
  await client.conversations.delete(recordId);
@@ -2565,11 +3382,11 @@ function useThreads(limit = DEFAULT_LIMIT) {
2565
3382
  },
2566
3383
  [client]
2567
3384
  );
2568
- React18.useEffect(() => {
3385
+ React19.useEffect(() => {
2569
3386
  if (!isReady) return;
2570
3387
  void refreshThreads();
2571
3388
  }, [refreshThreads, isReady]);
2572
- React18.useEffect(() => {
3389
+ React19.useEffect(() => {
2573
3390
  if (!threadId || !isStreamLoading) return;
2574
3391
  const now = (/* @__PURE__ */ new Date()).toISOString();
2575
3392
  setThreadRecords((prev) => {
@@ -2589,7 +3406,7 @@ function useThreads(limit = DEFAULT_LIMIT) {
2589
3406
  return changed ? sortThreadRecords(next) : prev;
2590
3407
  });
2591
3408
  }, [threadId, isStreamLoading]);
2592
- React18.useEffect(() => {
3409
+ React19.useEffect(() => {
2593
3410
  if (!isReady || !threadId || isStreamLoading) return;
2594
3411
  let cancelled = false;
2595
3412
  void client.conversations.search({ where: { threadId }, limit: 1 }).then((result) => {
@@ -2603,7 +3420,7 @@ function useThreads(limit = DEFAULT_LIMIT) {
2603
3420
  cancelled = true;
2604
3421
  };
2605
3422
  }, [client, threadId, upsertThreadRecord, isReady, isStreamLoading]);
2606
- const threads = React18.useMemo(
3423
+ const threads = React19.useMemo(
2607
3424
  () => threadRecords.map((threadRecord) => toThreadItem(threadRecord)),
2608
3425
  [threadRecords]
2609
3426
  );
@@ -2620,10 +3437,10 @@ function useThreads(limit = DEFAULT_LIMIT) {
2620
3437
  }
2621
3438
 
2622
3439
  // src/components/thread/context-usage-indicator.tsx
2623
- import * as React19 from "react";
3440
+ import * as React20 from "react";
2624
3441
 
2625
3442
  // src/components/ui/progress-circle.tsx
2626
- import { jsx as jsx24, jsxs as jsxs12 } from "react/jsx-runtime";
3443
+ import { jsx as jsx25, jsxs as jsxs13 } from "react/jsx-runtime";
2627
3444
  function clamp(input, a, b) {
2628
3445
  return Math.max(Math.min(input, Math.max(a, b)), Math.min(a, b));
2629
3446
  }
@@ -2646,7 +3463,7 @@ var ProgressCircle = ({ value, className, ...restSvgProps }) => {
2646
3463
  return (
2647
3464
  // biome-ignore lint/a11y/useFocusableInteractive: false positive (progress + progressbar are not focusable interactives)
2648
3465
  // biome-ignore lint/nursery/useAriaPropsSupportedByRole: biome rule at odds with mdn docs (presumed nursary bug with rule)
2649
- /* @__PURE__ */ jsxs12(
3466
+ /* @__PURE__ */ jsxs13(
2650
3467
  "svg",
2651
3468
  {
2652
3469
  role: "progressbar",
@@ -2657,8 +3474,8 @@ var ProgressCircle = ({ value, className, ...restSvgProps }) => {
2657
3474
  "aria-valuemax": 100,
2658
3475
  ...restSvgProps,
2659
3476
  children: [
2660
- /* @__PURE__ */ jsx24("circle", { ...commonParams, className: "stroke-current/25" }),
2661
- /* @__PURE__ */ jsx24(
3477
+ /* @__PURE__ */ jsx25("circle", { ...commonParams, className: "stroke-current/25" }),
3478
+ /* @__PURE__ */ jsx25(
2662
3479
  "circle",
2663
3480
  {
2664
3481
  ...commonParams,
@@ -2677,7 +3494,7 @@ var ProgressCircle = ({ value, className, ...restSvgProps }) => {
2677
3494
  };
2678
3495
 
2679
3496
  // src/components/thread/context-usage-indicator.tsx
2680
- import { jsx as jsx25, jsxs as jsxs13 } from "react/jsx-runtime";
3497
+ import { jsx as jsx26, jsxs as jsxs14 } from "react/jsx-runtime";
2681
3498
  var kNumberFormatter = new Intl.NumberFormat("en-US", {
2682
3499
  minimumFractionDigits: 0,
2683
3500
  maximumFractionDigits: 1
@@ -2710,20 +3527,20 @@ function ContextUsageIndicator({
2710
3527
  }) {
2711
3528
  const { t } = useChatkitTranslation();
2712
3529
  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({
3530
+ const [maxContextSize, setMaxContextSize] = React20.useState(null);
3531
+ const [usedContextSize, setUsedContextSize] = React20.useState(null);
3532
+ const [assistantAgentKey, setAssistantAgentKey] = React20.useState(null);
3533
+ const latestRealtimeUsageRef = React20.useRef({
2717
3534
  threadId: null,
2718
3535
  agentKey: null,
2719
3536
  usedTokens: null
2720
3537
  });
2721
- const realtimeUsage = React19.useMemo(
3538
+ const realtimeUsage = React20.useMemo(
2722
3539
  () => getThreadContextUsage(stream.contextUsageByAgentKey, assistantAgentKey),
2723
3540
  [assistantAgentKey, stream.contextUsageByAgentKey]
2724
3541
  );
2725
3542
  const realtimeUsedContextSize = getThreadContextUsageTotalTokens(realtimeUsage);
2726
- React19.useEffect(() => {
3543
+ React20.useEffect(() => {
2727
3544
  if (!stream.client || !stream.assistantId) {
2728
3545
  setMaxContextSize(null);
2729
3546
  setAssistantAgentKey(null);
@@ -2743,18 +3560,18 @@ function ContextUsageIndicator({
2743
3560
  cancelled = true;
2744
3561
  };
2745
3562
  }, [stream.client, stream.assistantId]);
2746
- React19.useEffect(() => {
3563
+ React20.useEffect(() => {
2747
3564
  latestRealtimeUsageRef.current = {
2748
3565
  threadId: stream.threadId ?? null,
2749
3566
  agentKey: assistantAgentKey,
2750
3567
  usedTokens: realtimeUsedContextSize
2751
3568
  };
2752
3569
  }, [assistantAgentKey, realtimeUsedContextSize, stream.threadId]);
2753
- React19.useEffect(() => {
3570
+ React20.useEffect(() => {
2754
3571
  if (realtimeUsedContextSize == null) return;
2755
3572
  setUsedContextSize(realtimeUsedContextSize);
2756
3573
  }, [realtimeUsedContextSize]);
2757
- React19.useEffect(() => {
3574
+ React20.useEffect(() => {
2758
3575
  if (!stream.client) {
2759
3576
  setUsedContextSize(null);
2760
3577
  return;
@@ -2819,8 +3636,8 @@ function ContextUsageIndicator({
2819
3636
  });
2820
3637
  const usageLabelWithSuffix = usageLabel.endsWith(":") ? usageLabel : `${usageLabel}:`;
2821
3638
  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(
3639
+ return /* @__PURE__ */ jsxs14(Tooltip, { children: [
3640
+ /* @__PURE__ */ jsx26(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx26(
2824
3641
  "button",
2825
3642
  {
2826
3643
  type: "button",
@@ -2829,20 +3646,21 @@ function ContextUsageIndicator({
2829
3646
  className
2830
3647
  ),
2831
3648
  "aria-label": `${usageLabelWithSuffix} ${usageFullLabel}. ${usageTokensLabel}`,
2832
- children: /* @__PURE__ */ jsx25(ProgressCircle, { value: percent, className: cn("size-3.5", progressClassName) })
3649
+ children: /* @__PURE__ */ jsx26(ProgressCircle, { value: percent, className: cn("size-3.5", progressClassName) })
2833
3650
  }
2834
3651
  ) }),
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 })
3652
+ /* @__PURE__ */ jsxs14(TooltipContent, { side: "top", sideOffset: 6, className: "space-y-0.5 px-3 py-2 text-center", children: [
3653
+ /* @__PURE__ */ jsx26("div", { className: "text-primary-foreground/70", children: usageLabelWithSuffix }),
3654
+ /* @__PURE__ */ jsx26("div", { className: "font-medium text-primary-foreground/80", children: usageFullLabel }),
3655
+ /* @__PURE__ */ jsx26("div", { className: "text-sm font-semibold", children: usageTokensLabel })
2839
3656
  ] })
2840
3657
  ] });
2841
3658
  }
2842
3659
 
2843
3660
  // src/components/chat.tsx
2844
- import { Fragment as Fragment3, jsx as jsx26, jsxs as jsxs14 } from "react/jsx-runtime";
3661
+ import { Fragment as Fragment3, jsx as jsx27, jsxs as jsxs15 } from "react/jsx-runtime";
2845
3662
  var defaultApiUrl2 = import.meta.env.VITE_XPERTAI_API_URL;
3663
+ var COMPOSER_INPUT_MAX_HEIGHT = 128;
2846
3664
  function formatMessageContent(content) {
2847
3665
  if (typeof content === "string") {
2848
3666
  return content;
@@ -2864,6 +3682,81 @@ function formatMessageContent(content) {
2864
3682
  }
2865
3683
  return "";
2866
3684
  }
3685
+ function getClosestQuoteContainer(node) {
3686
+ if (!node) {
3687
+ return null;
3688
+ }
3689
+ const element = node instanceof HTMLElement ? node : node instanceof Text ? node.parentElement : null;
3690
+ return element?.closest("[data-quote-message-id]") ?? null;
3691
+ }
3692
+ function ReferenceChip({
3693
+ reference,
3694
+ variant,
3695
+ onRemove,
3696
+ removeLabel
3697
+ }) {
3698
+ const metaLine = getReferenceMetaLine(reference);
3699
+ const isComposer = variant === "composer";
3700
+ const Icon = reference.type === "quote" ? Quote : FileText2;
3701
+ return /* @__PURE__ */ jsxs15(
3702
+ "div",
3703
+ {
3704
+ className: cn(
3705
+ "flex items-start gap-2 rounded-md px-2 py-1",
3706
+ isComposer ? "bg-muted text-foreground" : "bg-primary-foreground/20"
3707
+ ),
3708
+ title: getReferenceTitle(reference),
3709
+ children: [
3710
+ /* @__PURE__ */ jsx27(
3711
+ Icon,
3712
+ {
3713
+ size: isComposer ? 14 : 12,
3714
+ className: cn(
3715
+ "mt-0.5 shrink-0",
3716
+ isComposer ? "text-muted-foreground" : "text-primary-foreground/80"
3717
+ )
3718
+ }
3719
+ ),
3720
+ /* @__PURE__ */ jsxs15("div", { className: "min-w-0 flex-1", children: [
3721
+ /* @__PURE__ */ jsx27(
3722
+ "div",
3723
+ {
3724
+ className: cn(
3725
+ "truncate",
3726
+ isComposer ? "text-sm" : "text-xs font-medium"
3727
+ ),
3728
+ children: getReferenceLabel(reference)
3729
+ }
3730
+ ),
3731
+ metaLine && /* @__PURE__ */ jsx27(
3732
+ "div",
3733
+ {
3734
+ className: cn(
3735
+ "truncate",
3736
+ isComposer ? "text-xs text-muted-foreground" : "text-[10px] text-primary-foreground/75"
3737
+ ),
3738
+ children: metaLine
3739
+ }
3740
+ )
3741
+ ] }),
3742
+ onRemove && removeLabel && /* @__PURE__ */ jsx27(
3743
+ "button",
3744
+ {
3745
+ type: "button",
3746
+ onClick: onRemove,
3747
+ className: cn(
3748
+ "ml-1 rounded-full p-0.5",
3749
+ isComposer ? "hover:bg-muted-foreground/20" : "hover:bg-primary-foreground/20"
3750
+ ),
3751
+ title: removeLabel,
3752
+ "aria-label": removeLabel,
3753
+ children: /* @__PURE__ */ jsx27(X2, { size: 12 })
3754
+ }
3755
+ )
3756
+ ]
3757
+ }
3758
+ );
3759
+ }
2867
3760
  function Chat({
2868
3761
  className,
2869
3762
  options,
@@ -2880,17 +3773,21 @@ function Chat({
2880
3773
  const apiUrl = options?.api?.apiUrl || defaultApiUrl2;
2881
3774
  const { setStream } = useStreamManager();
2882
3775
  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);
3776
+ const { theme } = useTheme();
3777
+ const [isHistoryLoading, setIsHistoryLoading] = React21.useState(false);
3778
+ const [historyError, setHistoryError] = React21.useState(null);
3779
+ const [assistantName, setAssistantName] = React21.useState(null);
3780
+ const [assistantAvatar, setAssistantAvatar] = React21.useState(null);
2887
3781
  const LOADING_DOTS_MIN_DURATION = 800;
2888
- const [showLoadingDots, setShowLoadingDots] = React20.useState(false);
2889
- const loadingStartTimeRef = React20.useRef(null);
2890
- React20.useEffect(() => {
3782
+ const STREAMING_STATUS_REFRESH_MS = 250;
3783
+ const [showLoadingDots, setShowLoadingDots] = React21.useState(false);
3784
+ const [streamingNow, setStreamingNow] = React21.useState(() => Date.now());
3785
+ const loadingStartTimeRef = React21.useRef(null);
3786
+ const lastStreamOutputAtRef = React21.useRef(null);
3787
+ React21.useEffect(() => {
2891
3788
  setStream(stream);
2892
3789
  }, [setStream, stream]);
2893
- React20.useEffect(() => {
3790
+ React21.useEffect(() => {
2894
3791
  if (stream.isLoading) {
2895
3792
  if (!loadingStartTimeRef.current) {
2896
3793
  loadingStartTimeRef.current = Date.now();
@@ -2913,67 +3810,180 @@ function Chat({
2913
3810
  }
2914
3811
  }
2915
3812
  }, [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);
3813
+ React21.useEffect(() => {
3814
+ if (!stream.isLoading) {
3815
+ lastStreamOutputAtRef.current = null;
3816
+ setStreamingNow(Date.now());
3817
+ return;
3818
+ }
3819
+ const now = Date.now();
3820
+ lastStreamOutputAtRef.current = now;
3821
+ setStreamingNow(now);
3822
+ }, [stream.messages, stream.isLoading]);
3823
+ React21.useEffect(() => {
3824
+ if (!stream.isLoading) {
3825
+ return;
3826
+ }
3827
+ const timer = window.setInterval(() => {
3828
+ setStreamingNow(Date.now());
3829
+ }, STREAMING_STATUS_REFRESH_MS);
3830
+ return () => window.clearInterval(timer);
3831
+ }, [stream.isLoading]);
3832
+ const [draft, setDraft] = React21.useState("");
3833
+ const [selectedTool, setSelectedTool] = React21.useState(
3834
+ null
3835
+ );
3836
+ const [attachments, setAttachments] = React21.useState([]);
3837
+ const [references, setReferences] = React21.useState([]);
3838
+ const [quoteSelection, setQuoteSelection] = React21.useState(null);
3839
+ const [isAtBottom, setIsAtBottom] = React21.useState(true);
3840
+ const [hasUpdatesBelow, setHasUpdatesBelow] = React21.useState(false);
2921
3841
  const {
2922
3842
  threads,
2923
3843
  deleteThread,
2924
3844
  refreshThreads,
2925
3845
  isLoading: isThreadsLoading
2926
3846
  } = 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);
3847
+ const viewportRef = React21.useRef(null);
3848
+ const fileInputRef = React21.useRef(null);
3849
+ const composerInputRef = React21.useRef(null);
3850
+ const shouldAutoScrollRef = React21.useRef(true);
3851
+ const forceFollowRef = React21.useRef(false);
3852
+ const previousMessageCountRef = React21.useRef(0);
3853
+ const previousScrollTopRef = React21.useRef(0);
3854
+ const autoScrollFrameRef = React21.useRef(null);
3855
+ const isPointerDownRef = React21.useRef(false);
3856
+ const lastTouchYRef = React21.useRef(null);
2936
3857
  const resolvedTitle = title ?? t("chat.title");
2937
3858
  const resolvedPlaceholder = placeholder ?? t("chat.placeholder");
2938
3859
  const inputPlaceholder = selectedTool?.placeholderOverride ?? composer?.placeholder ?? resolvedPlaceholder;
2939
- const messages = React20.useMemo(() => stream.messages ?? [], [stream.messages]);
3860
+ const messages = React21.useMemo(
3861
+ () => stream.messages ?? [],
3862
+ [stream.messages]
3863
+ );
2940
3864
  const trimmedDraft = draft.trim();
2941
- const cancelPendingAutoScroll = React20.useCallback(() => {
3865
+ const hasReferences = references.length > 0;
3866
+ const pendingFollowUps = React21.useMemo(
3867
+ () => [...stream.pendingFollowUps ?? []].sort(
3868
+ (a, b) => a.createdAt - b.createdAt
3869
+ ),
3870
+ [stream.pendingFollowUps]
3871
+ );
3872
+ const clearQuoteSelection = React21.useCallback(() => {
3873
+ setQuoteSelection(null);
3874
+ }, []);
3875
+ useParentMessenger({
3876
+ onSetComposerValue: React21.useCallback(
3877
+ (payload) => {
3878
+ if (!payload) {
3879
+ return;
3880
+ }
3881
+ if (typeof payload.text === "string") {
3882
+ setDraft(payload.text);
3883
+ }
3884
+ if (Array.isArray(payload.references)) {
3885
+ const nextReferences = normalizeReferences(payload.references);
3886
+ setReferences(
3887
+ (previous) => payload.appendReferences ? mergeReferences(previous, nextReferences) : nextReferences
3888
+ );
3889
+ }
3890
+ if (payload.selectedToolId !== void 0) {
3891
+ const nextTool = payload.selectedToolId === null ? null : (composer?.tools ?? []).find(
3892
+ (tool) => tool.id === payload.selectedToolId
3893
+ ) ?? null;
3894
+ setSelectedTool(nextTool);
3895
+ }
3896
+ },
3897
+ [composer?.tools]
3898
+ ),
3899
+ onFocusComposer: React21.useCallback(() => {
3900
+ composerInputRef.current?.focus();
3901
+ }, [])
3902
+ });
3903
+ const syncQuoteSelection = React21.useCallback(() => {
3904
+ if (typeof window === "undefined") {
3905
+ clearQuoteSelection();
3906
+ return;
3907
+ }
3908
+ const selection = window.getSelection();
3909
+ if (!selection || selection.isCollapsed || selection.rangeCount === 0) {
3910
+ clearQuoteSelection();
3911
+ return;
3912
+ }
3913
+ const text = selection.toString().trim();
3914
+ if (!text) {
3915
+ clearQuoteSelection();
3916
+ return;
3917
+ }
3918
+ const anchorContainer = getClosestQuoteContainer(selection.anchorNode);
3919
+ const focusContainer = getClosestQuoteContainer(selection.focusNode);
3920
+ if (!anchorContainer || !focusContainer || anchorContainer !== focusContainer || !viewportRef.current?.contains(anchorContainer)) {
3921
+ clearQuoteSelection();
3922
+ return;
3923
+ }
3924
+ const range = selection.getRangeAt(0);
3925
+ const rect = range.getBoundingClientRect();
3926
+ if (rect.width === 0 && rect.height === 0) {
3927
+ clearQuoteSelection();
3928
+ return;
3929
+ }
3930
+ const top = rect.bottom + 8 > window.innerHeight - 48 ? Math.max(12, rect.top - 44) : rect.bottom + 8;
3931
+ const left = Math.min(
3932
+ Math.max(24, rect.left + rect.width / 2),
3933
+ window.innerWidth - 24
3934
+ );
3935
+ const source = anchorContainer.dataset.quoteSource?.trim() || void 0;
3936
+ const messageId = anchorContainer.dataset.quoteMessageId?.trim() || void 0;
3937
+ setQuoteSelection({
3938
+ reference: {
3939
+ type: "quote",
3940
+ text,
3941
+ ...messageId ? { messageId } : {},
3942
+ ...source ? { source, label: source } : {}
3943
+ },
3944
+ top,
3945
+ left
3946
+ });
3947
+ }, [clearQuoteSelection]);
3948
+ const cancelPendingAutoScroll = React21.useCallback(() => {
2942
3949
  if (autoScrollFrameRef.current !== null) {
2943
3950
  cancelAnimationFrame(autoScrollFrameRef.current);
2944
3951
  autoScrollFrameRef.current = null;
2945
3952
  }
2946
3953
  }, []);
2947
- const disableAutoFollow = React20.useCallback(() => {
3954
+ const disableAutoFollow = React21.useCallback(() => {
2948
3955
  forceFollowRef.current = false;
2949
3956
  shouldAutoScrollRef.current = false;
2950
3957
  cancelPendingAutoScroll();
2951
3958
  }, [cancelPendingAutoScroll]);
2952
- const enableAutoFollow = React20.useCallback(() => {
3959
+ const enableAutoFollow = React21.useCallback(() => {
2953
3960
  forceFollowRef.current = true;
2954
3961
  shouldAutoScrollRef.current = true;
2955
3962
  setHasUpdatesBelow(false);
2956
3963
  }, []);
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
- });
3964
+ const scrollToBottom = React21.useCallback(
3965
+ (smooth = false, force = false) => {
3966
+ if (force) {
3967
+ enableAutoFollow();
2973
3968
  }
2974
- });
2975
- }, [cancelPendingAutoScroll, enableAutoFollow]);
2976
- React20.useEffect(() => {
3969
+ cancelPendingAutoScroll();
3970
+ autoScrollFrameRef.current = requestAnimationFrame(() => {
3971
+ autoScrollFrameRef.current = null;
3972
+ const viewport = viewportRef.current;
3973
+ if (viewport) {
3974
+ if (!force && !shouldAutoScrollRef.current) {
3975
+ return;
3976
+ }
3977
+ viewport.scrollTo({
3978
+ top: viewport.scrollHeight,
3979
+ behavior: smooth ? "smooth" : "instant"
3980
+ });
3981
+ }
3982
+ });
3983
+ },
3984
+ [cancelPendingAutoScroll, enableAutoFollow]
3985
+ );
3986
+ React21.useEffect(() => {
2977
3987
  const viewport = viewportRef.current;
2978
3988
  if (!viewport) return;
2979
3989
  previousScrollTopRef.current = viewport.scrollTop;
@@ -3025,13 +4035,23 @@ function Chat({
3025
4035
  };
3026
4036
  updateAutoScrollState();
3027
4037
  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 });
4038
+ viewport.addEventListener("pointerdown", handlePointerDown, {
4039
+ passive: true
4040
+ });
4041
+ viewport.addEventListener("scroll", updateAutoScrollState, {
4042
+ passive: true
4043
+ });
4044
+ viewport.addEventListener("touchstart", handleTouchStart, {
4045
+ passive: true
4046
+ });
3031
4047
  viewport.addEventListener("touchmove", handleTouchMove, { passive: true });
3032
4048
  viewport.addEventListener("touchend", handleTouchEnd, { passive: true });
3033
- window.addEventListener("pointerup", stopPointerTracking, { passive: true });
3034
- window.addEventListener("pointercancel", stopPointerTracking, { passive: true });
4049
+ window.addEventListener("pointerup", stopPointerTracking, {
4050
+ passive: true
4051
+ });
4052
+ window.addEventListener("pointercancel", stopPointerTracking, {
4053
+ passive: true
4054
+ });
3035
4055
  return () => {
3036
4056
  cancelPendingAutoScroll();
3037
4057
  viewport.removeEventListener("wheel", handleWheel);
@@ -3044,14 +4064,14 @@ function Chat({
3044
4064
  window.removeEventListener("pointercancel", stopPointerTracking);
3045
4065
  };
3046
4066
  }, [cancelPendingAutoScroll, disableAutoFollow]);
3047
- React20.useEffect(() => {
4067
+ React21.useEffect(() => {
3048
4068
  shouldAutoScrollRef.current = true;
3049
4069
  forceFollowRef.current = false;
3050
4070
  previousScrollTopRef.current = 0;
3051
4071
  setIsAtBottom(true);
3052
4072
  setHasUpdatesBelow(false);
3053
4073
  }, [stream.threadId]);
3054
- React20.useEffect(() => {
4074
+ React21.useEffect(() => {
3055
4075
  const messageCountChanged = messages.length !== previousMessageCountRef.current;
3056
4076
  previousMessageCountRef.current = messages.length;
3057
4077
  if (!shouldAutoScrollRef.current) {
@@ -3065,16 +4085,85 @@ function Chat({
3065
4085
  }
3066
4086
  }, [stream.isLoading, messages, scrollToBottom]);
3067
4087
  const effectiveClientSecret = stream.apiKey?.trim() ? stream.apiKey : clientSecret;
3068
- const hasApiKey = Boolean(effectiveClientSecret.trim());
3069
- const missingConfig = !apiUrl || !hasApiKey;
4088
+ const missingConfigKind = getMissingApiConfigurationKind({
4089
+ apiUrl,
4090
+ clientSecret: effectiveClientSecret
4091
+ });
4092
+ const missingConfig = Boolean(missingConfigKind);
4093
+ const missingConfigShortMessage = React21.useMemo(() => {
4094
+ switch (missingConfigKind) {
4095
+ case "apiUrl":
4096
+ return t("chat.missingApiUrlShort");
4097
+ case "clientSecret":
4098
+ return t("chat.missingClientSecretShort");
4099
+ case "apiUrlAndClientSecret":
4100
+ return t("chat.missingApiUrlAndClientSecretShort");
4101
+ default:
4102
+ return t("chat.missingConfigShort");
4103
+ }
4104
+ }, [missingConfigKind, t]);
4105
+ const missingConfigDetailMessage = React21.useMemo(() => {
4106
+ switch (missingConfigKind) {
4107
+ case "apiUrl":
4108
+ return t("chat.missingApiUrlDetail");
4109
+ case "clientSecret":
4110
+ return t("chat.missingClientSecretDetail");
4111
+ case "apiUrlAndClientSecret":
4112
+ return t("chat.missingApiUrlAndClientSecretDetail");
4113
+ default:
4114
+ return t("chat.missingConfigDetail");
4115
+ }
4116
+ }, [missingConfigKind, t]);
3070
4117
  const showMissingConfig = !isClientSecretInitializing && missingConfig;
3071
4118
  const hasUploadingFiles = attachments.some((a) => a.status === "uploading");
3072
- const isSendDisabled = !trimmedDraft || stream.isLoading || missingConfig || isHistoryLoading || hasUploadingFiles;
3073
- React20.useEffect(() => {
4119
+ const isSendDisabled = !trimmedDraft && !hasReferences || missingConfig || isHistoryLoading || hasUploadingFiles;
4120
+ const resizeComposerInput = React21.useCallback(() => {
4121
+ const textarea = composerInputRef.current;
4122
+ if (!textarea) {
4123
+ return;
4124
+ }
4125
+ textarea.style.height = "auto";
4126
+ const nextHeight = Math.min(
4127
+ textarea.scrollHeight,
4128
+ COMPOSER_INPUT_MAX_HEIGHT
4129
+ );
4130
+ textarea.style.height = `${nextHeight}px`;
4131
+ textarea.style.overflowY = textarea.scrollHeight > COMPOSER_INPUT_MAX_HEIGHT ? "auto" : "hidden";
4132
+ }, []);
4133
+ React21.useEffect(() => {
4134
+ resizeComposerInput();
4135
+ }, [draft, resizeComposerInput]);
4136
+ React21.useEffect(() => {
4137
+ document.addEventListener("selectionchange", syncQuoteSelection);
4138
+ return () => {
4139
+ document.removeEventListener("selectionchange", syncQuoteSelection);
4140
+ };
4141
+ }, [syncQuoteSelection]);
4142
+ React21.useEffect(() => {
4143
+ const viewport = viewportRef.current;
4144
+ if (!viewport) {
4145
+ return;
4146
+ }
4147
+ const handleViewportScroll = () => {
4148
+ clearQuoteSelection();
4149
+ };
4150
+ viewport.addEventListener("scroll", handleViewportScroll, {
4151
+ passive: true
4152
+ });
4153
+ window.addEventListener("resize", handleViewportScroll, { passive: true });
4154
+ return () => {
4155
+ viewport.removeEventListener("scroll", handleViewportScroll);
4156
+ window.removeEventListener("resize", handleViewportScroll);
4157
+ };
4158
+ }, [clearQuoteSelection]);
4159
+ React21.useEffect(() => {
4160
+ clearQuoteSelection();
4161
+ }, [messages.length, stream.threadId, clearQuoteSelection]);
4162
+ React21.useEffect(() => {
3074
4163
  if (missingConfig) return;
3075
4164
  void refreshThreads();
3076
4165
  }, [missingConfig, refreshThreads]);
3077
- React20.useEffect(() => {
4166
+ React21.useEffect(() => {
3078
4167
  if (missingConfig || !stream.client || !stream.assistantId) {
3079
4168
  setAssistantName(null);
3080
4169
  setAssistantAvatar(null);
@@ -3105,80 +4194,186 @@ function Chat({
3105
4194
  mimetype: a.storageFile?.mimetype ?? a.file.type,
3106
4195
  size: a.storageFile?.size ?? a.file.size
3107
4196
  }));
4197
+ const submitDraft = React21.useCallback(
4198
+ (followUpOverride) => {
4199
+ if (isSendDisabled) return;
4200
+ const filesToSend = uploadedFiles.length > 0 ? [...uploadedFiles] : void 0;
4201
+ const referencesToSend = references.length > 0 ? [...references] : void 0;
4202
+ const nextFollowUpMode = stream.isLoading ? followUpOverride ?? stream.followUpBehavior : void 0;
4203
+ const humanInput = buildHumanMessageInputPayload({
4204
+ content: trimmedDraft,
4205
+ references: referencesToSend
4206
+ });
4207
+ if (!humanInput) {
4208
+ return;
4209
+ }
4210
+ const displayContent = trimmedDraft || (referencesToSend ? t("chat.referencedContentOnly") : "");
4211
+ const newMessage = {
4212
+ id: createMessageId(),
4213
+ type: "human",
4214
+ content: displayContent,
4215
+ submittedInput: humanInput.input,
4216
+ ...humanInput.referenceComposition ? { referenceComposition: humanInput.referenceComposition } : {},
4217
+ ...filesToSend ? { attachments: filesToSend } : {},
4218
+ ...referencesToSend ? { references: referencesToSend } : {}
4219
+ };
4220
+ setDraft("");
4221
+ const inputPayload = {
4222
+ ...humanInput
4223
+ };
4224
+ if (filesToSend) {
4225
+ inputPayload.files = filesToSend;
4226
+ }
4227
+ const requestOptions = buildInjectedRequestOptions({
4228
+ defaults: options?.request,
4229
+ humanInput: inputPayload
4230
+ });
4231
+ stream.submit(
4232
+ {
4233
+ input: inputPayload,
4234
+ ...requestOptions.state ? { state: requestOptions.state } : {}
4235
+ },
4236
+ {
4237
+ ...nextFollowUpMode ? { followUpMode: nextFollowUpMode } : {},
4238
+ ...requestOptions.context ? { context: requestOptions.context } : {},
4239
+ ...requestOptions.config ? { config: requestOptions.config } : {},
4240
+ ...!nextFollowUpMode ? {
4241
+ optimisticValues: (prev) => {
4242
+ const prevMessages = prev?.messages ?? [];
4243
+ return { ...prev, messages: [...prevMessages, newMessage] };
4244
+ }
4245
+ } : {}
4246
+ }
4247
+ );
4248
+ scrollToBottom(true, true);
4249
+ if (selectedTool && !selectedTool.pinned) {
4250
+ setSelectedTool(null);
4251
+ }
4252
+ setAttachments([]);
4253
+ setReferences([]);
4254
+ },
4255
+ [
4256
+ isSendDisabled,
4257
+ options?.request,
4258
+ references,
4259
+ scrollToBottom,
4260
+ selectedTool,
4261
+ stream,
4262
+ trimmedDraft,
4263
+ uploadedFiles,
4264
+ t
4265
+ ]
4266
+ );
3108
4267
  const handleSubmit = (event) => {
3109
4268
  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
- }
4269
+ submitDraft();
4270
+ };
4271
+ const handleEditPendingFollowUp = React21.useCallback(
4272
+ (id) => {
4273
+ const item = pendingFollowUps.find(
4274
+ (entry) => entry.id === id && entry.mode === "queue"
4275
+ );
4276
+ if (!item) {
4277
+ return;
3141
4278
  }
4279
+ const text = item.request?.input?.input?.trim() ?? "";
4280
+ const nextReferences = normalizeReferences(
4281
+ item.request?.input?.references
4282
+ );
4283
+ stream.removePendingFollowUp(id);
4284
+ setDraft(text);
4285
+ setReferences(nextReferences);
4286
+ requestAnimationFrame(() => {
4287
+ const input = composerInputRef.current;
4288
+ if (!input) {
4289
+ return;
4290
+ }
4291
+ input.focus();
4292
+ const position = text.length;
4293
+ input.setSelectionRange(position, position);
4294
+ });
4295
+ },
4296
+ [pendingFollowUps, stream]
4297
+ );
4298
+ const handleQuoteSelection = React21.useCallback(() => {
4299
+ if (!quoteSelection) {
4300
+ return;
4301
+ }
4302
+ setReferences(
4303
+ (previous) => mergeReferences(previous, [quoteSelection.reference])
3142
4304
  );
3143
- scrollToBottom(true, true);
3144
- if (selectedTool && !selectedTool.pinned) {
3145
- setSelectedTool(null);
4305
+ clearQuoteSelection();
4306
+ if (typeof window !== "undefined") {
4307
+ window.getSelection()?.removeAllRanges();
3146
4308
  }
3147
- setAttachments([]);
3148
- };
4309
+ composerInputRef.current?.focus();
4310
+ }, [clearQuoteSelection, quoteSelection]);
3149
4311
  const handleAttachmentClick = () => {
3150
4312
  fileInputRef.current?.click();
3151
4313
  };
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
- )
3159
- );
3160
- } catch (error) {
4314
+ const handleComposerKeyDown = (event) => {
4315
+ if (event.key !== "Enter") {
4316
+ return;
4317
+ }
4318
+ if (event.shiftKey && (event.metaKey || event.ctrlKey)) {
4319
+ if (event.nativeEvent.isComposing) {
4320
+ return;
4321
+ }
4322
+ event.preventDefault();
4323
+ if (isSendDisabled) {
4324
+ return;
4325
+ }
4326
+ submitDraft(stream.followUpBehavior === "queue" ? "steer" : "queue");
4327
+ return;
4328
+ }
4329
+ if (event.shiftKey) {
4330
+ return;
4331
+ }
4332
+ if (event.nativeEvent.isComposing) {
4333
+ return;
4334
+ }
4335
+ event.preventDefault();
4336
+ if (isSendDisabled) {
4337
+ return;
4338
+ }
4339
+ submitDraft();
4340
+ };
4341
+ const uploadFile = React21.useCallback(
4342
+ async (localId, file) => {
4343
+ try {
4344
+ const result = await stream.client.contexts.uploadFile(file);
4345
+ setAttachments(
4346
+ (prev) => prev.map(
4347
+ (item) => item.localId === localId ? { ...item, status: "success", storageFile: result } : item
4348
+ )
4349
+ );
4350
+ } catch (error) {
4351
+ setAttachments(
4352
+ (prev) => prev.map(
4353
+ (item) => item.localId === localId ? {
4354
+ ...item,
4355
+ status: "error",
4356
+ error: error instanceof Error ? error.message : "Upload failed"
4357
+ } : item
4358
+ )
4359
+ );
4360
+ }
4361
+ },
4362
+ [stream.client]
4363
+ );
4364
+ const handleRetryUpload = React21.useCallback(
4365
+ (localId) => {
4366
+ const attachment = attachments.find((a) => a.localId === localId);
4367
+ if (!attachment || attachment.status !== "error") return;
3161
4368
  setAttachments(
3162
4369
  (prev) => prev.map(
3163
- (item) => item.localId === localId ? {
3164
- ...item,
3165
- status: "error",
3166
- error: error instanceof Error ? error.message : "Upload failed"
3167
- } : item
4370
+ (item) => item.localId === localId ? { ...item, status: "uploading", error: void 0 } : item
3168
4371
  )
3169
4372
  );
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]);
4373
+ void uploadFile(localId, attachment.file);
4374
+ },
4375
+ [attachments, uploadFile]
4376
+ );
3182
4377
  const handleFileChange = (event) => {
3183
4378
  const files = event.target.files;
3184
4379
  if (!files || files.length === 0) return;
@@ -3212,12 +4407,15 @@ function Chat({
3212
4407
  if (!attachment) return;
3213
4408
  if (attachment.status === "success" && attachment.storageFile?.id) {
3214
4409
  try {
3215
- await fetch(`${stream.apiUrl}/contexts/file/${attachment.storageFile.id}`, {
3216
- method: "DELETE",
3217
- headers: {
3218
- "Authorization": `Bearer ${effectiveClientSecret}`
4410
+ await fetch(
4411
+ `${stream.apiUrl}/contexts/file/${attachment.storageFile.id}`,
4412
+ {
4413
+ method: "DELETE",
4414
+ headers: {
4415
+ Authorization: `Bearer ${effectiveClientSecret}`
4416
+ }
3219
4417
  }
3220
- });
4418
+ );
3221
4419
  } catch {
3222
4420
  }
3223
4421
  }
@@ -3227,27 +4425,31 @@ function Chat({
3227
4425
  setSelectedTool((prev) => prev?.id === tool.id ? null : tool);
3228
4426
  };
3229
4427
  const handlePromptClick = (prompt) => {
3230
- if (missingConfig || stream.isLoading || isHistoryLoading) return;
4428
+ if (missingConfig || isHistoryLoading) return;
3231
4429
  const newMessage = {
3232
4430
  id: createMessageId(),
3233
4431
  type: "human",
3234
4432
  content: prompt
3235
4433
  };
4434
+ const nextFollowUpMode = stream.isLoading ? stream.followUpBehavior : void 0;
3236
4435
  stream.submit(
3237
4436
  { input: { input: prompt } },
3238
4437
  {
3239
- optimisticValues: (prev) => {
3240
- const prevMessages = prev?.messages ?? [];
3241
- return { ...prev, messages: [...prevMessages, newMessage] };
3242
- }
4438
+ ...nextFollowUpMode ? { followUpMode: nextFollowUpMode } : {},
4439
+ ...!nextFollowUpMode ? {
4440
+ optimisticValues: (prev) => {
4441
+ const prevMessages = prev?.messages ?? [];
4442
+ return { ...prev, messages: [...prevMessages, newMessage] };
4443
+ }
4444
+ } : {}
3243
4445
  }
3244
4446
  );
3245
4447
  scrollToBottom(true, true);
3246
4448
  };
3247
- const loadConversationMessages = React20.useCallback(
4449
+ const loadConversationMessages = React21.useCallback(
3248
4450
  async (recordId) => {
3249
4451
  if (missingConfig) {
3250
- setHistoryError(t("chat.missingConfigShort"));
4452
+ setHistoryError(missingConfigShortMessage);
3251
4453
  return;
3252
4454
  }
3253
4455
  setHistoryError(null);
@@ -3263,7 +4465,7 @@ function Chat({
3263
4465
  setIsHistoryLoading(false);
3264
4466
  }
3265
4467
  },
3266
- [missingConfig, stream, t]
4468
+ [missingConfig, missingConfigShortMessage, stream, t]
3267
4469
  );
3268
4470
  const handleNewThread = async () => {
3269
4471
  if (missingConfig || isHistoryLoading) return;
@@ -3306,12 +4508,16 @@ function Chat({
3306
4508
  };
3307
4509
  const handleRetry = (messageIndex) => {
3308
4510
  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") {
4511
+ const lastHumanMessage = [...messagesUpToIndex].reverse().find((m) => String(m.type) === "human");
4512
+ const humanInput = buildHumanMessageInputPayload({
4513
+ content: lastHumanMessage && typeof lastHumanMessage.content === "string" ? lastHumanMessage.content : "",
4514
+ submittedInput: lastHumanMessage?.submittedInput,
4515
+ references: lastHumanMessage?.references,
4516
+ referenceComposition: lastHumanMessage?.referenceComposition
4517
+ });
4518
+ if (humanInput) {
3313
4519
  stream.submit(
3314
- { input: { input: lastHumanMessage.content } },
4520
+ { input: humanInput },
3315
4521
  {
3316
4522
  optimisticValues: (prev) => {
3317
4523
  const prevMessages = prev?.messages ?? [];
@@ -3326,18 +4532,18 @@ function Chat({
3326
4532
  }
3327
4533
  };
3328
4534
  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(
4535
+ const currentThread = React21.useMemo(
3330
4536
  () => threads.find((item) => item.id === stream.threadId),
3331
4537
  [threads, stream.threadId]
3332
4538
  );
3333
4539
  const errorMessage = stream.error instanceof Error ? stream.error.message : void 0;
3334
- const threadErrorMessage = React20.useMemo(() => {
4540
+ const threadErrorMessage = React21.useMemo(() => {
3335
4541
  if (currentThread?.status !== "error") return void 0;
3336
4542
  const message = currentThread.error?.trim();
3337
4543
  return message || t("thread.errorToast");
3338
4544
  }, [currentThread, t]);
3339
4545
  const assistantTitle = assistantName || resolvedTitle;
3340
- return /* @__PURE__ */ jsxs14(
4546
+ return /* @__PURE__ */ jsxs15(
3341
4547
  "div",
3342
4548
  {
3343
4549
  ref: viewportRef,
@@ -3346,10 +4552,10 @@ function Chat({
3346
4552
  className
3347
4553
  ),
3348
4554
  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(
4555
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between border-b p-2 sticky top-0 z-10 bg-background", children: [
4556
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-3 overflow-hidden", children: [
4557
+ /* @__PURE__ */ jsxs15("div", { className: "relative shrink-0", children: [
4558
+ /* @__PURE__ */ jsx27(
3353
4559
  ChatkitAvatar,
3354
4560
  {
3355
4561
  avatar: assistantAvatar,
@@ -3357,15 +4563,22 @@ function Chat({
3357
4563
  label: assistantTitle
3358
4564
  }
3359
4565
  ),
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" })
4566
+ /* @__PURE__ */ jsx27("span", { className: "absolute bottom-0 right-0 h-2.5 w-2.5 rounded-full border-2 border-background bg-green-500" })
3361
4567
  ] }),
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") })
4568
+ /* @__PURE__ */ jsxs15("div", { className: "truncate", children: [
4569
+ /* @__PURE__ */ jsx27(
4570
+ "h2",
4571
+ {
4572
+ className: "text-lg font-semibold truncate",
4573
+ title: assistantTitle,
4574
+ children: assistantTitle
4575
+ }
4576
+ ),
4577
+ /* @__PURE__ */ jsx27("p", { className: "text-xs text-muted-foreground", children: t("chat.statusOnline") })
3365
4578
  ] })
3366
4579
  ] }),
3367
- history?.enabled !== false && /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1", children: [
3368
- /* @__PURE__ */ jsx26(
4580
+ history?.enabled !== false && /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1", children: [
4581
+ /* @__PURE__ */ jsx27(
3369
4582
  "button",
3370
4583
  {
3371
4584
  type: "button",
@@ -3378,10 +4591,10 @@ function Chat({
3378
4591
  "disabled:opacity-50 disabled:cursor-not-allowed"
3379
4592
  ),
3380
4593
  title: t("history.newThread"),
3381
- children: /* @__PURE__ */ jsx26(Pencil3, { size: 16 })
4594
+ children: /* @__PURE__ */ jsx27(Pencil3, { size: 16 })
3382
4595
  }
3383
4596
  ),
3384
- /* @__PURE__ */ jsx26(
4597
+ /* @__PURE__ */ jsx27(
3385
4598
  HistorySidebar,
3386
4599
  {
3387
4600
  threads,
@@ -3395,23 +4608,45 @@ function Chat({
3395
4608
  )
3396
4609
  ] })
3397
4610
  ] }),
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(
4611
+ /* @__PURE__ */ jsxs15("div", { className: "flex-1 p-4", children: [
4612
+ errorMessage && /* @__PURE__ */ jsx27("div", { className: "mb-4 rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: errorMessage }),
4613
+ historyError && /* @__PURE__ */ jsx27("div", { className: "mb-4 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900", children: historyError }),
4614
+ showMissingConfig && /* @__PURE__ */ jsx27("div", { className: "mb-4 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900", children: missingConfigDetailMessage }),
4615
+ isHistoryLoading && /* @__PURE__ */ jsx27("div", { className: "mb-4 rounded-lg border border-muted px-3 py-2 text-sm text-muted-foreground", children: t("chat.loadingThread") }),
4616
+ messages.length === 0 ? /* @__PURE__ */ jsx27(
3404
4617
  StartScreen,
3405
4618
  {
3406
4619
  startScreen,
3407
4620
  onPromptClick: handlePromptClick
3408
4621
  }
3409
- ) : /* @__PURE__ */ jsxs14("div", { className: "space-y-4", children: [
4622
+ ) : /* @__PURE__ */ jsxs15("div", { className: "space-y-4", children: [
3410
4623
  messages.map((message, index) => {
3411
4624
  const messageType = String(message.type);
3412
4625
  const isAssistantMessage = messageType === "assistant" || messageType === "ai";
4626
+ const isStreamingMessage = stream.isLoading && index === messages.length - 1;
4627
+ const streamingStatus = isAssistantMessage ? getAssistantStreamingStatus(
4628
+ {
4629
+ ...message,
4630
+ lastStreamOutputAt: lastStreamOutputAtRef.current
4631
+ },
4632
+ isStreamingMessage,
4633
+ { now: streamingNow }
4634
+ ) : null;
4635
+ if (isAssistantMessage && !hasRenderableAssistantMessage(message) && !streamingStatus) {
4636
+ return null;
4637
+ }
3413
4638
  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(
4639
+ const hasPlainRenderableContent = messageContent.trim().length > 0;
4640
+ const humanMessage = message;
4641
+ const humanReferences = humanMessage.references ?? [];
4642
+ const humanAttachments = humanMessage.attachments ?? [];
4643
+ const hasHumanAttachments = message.type === "human" && humanAttachments.length > 0;
4644
+ const canQuoteMessage = message.type === "human" || isAssistantMessage;
4645
+ const quoteSource = message.type === "human" ? t("chat.youLabel") : assistantTitle;
4646
+ if (!isAssistantMessage && !hasPlainRenderableContent && !hasHumanAttachments && humanReferences.length === 0) {
4647
+ return null;
4648
+ }
4649
+ return /* @__PURE__ */ jsx27(
3415
4650
  "div",
3416
4651
  {
3417
4652
  className: cn(
@@ -3419,53 +4654,66 @@ function Chat({
3419
4654
  message.type === "human" ? "justify-end" : "justify-start -ml-1"
3420
4655
  // AI messages: slightly closer to left
3421
4656
  ),
3422
- children: /* @__PURE__ */ jsxs14("div", { className: "flex flex-col px-3 overflow-hidden", children: [
3423
- /* @__PURE__ */ jsx26(
4657
+ children: /* @__PURE__ */ jsxs15("div", { className: "flex flex-col px-3 overflow-hidden", children: [
4658
+ /* @__PURE__ */ jsx27(
3424
4659
  "div",
3425
4660
  {
4661
+ ...canQuoteMessage ? {
4662
+ "data-quote-message-id": message.id,
4663
+ "data-quote-source": quoteSource
4664
+ } : {},
3426
4665
  className: cn(
3427
4666
  "max-w-full rounded-2xl",
3428
4667
  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
4668
  // AI messages: use chat-specific foreground color
3430
4669
  ),
3431
- children: isAssistantMessage ? /* @__PURE__ */ jsx26(
4670
+ children: isAssistantMessage ? /* @__PURE__ */ jsx27(
3432
4671
  AssistantMessage,
3433
4672
  {
3434
4673
  message: {
3435
4674
  ...message,
3436
4675
  type: "assistant"
3437
4676
  },
3438
- isStreaming: stream.isLoading && index === messages.length - 1
4677
+ isStreaming: isStreamingMessage,
4678
+ streamingStatus
3439
4679
  }
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(
4680
+ ) : /* @__PURE__ */ jsxs15(Fragment3, { children: [
4681
+ message.type === "human" && humanReferences.length > 0 && /* @__PURE__ */ jsx27("div", { className: "mb-2 flex flex-wrap gap-1.5", children: humanReferences.map((reference) => /* @__PURE__ */ jsx27(
4682
+ ReferenceChip,
4683
+ {
4684
+ reference,
4685
+ variant: "message"
4686
+ },
4687
+ getReferenceKey(reference)
4688
+ )) }),
4689
+ message.type === "human" && humanAttachments.length > 0 && /* @__PURE__ */ jsx27("div", { className: "flex flex-wrap gap-1.5 mb-2", children: humanAttachments.map((file, fileIndex) => /* @__PURE__ */ jsxs15(
3442
4690
  "div",
3443
4691
  {
3444
4692
  className: "flex items-center gap-1.5 rounded-md bg-primary-foreground/20 px-2 py-1 text-xs",
3445
4693
  children: [
3446
- /* @__PURE__ */ jsx26(FileText2, { size: 12 }),
3447
- /* @__PURE__ */ jsx26("span", { className: "max-w-[100px] truncate", children: file.originalName })
4694
+ /* @__PURE__ */ jsx27(FileText2, { size: 12 }),
4695
+ /* @__PURE__ */ jsx27("span", { className: "max-w-[100px] truncate", children: file.originalName })
3448
4696
  ]
3449
4697
  },
3450
4698
  fileIndex
3451
4699
  )) }),
3452
- Array.isArray(message.content) ? message.content.map((part, partIndex) => /* @__PURE__ */ jsx26(
4700
+ Array.isArray(message.content) ? message.content.map((part, partIndex) => /* @__PURE__ */ jsx27(
3453
4701
  "p",
3454
4702
  {
3455
4703
  className: "wrap-break-word text-sm leading-relaxed",
3456
4704
  children: formatMessageContent(part)
3457
4705
  },
3458
4706
  `${part.type}-${partIndex}`
3459
- )) : /* @__PURE__ */ jsx26("span", { className: "wrap-break-word text-sm leading-relaxed", children: formatMessageContent(message.content) })
4707
+ )) : /* @__PURE__ */ jsx27("span", { className: "wrap-break-word text-sm leading-relaxed", children: formatMessageContent(message.content) })
3460
4708
  ] })
3461
4709
  }
3462
4710
  ),
3463
- /* @__PURE__ */ jsx26(
4711
+ /* @__PURE__ */ jsx27(
3464
4712
  MessageActions,
3465
4713
  {
3466
4714
  content: messageContent,
3467
4715
  isAssistant: isAssistantMessage,
3468
- isStreaming: stream.isLoading && index === messages.length - 1,
4716
+ isStreaming: isStreamingMessage,
3469
4717
  onRetry: isAssistantMessage && !stream.isLoading && index === messages.length - 1 ? () => handleRetry(index) : void 0
3470
4718
  }
3471
4719
  )
@@ -3478,18 +4726,34 @@ function Chat({
3478
4726
  const lastMessage = messages[messages.length - 1];
3479
4727
  const lastMessageType = lastMessage ? String(lastMessage.type) : "";
3480
4728
  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
- ] }) }) });
4729
+ const lastAssistantStatus = isLastMessageFromAI ? getAssistantStreamingStatus(
4730
+ {
4731
+ ...lastMessage,
4732
+ lastStreamOutputAt: lastStreamOutputAtRef.current
4733
+ },
4734
+ stream.isLoading,
4735
+ { now: streamingNow }
4736
+ ) : null;
4737
+ if (lastAssistantStatus) return null;
4738
+ const fallbackStreamingStatus = getAssistantStreamingStatus(
4739
+ {
4740
+ status: void 0,
4741
+ reasoning: void 0,
4742
+ lastStreamOutputAt: lastStreamOutputAtRef.current
4743
+ },
4744
+ stream.isLoading,
4745
+ { now: streamingNow }
4746
+ );
4747
+ return /* @__PURE__ */ jsx27("div", { className: "flex justify-start gap-3 -ml-2", children: /* @__PURE__ */ jsx27("div", { className: "max-w-full rounded-2xl py-2.5", children: /* @__PURE__ */ jsx27(
4748
+ AssistantStreamingIndicator,
4749
+ {
4750
+ status: fallbackStreamingStatus ?? "loading"
4751
+ }
4752
+ ) }) });
3489
4753
  })()
3490
4754
  ] })
3491
4755
  ] }),
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(
4756
+ !isAtBottom && messages.length > 0 && /* @__PURE__ */ jsx27("div", { className: "sticky bottom-20 z-20 flex justify-center px-4 pointer-events-none", children: /* @__PURE__ */ jsx27(
3493
4757
  Button,
3494
4758
  {
3495
4759
  type: "button",
@@ -3502,12 +4766,40 @@ function Chat({
3502
4766
  onClick: () => scrollToBottom(true, true),
3503
4767
  "aria-label": t("chat.scrollToBottom"),
3504
4768
  title: t("chat.scrollToBottom"),
3505
- children: /* @__PURE__ */ jsx26(ArrowDown, { size: 16 })
4769
+ children: /* @__PURE__ */ jsx27(ArrowDown, { size: 16 })
3506
4770
  }
3507
4771
  ) }),
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(
4772
+ quoteSelection && /* @__PURE__ */ jsx27(
4773
+ "div",
4774
+ {
4775
+ className: "pointer-events-none fixed z-50",
4776
+ style: {
4777
+ top: `${quoteSelection.top}px`,
4778
+ left: `${quoteSelection.left}px`,
4779
+ transform: "translateX(-50%)"
4780
+ },
4781
+ children: /* @__PURE__ */ jsxs15(
4782
+ Button,
4783
+ {
4784
+ type: "button",
4785
+ size: "sm",
4786
+ variant: "secondary",
4787
+ className: "pointer-events-auto shadow-lg",
4788
+ onMouseDown: (event) => event.preventDefault(),
4789
+ onClick: handleQuoteSelection,
4790
+ "aria-label": t("composer.quoteSelection"),
4791
+ title: t("composer.quoteSelection"),
4792
+ children: [
4793
+ /* @__PURE__ */ jsx27(Quote, { size: 14 }),
4794
+ t("composer.quoteSelection")
4795
+ ]
4796
+ }
4797
+ )
4798
+ }
4799
+ ),
4800
+ /* @__PURE__ */ jsxs15("div", { className: "p-2 sticky bottom-0 z-10 bg-background", children: [
4801
+ threadErrorMessage && /* @__PURE__ */ jsx27("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 }),
4802
+ /* @__PURE__ */ jsx27(
3511
4803
  "input",
3512
4804
  {
3513
4805
  ref: fileInputRef,
@@ -3518,7 +4810,7 @@ function Chat({
3518
4810
  className: "hidden"
3519
4811
  }
3520
4812
  ),
3521
- attachments.length > 0 && /* @__PURE__ */ jsx26("div", { className: "mb-3 flex flex-wrap gap-2", children: attachments.map((item) => /* @__PURE__ */ jsxs14(
4813
+ attachments.length > 0 && /* @__PURE__ */ jsx27("div", { className: "mb-3 flex flex-wrap gap-2", children: attachments.map((item) => /* @__PURE__ */ jsxs15(
3522
4814
  "div",
3523
4815
  {
3524
4816
  className: cn(
@@ -3526,24 +4818,36 @@ function Chat({
3526
4818
  item.status === "error" ? "bg-destructive/10 border border-destructive/30" : "bg-muted"
3527
4819
  ),
3528
4820
  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(
4821
+ item.status === "uploading" && /* @__PURE__ */ jsx27(
4822
+ Loader22,
4823
+ {
4824
+ size: 14,
4825
+ className: "animate-spin text-muted-foreground"
4826
+ }
4827
+ ),
4828
+ item.status === "success" && /* @__PURE__ */ jsx27(FileText2, { size: 14, className: "text-muted-foreground" }),
4829
+ item.status === "error" && /* @__PURE__ */ jsx27(FileText2, { size: 14, className: "text-destructive" }),
4830
+ /* @__PURE__ */ jsx27(
4831
+ "span",
4832
+ {
4833
+ className: cn(
4834
+ "max-w-30 truncate",
4835
+ item.status === "error" && "text-destructive"
4836
+ ),
4837
+ children: item.file.name
4838
+ }
4839
+ ),
4840
+ item.status === "error" && /* @__PURE__ */ jsx27(
3537
4841
  "button",
3538
4842
  {
3539
4843
  type: "button",
3540
4844
  onClick: () => handleRetryUpload(item.localId),
3541
4845
  className: "ml-1 rounded-full p-0.5 text-destructive hover:bg-destructive/20",
3542
4846
  title: t("chat.retryUpload"),
3543
- children: /* @__PURE__ */ jsx26(RefreshCw2, { size: 12 })
4847
+ children: /* @__PURE__ */ jsx27(RefreshCw2, { size: 12 })
3544
4848
  }
3545
4849
  ),
3546
- /* @__PURE__ */ jsx26(
4850
+ /* @__PURE__ */ jsx27(
3547
4851
  "button",
3548
4852
  {
3549
4853
  type: "button",
@@ -3552,67 +4856,98 @@ function Chat({
3552
4856
  "ml-1 rounded-full p-0.5",
3553
4857
  item.status === "error" ? "text-destructive hover:bg-destructive/20" : "hover:bg-muted-foreground/20"
3554
4858
  ),
3555
- children: /* @__PURE__ */ jsx26(X2, { size: 12 })
4859
+ children: /* @__PURE__ */ jsx27(X2, { size: 12 })
3556
4860
  }
3557
4861
  )
3558
4862
  ]
3559
4863
  },
3560
4864
  item.localId
3561
4865
  )) }),
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(
4866
+ references.length > 0 && /* @__PURE__ */ jsx27("div", { className: "mb-3 flex flex-wrap gap-2", children: references.map((reference) => /* @__PURE__ */ jsx27(
4867
+ ReferenceChip,
4868
+ {
4869
+ reference,
4870
+ variant: "composer",
4871
+ onRemove: () => setReferences(
4872
+ (previous) => previous.filter(
4873
+ (item) => getReferenceKey(item) !== getReferenceKey(reference)
4874
+ )
4875
+ ),
4876
+ removeLabel: t("composer.removeReference")
4877
+ },
4878
+ getReferenceKey(reference)
4879
+ )) }),
4880
+ selectedTool && /* @__PURE__ */ jsxs15("div", { className: "mb-2 flex items-center gap-2", children: [
4881
+ /* @__PURE__ */ jsx27("span", { className: "rounded-full bg-primary/10 px-2 py-0.5 text-xs font-medium text-primary", children: selectedTool.shortLabel ?? selectedTool.label }),
4882
+ /* @__PURE__ */ jsx27(
3565
4883
  "button",
3566
4884
  {
3567
4885
  type: "button",
3568
4886
  onClick: () => setSelectedTool(null),
3569
4887
  className: "rounded-full p-0.5 text-muted-foreground hover:bg-muted",
3570
- children: /* @__PURE__ */ jsx26(X2, { size: 12 })
4888
+ children: /* @__PURE__ */ jsx27(X2, { size: 12 })
3571
4889
  }
3572
4890
  )
3573
4891
  ] }),
3574
- /* @__PURE__ */ jsx26("form", { className: "flex items-center", onSubmit: handleSubmit, children: /* @__PURE__ */ jsxs14(
4892
+ /* @__PURE__ */ jsx27(
4893
+ PendingFollowUps,
4894
+ {
4895
+ items: pendingFollowUps,
4896
+ isLoading: stream.isLoading,
4897
+ followUpBehavior: stream.followUpBehavior,
4898
+ onBehaviorChange: stream.setFollowUpBehavior,
4899
+ onPromoteToSteer: (id) => stream.promotePendingFollowUpToSteer(id),
4900
+ canSendNow: stream.canSendPendingFollowUpNow,
4901
+ onSendNow: (id) => stream.sendPendingFollowUpNow(id),
4902
+ onEdit: handleEditPendingFollowUp,
4903
+ onRemove: stream.removePendingFollowUp
4904
+ }
4905
+ ),
4906
+ /* @__PURE__ */ jsx27("form", { className: "flex items-end", onSubmit: handleSubmit, children: /* @__PURE__ */ jsxs15(
3575
4907
  "div",
3576
4908
  {
3577
4909
  className: cn(
3578
- "flex flex-1 items-center gap-1 rounded-xl",
4910
+ "flex flex-1 items-end gap-1 rounded-xl",
3579
4911
  "bg-background border border-border shadow-sm",
3580
4912
  "pl-1.5 pr-1.5 py-1",
3581
4913
  "focus-within:border-muted-foreground/30 focus-within:shadow-md",
3582
- "transition-shadow duration-200"
4914
+ "transition-shadow duration-200",
4915
+ getRoundedClass(theme.radius)
3583
4916
  ),
3584
4917
  children: [
3585
- /* @__PURE__ */ jsx26(
4918
+ /* @__PURE__ */ jsx27(
3586
4919
  ComposerMenu,
3587
4920
  {
3588
4921
  composer,
3589
4922
  onAttachmentClick: handleAttachmentClick,
3590
4923
  onToolSelect: handleToolSelect,
3591
4924
  selectedTool,
3592
- disabled: stream.isLoading || missingConfig || isHistoryLoading
4925
+ disabled: missingConfig || isHistoryLoading
3593
4926
  }
3594
4927
  ),
3595
- /* @__PURE__ */ jsx26(
3596
- "input",
4928
+ /* @__PURE__ */ jsx27(
4929
+ "textarea",
3597
4930
  {
3598
- type: "text",
4931
+ ref: composerInputRef,
3599
4932
  value: draft,
3600
4933
  onChange: (event) => setDraft(event.target.value),
4934
+ onKeyDown: handleComposerKeyDown,
4935
+ rows: 1,
3601
4936
  placeholder: inputPlaceholder,
3602
- disabled: stream.isLoading || missingConfig || isHistoryLoading,
4937
+ disabled: missingConfig || isHistoryLoading,
3603
4938
  className: cn(
3604
- "flex-1 bg-transparent text-sm text-foreground outline-none pr-2",
4939
+ "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
4940
  "placeholder:text-muted-foreground",
3606
4941
  "disabled:cursor-not-allowed disabled:opacity-50"
3607
- ),
3608
- autoComplete: "off"
4942
+ )
3609
4943
  }
3610
4944
  ),
3611
- /* @__PURE__ */ jsx26(
4945
+ /* @__PURE__ */ jsx27(
3612
4946
  SendButton,
3613
4947
  {
3614
4948
  disabled: isSendDisabled,
3615
4949
  isLoading: stream.isLoading,
4950
+ showStop: stream.isLoading && !trimmedDraft,
3616
4951
  onStop: () => stream.stop(),
3617
4952
  stopLabel: t("chat.stop"),
3618
4953
  sendLabel: t("chat.send")
@@ -3621,7 +4956,7 @@ function Chat({
3621
4956
  ]
3622
4957
  }
3623
4958
  ) }),
3624
- disclaimer?.text && /* @__PURE__ */ jsx26(
4959
+ disclaimer?.text && /* @__PURE__ */ jsx27(
3625
4960
  "p",
3626
4961
  {
3627
4962
  className: cn(
@@ -3631,9 +4966,9 @@ function Chat({
3631
4966
  children: disclaimer.text
3632
4967
  }
3633
4968
  ),
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" })
4969
+ /* @__PURE__ */ jsxs15("div", { className: "mt-2 flex items-center justify-center gap-2 text-xs text-muted-foreground", children: [
4970
+ /* @__PURE__ */ jsx27("span", { children: t("chat.poweredBy") }),
4971
+ /* @__PURE__ */ jsx27(ContextUsageIndicator, { className: "absolute right-4" })
3637
4972
  ] })
3638
4973
  ] })
3639
4974
  ]
@@ -3642,11 +4977,11 @@ function Chat({
3642
4977
  }
3643
4978
 
3644
4979
  // 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(
4980
+ import * as React22 from "react";
4981
+ import { jsx as jsx28 } from "react/jsx-runtime";
4982
+ var Input = React22.forwardRef(
3648
4983
  ({ className, type, ...props }, ref) => {
3649
- return /* @__PURE__ */ jsx27(
4984
+ return /* @__PURE__ */ jsx28(
3650
4985
  "input",
3651
4986
  {
3652
4987
  ref,
@@ -3663,10 +4998,10 @@ var Input = React21.forwardRef(
3663
4998
  Input.displayName = "Input";
3664
4999
 
3665
5000
  // 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(
5001
+ import * as React23 from "react";
5002
+ import { jsx as jsx29 } from "react/jsx-runtime";
5003
+ var Separator = React23.forwardRef(
5004
+ ({ className, orientation = "horizontal", ...props }, ref) => /* @__PURE__ */ jsx29(
3670
5005
  "div",
3671
5006
  {
3672
5007
  ref,